Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/dash/eval.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 22414 byte(s)
-updated to klibc-1.5.19
1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <stdlib.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39
40 /*
41 * Evaluate a command.
42 */
43
44 #include "shell.h"
45 #include "nodes.h"
46 #include "syntax.h"
47 #include "expand.h"
48 #include "parser.h"
49 #include "jobs.h"
50 #include "eval.h"
51 #include "builtins.h"
52 #include "options.h"
53 #include "exec.h"
54 #include "redir.h"
55 #include "input.h"
56 #include "output.h"
57 #include "trap.h"
58 #include "var.h"
59 #include "memalloc.h"
60 #include "error.h"
61 #include "show.h"
62 #include "mystring.h"
63 #ifndef SMALL
64 #include "myhistedit.h"
65 #endif
66
67
68 /* flags in argument to evaltree */
69 #define EV_EXIT 01 /* exit after evaluating tree */
70 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
71 #define EV_BACKCMD 04 /* command executing within back quotes */
72
73 int evalskip; /* set if we are skipping commands */
74 STATIC int skipcount; /* number of levels to skip */
75 MKINIT int loopnest; /* current loop nesting level */
76 static int funcnest; /* depth of function calls */
77
78
79 char *commandname;
80 struct strlist *cmdenviron;
81 int exitstatus; /* exit status of last command */
82 int back_exitstatus; /* exit status of backquoted command */
83
84
85 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
86 STATIC
87 #endif
88 void evaltreenr(union node *, int) __attribute__ ((__noreturn__));
89 STATIC void evalloop(union node *, int);
90 STATIC void evalfor(union node *, int);
91 STATIC void evalcase(union node *, int);
92 STATIC void evalsubshell(union node *, int);
93 STATIC void expredir(union node *);
94 STATIC void evalpipe(union node *, int);
95 #ifdef notyet
96 STATIC void evalcommand(union node *, int, struct backcmd *);
97 #else
98 STATIC void evalcommand(union node *, int);
99 #endif
100 STATIC int evalbltin(const struct builtincmd *, int, char **, int);
101 STATIC int evalfun(struct funcnode *, int, char **, int);
102 STATIC void prehash(union node *);
103 STATIC int eprintlist(struct output *, struct strlist *, int);
104 STATIC int bltincmd(int, char **);
105
106
107 STATIC const struct builtincmd bltin = {
108 name: nullstr,
109 builtin: bltincmd
110 };
111
112
113 /*
114 * Called to reset things after an exception.
115 */
116
117 #ifdef mkinit
118 INCLUDE "eval.h"
119
120 RESET {
121 evalskip = 0;
122 loopnest = 0;
123 }
124 #endif
125
126
127
128 /*
129 * The eval commmand.
130 */
131
132 static int evalcmd(int argc, char **argv, int flags)
133 {
134 char *p;
135 char *concat;
136 char **ap;
137
138 if (argc > 1) {
139 p = argv[1];
140 if (argc > 2) {
141 STARTSTACKSTR(concat);
142 ap = argv + 2;
143 for (;;) {
144 concat = stputs(p, concat);
145 if ((p = *ap++) == NULL)
146 break;
147 STPUTC(' ', concat);
148 }
149 STPUTC('\0', concat);
150 p = grabstackstr(concat);
151 }
152 return evalstring(p, flags & EV_TESTED);
153 }
154 return 0;
155 }
156
157
158 /*
159 * Execute a command or commands contained in a string.
160 */
161
162 int
163 evalstring(char *s, int flags)
164 {
165 union node *n;
166 struct stackmark smark;
167 int status;
168
169 setinputstring(s);
170 setstackmark(&smark);
171
172 status = 0;
173 while ((n = parsecmd(0)) != NEOF) {
174 evaltree(n, flags);
175 status = exitstatus;
176 popstackmark(&smark);
177 if (evalskip)
178 break;
179 }
180 popfile();
181
182 return status;
183 }
184
185
186
187 /*
188 * Evaluate a parse tree. The value is left in the global variable
189 * exitstatus.
190 */
191
192 void
193 evaltree(union node *n, int flags)
194 {
195 int checkexit = 0;
196 void (*evalfn)(union node *, int);
197 unsigned isor;
198 int status;
199 if (n == NULL) {
200 TRACE(("evaltree(NULL) called\n"));
201 goto out;
202 }
203 #ifndef SMALL
204 displayhist = 1; /* show history substitutions done with fc */
205 #endif
206 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
207 getpid(), n, n->type, flags));
208 switch (n->type) {
209 default:
210 #ifdef DEBUG
211 out1fmt("Node type = %d\n", n->type);
212 #ifndef USE_GLIBC_STDIO
213 flushout(out1);
214 #endif
215 break;
216 #endif
217 case NNOT:
218 evaltree(n->nnot.com, EV_TESTED);
219 status = !exitstatus;
220 goto setstatus;
221 case NREDIR:
222 expredir(n->nredir.redirect);
223 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
224 if (!status) {
225 evaltree(n->nredir.n, flags & EV_TESTED);
226 status = exitstatus;
227 }
228 popredir(0);
229 goto setstatus;
230 case NCMD:
231 #ifdef notyet
232 if (eflag && !(flags & EV_TESTED))
233 checkexit = ~0;
234 evalcommand(n, flags, (struct backcmd *)NULL);
235 break;
236 #else
237 evalfn = evalcommand;
238 checkexit:
239 if (eflag && !(flags & EV_TESTED))
240 checkexit = ~0;
241 goto calleval;
242 #endif
243 case NFOR:
244 evalfn = evalfor;
245 goto calleval;
246 case NWHILE:
247 case NUNTIL:
248 evalfn = evalloop;
249 goto calleval;
250 case NSUBSHELL:
251 case NBACKGND:
252 evalfn = evalsubshell;
253 goto calleval;
254 case NPIPE:
255 evalfn = evalpipe;
256 #ifdef notyet
257 if (eflag && !(flags & EV_TESTED))
258 checkexit = ~0;
259 goto calleval;
260 #else
261 goto checkexit;
262 #endif
263 case NCASE:
264 evalfn = evalcase;
265 goto calleval;
266 case NAND:
267 case NOR:
268 case NSEMI:
269 #if NAND + 1 != NOR
270 #error NAND + 1 != NOR
271 #endif
272 #if NOR + 1 != NSEMI
273 #error NOR + 1 != NSEMI
274 #endif
275 isor = n->type - NAND;
276 evaltree(
277 n->nbinary.ch1,
278 (flags | ((isor >> 1) - 1)) & EV_TESTED
279 );
280 if (!exitstatus == isor)
281 break;
282 if (!evalskip) {
283 n = n->nbinary.ch2;
284 evaln:
285 evalfn = evaltree;
286 calleval:
287 evalfn(n, flags);
288 break;
289 }
290 break;
291 case NIF:
292 evaltree(n->nif.test, EV_TESTED);
293 if (evalskip)
294 break;
295 if (exitstatus == 0) {
296 n = n->nif.ifpart;
297 goto evaln;
298 } else if (n->nif.elsepart) {
299 n = n->nif.elsepart;
300 goto evaln;
301 }
302 goto success;
303 case NDEFUN:
304 defun(n->narg.text, n->narg.next);
305 success:
306 status = 0;
307 setstatus:
308 exitstatus = status;
309 break;
310 }
311 out:
312 if ((checkexit & exitstatus) ||
313 (pendingsigs && dotrap()) ||
314 (flags & EV_EXIT))
315 exraise(EXEXIT);
316 }
317
318
319 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
320 STATIC
321 #endif
322 void evaltreenr(union node *n, int flags)
323 #ifdef HAVE_ATTRIBUTE_ALIAS
324 __attribute__ ((alias("evaltree")));
325 #else
326 {
327 evaltree(n, flags);
328 abort();
329 }
330 #endif
331
332
333 STATIC void
334 evalloop(union node *n, int flags)
335 {
336 int status;
337
338 loopnest++;
339 status = 0;
340 flags &= EV_TESTED;
341 for (;;) {
342 int i;
343
344 evaltree(n->nbinary.ch1, EV_TESTED);
345 if (evalskip) {
346 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
347 evalskip = 0;
348 continue;
349 }
350 if (evalskip == SKIPBREAK && --skipcount <= 0)
351 evalskip = 0;
352 break;
353 }
354 i = exitstatus;
355 if (n->type != NWHILE)
356 i = !i;
357 if (i != 0)
358 break;
359 evaltree(n->nbinary.ch2, flags);
360 status = exitstatus;
361 if (evalskip)
362 goto skipping;
363 }
364 loopnest--;
365 exitstatus = status;
366 }
367
368
369
370 STATIC void
371 evalfor(union node *n, int flags)
372 {
373 struct arglist arglist;
374 union node *argp;
375 struct strlist *sp;
376 struct stackmark smark;
377
378 setstackmark(&smark);
379 arglist.lastp = &arglist.list;
380 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
381 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
382 /* XXX */
383 if (evalskip)
384 goto out;
385 }
386 *arglist.lastp = NULL;
387
388 exitstatus = 0;
389 loopnest++;
390 flags &= EV_TESTED;
391 for (sp = arglist.list ; sp ; sp = sp->next) {
392 setvar(n->nfor.var, sp->text, 0);
393 evaltree(n->nfor.body, flags);
394 if (evalskip) {
395 if (evalskip == SKIPCONT && --skipcount <= 0) {
396 evalskip = 0;
397 continue;
398 }
399 if (evalskip == SKIPBREAK && --skipcount <= 0)
400 evalskip = 0;
401 break;
402 }
403 }
404 loopnest--;
405 out:
406 popstackmark(&smark);
407 }
408
409
410
411 STATIC void
412 evalcase(union node *n, int flags)
413 {
414 union node *cp;
415 union node *patp;
416 struct arglist arglist;
417 struct stackmark smark;
418
419 setstackmark(&smark);
420 arglist.lastp = &arglist.list;
421 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
422 exitstatus = 0;
423 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
424 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
425 if (casematch(patp, arglist.list->text)) {
426 if (evalskip == 0) {
427 evaltree(cp->nclist.body, flags);
428 }
429 goto out;
430 }
431 }
432 }
433 out:
434 popstackmark(&smark);
435 }
436
437
438
439 /*
440 * Kick off a subshell to evaluate a tree.
441 */
442
443 STATIC void
444 evalsubshell(union node *n, int flags)
445 {
446 struct job *jp;
447 int backgnd = (n->type == NBACKGND);
448 int status;
449
450 expredir(n->nredir.redirect);
451 if (!backgnd && flags & EV_EXIT && !trap[0])
452 goto nofork;
453 INTOFF;
454 jp = makejob(n, 1);
455 if (forkshell(jp, n, backgnd) == 0) {
456 INTON;
457 flags |= EV_EXIT;
458 if (backgnd)
459 flags &=~ EV_TESTED;
460 nofork:
461 redirect(n->nredir.redirect, 0);
462 evaltreenr(n->nredir.n, flags);
463 /* never returns */
464 }
465 status = 0;
466 if (! backgnd)
467 status = waitforjob(jp);
468 exitstatus = status;
469 INTON;
470 }
471
472
473
474 /*
475 * Compute the names of the files in a redirection list.
476 */
477
478 STATIC void
479 expredir(union node *n)
480 {
481 union node *redir;
482
483 for (redir = n ; redir ; redir = redir->nfile.next) {
484 struct arglist fn;
485 fn.lastp = &fn.list;
486 switch (redir->type) {
487 case NFROMTO:
488 case NFROM:
489 case NTO:
490 case NCLOBBER:
491 case NAPPEND:
492 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
493 redir->nfile.expfname = fn.list->text;
494 break;
495 case NFROMFD:
496 case NTOFD:
497 if (redir->ndup.vname) {
498 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
499 fixredir(redir, fn.list->text, 1);
500 }
501 break;
502 }
503 }
504 }
505
506
507
508 /*
509 * Evaluate a pipeline. All the processes in the pipeline are children
510 * of the process creating the pipeline. (This differs from some versions
511 * of the shell, which make the last process in a pipeline the parent
512 * of all the rest.)
513 */
514
515 STATIC void
516 evalpipe(union node *n, int flags)
517 {
518 struct job *jp;
519 struct nodelist *lp;
520 int pipelen;
521 int prevfd;
522 int pip[2];
523
524 TRACE(("evalpipe(0x%lx) called\n", (long)n));
525 pipelen = 0;
526 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
527 pipelen++;
528 flags |= EV_EXIT;
529 INTOFF;
530 jp = makejob(n, pipelen);
531 prevfd = -1;
532 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
533 prehash(lp->n);
534 pip[1] = -1;
535 if (lp->next) {
536 if (pipe(pip) < 0) {
537 close(prevfd);
538 sh_error("Pipe call failed");
539 }
540 }
541 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
542 INTON;
543 if (pip[1] >= 0) {
544 close(pip[0]);
545 }
546 if (prevfd > 0) {
547 dup2(prevfd, 0);
548 close(prevfd);
549 }
550 if (pip[1] > 1) {
551 dup2(pip[1], 1);
552 close(pip[1]);
553 }
554 evaltreenr(lp->n, flags);
555 /* never returns */
556 }
557 if (prevfd >= 0)
558 close(prevfd);
559 prevfd = pip[0];
560 close(pip[1]);
561 }
562 if (n->npipe.backgnd == 0) {
563 exitstatus = waitforjob(jp);
564 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
565 }
566 INTON;
567 }
568
569
570
571 /*
572 * Execute a command inside back quotes. If it's a builtin command, we
573 * want to save its output in a block obtained from malloc. Otherwise
574 * we fork off a subprocess and get the output of the command via a pipe.
575 * Should be called with interrupts off.
576 */
577
578 void
579 evalbackcmd(union node *n, struct backcmd *result)
580 {
581 result->fd = -1;
582 result->buf = NULL;
583 result->nleft = 0;
584 result->jp = NULL;
585 if (n == NULL) {
586 goto out;
587 }
588
589 #ifdef notyet
590 /*
591 * For now we disable executing builtins in the same
592 * context as the shell, because we are not keeping
593 * enough state to recover from changes that are
594 * supposed only to affect subshells. eg. echo "`cd /`"
595 */
596 if (n->type == NCMD) {
597 struct ifsregion saveifs;
598 struct ifsregion *savelastp;
599 struct nodelist *saveargbackq;
600
601 saveifs = ifsfirst;
602 savelastp = ifslastp;
603 saveargbackq = argbackq;
604
605 exitstatus = oexitstatus;
606 evalcommand(n, EV_BACKCMD, result);
607
608 ifsfirst = saveifs;
609 ifslastp = savelastp;
610 argbackq = saveargbackq;
611 } else
612 #endif
613 {
614 int pip[2];
615 struct job *jp;
616
617 if (pipe(pip) < 0)
618 sh_error("Pipe call failed");
619 jp = makejob(n, 1);
620 if (forkshell(jp, n, FORK_NOJOB) == 0) {
621 FORCEINTON;
622 close(pip[0]);
623 if (pip[1] != 1) {
624 dup2(pip[1], 1);
625 close(pip[1]);
626 }
627 eflag = 0;
628 evaltreenr(n, EV_EXIT);
629 /* NOTREACHED */
630 }
631 close(pip[1]);
632 result->fd = pip[0];
633 result->jp = jp;
634 }
635 out:
636 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
637 result->fd, result->buf, result->nleft, result->jp));
638 }
639
640 static char **
641 parse_command_args(char **argv, const char **path)
642 {
643 char *cp, c;
644
645 for (;;) {
646 cp = *++argv;
647 if (!cp)
648 return 0;
649 if (*cp++ != '-')
650 break;
651 if (!(c = *cp++))
652 break;
653 if (c == '-' && !*cp) {
654 argv++;
655 break;
656 }
657 do {
658 switch (c) {
659 case 'p':
660 *path = defpath;
661 break;
662 default:
663 /* run 'typecmd' for other options */
664 return 0;
665 }
666 } while ((c = *cp++));
667 }
668 return argv;
669 }
670
671
672
673 /*
674 * Execute a simple command.
675 */
676
677 STATIC void
678 #ifdef notyet
679 evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
680 #else
681 evalcommand(union node *cmd, int flags)
682 #endif
683 {
684 struct stackmark smark;
685 union node *argp;
686 struct arglist arglist;
687 struct arglist varlist;
688 char **argv;
689 int argc;
690 struct strlist *sp;
691 #ifdef notyet
692 int pip[2];
693 #endif
694 struct cmdentry cmdentry;
695 struct job *jp;
696 char *lastarg;
697 const char *path;
698 int spclbltin;
699 int execcmd;
700 int status;
701 char **nargv;
702
703 /* First expand the arguments. */
704 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
705 setstackmark(&smark);
706 back_exitstatus = 0;
707
708 cmdentry.cmdtype = CMDBUILTIN;
709 cmdentry.u.cmd = &bltin;
710 varlist.lastp = &varlist.list;
711 *varlist.lastp = NULL;
712 arglist.lastp = &arglist.list;
713 *arglist.lastp = NULL;
714
715 argc = 0;
716 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
717 struct strlist **spp;
718
719 spp = arglist.lastp;
720 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
721 for (sp = *spp; sp; sp = sp->next)
722 argc++;
723 }
724
725 /* Reserve one extra spot at the front for shellexec. */
726 nargv = stalloc(sizeof (char *) * (argc + 2));
727 argv = ++nargv;
728 for (sp = arglist.list ; sp ; sp = sp->next) {
729 TRACE(("evalcommand arg: %s\n", sp->text));
730 *nargv++ = sp->text;
731 }
732 *nargv = NULL;
733
734 lastarg = NULL;
735 if (iflag && funcnest == 0 && argc > 0)
736 lastarg = nargv[-1];
737
738 preverrout.fd = 2;
739 expredir(cmd->ncmd.redirect);
740 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
741
742 path = vpath.text;
743 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
744 struct strlist **spp;
745 char *p;
746
747 spp = varlist.lastp;
748 expandarg(argp, &varlist, EXP_VARTILDE);
749
750 /*
751 * Modify the command lookup path, if a PATH= assignment
752 * is present
753 */
754 p = (*spp)->text;
755 if (varequal(p, path))
756 path = p;
757 }
758
759 /* Print the command if xflag is set. */
760 if (xflag) {
761 struct output *out;
762 int sep;
763
764 out = &preverrout;
765 outstr(expandstr(ps4val()), out);
766 sep = 0;
767 sep = eprintlist(out, varlist.list, sep);
768 eprintlist(out, arglist.list, sep);
769 outcslow('\n', out);
770 #ifdef FLUSHERR
771 flushout(out);
772 #endif
773 }
774
775 execcmd = 0;
776 spclbltin = -1;
777
778 /* Now locate the command. */
779 if (argc) {
780 const char *oldpath;
781 int cmd_flag = DO_ERR;
782
783 path += 5;
784 oldpath = path;
785 for (;;) {
786 find_command(argv[0], &cmdentry, cmd_flag, path);
787 if (cmdentry.cmdtype == CMDUNKNOWN) {
788 status = 127;
789 #ifdef FLUSHERR
790 flushout(&errout);
791 #endif
792 goto bail;
793 }
794
795 /* implement bltin and command here */
796 if (cmdentry.cmdtype != CMDBUILTIN)
797 break;
798 if (spclbltin < 0)
799 spclbltin =
800 cmdentry.u.cmd->flags &
801 BUILTIN_SPECIAL
802 ;
803 if (cmdentry.u.cmd == EXECCMD)
804 execcmd++;
805 if (cmdentry.u.cmd != COMMANDCMD)
806 break;
807
808 path = oldpath;
809 nargv = parse_command_args(argv, &path);
810 if (!nargv)
811 break;
812 argc -= nargv - argv;
813 argv = nargv;
814 cmd_flag |= DO_NOFUNC;
815 }
816 }
817
818 if (status) {
819 /* We have a redirection error. */
820 if (spclbltin > 0)
821 exraise(EXERROR);
822 bail:
823 exitstatus = status;
824 goto out;
825 }
826
827 /* Execute the command. */
828 switch (cmdentry.cmdtype) {
829 default:
830 /* Fork off a child process if necessary. */
831 if (!(flags & EV_EXIT) || trap[0]) {
832 INTOFF;
833 jp = makejob(cmd, 1);
834 if (forkshell(jp, cmd, FORK_FG) != 0) {
835 exitstatus = waitforjob(jp);
836 INTON;
837 break;
838 }
839 FORCEINTON;
840 }
841 listsetvar(varlist.list, VEXPORT|VSTACK);
842 shellexec(argv, path, cmdentry.u.index);
843 /* NOTREACHED */
844
845 case CMDBUILTIN:
846 cmdenviron = varlist.list;
847 if (cmdenviron) {
848 struct strlist *list = cmdenviron;
849 int i = VNOSET;
850 if (spclbltin > 0 || argc == 0) {
851 i = 0;
852 if (execcmd && argc > 1)
853 i = VEXPORT;
854 }
855 listsetvar(list, i);
856 }
857 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
858 int status;
859 int i;
860
861 i = exception;
862 if (i == EXEXIT)
863 goto raise;
864
865 status = (i == EXINT) ? SIGINT + 128 : 2;
866 exitstatus = status;
867
868 if (i == EXINT || spclbltin > 0) {
869 raise:
870 longjmp(handler->loc, 1);
871 }
872 FORCEINTON;
873 }
874 break;
875
876 case CMDFUNCTION:
877 listsetvar(varlist.list, 0);
878 if (evalfun(cmdentry.u.func, argc, argv, flags))
879 goto raise;
880 break;
881 }
882
883 out:
884 popredir(execcmd);
885 if (lastarg)
886 /* dsl: I think this is intended to be used to support
887 * '_' in 'vi' command mode during line editing...
888 * However I implemented that within libedit itself.
889 */
890 setvar("_", lastarg, 0);
891 popstackmark(&smark);
892 }
893
894 STATIC int
895 evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
896 {
897 char *volatile savecmdname;
898 struct jmploc *volatile savehandler;
899 struct jmploc jmploc;
900 int status;
901 int i;
902
903 savecmdname = commandname;
904 if ((i = setjmp(jmploc.loc)))
905 goto cmddone;
906 savehandler = handler;
907 handler = &jmploc;
908 commandname = argv[0];
909 argptr = argv + 1;
910 optptr = NULL; /* initialize nextopt */
911 if (cmd == EVALCMD)
912 status = evalcmd(argc, argv, flags);
913 else
914 status = (*cmd->builtin)(argc, argv);
915 flushall();
916 status |= outerr(out1);
917 exitstatus = status;
918 cmddone:
919 freestdout();
920 commandname = savecmdname;
921 handler = savehandler;
922
923 return i;
924 }
925
926 STATIC int
927 evalfun(struct funcnode *func, int argc, char **argv, int flags)
928 {
929 volatile struct shparam saveparam;
930 struct localvar *volatile savelocalvars;
931 struct jmploc *volatile savehandler;
932 struct jmploc jmploc;
933 int e;
934
935 saveparam = shellparam;
936 savelocalvars = localvars;
937 if ((e = setjmp(jmploc.loc))) {
938 goto funcdone;
939 }
940 INTOFF;
941 savehandler = handler;
942 handler = &jmploc;
943 localvars = NULL;
944 shellparam.malloc = 0;
945 func->count++;
946 funcnest++;
947 INTON;
948 shellparam.nparam = argc - 1;
949 shellparam.p = argv + 1;
950 shellparam.optind = 1;
951 shellparam.optoff = -1;
952 evaltree(&func->n, flags & EV_TESTED);
953 funcdone:
954 INTOFF;
955 funcnest--;
956 freefunc(func);
957 poplocalvars();
958 localvars = savelocalvars;
959 freeparam(&shellparam);
960 shellparam = saveparam;
961 handler = savehandler;
962 INTON;
963 evalskip &= ~SKIPFUNC;
964 return e;
965 }
966
967
968 /*
969 * Search for a command. This is called before we fork so that the
970 * location of the command will be available in the parent as well as
971 * the child. The check for "goodname" is an overly conservative
972 * check that the name will not be subject to expansion.
973 */
974
975 STATIC void
976 prehash(union node *n)
977 {
978 struct cmdentry entry;
979
980 if (n->type == NCMD && n->ncmd.args)
981 if (goodname(n->ncmd.args->narg.text))
982 find_command(n->ncmd.args->narg.text, &entry, 0,
983 pathval());
984 }
985
986
987
988 /*
989 * Builtin commands. Builtin commands whose functions are closely
990 * tied to evaluation are implemented here.
991 */
992
993 /*
994 * No command given.
995 */
996
997 STATIC int
998 bltincmd(int argc, char **argv)
999 {
1000 /*
1001 * Preserve exitstatus of a previous possible redirection
1002 * as POSIX mandates
1003 */
1004 return back_exitstatus;
1005 }
1006
1007
1008 /*
1009 * Handle break and continue commands. Break, continue, and return are
1010 * all handled by setting the evalskip flag. The evaluation routines
1011 * above all check this flag, and if it is set they start skipping
1012 * commands rather than executing them. The variable skipcount is
1013 * the number of loops to break/continue, or the number of function
1014 * levels to return. (The latter is always 1.) It should probably
1015 * be an error to break out of more loops than exist, but it isn't
1016 * in the standard shell so we don't make it one here.
1017 */
1018
1019 int
1020 breakcmd(int argc, char **argv)
1021 {
1022 int n = argc > 1 ? number(argv[1]) : 1;
1023
1024 if (n <= 0)
1025 badnum(argv[1]);
1026 if (n > loopnest)
1027 n = loopnest;
1028 if (n > 0) {
1029 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
1030 skipcount = n;
1031 }
1032 return 0;
1033 }
1034
1035
1036 /*
1037 * The return command.
1038 */
1039
1040 int
1041 returncmd(int argc, char **argv)
1042 {
1043 /*
1044 * If called outside a function, do what ksh does;
1045 * skip the rest of the file.
1046 */
1047 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
1048 return argv[1] ? number(argv[1]) : exitstatus;
1049 }
1050
1051
1052 int
1053 falsecmd(int argc, char **argv)
1054 {
1055 return 1;
1056 }
1057
1058
1059 int
1060 truecmd(int argc, char **argv)
1061 {
1062 return 0;
1063 }
1064
1065
1066 int
1067 execcmd(int argc, char **argv)
1068 {
1069 if (argc > 1) {
1070 iflag = 0; /* exit on error */
1071 mflag = 0;
1072 optschanged();
1073 shellexec(argv + 1, pathval(), 0);
1074 }
1075 return 0;
1076 }
1077
1078
1079 STATIC int
1080 eprintlist(struct output *out, struct strlist *sp, int sep)
1081 {
1082 while (sp) {
1083 const char *p;
1084
1085 p = " %s" + (1 - sep);
1086 sep |= 1;
1087 outfmt(out, p, sp->text);
1088 sp = sp->next;
1089 }
1090
1091 return sep;
1092 }