1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 06/08/95";
13 #endif /* not lint */
14
15 #include <signal.h>
16 #include <unistd.h>
17
18 /*
19 * Evaluate a command.
20 */
21
22 #include "shell.h"
23 #include "nodes.h"
24 #include "syntax.h"
25 #include "expand.h"
26 #include "parser.h"
27 #include "jobs.h"
28 #include "eval.h"
29 #include "builtins.h"
30 #include "options.h"
31 #include "exec.h"
32 #include "redir.h"
33 #include "input.h"
34 #include "output.h"
35 #include "trap.h"
36 #include "var.h"
37 #include "memalloc.h"
38 #include "error.h"
39 #include "show.h"
40 #include "mystring.h"
41 #ifndef NO_HISTORY
42 #include "myhistedit.h"
43 #endif
44
45
46 /* flags in argument to evaltree */
47 #define EV_EXIT 01 /* exit after evaluating tree */
48 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
49 #define EV_BACKCMD 04 /* command executing within back quotes */
50
51
52 /* reasons for skipping commands (see comment on breakcmd routine) */
53 #define SKIPBREAK 1
54 #define SKIPCONT 2
55 #define SKIPFUNC 3
56
57 MKINIT int evalskip; /* set if we are skipping commands */
58 STATIC int skipcount; /* number of levels to skip */
59 MKINIT int loopnest; /* current loop nesting level */
60 int funcnest; /* depth of function calls */
61
62
63 char *commandname;
64 struct strlist *cmdenviron;
65 int exitstatus; /* exit status of last command */
66 int oexitstatus; /* saved exit status */
67
68
69 STATIC void evalloop __P((union node *));
70 STATIC void evalfor __P((union node *));
71 STATIC void evalcase __P((union node *, int));
72 STATIC void evalsubshell __P((union node *, int));
73 STATIC void expredir __P((union node *));
74 STATIC void evalpipe __P((union node *));
75 STATIC void evalcommand __P((union node *, int, struct backcmd *));
76 STATIC void prehash __P((union node *));
77
78
79 /*
80 * Called to reset things after an exception.
81 */
82
83 #ifdef mkinit
84 INCLUDE "eval.h"
85
86 RESET {
87 evalskip = 0;
88 loopnest = 0;
89 funcnest = 0;
90 }
91
92 SHELLPROC {
93 exitstatus = 0;
94 }
95 #endif
96
97
98
99 /*
100 * The eval commmand.
101 */
102
103 int
evalcmd(argc,argv)104 evalcmd(argc, argv)
105 int argc;
106 char **argv;
107 {
108 char *p;
109 char *concat;
110 char **ap;
111
112 if (argc > 1) {
113 p = argv[1];
114 if (argc > 2) {
115 STARTSTACKSTR(concat);
116 ap = argv + 2;
117 for (;;) {
118 while (*p)
119 STPUTC(*p++, concat);
120 if ((p = *ap++) == NULL)
121 break;
122 STPUTC(' ', concat);
123 }
124 STPUTC('\0', concat);
125 p = grabstackstr(concat);
126 }
127 evalstring(p);
128 }
129 return exitstatus;
130 }
131
132
133 /*
134 * Execute a command or commands contained in a string.
135 */
136
137 void
evalstring(s)138 evalstring(s)
139 char *s;
140 {
141 union node *n;
142 struct stackmark smark;
143
144 setstackmark(&smark);
145 setinputstring(s, 1);
146 while ((n = parsecmd(0)) != NEOF) {
147 evaltree(n, 0);
148 popstackmark(&smark);
149 }
150 popfile();
151 popstackmark(&smark);
152 }
153
154
155
156 /*
157 * Evaluate a parse tree. The value is left in the global variable
158 * exitstatus.
159 */
160
161 void
evaltree(n,flags)162 evaltree(n, flags)
163 union node *n;
164 int flags;
165 {
166 if (n == NULL) {
167 TRACE(("evaltree(NULL) called\n"));
168 exitstatus = 0;
169 goto out;
170 }
171 #ifndef NO_HISTORY
172 displayhist = 1; /* show history substitutions done with fc */
173 #endif
174 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
175 switch (n->type) {
176 case NSEMI:
177 evaltree(n->nbinary.ch1, 0);
178 if (evalskip)
179 goto out;
180 evaltree(n->nbinary.ch2, flags);
181 break;
182 case NAND:
183 evaltree(n->nbinary.ch1, EV_TESTED);
184 if (evalskip || exitstatus != 0)
185 goto out;
186 evaltree(n->nbinary.ch2, flags);
187 break;
188 case NOR:
189 evaltree(n->nbinary.ch1, EV_TESTED);
190 if (evalskip || exitstatus == 0)
191 goto out;
192 evaltree(n->nbinary.ch2, flags);
193 break;
194 case NREDIR:
195 expredir(n->nredir.redirect);
196 redirect(n->nredir.redirect, REDIR_PUSH);
197 evaltree(n->nredir.n, flags);
198 popredir();
199 break;
200 case NSUBSHELL:
201 evalsubshell(n, flags);
202 break;
203 case NBACKGND:
204 evalsubshell(n, flags);
205 break;
206 case NIF: {
207 int status;
208
209 evaltree(n->nif.test, EV_TESTED);
210 status = exitstatus;
211 exitstatus = 0;
212 if (evalskip)
213 goto out;
214 if (status == 0)
215 evaltree(n->nif.ifpart, flags);
216 else if (n->nif.elsepart)
217 evaltree(n->nif.elsepart, flags);
218 break;
219 }
220 case NWHILE:
221 case NUNTIL:
222 evalloop(n);
223 break;
224 case NFOR:
225 evalfor(n);
226 break;
227 case NCASE:
228 evalcase(n, flags);
229 break;
230 case NDEFUN:
231 defun(n->narg.text, n->narg.next);
232 exitstatus = 0;
233 break;
234 case NNOT:
235 evaltree(n->nnot.com, EV_TESTED);
236 exitstatus = !exitstatus;
237 break;
238
239 case NPIPE:
240 evalpipe(n);
241 break;
242 case NCMD:
243 evalcommand(n, flags, (struct backcmd *)NULL);
244 break;
245 default:
246 out1fmt("Node type = %d\n", n->type);
247 flushout(&output);
248 break;
249 }
250 out:
251 if (pendingsigs)
252 dotrap();
253 if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED)))
254 exitshell(exitstatus);
255 }
256
257
258 STATIC void
evalloop(n)259 evalloop(n)
260 union node *n;
261 {
262 int status;
263
264 loopnest++;
265 status = 0;
266 for (;;) {
267 evaltree(n->nbinary.ch1, EV_TESTED);
268 if (evalskip) {
269 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
270 evalskip = 0;
271 continue;
272 }
273 if (evalskip == SKIPBREAK && --skipcount <= 0)
274 evalskip = 0;
275 break;
276 }
277 if (n->type == NWHILE) {
278 if (exitstatus != 0)
279 break;
280 } else {
281 if (exitstatus == 0)
282 break;
283 }
284 evaltree(n->nbinary.ch2, 0);
285 status = exitstatus;
286 if (evalskip)
287 goto skipping;
288 }
289 loopnest--;
290 exitstatus = status;
291 }
292
293
294
295 STATIC void
evalfor(n)296 evalfor(n)
297 union node *n;
298 {
299 struct arglist arglist;
300 union node *argp;
301 struct strlist *sp;
302 struct stackmark smark;
303
304 setstackmark(&smark);
305 arglist.lastp = &arglist.list;
306 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
307 oexitstatus = exitstatus;
308 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
309 if (evalskip)
310 goto out;
311 }
312 *arglist.lastp = NULL;
313
314 exitstatus = 0;
315 loopnest++;
316 for (sp = arglist.list ; sp ; sp = sp->next) {
317 setvar(n->nfor.var, sp->text, 0);
318 evaltree(n->nfor.body, 0);
319 if (evalskip) {
320 if (evalskip == SKIPCONT && --skipcount <= 0) {
321 evalskip = 0;
322 continue;
323 }
324 if (evalskip == SKIPBREAK && --skipcount <= 0)
325 evalskip = 0;
326 break;
327 }
328 }
329 loopnest--;
330 out:
331 popstackmark(&smark);
332 }
333
334
335
336 STATIC void
evalcase(n,flags)337 evalcase(n, flags)
338 union node *n;
339 int flags;
340 {
341 union node *cp;
342 union node *patp;
343 struct arglist arglist;
344 struct stackmark smark;
345
346 setstackmark(&smark);
347 arglist.lastp = &arglist.list;
348 oexitstatus = exitstatus;
349 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
350 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
351 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
352 if (casematch(patp, arglist.list->text)) {
353 if (evalskip == 0) {
354 evaltree(cp->nclist.body, flags);
355 }
356 goto out;
357 }
358 }
359 }
360 out:
361 popstackmark(&smark);
362 }
363
364
365
366 /*
367 * Kick off a subshell to evaluate a tree.
368 */
369
370 STATIC void
evalsubshell(n,flags)371 evalsubshell(n, flags)
372 union node *n;
373 int flags;
374 {
375 struct job *jp;
376 int backgnd = (n->type == NBACKGND);
377
378 expredir(n->nredir.redirect);
379 jp = makejob(n, 1);
380 if (forkshell(jp, n, backgnd) == 0) {
381 if (backgnd)
382 flags &=~ EV_TESTED;
383 redirect(n->nredir.redirect, 0);
384 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
385 }
386 if (! backgnd) {
387 INTOFF;
388 exitstatus = waitforjob(jp);
389 INTON;
390 }
391 }
392
393
394
395 /*
396 * Compute the names of the files in a redirection list.
397 */
398
399 STATIC void
expredir(n)400 expredir(n)
401 union node *n;
402 {
403 register union node *redir;
404
405 for (redir = n ; redir ; redir = redir->nfile.next) {
406 struct arglist fn;
407 fn.lastp = &fn.list;
408 oexitstatus = exitstatus;
409 switch (redir->type) {
410 case NFROM:
411 case NTO:
412 case NAPPEND:
413 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
414 redir->nfile.expfname = fn.list->text;
415 break;
416 case NFROMFD:
417 case NTOFD:
418 if (redir->ndup.vname) {
419 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
420 fixredir(redir, fn.list->text, 1);
421 }
422 break;
423 }
424 }
425 }
426
427
428
429 /*
430 * Evaluate a pipeline. All the processes in the pipeline are children
431 * of the process creating the pipeline. (This differs from some versions
432 * of the shell, which make the last process in a pipeline the parent
433 * of all the rest.)
434 */
435
436 STATIC void
evalpipe(n)437 evalpipe(n)
438 union node *n;
439 {
440 struct job *jp;
441 struct nodelist *lp;
442 int pipelen;
443 int prevfd;
444 int pip[2];
445
446 TRACE(("evalpipe(0x%lx) called\n", (long)n));
447 pipelen = 0;
448 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
449 pipelen++;
450 INTOFF;
451 jp = makejob(n, pipelen);
452 prevfd = -1;
453 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
454 prehash(lp->n);
455 pip[1] = -1;
456 if (lp->next) {
457 if (pipe(pip) < 0) {
458 close(prevfd);
459 error("Pipe call failed");
460 }
461 }
462 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
463 INTON;
464 if (prevfd > 0) {
465 close(0);
466 copyfd(prevfd, 0);
467 close(prevfd);
468 }
469 if (pip[1] >= 0) {
470 close(pip[0]);
471 if (pip[1] != 1) {
472 close(1);
473 copyfd(pip[1], 1);
474 close(pip[1]);
475 }
476 }
477 evaltree(lp->n, EV_EXIT);
478 }
479 if (prevfd >= 0)
480 close(prevfd);
481 prevfd = pip[0];
482 close(pip[1]);
483 }
484 INTON;
485 if (n->npipe.backgnd == 0) {
486 INTOFF;
487 exitstatus = waitforjob(jp);
488 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
489 INTON;
490 }
491 }
492
493
494
495 /*
496 * Execute a command inside back quotes. If it's a builtin command, we
497 * want to save its output in a block obtained from malloc. Otherwise
498 * we fork off a subprocess and get the output of the command via a pipe.
499 * Should be called with interrupts off.
500 */
501
502 void
evalbackcmd(n,result)503 evalbackcmd(n, result)
504 union node *n;
505 struct backcmd *result;
506 {
507 int pip[2];
508 struct job *jp;
509 struct stackmark smark; /* unnecessary */
510
511 setstackmark(&smark);
512 result->fd = -1;
513 result->buf = NULL;
514 result->nleft = 0;
515 result->jp = NULL;
516 if (n == NULL) {
517 exitstatus = 0;
518 goto out;
519 }
520 if (n->type == NCMD) {
521 exitstatus = oexitstatus;
522 evalcommand(n, EV_BACKCMD, result);
523 } else {
524 exitstatus = 0;
525 if (pipe(pip) < 0)
526 error("Pipe call failed");
527 jp = makejob(n, 1);
528 if (forkshell(jp, n, FORK_NOJOB) == 0) {
529 FORCEINTON;
530 close(pip[0]);
531 if (pip[1] != 1) {
532 close(1);
533 copyfd(pip[1], 1);
534 close(pip[1]);
535 }
536 evaltree(n, EV_EXIT);
537 }
538 close(pip[1]);
539 result->fd = pip[0];
540 result->jp = jp;
541 }
542 out:
543 popstackmark(&smark);
544 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
545 result->fd, result->buf, result->nleft, result->jp));
546 }
547
548
549
550 /*
551 * Execute a simple command.
552 */
553
554 STATIC void
evalcommand(cmd,flags,backcmd)555 evalcommand(cmd, flags, backcmd)
556 union node *cmd;
557 int flags;
558 struct backcmd *backcmd;
559 {
560 struct stackmark smark;
561 union node *argp;
562 struct arglist arglist;
563 struct arglist varlist;
564 char **argv;
565 int argc;
566 char **envp;
567 int varflag;
568 struct strlist *sp;
569 int mode;
570 int pip[2];
571 struct cmdentry cmdentry;
572 struct job *jp;
573 struct jmploc jmploc;
574 struct jmploc *volatile savehandler;
575 char *volatile savecmdname;
576 volatile struct shparam saveparam;
577 struct localvar *volatile savelocalvars;
578 volatile int e;
579 char *lastarg;
580 #if __GNUC__
581 /* Avoid longjmp clobbering */
582 (void) &argv;
583 (void) &argc;
584 (void) &lastarg;
585 (void) &flags;
586 #endif
587
588 /* First expand the arguments. */
589 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
590 setstackmark(&smark);
591 arglist.lastp = &arglist.list;
592 varlist.lastp = &varlist.list;
593 varflag = 1;
594 oexitstatus = exitstatus;
595 exitstatus = 0;
596 for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
597 char *p = argp->narg.text;
598 if (varflag && is_name(*p)) {
599 do {
600 p++;
601 } while (is_in_name(*p));
602 if (*p == '=') {
603 expandarg(argp, &varlist, EXP_VARTILDE);
604 continue;
605 }
606 }
607 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
608 varflag = 0;
609 }
610 *arglist.lastp = NULL;
611 *varlist.lastp = NULL;
612 expredir(cmd->ncmd.redirect);
613 argc = 0;
614 for (sp = arglist.list ; sp ; sp = sp->next)
615 argc++;
616 argv = stalloc(sizeof (char *) * (argc + 1));
617
618 for (sp = arglist.list ; sp ; sp = sp->next) {
619 TRACE(("evalcommand arg: %s\n", sp->text));
620 *argv++ = sp->text;
621 }
622 *argv = NULL;
623 lastarg = NULL;
624 if (iflag && funcnest == 0 && argc > 0)
625 lastarg = argv[-1];
626 argv -= argc;
627
628 /* Print the command if xflag is set. */
629 if (xflag) {
630 outc('+', &errout);
631 for (sp = varlist.list ; sp ; sp = sp->next) {
632 outc(' ', &errout);
633 out2str(sp->text);
634 }
635 for (sp = arglist.list ; sp ; sp = sp->next) {
636 outc(' ', &errout);
637 out2str(sp->text);
638 }
639 outc('\n', &errout);
640 flushout(&errout);
641 }
642
643 /* Now locate the command. */
644 if (argc == 0) {
645 cmdentry.cmdtype = CMDBUILTIN;
646 cmdentry.u.index = BLTINCMD;
647 } else {
648 static const char PATH[] = "PATH=";
649 char *path = pathval();
650
651 /*
652 * Modify the command lookup path, if a PATH= assignment
653 * is present
654 */
655 for (sp = varlist.list ; sp ; sp = sp->next)
656 if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0)
657 path = sp->text + sizeof(PATH) - 1;
658
659 find_command(argv[0], &cmdentry, 1, path);
660 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
661 exitstatus = 1;
662 flushout(&errout);
663 return;
664 }
665 /* implement the bltin builtin here */
666 if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) {
667 for (;;) {
668 argv++;
669 if (--argc == 0)
670 break;
671 if ((cmdentry.u.index = find_builtin(*argv)) < 0) {
672 outfmt(&errout, "%s: not found\n", *argv);
673 exitstatus = 1;
674 flushout(&errout);
675 return;
676 }
677 if (cmdentry.u.index != BLTINCMD)
678 break;
679 }
680 }
681 }
682
683 /* Fork off a child process if necessary. */
684 if (cmd->ncmd.backgnd
685 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
686 || ((flags & EV_BACKCMD) != 0
687 && (cmdentry.cmdtype != CMDBUILTIN
688 || cmdentry.u.index == DOTCMD
689 || cmdentry.u.index == EVALCMD))) {
690 jp = makejob(cmd, 1);
691 mode = cmd->ncmd.backgnd;
692 if (flags & EV_BACKCMD) {
693 mode = FORK_NOJOB;
694 if (pipe(pip) < 0)
695 error("Pipe call failed");
696 }
697 if (forkshell(jp, cmd, mode) != 0)
698 goto parent; /* at end of routine */
699 if (flags & EV_BACKCMD) {
700 FORCEINTON;
701 close(pip[0]);
702 if (pip[1] != 1) {
703 close(1);
704 copyfd(pip[1], 1);
705 close(pip[1]);
706 }
707 }
708 flags |= EV_EXIT;
709 }
710
711 /* This is the child process if a fork occurred. */
712 /* Execute the command. */
713 if (cmdentry.cmdtype == CMDFUNCTION) {
714 trputs("Shell function: "); trargs(argv);
715 redirect(cmd->ncmd.redirect, REDIR_PUSH);
716 saveparam = shellparam;
717 shellparam.malloc = 0;
718 shellparam.nparam = argc - 1;
719 shellparam.p = argv + 1;
720 shellparam.optnext = NULL;
721 INTOFF;
722 savelocalvars = localvars;
723 localvars = NULL;
724 INTON;
725 if (setjmp(jmploc.loc)) {
726 if (exception == EXSHELLPROC)
727 freeparam((struct shparam *)&saveparam);
728 else {
729 freeparam(&shellparam);
730 shellparam = saveparam;
731 }
732 poplocalvars();
733 localvars = savelocalvars;
734 handler = savehandler;
735 longjmp(handler->loc, 1);
736 }
737 savehandler = handler;
738 handler = &jmploc;
739 for (sp = varlist.list ; sp ; sp = sp->next)
740 mklocal(sp->text);
741 funcnest++;
742 evaltree(cmdentry.u.func, 0);
743 funcnest--;
744 INTOFF;
745 poplocalvars();
746 localvars = savelocalvars;
747 freeparam(&shellparam);
748 shellparam = saveparam;
749 handler = savehandler;
750 popredir();
751 INTON;
752 if (evalskip == SKIPFUNC) {
753 evalskip = 0;
754 skipcount = 0;
755 }
756 if (flags & EV_EXIT)
757 exitshell(exitstatus);
758 } else if (cmdentry.cmdtype == CMDBUILTIN) {
759 trputs("builtin command: "); trargs(argv);
760 mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
761 if (flags == EV_BACKCMD) {
762 memout.nleft = 0;
763 memout.nextc = memout.buf;
764 memout.bufsize = 64;
765 mode |= REDIR_BACKQ;
766 }
767 redirect(cmd->ncmd.redirect, mode);
768 savecmdname = commandname;
769 cmdenviron = varlist.list;
770 e = -1;
771 if (setjmp(jmploc.loc)) {
772 e = exception;
773 exitstatus = (e == EXINT)? SIGINT+128 : 2;
774 goto cmddone;
775 }
776 savehandler = handler;
777 handler = &jmploc;
778 commandname = argv[0];
779 argptr = argv + 1;
780 optptr = NULL; /* initialize nextopt */
781 exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
782 flushall();
783 cmddone:
784 out1 = &output;
785 out2 = &errout;
786 freestdout();
787 if (e != EXSHELLPROC) {
788 commandname = savecmdname;
789 if (flags & EV_EXIT) {
790 exitshell(exitstatus);
791 }
792 }
793 handler = savehandler;
794 if (e != -1) {
795 if (e != EXERROR || cmdentry.u.index == BLTINCMD
796 || cmdentry.u.index == DOTCMD
797 || cmdentry.u.index == EVALCMD
798 #ifndef NO_HISTORY
799 || cmdentry.u.index == HISTCMD
800 #endif
801 || cmdentry.u.index == EXECCMD)
802 exraise(e);
803 FORCEINTON;
804 }
805 if (cmdentry.u.index != EXECCMD)
806 popredir();
807 if (flags == EV_BACKCMD) {
808 backcmd->buf = memout.buf;
809 backcmd->nleft = memout.nextc - memout.buf;
810 memout.buf = NULL;
811 }
812 } else {
813 trputs("normal command: "); trargs(argv);
814 clearredir();
815 redirect(cmd->ncmd.redirect, 0);
816 for (sp = varlist.list ; sp ; sp = sp->next)
817 setvareq(sp->text, VEXPORT|VSTACK);
818 envp = environment();
819 shellexec(argv, envp, pathval(), cmdentry.u.index);
820 /*NOTREACHED*/
821 }
822 goto out;
823
824 parent: /* parent process gets here (if we forked) */
825 if (mode == 0) { /* argument to fork */
826 INTOFF;
827 exitstatus = waitforjob(jp);
828 INTON;
829 } else if (mode == 2) {
830 backcmd->fd = pip[0];
831 close(pip[1]);
832 backcmd->jp = jp;
833 }
834
835 out:
836 if (lastarg)
837 setvar("_", lastarg, 0);
838 popstackmark(&smark);
839 }
840
841
842
843 /*
844 * Search for a command. This is called before we fork so that the
845 * location of the command will be available in the parent as well as
846 * the child. The check for "goodname" is an overly conservative
847 * check that the name will not be subject to expansion.
848 */
849
850 STATIC void
prehash(n)851 prehash(n)
852 union node *n;
853 {
854 struct cmdentry entry;
855
856 if (n->type == NCMD && n->ncmd.args)
857 if (goodname(n->ncmd.args->narg.text))
858 find_command(n->ncmd.args->narg.text, &entry, 0,
859 pathval());
860 }
861
862
863
864 /*
865 * Builtin commands. Builtin commands whose functions are closely
866 * tied to evaluation are implemented here.
867 */
868
869 /*
870 * No command given, or a bltin command with no arguments. Set the
871 * specified variables.
872 */
873
874 int
bltincmd(argc,argv)875 bltincmd(argc, argv)
876 int argc;
877 char **argv;
878 {
879 listsetvar(cmdenviron);
880 /*
881 * Preserve exitstatus of a previous possible redirection
882 * as POSIX mandates
883 */
884 return exitstatus;
885 }
886
887
888 /*
889 * Handle break and continue commands. Break, continue, and return are
890 * all handled by setting the evalskip flag. The evaluation routines
891 * above all check this flag, and if it is set they start skipping
892 * commands rather than executing them. The variable skipcount is
893 * the number of loops to break/continue, or the number of function
894 * levels to return. (The latter is always 1.) It should probably
895 * be an error to break out of more loops than exist, but it isn't
896 * in the standard shell so we don't make it one here.
897 */
898
899 int
breakcmd(argc,argv)900 breakcmd(argc, argv)
901 int argc;
902 char **argv;
903 {
904 int n;
905
906 n = 1;
907 if (argc > 1)
908 n = number(argv[1]);
909 if (n > loopnest)
910 n = loopnest;
911 if (n > 0) {
912 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
913 skipcount = n;
914 }
915 return 0;
916 }
917
918
919 /*
920 * The return command.
921 */
922
923 int
returncmd(argc,argv)924 returncmd(argc, argv)
925 int argc;
926 char **argv;
927 {
928 int ret;
929
930 ret = exitstatus;
931 if (argc > 1)
932 ret = number(argv[1]);
933 if (funcnest) {
934 evalskip = SKIPFUNC;
935 skipcount = 1;
936 }
937 return ret;
938 }
939
940
941 int
falsecmd(argc,argv)942 falsecmd(argc, argv)
943 int argc;
944 char **argv;
945 {
946 return 1;
947 }
948
949
950 int
truecmd(argc,argv)951 truecmd(argc, argv)
952 int argc;
953 char **argv;
954 {
955 return 0;
956 }
957
958
959 int
execcmd(argc,argv)960 execcmd(argc, argv)
961 int argc;
962 char **argv;
963 {
964 if (argc > 1) {
965 struct strlist *sp;
966
967 iflag = 0; /* exit on error */
968 mflag = 0;
969 optschanged();
970 for (sp = cmdenviron; sp ; sp = sp->next)
971 setvareq(sp->text, VEXPORT|VSTACK);
972 shellexec(argv + 1, environment(), pathval(), 0);
973
974 }
975 return 0;
976 }
977