90725a1780f430e49058770c97bd77e4373e851a
[oweals/busybox.git] / shell / ash.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * ash shell port for busybox
4  *
5  * Copyright (c) 1989, 1991, 1993, 1994
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Kenneth Almquist.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24  *
25  * This version of ash is adapted from the source in Debian's ash 0.3.8-5 
26  * package.  
27  *
28  * Modified by Erik Andersen <andersee@debian.org> to be used in
29  * busybox, based in part on prior work done by Vladimir Oleynik
30  * <vodz@usa.net>
31  *
32  * Original copyright notice is retained at the end of this file.
33  */
34
35 #undef _GNU_SOURCE
36 #undef ASH_TYPE
37 #undef ASH_GETOPTS
38 #undef ASH_MATH_SUPPORT
39 #undef FNMATCH_BROKEN
40 #undef GLOB_BROKEN
41
42 #include <assert.h>
43 #include <ctype.h>
44 #include <dirent.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <limits.h>
48 #include <paths.h>
49 #include <pwd.h>
50 #include <setjmp.h>
51 #include <signal.h>
52 #include <stdarg.h>
53 #include <stdbool.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <sysexits.h>
58 #include <unistd.h>
59 #include <sys/stat.h>
60 #include <sys/cdefs.h>
61 #include <sys/ioctl.h>
62 #include <sys/param.h>
63 #include <sys/resource.h>
64 #include <sys/time.h>
65 #include <sys/times.h>
66 #include <sys/types.h>
67 #include <sys/wait.h>
68
69
70 #if !defined(FNMATCH_BROKEN)
71 #include <fnmatch.h>
72 #endif
73 #if !defined(GLOB_BROKEN)
74 #include <glob.h>
75 #endif
76
77 #if JOBS
78 #include <termios.h>
79 #undef CEOF                     /* syntax.h redefines this */
80 #endif
81
82 #include "cmdedit.h"
83 #include "busybox.h"
84 #include "ash.h"
85
86
87 #define _DIAGASSERT(x)
88
89 #define ATABSIZE 39
90
91 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
92 #define S_CATCH 2               /* signal is caught */
93 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
94 #define S_HARD_IGN 4            /* signal is ignored permenantly */
95 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
96
97
98
99 struct alias *atab[ATABSIZE];
100
101 static void setalias __P((char *, char *));
102 static struct alias **hashalias __P((const char *));
103 static struct alias *freealias __P((struct alias *));
104 static struct alias **__lookupalias __P((const char *));
105 static char *trap[NSIG];                /* trap handler commands */
106 static char sigmode[NSIG - 1];  /* current value of signal */
107 static char gotsig[NSIG - 1];           /* indicates specified signal received */
108 static int pendingsigs;                 /* indicates some signal received */
109
110
111 static void
112 setalias(name, val)
113         char *name, *val;
114 {
115         struct alias *ap, **app;
116
117         app = __lookupalias(name);
118         ap = *app;
119         INTOFF;
120         if (ap) {
121                 if (!(ap->flag & ALIASINUSE)) {
122                         ckfree(ap->val);
123                 }
124                 ap->val = savestr(val);
125                 ap->flag &= ~ALIASDEAD;
126         } else {
127                 /* not found */
128                 ap = ckmalloc(sizeof (struct alias));
129                 ap->name = savestr(name);
130                 ap->val = savestr(val);
131                 ap->flag = 0;
132                 ap->next = 0;
133                 *app = ap;
134         }
135         INTON;
136 }
137
138 static int
139 unalias(name)
140         char *name;
141         {
142         struct alias **app;
143
144         app = __lookupalias(name);
145
146         if (*app) {
147                 INTOFF;
148                 *app = freealias(*app);
149                 INTON;
150                 return (0);
151         }
152
153         return (1);
154 }
155
156 #ifdef mkinit
157 static void rmaliases __P((void));
158
159 SHELLPROC {
160         rmaliases();
161 }
162 #endif
163
164 static void
165 rmaliases() {
166         struct alias *ap, **app;
167         int i;
168
169         INTOFF;
170         for (i = 0; i < ATABSIZE; i++) {
171                 app = &atab[i];
172                 for (ap = *app; ap; ap = *app) {
173                         *app = freealias(*app);
174                         if (ap == *app) {
175                                 app = &ap->next;
176                         }
177                 }
178         }
179         INTON;
180 }
181
182 struct alias *
183 lookupalias(name, check)
184         const char *name;
185         int check;
186 {
187         struct alias *ap = *__lookupalias(name);
188
189         if (check && ap && (ap->flag & ALIASINUSE))
190                 return (NULL);
191         return (ap);
192 }
193
194
195 /*
196  * TODO - sort output
197  */
198 static int
199 aliascmd(argc, argv)
200         int argc;
201         char **argv;
202 {
203         char *n, *v;
204         int ret = 0;
205         struct alias *ap;
206
207         if (argc == 1) {
208                 int i;
209
210                 for (i = 0; i < ATABSIZE; i++)
211                         for (ap = atab[i]; ap; ap = ap->next) {
212                                 printalias(ap);
213                         }
214                 return (0);
215         }
216         while ((n = *++argv) != NULL) {
217                 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
218                         if ((ap = *__lookupalias(n)) == NULL) {
219                                 outfmt(out2, "%s: %s not found\n", "alias", n);
220                                 ret = 1;
221                         } else
222                                 printalias(ap);
223                 }
224                 else {
225                         *v++ = '\0';
226                         setalias(n, v);
227                 }
228         }
229
230         return (ret);
231 }
232
233 static int
234 unaliascmd(argc, argv)
235         int argc;
236         char **argv;
237 {
238         int i;
239
240         while ((i = nextopt("a")) != '\0') {
241                 if (i == 'a') {
242                         rmaliases();
243                         return (0);
244                 }
245         }
246         for (i = 0; *argptr; argptr++) {
247                 if (unalias(*argptr)) {
248                         outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
249                         i = 1;
250                 }
251         }
252
253         return (i);
254 }
255
256 static struct alias **
257 hashalias(p)
258         const char *p;
259         {
260         unsigned int hashval;
261
262         hashval = *p << 4;
263         while (*p)
264                 hashval+= *p++;
265         return &atab[hashval % ATABSIZE];
266 }
267
268 static struct alias *
269 freealias(struct alias *ap) {
270         struct alias *next;
271
272         if (ap->flag & ALIASINUSE) {
273                 ap->flag |= ALIASDEAD;
274                 return ap;
275         }
276
277         next = ap->next;
278         ckfree(ap->name);
279         ckfree(ap->val);
280         ckfree(ap);
281         return next;
282 }
283
284 static void
285 printalias(const struct alias *ap) {
286         char *p;
287
288         p = single_quote(ap->val);
289         out1fmt("alias %s=%s\n", ap->name, p);
290         stunalloc(p);
291 }
292
293 static struct alias **
294 __lookupalias(const char *name) {
295         struct alias **app = hashalias(name);
296
297         for (; *app; app = &(*app)->next) {
298                 if (equal(name, (*app)->name)) {
299                         break;
300                 }
301         }
302
303         return app;
304 }
305
306 #ifdef ASH_MATH_SUPPORT
307 /* The generated file arith.c has been snipped.  If you want this
308  * stuff back in, feel free to add it to your own copy.  */
309 #endif
310
311 /*
312  * This file was generated by the mkbuiltins program.
313  */
314
315 static int bgcmd __P((int, char **));
316 static int breakcmd __P((int, char **));
317 static int cdcmd __P((int, char **));
318 static int commandcmd __P((int, char **));
319 static int dotcmd __P((int, char **));
320 static int evalcmd __P((int, char **));
321 static int execcmd __P((int, char **));
322 static int exitcmd __P((int, char **));
323 static int exportcmd __P((int, char **));
324 static int histcmd __P((int, char **));
325 static int fgcmd __P((int, char **));
326 static int hashcmd __P((int, char **));
327 static int jobscmd __P((int, char **));
328 static int killcmd __P((int, char **));
329 static int localcmd __P((int, char **));
330 static int pwdcmd __P((int, char **));
331 static int readcmd __P((int, char **));
332 static int returncmd __P((int, char **));
333 static int setcmd __P((int, char **));
334 static int setvarcmd __P((int, char **));
335 static int shiftcmd __P((int, char **));
336 static int trapcmd __P((int, char **));
337 static int umaskcmd __P((int, char **));
338 static int unaliascmd __P((int, char **));
339 static int unsetcmd __P((int, char **));
340 static int waitcmd __P((int, char **));
341 static int aliascmd __P((int, char **));
342 static int ulimitcmd __P((int, char **));
343 static int timescmd __P((int, char **));
344 #ifdef ASH_MATH_SUPPORT
345 static int expcmd __P((int, char **));
346 #endif
347 #ifdef ASH_TYPE
348 static int typecmd __P((int, char **));
349 #endif
350 #ifdef ASH_GETOPTS
351 static int getoptscmd __P((int, char **));
352 #endif
353 #ifndef BB_TRUE_FALSE
354 static int true_main __P((int, char **));
355 static int false_main __P((int, char **));
356 #endif
357
358 static struct builtincmd *DOTCMD;
359 static struct builtincmd *BLTINCMD;
360 static struct builtincmd *COMMANDCMD;
361 static struct builtincmd *EXECCMD;
362 static struct builtincmd *EVALCMD;
363
364 /* It is CRUCIAL that this listing be kept in ascii order, otherwise
365  * the binary search in find_builtin() will stop working. If you value
366  * your kneecaps, you'll be sure to *make sure* that any changes made
367  * to this array result in the listing remaining in ascii order. You
368  * have been warned.
369  */
370 static const struct builtincmd builtincmds[] = {
371         { ".", dotcmd, 1 },
372         { ":", true_main, 1 },
373         { "alias", aliascmd, 6 },
374         { "bg", bgcmd, 2 },
375         { "break", breakcmd, 1 },
376         { "builtin", bltincmd, 1 },
377         { "cd", cdcmd, 2 },
378         { "chdir", cdcmd, 0 },
379         { "command", commandcmd, 2 },
380         { "continue", breakcmd, 1 },
381         { "eval", evalcmd, 1 },
382         { "exec", execcmd, 1 },
383         { "exit", exitcmd, 1 },
384 #ifdef ASH_MATH_SUPPORT
385         { "exp", expcmd, 0 },
386 #endif
387         { "export", exportcmd, 5 },
388         { "false", false_main, 2 },
389         { "fc", histcmd, 2 },
390         { "fg", fgcmd, 2 },
391 #ifdef ASH_GETOPTS
392         { "getopts", getoptscmd, 2 },
393 #endif  
394         { "hash", hashcmd, 0 },
395         { "jobs", jobscmd, 2 },
396         { "kill", killcmd, 2 },
397 #ifdef ASH_MATH_SUPPORT
398         { "let", expcmd, 0 },
399 #endif
400         { "local", localcmd, 4 },
401         { "pwd", pwdcmd, 0 },
402         { "read", readcmd, 2 },
403         { "readonly", exportcmd, 5 },
404         { "return", returncmd, 1 },
405         { "set", setcmd, 1 },
406         { "setvar", setvarcmd, 0 },
407         { "shift", shiftcmd, 1 },
408         { "times", timescmd, 1 },
409         { "trap", trapcmd, 1 },
410         { "true", true_main, 2 },
411 #ifdef ASH_TYPE
412         { "type", typecmd, 0 },
413 #endif
414         { "ulimit", ulimitcmd, 0 },
415         { "umask", umaskcmd, 2 },
416         { "unalias", unaliascmd, 2 },
417         { "unset", unsetcmd, 1 },
418         { "wait", waitcmd, 2 },
419 };
420 #define NUMBUILTINS  (sizeof (builtincmds) / sizeof (struct builtincmd) )
421
422
423 /*      $NetBSD: cd.c,v 1.27 1999/07/09 03:05:49 christos Exp $ */
424
425 static int docd __P((char *, int));
426 static char *getcomponent __P((void));
427 static void updatepwd __P((char *));
428 static void getpwd __P((void));
429
430 static char *curdir = nullstr;          /* current working directory */
431 static char *cdcomppath;
432
433 #ifdef mkinit
434 INCLUDE "cd.h"
435 INIT {
436         setpwd(0, 0);
437 }
438 #endif
439
440 static int
441 cdcmd(argc, argv)
442         int argc;
443         char **argv;
444 {
445         const char *dest;
446         const char *path;
447         char *p;
448         struct stat statb;
449         int print = 0;
450
451         nextopt(nullstr);
452         if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
453                 error("HOME not set");
454         if (*dest == '\0')
455                 dest = ".";
456         if (dest[0] == '-' && dest[1] == '\0') {
457                 dest = bltinlookup("OLDPWD");
458                 if (!dest || !*dest) {
459                         dest = curdir;
460                 }
461                 print = 1;
462                 if (dest)
463                         print = 1;
464                 else
465                         dest = ".";
466         }
467         if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
468                 path = nullstr;
469         while ((p = padvance(&path, dest)) != NULL) {
470                 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
471                         if (!print) {
472                                 /*
473                                  * XXX - rethink
474                                  */
475                                 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
476                                         p += 2;
477                                 print = strcmp(p, dest);
478                         }
479                         if (docd(p, print) >= 0)
480                                 return 0;
481
482                 }
483         }
484         error("can't cd to %s", dest);
485         /* NOTREACHED */
486 }
487
488
489 /*
490  * Actually do the chdir.  In an interactive shell, print the
491  * directory name if "print" is nonzero.
492  */
493
494 static int
495 docd(dest, print)
496         char *dest;
497         int print;
498 {
499         char *p;
500         char *q;
501         char *component;
502         struct stat statb;
503         int first;
504         int badstat;
505
506         TRACE(("docd(\"%s\", %d) called\n", dest, print));
507
508         /*
509          *  Check each component of the path. If we find a symlink or
510          *  something we can't stat, clear curdir to force a getcwd()
511          *  next time we get the value of the current directory.
512          */
513         badstat = 0;
514         cdcomppath = sstrdup(dest);
515         STARTSTACKSTR(p);
516         if (*dest == '/') {
517                 STPUTC('/', p);
518                 cdcomppath++;
519         }
520         first = 1;
521         while ((q = getcomponent()) != NULL) {
522                 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
523                         continue;
524                 if (! first)
525                         STPUTC('/', p);
526                 first = 0;
527                 component = q;
528                 while (*q)
529                         STPUTC(*q++, p);
530                 if (equal(component, ".."))
531                         continue;
532                 STACKSTRNUL(p);
533                 if ((lstat(stackblock(), &statb) < 0)
534                     || (S_ISLNK(statb.st_mode)))  {
535                         /* print = 1; */
536                         badstat = 1;
537                         break;
538                 }
539         }
540
541         INTOFF;
542         if (chdir(dest) < 0) {
543                 INTON;
544                 return -1;
545         }
546         updatepwd(badstat ? NULL : dest);
547         INTON;
548         if (print && iflag)
549                 out1fmt(snlfmt, curdir);
550         return 0;
551 }
552
553
554 /*
555  * Get the next component of the path name pointed to by cdcomppath.
556  * This routine overwrites the string pointed to by cdcomppath.
557  */
558
559 static char *
560 getcomponent() {
561         char *p;
562         char *start;
563
564         if ((p = cdcomppath) == NULL)
565                 return NULL;
566         start = cdcomppath;
567         while (*p != '/' && *p != '\0')
568                 p++;
569         if (*p == '\0') {
570                 cdcomppath = NULL;
571         } else {
572                 *p++ = '\0';
573                 cdcomppath = p;
574         }
575         return start;
576 }
577
578
579
580 /*
581  * Update curdir (the name of the current directory) in response to a
582  * cd command.  We also call hashcd to let the routines in exec.c know
583  * that the current directory has changed.
584  */
585
586 static void
587 updatepwd(dir)
588         char *dir;
589         {
590         char *new;
591         char *p;
592         size_t len;
593
594         hashcd();                               /* update command hash table */
595
596         /*
597          * If our argument is NULL, we don't know the current directory
598          * any more because we traversed a symbolic link or something
599          * we couldn't stat().
600          */
601         if (dir == NULL || curdir == nullstr)  {
602                 setpwd(0, 1);
603                 return;
604         }
605         len = strlen(dir);
606         cdcomppath = sstrdup(dir);
607         STARTSTACKSTR(new);
608         if (*dir != '/') {
609                 p = curdir;
610                 while (*p)
611                         STPUTC(*p++, new);
612                 if (p[-1] == '/')
613                         STUNPUTC(new);
614         }
615         while ((p = getcomponent()) != NULL) {
616                 if (equal(p, "..")) {
617                         while (new > stackblock() && (STUNPUTC(new), *new) != '/');
618                 } else if (*p != '\0' && ! equal(p, ".")) {
619                         STPUTC('/', new);
620                         while (*p)
621                                 STPUTC(*p++, new);
622                 }
623         }
624         if (new == stackblock())
625                 STPUTC('/', new);
626         STACKSTRNUL(new);
627         setpwd(stackblock(), 1);
628 }
629
630
631
632 static int
633 pwdcmd(argc, argv)
634         int argc;
635         char **argv;
636 {
637         out1fmt(snlfmt, curdir);
638         return 0;
639 }
640
641
642
643
644 #define MAXPWD 256
645
646 /*
647  * Find out what the current directory is. If we already know the current
648  * directory, this routine returns immediately.
649  */
650 static void
651 getpwd()
652 {
653         char buf[MAXPWD];
654
655         /*
656          * Things are a bit complicated here; we could have just used
657          * getcwd, but traditionally getcwd is implemented using popen
658          * to /bin/pwd. This creates a problem for us, since we cannot
659          * keep track of the job if it is being ran behind our backs.
660          * So we re-implement getcwd(), and we suppress interrupts
661          * throughout the process. This is not completely safe, since
662          * the user can still break out of it by killing the pwd program.
663          * We still try to use getcwd for systems that we know have a
664          * c implementation of getcwd, that does not open a pipe to
665          * /bin/pwd.
666          */
667 #if defined(__NetBSD__) || defined(__SVR4) || defined(__GLIBC__)
668                 
669         if (getcwd(buf, sizeof(buf)) == NULL) {
670                 char *pwd = getenv("PWD");
671                 struct stat stdot, stpwd;
672
673                 if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
674                     stat(pwd, &stpwd) != -1 &&
675                     stdot.st_dev == stpwd.st_dev &&
676                     stdot.st_ino == stpwd.st_ino) {
677                         curdir = savestr(pwd);
678                         return;
679                 }
680                 error("getcwd() failed: %s", strerror(errno));
681         }
682         curdir = savestr(buf);
683 #else
684         {
685                 char *p;
686                 int i;
687                 int status;
688                 struct job *jp;
689                 int pip[2];
690
691                 if (pipe(pip) < 0)
692                         error("Pipe call failed");
693                 jp = makejob((union node *)NULL, 1);
694                 if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) {
695                         (void) close(pip[0]);
696                         if (pip[1] != 1) {
697                                 close(1);
698                                 dup_as_newfd(pip[1], 1);
699                                 close(pip[1]);
700                         }
701                         (void) execl("/bin/pwd", "pwd", (char *)0);
702                         error("Cannot exec /bin/pwd");
703                 }
704                 (void) close(pip[1]);
705                 pip[1] = -1;
706                 p = buf;
707                 while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0
708                      || (i == -1 && errno == EINTR)) {
709                         if (i > 0)
710                                 p += i;
711                 }
712                 (void) close(pip[0]);
713                 pip[0] = -1;
714                 status = waitforjob(jp);
715                 if (status != 0)
716                         error((char *)0);
717                 if (i < 0 || p == buf || p[-1] != '\n')
718                         error("pwd command failed");
719                 p[-1] = '\0';
720         }
721         curdir = savestr(buf);
722 #endif
723 }
724
725 static void
726 setpwd(const char *val, int setold)
727 {
728         if (setold) {
729                 setvar("OLDPWD", curdir, VEXPORT);
730         }
731         INTOFF;
732         if (curdir != nullstr) {
733                 free(curdir);
734                 curdir = nullstr;
735         }
736         if (!val) {
737                 getpwd();
738         } else {
739                 curdir = savestr(val);
740         }
741         INTON;
742         setvar("PWD", curdir, VEXPORT);
743 }
744
745 /*      $NetBSD: error.c,v 1.23 2000/07/03 03:26:19 matt Exp $  */
746
747 /*
748  * Errors and exceptions.
749  */
750
751 /*
752  * Code to handle exceptions in C.
753  */
754
755 struct jmploc *handler;
756 static int exception;
757 volatile int suppressint;
758 volatile int intpending;
759
760
761 static void exverror __P((int, const char *, va_list))
762     __attribute__((__noreturn__));
763
764 /*
765  * Called to raise an exception.  Since C doesn't include exceptions, we
766  * just do a longjmp to the exception handler.  The type of exception is
767  * stored in the global variable "exception".
768  */
769
770 static void
771 exraise(e)
772         int e;
773 {
774 #ifdef DEBUG
775         if (handler == NULL)
776                 abort();
777 #endif
778         exception = e;
779         longjmp(handler->loc, 1);
780 }
781
782
783 /*
784  * Called from trap.c when a SIGINT is received.  (If the user specifies
785  * that SIGINT is to be trapped or ignored using the trap builtin, then
786  * this routine is not called.)  Suppressint is nonzero when interrupts
787  * are held using the INTOFF macro.  The call to _exit is necessary because
788  * there is a short period after a fork before the signal handlers are
789  * set to the appropriate value for the child.  (The test for iflag is
790  * just defensive programming.)
791  */
792
793 static void
794 onint() {
795         sigset_t mysigset;
796
797         if (suppressint) {
798                 intpending++;
799                 return;
800         }
801         intpending = 0;
802         sigemptyset(&mysigset);
803         sigprocmask(SIG_SETMASK, &mysigset, NULL);
804         if (rootshell && iflag)
805                 exraise(EXINT);
806         else {
807                 signal(SIGINT, SIG_DFL);
808                 raise(SIGINT);
809         }
810         /* NOTREACHED */
811 }
812
813
814 /*
815  * Exverror is called to raise the error exception.  If the first argument
816  * is not NULL then error prints an error message using printf style
817  * formatting.  It then raises the error exception.
818  */
819 static void
820 exverror(cond, msg, ap)
821         int cond;
822         const char *msg;
823         va_list ap;
824 {
825         CLEAR_PENDING_INT;
826         INTOFF;
827
828 #ifdef DEBUG
829         if (msg)
830                 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
831         else
832                 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
833 #endif
834         if (msg) {
835                 if (commandname)
836                         outfmt(&errout, "%s: ", commandname);
837                 doformat(&errout, msg, ap);
838 #if FLUSHERR
839                 outc('\n', &errout);
840 #else
841                 outcslow('\n', &errout);
842 #endif
843         }
844         flushall();
845         exraise(cond);
846         /* NOTREACHED */
847 }
848
849
850 #ifdef __STDC__
851 static void
852 error(const char *msg, ...)
853 #else
854 static void
855 error(va_alist)
856         va_dcl
857 #endif
858 {
859 #ifndef __STDC__
860         const char *msg;
861 #endif
862         va_list ap;
863 #ifdef __STDC__
864         va_start(ap, msg);
865 #else
866         va_start(ap);
867         msg = va_arg(ap, const char *);
868 #endif
869         exverror(EXERROR, msg, ap);
870         /* NOTREACHED */
871         va_end(ap);
872 }
873
874
875 #ifdef __STDC__
876 static void
877 exerror(int cond, const char *msg, ...)
878 #else
879 static void
880 exerror(va_alist)
881         va_dcl
882 #endif
883 {
884 #ifndef __STDC__
885         int cond;
886         const char *msg;
887 #endif
888         va_list ap;
889 #ifdef __STDC__
890         va_start(ap, msg);
891 #else
892         va_start(ap);
893         cond = va_arg(ap, int);
894         msg = va_arg(ap, const char *);
895 #endif
896         exverror(cond, msg, ap);
897         /* NOTREACHED */
898         va_end(ap);
899 }
900
901
902
903 /*
904  * Table of error messages.
905  */
906
907 struct errname {
908         short errcode;          /* error number */
909         short action;           /* operation which encountered the error */
910         const char *msg;        /* text describing the error */
911 };
912
913
914 #define ALL (E_OPEN|E_CREAT|E_EXEC)
915
916 static const struct errname errormsg[] = {
917         { EINTR,        ALL,    "interrupted" },
918         { EACCES,       ALL,    "permission denied" },
919         { EIO,          ALL,    "I/O error" },
920         { ENOENT,       E_OPEN, "no such file" },
921         { ENOENT,       E_CREAT,"directory nonexistent" },
922         { ENOENT,       E_EXEC, "not found" },
923         { ENOTDIR,      E_OPEN, "no such file" },
924         { ENOTDIR,      E_CREAT,"directory nonexistent" },
925         { ENOTDIR,      E_EXEC, "not found" },
926         { EISDIR,       ALL,    "is a directory" },
927         { EEXIST,       E_CREAT,"file exists" },
928 #ifdef notdef
929         { EMFILE,       ALL,    "too many open files" },
930 #endif
931         { ENFILE,       ALL,    "file table overflow" },
932         { ENOSPC,       ALL,    "file system full" },
933 #ifdef EDQUOT
934         { EDQUOT,       ALL,    "disk quota exceeded" },
935 #endif
936 #ifdef ENOSR
937         { ENOSR,        ALL,    "no streams resources" },
938 #endif
939         { ENXIO,        ALL,    "no such device or address" },
940         { EROFS,        ALL,    "read-only file system" },
941         { ETXTBSY,      ALL,    "text busy" },
942 #ifdef SYSV
943         { EAGAIN,       E_EXEC, "not enough memory" },
944 #endif
945         { ENOMEM,       ALL,    "not enough memory" },
946 #ifdef ENOLINK
947         { ENOLINK,      ALL,    "remote access failed" },
948 #endif
949 #ifdef EMULTIHOP
950         { EMULTIHOP,    ALL,    "remote access failed" },
951 #endif
952 #ifdef ECOMM
953         { ECOMM,        ALL,    "remote access failed" },
954 #endif
955 #ifdef ESTALE
956         { ESTALE,       ALL,    "remote access failed" },
957 #endif
958 #ifdef ETIMEDOUT
959         { ETIMEDOUT,    ALL,    "remote access failed" },
960 #endif
961 #ifdef ELOOP
962         { ELOOP,        ALL,    "symbolic link loop" },
963 #endif
964         { E2BIG,        E_EXEC, "argument list too long" },
965 #ifdef ELIBACC
966         { ELIBACC,      E_EXEC, "shared library missing" },
967 #endif
968         { 0,            0,      NULL },
969 };
970
971
972 /*
973  * Return a string describing an error.  The returned string may be a
974  * pointer to a static buffer that will be overwritten on the next call.
975  * Action describes the operation that got the error.
976  */
977
978 static const char *
979 errmsg(e, action)
980         int e;
981         int action;
982 {
983         struct errname const *ep;
984         static char buf[12];
985
986         for (ep = errormsg ; ep->errcode ; ep++) {
987                 if (ep->errcode == e && (ep->action & action) != 0)
988                         return ep->msg;
989         }
990         fmtstr(buf, sizeof buf, "error %d", e);
991         return buf;
992 }
993
994
995 #ifdef REALLY_SMALL
996 static void
997 __inton() {
998         if (--suppressint == 0 && intpending) {
999                 onint();
1000         }
1001 }
1002 #endif
1003 /*      $NetBSD: eval.c,v 1.57 2001/02/04 19:52:06 christos Exp $       */
1004
1005
1006 /* flags in argument to evaltree */
1007 #define EV_EXIT 01              /* exit after evaluating tree */
1008 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
1009 #define EV_BACKCMD 04           /* command executing within back quotes */
1010
1011 static int evalskip;                    /* set if we are skipping commands */
1012 static int skipcount;           /* number of levels to skip */
1013 static int loopnest;            /* current loop nesting level */
1014 static int funcnest;                    /* depth of function calls */
1015
1016
1017 static char *commandname;
1018 struct strlist *cmdenviron;
1019 static int exitstatus;                  /* exit status of last command */
1020 static int oexitstatus;         /* saved exit status */
1021
1022
1023 static void evalloop __P((union node *, int));
1024 static void evalfor __P((union node *, int));
1025 static void evalcase __P((union node *, int));
1026 static void evalsubshell __P((union node *, int));
1027 static void expredir __P((union node *));
1028 static void evalpipe __P((union node *));
1029 #ifdef notyet
1030 static void evalcommand __P((union node *, int, struct backcmd *));
1031 #else
1032 static void evalcommand __P((union node *, int));
1033 #endif
1034 static void prehash __P((union node *));
1035 static void eprintlist __P((struct strlist *));
1036
1037
1038 /*
1039  * Called to reset things after an exception.
1040  */
1041
1042 #ifdef mkinit
1043 INCLUDE "eval.h"
1044
1045 RESET {
1046         evalskip = 0;
1047         loopnest = 0;
1048         funcnest = 0;
1049 }
1050
1051 SHELLPROC {
1052         exitstatus = 0;
1053 }
1054 #endif
1055
1056
1057
1058 /*
1059  * The eval commmand.
1060  */
1061
1062 static int
1063 evalcmd(argc, argv)
1064         int argc;
1065         char **argv;
1066 {
1067         char *p;
1068         char *concat;
1069         char **ap;
1070
1071         if (argc > 1) {
1072                 p = argv[1];
1073                 if (argc > 2) {
1074                         STARTSTACKSTR(concat);
1075                         ap = argv + 2;
1076                         for (;;) {
1077                                 while (*p)
1078                                         STPUTC(*p++, concat);
1079                                 if ((p = *ap++) == NULL)
1080                                         break;
1081                                 STPUTC(' ', concat);
1082                         }
1083                         STPUTC('\0', concat);
1084                         p = grabstackstr(concat);
1085                 }
1086                 evalstring(p, EV_TESTED);
1087         }
1088         return exitstatus;
1089 }
1090
1091
1092 /*
1093  * Execute a command or commands contained in a string.
1094  */
1095
1096 static void
1097 evalstring(s, flag)
1098         char *s;
1099         int flag;
1100         {
1101         union node *n;
1102         struct stackmark smark;
1103
1104         setstackmark(&smark);
1105         setinputstring(s);
1106         while ((n = parsecmd(0)) != NEOF) {
1107                 evaltree(n, flag);
1108                 popstackmark(&smark);
1109         }
1110         popfile();
1111         popstackmark(&smark);
1112 }
1113
1114
1115
1116 /*
1117  * Evaluate a parse tree.  The value is left in the global variable
1118  * exitstatus.
1119  */
1120
1121 static void
1122 evaltree(n, flags)
1123         union node *n;
1124         int flags;
1125 {
1126         int checkexit = 0;
1127         if (n == NULL) {
1128                 TRACE(("evaltree(NULL) called\n"));
1129                 goto out;
1130         }
1131         TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
1132         switch (n->type) {
1133         case NSEMI:
1134                 evaltree(n->nbinary.ch1, flags & EV_TESTED);
1135                 if (evalskip)
1136                         goto out;
1137                 evaltree(n->nbinary.ch2, flags);
1138                 break;
1139         case NAND:
1140                 evaltree(n->nbinary.ch1, EV_TESTED);
1141                 if (evalskip || exitstatus != 0)
1142                         goto out;
1143                 evaltree(n->nbinary.ch2, flags);
1144                 break;
1145         case NOR:
1146                 evaltree(n->nbinary.ch1, EV_TESTED);
1147                 if (evalskip || exitstatus == 0)
1148                         goto out;
1149                 evaltree(n->nbinary.ch2, flags);
1150                 break;
1151         case NREDIR:
1152                 expredir(n->nredir.redirect);
1153                 redirect(n->nredir.redirect, REDIR_PUSH);
1154                 evaltree(n->nredir.n, flags);
1155                 popredir();
1156                 break;
1157         case NSUBSHELL:
1158                 evalsubshell(n, flags);
1159                 break;
1160         case NBACKGND:
1161                 evalsubshell(n, flags);
1162                 break;
1163         case NIF: {
1164                 evaltree(n->nif.test, EV_TESTED);
1165                 if (evalskip)
1166                         goto out;
1167                 if (exitstatus == 0)
1168                         evaltree(n->nif.ifpart, flags);
1169                 else if (n->nif.elsepart)
1170                         evaltree(n->nif.elsepart, flags);
1171                 else
1172                         exitstatus = 0;
1173                 break;
1174         }
1175         case NWHILE:
1176         case NUNTIL:
1177                 evalloop(n, flags);
1178                 break;
1179         case NFOR:
1180                 evalfor(n, flags);
1181                 break;
1182         case NCASE:
1183                 evalcase(n, flags);
1184                 break;
1185         case NDEFUN: {
1186                 struct builtincmd *bcmd;
1187                 if (
1188                         (bcmd = find_builtin(n->narg.text)) &&
1189                         bcmd->flags & BUILTIN_SPECIAL
1190                 ) {
1191                         outfmt(out2, "%s is a special built-in\n", n->narg.text);
1192                         exitstatus = 1;
1193                         break;
1194                 }
1195                 defun(n->narg.text, n->narg.next);
1196                 exitstatus = 0;
1197                 break;
1198         }
1199         case NNOT:
1200                 evaltree(n->nnot.com, EV_TESTED);
1201                 exitstatus = !exitstatus;
1202                 break;
1203
1204         case NPIPE:
1205                 evalpipe(n);
1206                 checkexit = 1;
1207                 break;
1208         case NCMD:
1209 #ifdef notyet
1210                 evalcommand(n, flags, (struct backcmd *)NULL);
1211 #else
1212                 evalcommand(n, flags);
1213 #endif
1214                 checkexit = 1;
1215                 break;
1216 #ifdef DEBUG
1217         default:
1218                 out1fmt("Node type = %d\n", n->type);
1219 #ifndef USE_GLIBC_STDIO
1220                 flushout(out1);
1221 #endif
1222                 break;
1223 #endif
1224         }
1225 out:
1226         if (pendingsigs)
1227                 dotrap();
1228         if (
1229                 flags & EV_EXIT ||
1230                 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
1231         )
1232                 exitshell(exitstatus);
1233 }
1234
1235
1236 static void
1237 evalloop(n, flags)
1238         union node *n;
1239         int flags;
1240 {
1241         int status;
1242
1243         loopnest++;
1244         status = 0;
1245         for (;;) {
1246                 evaltree(n->nbinary.ch1, EV_TESTED);
1247                 if (evalskip) {
1248 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
1249                                 evalskip = 0;
1250                                 continue;
1251                         }
1252                         if (evalskip == SKIPBREAK && --skipcount <= 0)
1253                                 evalskip = 0;
1254                         break;
1255                 }
1256                 if (n->type == NWHILE) {
1257                         if (exitstatus != 0)
1258                                 break;
1259                 } else {
1260                         if (exitstatus == 0)
1261                                 break;
1262                 }
1263                 evaltree(n->nbinary.ch2, flags & EV_TESTED);
1264                 status = exitstatus;
1265                 if (evalskip)
1266                         goto skipping;
1267         }
1268         loopnest--;
1269         exitstatus = status;
1270 }
1271
1272
1273
1274 static void
1275 evalfor(n, flags)
1276     union node *n;
1277     int flags;
1278 {
1279         struct arglist arglist;
1280         union node *argp;
1281         struct strlist *sp;
1282         struct stackmark smark;
1283
1284         setstackmark(&smark);
1285         arglist.lastp = &arglist.list;
1286         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
1287                 oexitstatus = exitstatus;
1288                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
1289                 if (evalskip)
1290                         goto out;
1291         }
1292         *arglist.lastp = NULL;
1293
1294         exitstatus = 0;
1295         loopnest++;
1296         for (sp = arglist.list ; sp ; sp = sp->next) {
1297                 setvar(n->nfor.var, sp->text, 0);
1298                 evaltree(n->nfor.body, flags & EV_TESTED);
1299                 if (evalskip) {
1300                         if (evalskip == SKIPCONT && --skipcount <= 0) {
1301                                 evalskip = 0;
1302                                 continue;
1303                         }
1304                         if (evalskip == SKIPBREAK && --skipcount <= 0)
1305                                 evalskip = 0;
1306                         break;
1307                 }
1308         }
1309         loopnest--;
1310 out:
1311         popstackmark(&smark);
1312 }
1313
1314
1315
1316 static void
1317 evalcase(n, flags)
1318         union node *n;
1319         int flags;
1320 {
1321         union node *cp;
1322         union node *patp;
1323         struct arglist arglist;
1324         struct stackmark smark;
1325
1326         setstackmark(&smark);
1327         arglist.lastp = &arglist.list;
1328         oexitstatus = exitstatus;
1329         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
1330         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
1331                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
1332                         if (casematch(patp, arglist.list->text)) {
1333                                 if (evalskip == 0) {
1334                                         evaltree(cp->nclist.body, flags);
1335                                 }
1336                                 goto out;
1337                         }
1338                 }
1339         }
1340 out:
1341         popstackmark(&smark);
1342 }
1343
1344
1345
1346 /*
1347  * Kick off a subshell to evaluate a tree.
1348  */
1349
1350 static void
1351 evalsubshell(n, flags)
1352         union node *n;
1353         int flags;
1354 {
1355         struct job *jp;
1356         int backgnd = (n->type == NBACKGND);
1357
1358         expredir(n->nredir.redirect);
1359         jp = makejob(n, 1);
1360         if (forkshell(jp, n, backgnd) == 0) {
1361                 if (backgnd)
1362                         flags &=~ EV_TESTED;
1363                 redirect(n->nredir.redirect, 0);
1364                 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
1365         }
1366         if (! backgnd) {
1367                 INTOFF;
1368                 exitstatus = waitforjob(jp);
1369                 INTON;
1370         }
1371 }
1372
1373
1374
1375 /*
1376  * Compute the names of the files in a redirection list.
1377  */
1378
1379 static void
1380 expredir(n)
1381         union node *n;
1382 {
1383         union node *redir;
1384
1385         for (redir = n ; redir ; redir = redir->nfile.next) {
1386                 struct arglist fn;
1387                 fn.lastp = &fn.list;
1388                 oexitstatus = exitstatus;
1389                 switch (redir->type) {
1390                 case NFROMTO:
1391                 case NFROM:
1392                 case NTO:
1393                 case NAPPEND:
1394                 case NTOOV:
1395                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
1396                         redir->nfile.expfname = fn.list->text;
1397                         break;
1398                 case NFROMFD:
1399                 case NTOFD:
1400                         if (redir->ndup.vname) {
1401                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
1402                                 fixredir(redir, fn.list->text, 1);
1403                         }
1404                         break;
1405                 }
1406         }
1407 }
1408
1409
1410
1411 /*
1412  * Evaluate a pipeline.  All the processes in the pipeline are children
1413  * of the process creating the pipeline.  (This differs from some versions
1414  * of the shell, which make the last process in a pipeline the parent
1415  * of all the rest.)
1416  */
1417
1418 static void
1419 evalpipe(n)
1420         union node *n;
1421 {
1422         struct job *jp;
1423         struct nodelist *lp;
1424         int pipelen;
1425         int prevfd;
1426         int pip[2];
1427
1428         TRACE(("evalpipe(0x%lx) called\n", (long)n));
1429         pipelen = 0;
1430         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
1431                 pipelen++;
1432         INTOFF;
1433         jp = makejob(n, pipelen);
1434         prevfd = -1;
1435         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
1436                 prehash(lp->n);
1437                 pip[1] = -1;
1438                 if (lp->next) {
1439                         if (pipe(pip) < 0) {
1440                                 close(prevfd);
1441                                 error("Pipe call failed");
1442                         }
1443                 }
1444                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
1445                         INTON;
1446                         if (prevfd > 0) {
1447                                 close(0);
1448                                 dup_as_newfd(prevfd, 0);
1449                                 close(prevfd);
1450                                 if (pip[0] == 0) {
1451                                         pip[0] = -1;
1452                                 }
1453                         }
1454                         if (pip[1] >= 0) {
1455                                 if (pip[0] >= 0) {
1456                                         close(pip[0]);
1457                                 }
1458                                 if (pip[1] != 1) {
1459                                         close(1);
1460                                         dup_as_newfd(pip[1], 1);
1461                                         close(pip[1]);
1462                                 }
1463                         }
1464                         evaltree(lp->n, EV_EXIT);
1465                 }
1466                 if (prevfd >= 0)
1467                         close(prevfd);
1468                 prevfd = pip[0];
1469                 close(pip[1]);
1470         }
1471         INTON;
1472         if (n->npipe.backgnd == 0) {
1473                 INTOFF;
1474                 exitstatus = waitforjob(jp);
1475                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
1476                 INTON;
1477         }
1478 }
1479
1480
1481
1482 /*
1483  * Execute a command inside back quotes.  If it's a builtin command, we
1484  * want to save its output in a block obtained from malloc.  Otherwise
1485  * we fork off a subprocess and get the output of the command via a pipe.
1486  * Should be called with interrupts off.
1487  */
1488
1489 static void
1490 evalbackcmd(n, result)
1491         union node *n;
1492         struct backcmd *result;
1493 {
1494         int pip[2];
1495         struct job *jp;
1496         struct stackmark smark;         /* unnecessary */
1497
1498         setstackmark(&smark);
1499         result->fd = -1;
1500         result->buf = NULL;
1501         result->nleft = 0;
1502         result->jp = NULL;
1503         if (n == NULL) {
1504                 exitstatus = 0;
1505                 goto out;
1506         }
1507 #ifdef notyet
1508         /*
1509          * For now we disable executing builtins in the same
1510          * context as the shell, because we are not keeping
1511          * enough state to recover from changes that are
1512          * supposed only to affect subshells. eg. echo "`cd /`"
1513          */
1514         if (n->type == NCMD) {
1515                 exitstatus = oexitstatus;
1516                 evalcommand(n, EV_BACKCMD, result);
1517         } else
1518 #endif
1519         {
1520                 exitstatus = 0;
1521                 if (pipe(pip) < 0)
1522                         error("Pipe call failed");
1523                 jp = makejob(n, 1);
1524                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
1525                         FORCEINTON;
1526                         close(pip[0]);
1527                         if (pip[1] != 1) {
1528                                 close(1);
1529                                 dup_as_newfd(pip[1], 1);
1530                                 close(pip[1]);
1531                         }
1532                         eflag = 0;
1533                         evaltree(n, EV_EXIT);
1534                 }
1535                 close(pip[1]);
1536                 result->fd = pip[0];
1537                 result->jp = jp;
1538         }
1539 out:
1540         popstackmark(&smark);
1541         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
1542                 result->fd, result->buf, result->nleft, result->jp));
1543 }
1544
1545
1546
1547 /*
1548  * Execute a simple command.
1549  */
1550
1551 static void
1552 #ifdef notyet
1553 evalcommand(cmd, flags, backcmd)
1554         union node *cmd;
1555         int flags;
1556         struct backcmd *backcmd;
1557 #else
1558 evalcommand(cmd, flags)
1559         union node *cmd;
1560         int flags;
1561 #endif
1562 {
1563         struct stackmark smark;
1564         union node *argp;
1565         struct arglist arglist;
1566         struct arglist varlist;
1567         char **argv;
1568         int argc;
1569         char **envp;
1570         struct strlist *sp;
1571         int mode;
1572 #ifdef notyet
1573         int pip[2];
1574 #endif
1575         struct cmdentry cmdentry;
1576         struct job *jp;
1577         char *volatile savecmdname;
1578         volatile struct shparam saveparam;
1579         struct localvar *volatile savelocalvars;
1580         volatile int e;
1581         char *lastarg;
1582         const char *path;
1583         const struct builtincmd *firstbltin;
1584         struct jmploc *volatile savehandler;
1585         struct jmploc jmploc;
1586 #if __GNUC__
1587         /* Avoid longjmp clobbering */
1588         (void) &argv;
1589         (void) &argc;
1590         (void) &lastarg;
1591         (void) &flags;
1592 #endif
1593
1594         /* First expand the arguments. */
1595         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
1596         setstackmark(&smark);
1597         arglist.lastp = &arglist.list;
1598         varlist.lastp = &varlist.list;
1599         arglist.list = 0;
1600         oexitstatus = exitstatus;
1601         exitstatus = 0;
1602         path = pathval();
1603         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
1604                 expandarg(argp, &varlist, EXP_VARTILDE);
1605         }
1606         for (
1607                 argp = cmd->ncmd.args; argp && !arglist.list;
1608                 argp = argp->narg.next
1609         ) {
1610                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1611         }
1612         if (argp) {
1613                 struct builtincmd *bcmd;
1614                 bool pseudovarflag;
1615                 bcmd = find_builtin(arglist.list->text);
1616                 pseudovarflag = bcmd && bcmd->flags & BUILTIN_ASSIGN;
1617                 for (; argp; argp = argp->narg.next) {
1618                         if (pseudovarflag && isassignment(argp->narg.text)) {
1619                                 expandarg(argp, &arglist, EXP_VARTILDE);
1620                                 continue;
1621                         }
1622                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
1623                 }
1624         }
1625         *arglist.lastp = NULL;
1626         *varlist.lastp = NULL;
1627         expredir(cmd->ncmd.redirect);
1628         argc = 0;
1629         for (sp = arglist.list ; sp ; sp = sp->next)
1630                 argc++;
1631         argv = stalloc(sizeof (char *) * (argc + 1));
1632
1633         for (sp = arglist.list ; sp ; sp = sp->next) {
1634                 TRACE(("evalcommand arg: %s\n", sp->text));
1635                 *argv++ = sp->text;
1636         }
1637         *argv = NULL;
1638         lastarg = NULL;
1639         if (iflag && funcnest == 0 && argc > 0)
1640                 lastarg = argv[-1];
1641         argv -= argc;
1642
1643         /* Print the command if xflag is set. */
1644         if (xflag) {
1645 #ifdef FLUSHERR
1646                 outc('+', &errout);
1647 #else
1648                 outcslow('+', &errout);
1649 #endif
1650                 eprintlist(varlist.list);
1651                 eprintlist(arglist.list);
1652 #ifdef FLUSHERR
1653                 outc('\n', &errout);
1654                 flushout(&errout);
1655 #else
1656                 outcslow('\n', &errout);
1657 #endif
1658         }
1659
1660         /* Now locate the command. */
1661         if (argc == 0) {
1662                 cmdentry.cmdtype = CMDBUILTIN;
1663                 firstbltin = cmdentry.u.cmd = BLTINCMD;
1664         } else {
1665                 const char *oldpath;
1666                 int findflag = DO_ERR;
1667                 int oldfindflag;
1668
1669                 /*
1670                  * Modify the command lookup path, if a PATH= assignment
1671                  * is present
1672                  */
1673                 for (sp = varlist.list ; sp ; sp = sp->next)
1674                         if (varequal(sp->text, defpathvar)) {
1675                                 path = sp->text + 5;
1676                                 findflag |= DO_BRUTE;
1677                         }
1678                 oldpath = path;
1679                 oldfindflag = findflag;
1680                 firstbltin = 0;
1681                 for(;;) {
1682                         find_command(argv[0], &cmdentry, findflag, path);
1683                         if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
1684                                 exitstatus = 127;
1685 #ifdef FLUSHERR
1686                                 flushout(&errout);
1687 #endif
1688                                 goto out;
1689                         }
1690                         /* implement bltin and command here */
1691                         if (cmdentry.cmdtype != CMDBUILTIN) {
1692                                 break;
1693                         }
1694                         if (!firstbltin) {
1695                                 firstbltin = cmdentry.u.cmd;
1696                         }
1697                         if (cmdentry.u.cmd == BLTINCMD) {
1698                                 for(;;) {
1699                                         struct builtincmd *bcmd;
1700
1701                                         argv++;
1702                                         if (--argc == 0)
1703                                                 goto found;
1704                                         if (!(bcmd = find_builtin(*argv))) {
1705                                                 outfmt(&errout, "%s: not found\n", *argv);
1706                                                 exitstatus = 127;
1707 #ifdef FLUSHERR
1708                                                 flushout(&errout);
1709 #endif
1710                                                 goto out;
1711                                         }
1712                                         cmdentry.u.cmd = bcmd;
1713                                         if (bcmd != BLTINCMD)
1714                                                 break;
1715                                 }
1716                         }
1717                         if (cmdentry.u.cmd == COMMANDCMD) {
1718                                 argv++;
1719                                 if (--argc == 0) {
1720                                         goto found;
1721                                 }
1722                                 if (*argv[0] == '-') {
1723                                         if (!equal(argv[0], "-p")) {
1724                                                 argv--;
1725                                                 argc++;
1726                                                 break;
1727                                         }
1728                                         argv++;
1729                                         if (--argc == 0) {
1730                                                 goto found;
1731                                         }
1732                                         path = defpath;
1733                                         findflag |= DO_BRUTE;
1734                                 } else {
1735                                         path = oldpath;
1736                                         findflag = oldfindflag;
1737                                 }
1738                                 findflag |= DO_NOFUN;
1739                                 continue;
1740                         }
1741 found:
1742                         break;
1743                 }
1744         }
1745
1746         /* Fork off a child process if necessary. */
1747         if (cmd->ncmd.backgnd
1748          || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
1749 #ifdef notyet
1750          || ((flags & EV_BACKCMD) != 0
1751             && (cmdentry.cmdtype != CMDBUILTIN
1752                  || cmdentry.u.bcmd == DOTCMD
1753                  || cmdentry.u.bcmd == EVALCMD))
1754 #endif
1755         ) {
1756                 jp = makejob(cmd, 1);
1757                 mode = cmd->ncmd.backgnd;
1758 #ifdef notyet
1759                 if (flags & EV_BACKCMD) {
1760                         mode = FORK_NOJOB;
1761                         if (pipe(pip) < 0)
1762                                 error("Pipe call failed");
1763                 }
1764 #endif
1765                 if (forkshell(jp, cmd, mode) != 0)
1766                         goto parent;    /* at end of routine */
1767 #ifdef notyet
1768                 if (flags & EV_BACKCMD) {
1769                         FORCEINTON;
1770                         close(pip[0]);
1771                         if (pip[1] != 1) {
1772                                 close(1);
1773                                 dup_as_newfd(pip[1], 1);
1774                                 close(pip[1]);
1775                         }
1776                 }
1777 #endif
1778                 flags |= EV_EXIT;
1779         }
1780
1781         /* This is the child process if a fork occurred. */
1782         /* Execute the command. */
1783         if (cmdentry.cmdtype == CMDFUNCTION) {
1784 #ifdef DEBUG
1785                 trputs("Shell function:  ");  trargs(argv);
1786 #endif
1787                 exitstatus = oexitstatus;
1788                 redirect(cmd->ncmd.redirect, REDIR_PUSH);
1789                 saveparam = shellparam;
1790                 shellparam.malloc = 0;
1791                 shellparam.nparam = argc - 1;
1792                 shellparam.p = argv + 1;
1793                 INTOFF;
1794                 savelocalvars = localvars;
1795                 localvars = NULL;
1796                 INTON;
1797                 if (setjmp(jmploc.loc)) {
1798                         if (exception == EXSHELLPROC) {
1799                                 freeparam((volatile struct shparam *)
1800                                     &saveparam);
1801                         } else {
1802                                 saveparam.optind = shellparam.optind;
1803                                 saveparam.optoff = shellparam.optoff;
1804                                 freeparam(&shellparam);
1805                                 shellparam = saveparam;
1806                         }
1807                         poplocalvars();
1808                         localvars = savelocalvars;
1809                         handler = savehandler;
1810                         longjmp(handler->loc, 1);
1811                 }
1812                 savehandler = handler;
1813                 handler = &jmploc;
1814                 for (sp = varlist.list ; sp ; sp = sp->next)
1815                         mklocal(sp->text);
1816                 funcnest++;
1817                 evaltree(cmdentry.u.func, flags & EV_TESTED);
1818                 funcnest--;
1819                 INTOFF;
1820                 poplocalvars();
1821                 localvars = savelocalvars;
1822                 saveparam.optind = shellparam.optind;
1823                 saveparam.optoff = shellparam.optoff;
1824                 freeparam(&shellparam);
1825                 shellparam = saveparam;
1826                 handler = savehandler;
1827                 popredir();
1828                 INTON;
1829                 if (evalskip == SKIPFUNC) {
1830                         evalskip = 0;
1831                         skipcount = 0;
1832                 }
1833                 if (flags & EV_EXIT)
1834                         exitshell(exitstatus);
1835         } else if (cmdentry.cmdtype == CMDBUILTIN) {
1836 #ifdef DEBUG
1837                 trputs("builtin command:  ");  trargs(argv);
1838 #endif
1839                 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
1840 #ifdef notyet
1841                 if (flags == EV_BACKCMD) {
1842 #ifdef USE_GLIBC_STDIO
1843                         openmemout();
1844 #else
1845                         memout.nleft = 0;
1846                         memout.nextc = memout.buf;
1847                         memout.bufsize = 64;
1848 #endif
1849                         mode |= REDIR_BACKQ;
1850                 }
1851 #endif
1852                 redirect(cmd->ncmd.redirect, mode);
1853                 savecmdname = commandname;
1854                 if (firstbltin->flags & BUILTIN_SPECIAL) {
1855                         listsetvar(varlist.list);
1856                 } else {
1857                         cmdenviron = varlist.list;
1858                 }
1859                 e = -1;
1860                 if (setjmp(jmploc.loc)) {
1861                         e = exception;
1862                         exitstatus = (e == EXINT)? SIGINT+128 : 2;
1863                         goto cmddone;
1864                 }
1865                 savehandler = handler;
1866                 handler = &jmploc;
1867                 commandname = argv[0];
1868                 argptr = argv + 1;
1869                 optptr = NULL;                  /* initialize nextopt */
1870                 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
1871                 flushall();
1872 cmddone:
1873                 exitstatus |= outerr(out1);
1874                 out1 = &output;
1875                 out2 = &errout;
1876                 freestdout();
1877                 cmdenviron = NULL;
1878                 if (e != EXSHELLPROC) {
1879                         commandname = savecmdname;
1880                         if (flags & EV_EXIT)
1881                                 exitshell(exitstatus);
1882                 }
1883                 handler = savehandler;
1884                 if (e != -1) {
1885                         if ((e != EXERROR && e != EXEXEC)
1886                            || cmdentry.u.cmd == BLTINCMD
1887                            || cmdentry.u.cmd == DOTCMD
1888                            || cmdentry.u.cmd == EVALCMD
1889                            || cmdentry.u.cmd == EXECCMD)
1890                                 exraise(e);
1891                         FORCEINTON;
1892                 }
1893                 if (cmdentry.u.cmd != EXECCMD)
1894                         popredir();
1895 #ifdef notyet
1896                 if (flags == EV_BACKCMD) {
1897                         INTOFF;
1898 #ifdef USE_GLIBC_STDIO
1899                         if (__closememout()) {
1900                                 error(
1901                                         "__closememout() failed: %s",
1902                                         strerror(errno)
1903                                 );
1904                         }
1905 #endif
1906                         backcmd->buf = memout.buf;
1907 #ifdef USE_GLIBC_STDIO
1908                         backcmd->nleft = memout.bufsize;
1909 #else
1910                         backcmd->nleft = memout.nextc - memout.buf;
1911 #endif
1912                         memout.buf = NULL;
1913                         INTON;
1914                 }
1915 #endif
1916         } else {
1917 #ifdef DEBUG
1918                 trputs("normal command:  ");  trargs(argv);
1919 #endif
1920                 redirect(cmd->ncmd.redirect, 0);
1921                 clearredir();
1922                 for (sp = varlist.list ; sp ; sp = sp->next)
1923                         setvareq(sp->text, VEXPORT|VSTACK);
1924                 envp = environment();
1925                 shellexec(argv, envp, path, cmdentry.u.index);
1926         }
1927         goto out;
1928
1929 parent: /* parent process gets here (if we forked) */
1930         if (mode == 0) {        /* argument to fork */
1931                 INTOFF;
1932                 exitstatus = waitforjob(jp);
1933                 INTON;
1934 #ifdef notyet
1935         } else if (mode == 2) {
1936                 backcmd->fd = pip[0];
1937                 close(pip[1]);
1938                 backcmd->jp = jp;
1939 #endif
1940         }
1941
1942 out:
1943         if (lastarg)
1944                 setvar("_", lastarg, 0);
1945         popstackmark(&smark);
1946 }
1947
1948
1949
1950 /*
1951  * Search for a command.  This is called before we fork so that the
1952  * location of the command will be available in the parent as well as
1953  * the child.  The check for "goodname" is an overly conservative
1954  * check that the name will not be subject to expansion.
1955  */
1956
1957 static void
1958 prehash(n)
1959         union node *n;
1960 {
1961         struct cmdentry entry;
1962
1963         if (n->type == NCMD && n->ncmd.args)
1964                 if (goodname(n->ncmd.args->narg.text))
1965                         find_command(n->ncmd.args->narg.text, &entry, 0,
1966                                      pathval());
1967 }
1968
1969
1970
1971 /*
1972  * Builtin commands.  Builtin commands whose functions are closely
1973  * tied to evaluation are implemented here.
1974  */
1975
1976 /*
1977  * No command given, or a bltin command with no arguments.  Set the
1978  * specified variables.
1979  */
1980
1981 int
1982 bltincmd(argc, argv)
1983         int argc;
1984         char **argv;
1985 {
1986         /*
1987          * Preserve exitstatus of a previous possible redirection
1988          * as POSIX mandates
1989          */
1990         return exitstatus;
1991 }
1992
1993
1994 /*
1995  * Handle break and continue commands.  Break, continue, and return are
1996  * all handled by setting the evalskip flag.  The evaluation routines
1997  * above all check this flag, and if it is set they start skipping
1998  * commands rather than executing them.  The variable skipcount is
1999  * the number of loops to break/continue, or the number of function
2000  * levels to return.  (The latter is always 1.)  It should probably
2001  * be an error to break out of more loops than exist, but it isn't
2002  * in the standard shell so we don't make it one here.
2003  */
2004
2005 static int
2006 breakcmd(argc, argv)
2007         int argc;
2008         char **argv;
2009 {
2010         int n = argc > 1 ? number(argv[1]) : 1;
2011
2012         if (n > loopnest)
2013                 n = loopnest;
2014         if (n > 0) {
2015                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
2016                 skipcount = n;
2017         }
2018         return 0;
2019 }
2020
2021
2022 /*
2023  * The return command.
2024  */
2025
2026 static int
2027 returncmd(argc, argv)
2028         int argc;
2029         char **argv;
2030 {
2031         int ret = argc > 1 ? number(argv[1]) : oexitstatus;
2032
2033         if (funcnest) {
2034                 evalskip = SKIPFUNC;
2035                 skipcount = 1;
2036                 return ret;
2037         }
2038         else {
2039                 /* Do what ksh does; skip the rest of the file */
2040                 evalskip = SKIPFILE;
2041                 skipcount = 1;
2042                 return ret;
2043         }
2044 }
2045
2046
2047 #ifndef BB_TRUE_FALSE
2048 static int
2049 false_main(argc, argv)
2050         int argc;
2051         char **argv;
2052 {
2053         return 1;
2054 }
2055
2056
2057 static int
2058 true_main(argc, argv)
2059         int argc;
2060         char **argv;
2061 {
2062         return 0;
2063 }
2064 #endif
2065
2066 static int
2067 execcmd(argc, argv)
2068         int argc;
2069         char **argv;
2070 {
2071         if (argc > 1) {
2072                 struct strlist *sp;
2073
2074                 iflag = 0;              /* exit on error */
2075                 mflag = 0;
2076                 optschanged();
2077                 for (sp = cmdenviron; sp ; sp = sp->next)
2078                         setvareq(sp->text, VEXPORT|VSTACK);
2079                 shellexec(argv + 1, environment(), pathval(), 0);
2080         }
2081         return 0;
2082 }
2083
2084 static void
2085 eprintlist(struct strlist *sp)
2086 {
2087         for (; sp; sp = sp->next) {
2088                 outfmt(&errout, " %s",sp->text);
2089         }
2090 }
2091 /*      $NetBSD: exec.c,v 1.32 2001/02/04 19:52:06 christos Exp $       */
2092
2093 /*
2094  * When commands are first encountered, they are entered in a hash table.
2095  * This ensures that a full path search will not have to be done for them
2096  * on each invocation.
2097  *
2098  * We should investigate converting to a linear search, even though that
2099  * would make the command name "hash" a misnomer.
2100  */
2101 #define CMDTABLESIZE 31         /* should be prime */
2102 #define ARB 1                   /* actual size determined at run time */
2103
2104
2105
2106 struct tblentry {
2107         struct tblentry *next;  /* next entry in hash chain */
2108         union param param;      /* definition of builtin function */
2109         short cmdtype;          /* index identifying command */
2110         char rehash;            /* if set, cd done since entry created */
2111         char cmdname[ARB];      /* name of command */
2112 };
2113
2114
2115 static struct tblentry *cmdtable[CMDTABLESIZE];
2116 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
2117 static int exerrno = 0;                 /* Last exec error */
2118
2119
2120 static void tryexec __P((char *, char **, char **));
2121 #if !defined(BSD) && !defined(linux)
2122 static void execinterp __P((char **, char **));
2123 #endif
2124 static void printentry __P((struct tblentry *, int));
2125 static void clearcmdentry __P((int));
2126 static struct tblentry *cmdlookup __P((char *, int));
2127 static void delete_cmd_entry __P((void));
2128 #ifdef ASH_TYPE
2129 static int describe_command __P((char *, int));
2130 #endif
2131 static int path_change __P((const char *, int *));
2132
2133
2134 /*
2135  * Exec a program.  Never returns.  If you change this routine, you may
2136  * have to change the find_command routine as well.
2137  */
2138
2139 static void
2140 shellexec(argv, envp, path, idx)
2141         char **argv, **envp;
2142         const char *path;
2143         int idx;
2144 {
2145         char *cmdname;
2146         int e;
2147
2148         if (strchr(argv[0], '/') != NULL) {
2149                 tryexec(argv[0], argv, envp);
2150                 e = errno;
2151         } else {
2152                 e = ENOENT;
2153                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
2154                         if (--idx < 0 && pathopt == NULL) {
2155                                 tryexec(cmdname, argv, envp);
2156                                 if (errno != ENOENT && errno != ENOTDIR)
2157                                         e = errno;
2158                         }
2159                         stunalloc(cmdname);
2160                 }
2161         }
2162
2163         /* Map to POSIX errors */
2164         switch (e) {
2165         case EACCES:
2166                 exerrno = 126;
2167                 break;
2168         case ENOENT:
2169                 exerrno = 127;
2170                 break;
2171         default:
2172                 exerrno = 2;
2173                 break;
2174         }
2175         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
2176         /* NOTREACHED */
2177 }
2178
2179
2180 static void
2181 tryexec(cmd, argv, envp)
2182         char *cmd;
2183         char **argv;
2184         char **envp;
2185         {
2186         int e;
2187 #if !defined(BSD) && !defined(linux)
2188         char *p;
2189 #endif
2190
2191 #ifdef SYSV
2192         do {
2193                 execve(cmd, argv, envp);
2194         } while (errno == EINTR);
2195 #else
2196         execve(cmd, argv, envp);
2197 #endif
2198         e = errno;
2199         if (e == ENOEXEC) {
2200                 INTOFF;
2201                 initshellproc();
2202                 setinputfile(cmd, 0);
2203                 commandname = arg0 = savestr(argv[0]);
2204 #if !defined(BSD) && !defined(linux)
2205                 INTON;
2206                 pgetc(); pungetc();             /* fill up input buffer */
2207                 p = parsenextc;
2208                 if (parsenleft > 2 && p[0] == '#' && p[1] == '!') {
2209                         argv[0] = cmd;
2210                         execinterp(argv, envp);
2211                 }
2212                 INTOFF;
2213 #endif
2214                 setparam(argv + 1);
2215                 exraise(EXSHELLPROC);
2216         }
2217         errno = e;
2218 }
2219
2220
2221 #if !defined(BSD) && !defined(linux)
2222 /*
2223  * Execute an interpreter introduced by "#!", for systems where this
2224  * feature has not been built into the kernel.  If the interpreter is
2225  * the shell, return (effectively ignoring the "#!").  If the execution
2226  * of the interpreter fails, exit.
2227  *
2228  * This code peeks inside the input buffer in order to avoid actually
2229  * reading any input.  It would benefit from a rewrite.
2230  */
2231
2232 #define NEWARGS 5
2233
2234 static void
2235 execinterp(argv, envp)
2236         char **argv, **envp;
2237         {
2238         int n;
2239         char *inp;
2240         char *outp;
2241         char c;
2242         char *p;
2243         char **ap;
2244         char *newargs[NEWARGS];
2245         int i;
2246         char **ap2;
2247         char **new;
2248
2249         n = parsenleft - 2;
2250         inp = parsenextc + 2;
2251         ap = newargs;
2252         for (;;) {
2253                 while (--n >= 0 && (*inp == ' ' || *inp == '\t'))
2254                         inp++;
2255                 if (n < 0)
2256                         goto bad;
2257                 if ((c = *inp++) == '\n')
2258                         break;
2259                 if (ap == &newargs[NEWARGS])
2260 bad:              error("Bad #! line");
2261                 STARTSTACKSTR(outp);
2262                 do {
2263                         STPUTC(c, outp);
2264                 } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n');
2265                 STPUTC('\0', outp);
2266                 n++, inp--;
2267                 *ap++ = grabstackstr(outp);
2268         }
2269         if (ap == newargs + 1) {        /* if no args, maybe no exec is needed */
2270                 p = newargs[0];
2271                 for (;;) {
2272                         if (equal(p, "sh") || equal(p, "ash")) {
2273                                 return;
2274                         }
2275                         while (*p != '/') {
2276                                 if (*p == '\0')
2277                                         goto break2;
2278                                 p++;
2279                         }
2280                         p++;
2281                 }
2282 break2:;
2283         }
2284         i = (char *)ap - (char *)newargs;               /* size in bytes */
2285         if (i == 0)
2286                 error("Bad #! line");
2287         for (ap2 = argv ; *ap2++ != NULL ; );
2288         new = ckmalloc(i + ((char *)ap2 - (char *)argv));
2289         ap = newargs, ap2 = new;
2290         while ((i -= sizeof (char **)) >= 0)
2291                 *ap2++ = *ap++;
2292         ap = argv;
2293         while (*ap2++ = *ap++);
2294         shellexec(new, envp, pathval(), 0);
2295         /* NOTREACHED */
2296 }
2297 #endif
2298
2299
2300
2301 /*
2302  * Do a path search.  The variable path (passed by reference) should be
2303  * set to the start of the path before the first call; padvance will update
2304  * this value as it proceeds.  Successive calls to padvance will return
2305  * the possible path expansions in sequence.  If an option (indicated by
2306  * a percent sign) appears in the path entry then the global variable
2307  * pathopt will be set to point to it; otherwise pathopt will be set to
2308  * NULL.
2309  */
2310
2311 static const char *pathopt;
2312
2313 static char *
2314 padvance(path, name)
2315         const char **path;
2316         const char *name;
2317         {
2318         const char *p;
2319         char *q;
2320         const char *start;
2321         int len;
2322
2323         if (*path == NULL)
2324                 return NULL;
2325         start = *path;
2326         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
2327         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
2328         while (stackblocksize() < len)
2329                 growstackblock();
2330         q = stackblock();
2331         if (p != start) {
2332                 memcpy(q, start, p - start);
2333                 q += p - start;
2334                 *q++ = '/';
2335         }
2336         strcpy(q, name);
2337         pathopt = NULL;
2338         if (*p == '%') {
2339                 pathopt = ++p;
2340                 while (*p && *p != ':')  p++;
2341         }
2342         if (*p == ':')
2343                 *path = p + 1;
2344         else
2345                 *path = NULL;
2346         return stalloc(len);
2347 }
2348
2349
2350
2351 /*** Command hashing code ***/
2352
2353
2354 static int
2355 hashcmd(argc, argv)
2356         int argc;
2357         char **argv;
2358 {
2359         struct tblentry **pp;
2360         struct tblentry *cmdp;
2361         int c;
2362         int verbose;
2363         struct cmdentry entry;
2364         char *name;
2365
2366         verbose = 0;
2367         while ((c = nextopt("rv")) != '\0') {
2368                 if (c == 'r') {
2369                         clearcmdentry(0);
2370                         return 0;
2371                 } else if (c == 'v') {
2372                         verbose++;
2373                 }
2374         }
2375         if (*argptr == NULL) {
2376                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2377                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2378                                 if (cmdp->cmdtype != CMDBUILTIN) {
2379                                         printentry(cmdp, verbose);
2380                                 }
2381                         }
2382                 }
2383                 return 0;
2384         }
2385         c = 0;
2386         while ((name = *argptr) != NULL) {
2387                 if ((cmdp = cmdlookup(name, 0)) != NULL
2388                  && (cmdp->cmdtype == CMDNORMAL
2389                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
2390                         delete_cmd_entry();
2391                 find_command(name, &entry, DO_ERR, pathval());
2392                 if (entry.cmdtype == CMDUNKNOWN) c = 1;
2393                 else if (verbose) {
2394                         cmdp = cmdlookup(name, 0);
2395                         if (cmdp) printentry(cmdp, verbose);
2396                         flushall();
2397                 }
2398                 argptr++;
2399         }
2400         return c;
2401 }
2402
2403
2404 static void
2405 printentry(cmdp, verbose)
2406         struct tblentry *cmdp;
2407         int verbose;
2408         {
2409         int idx;
2410         const char *path;
2411         char *name;
2412
2413         if (cmdp->cmdtype == CMDNORMAL) {
2414                 idx = cmdp->param.index;
2415                 path = pathval();
2416                 do {
2417                         name = padvance(&path, cmdp->cmdname);
2418                         stunalloc(name);
2419                 } while (--idx >= 0);
2420                 out1str(name);
2421         } else if (cmdp->cmdtype == CMDBUILTIN) {
2422                 out1fmt("builtin %s", cmdp->cmdname);
2423         } else if (cmdp->cmdtype == CMDFUNCTION) {
2424                 out1fmt("function %s", cmdp->cmdname);
2425                 if (verbose) {
2426                         INTOFF;
2427                         name = commandtext(cmdp->param.func);
2428                         out1fmt(" %s", name);
2429                         ckfree(name);
2430                         INTON;
2431                 }
2432 #ifdef DEBUG
2433         } else {
2434                 error("internal error: cmdtype %d", cmdp->cmdtype);
2435 #endif
2436         }
2437         out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
2438 }
2439
2440
2441
2442 /*
2443  * Resolve a command name.  If you change this routine, you may have to
2444  * change the shellexec routine as well.
2445  */
2446
2447 static void
2448 find_command(name, entry, act, path)
2449         char *name;
2450         struct cmdentry *entry;
2451         int act;
2452         const char *path;
2453 {
2454         struct tblentry *cmdp;
2455         int idx;
2456         int prev;
2457         char *fullname;
2458         struct stat statb;
2459         int e;
2460         int bltin;
2461         int firstchange;
2462         int updatetbl;
2463         bool regular;
2464         struct builtincmd *bcmd;
2465
2466         /* If name contains a slash, don't use the hash table */
2467         if (strchr(name, '/') != NULL) {
2468                 if (act & DO_ABS) {
2469                         while (stat(name, &statb) < 0) {
2470         #ifdef SYSV
2471                                 if (errno == EINTR)
2472                                         continue;
2473         #endif
2474                                 if (errno != ENOENT && errno != ENOTDIR)
2475                                         e = errno;
2476                                 entry->cmdtype = CMDUNKNOWN;
2477                                 entry->u.index = -1;
2478                                 return;
2479                         }
2480                         entry->cmdtype = CMDNORMAL;
2481                         entry->u.index = -1;
2482                         return;
2483                 }
2484                 entry->cmdtype = CMDNORMAL;
2485                 entry->u.index = 0;
2486                 return;
2487         }
2488
2489         updatetbl = 1;
2490         if (act & DO_BRUTE) {
2491                 firstchange = path_change(path, &bltin);
2492         } else {
2493                 bltin = builtinloc;
2494                 firstchange = 9999;
2495         }
2496
2497         /* If name is in the table, and not invalidated by cd, we're done */
2498         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
2499                 if (cmdp->cmdtype == CMDFUNCTION) {
2500                         if (act & DO_NOFUN) {
2501                                 updatetbl = 0;
2502                         } else {
2503                                 goto success;
2504                         }
2505                 } else if (act & DO_BRUTE) {
2506                         if ((cmdp->cmdtype == CMDNORMAL &&
2507                              cmdp->param.index >= firstchange) ||
2508                             (cmdp->cmdtype == CMDBUILTIN &&
2509                              ((builtinloc < 0 && bltin >= 0) ?
2510                               bltin : builtinloc) >= firstchange)) {
2511                                 /* need to recompute the entry */
2512                         } else {
2513                                 goto success;
2514                         }
2515                 } else {
2516                         goto success;
2517                 }
2518         }
2519
2520         bcmd = find_builtin(name);
2521         regular = bcmd && bcmd->flags & BUILTIN_REGULAR;
2522
2523         if (regular) {
2524                 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
2525                         goto success;
2526                 }
2527         } else if (act & DO_BRUTE) {
2528                 if (firstchange == 0) {
2529                         updatetbl = 0;
2530                 }
2531         }
2532
2533         /* If %builtin not in path, check for builtin next */
2534         if (regular || (bltin < 0 && bcmd)) {
2535 builtin:
2536                 if (!updatetbl) {
2537                         entry->cmdtype = CMDBUILTIN;
2538                         entry->u.cmd = bcmd;
2539                         return;
2540                 }
2541                 INTOFF;
2542                 cmdp = cmdlookup(name, 1);
2543                 cmdp->cmdtype = CMDBUILTIN;
2544                 cmdp->param.cmd = bcmd;
2545                 INTON;
2546                 goto success;
2547         }
2548
2549         /* We have to search path. */
2550         prev = -1;              /* where to start */
2551         if (cmdp && cmdp->rehash) {     /* doing a rehash */
2552                 if (cmdp->cmdtype == CMDBUILTIN)
2553                         prev = builtinloc;
2554                 else
2555                         prev = cmdp->param.index;
2556         }
2557
2558         e = ENOENT;
2559         idx = -1;
2560 loop:
2561         while ((fullname = padvance(&path, name)) != NULL) {
2562                 stunalloc(fullname);
2563                 idx++;
2564                 if (idx >= firstchange) {
2565                         updatetbl = 0;
2566                 }
2567                 if (pathopt) {
2568                         if (prefix("builtin", pathopt)) {
2569                                 if ((bcmd = find_builtin(name))) {
2570                                         goto builtin;
2571                                 }
2572                                 continue;
2573                         } else if (!(act & DO_NOFUN) &&
2574                                    prefix("func", pathopt)) {
2575                                 /* handled below */
2576                         } else {
2577                                 continue;       /* ignore unimplemented options */
2578                         }
2579                 }
2580                 /* if rehash, don't redo absolute path names */
2581                 if (fullname[0] == '/' && idx <= prev &&
2582                     idx < firstchange) {
2583                         if (idx < prev)
2584                                 continue;
2585                         TRACE(("searchexec \"%s\": no change\n", name));
2586                         goto success;
2587                 }
2588                 while (stat(fullname, &statb) < 0) {
2589 #ifdef SYSV
2590                         if (errno == EINTR)
2591                                 continue;
2592 #endif
2593                         if (errno != ENOENT && errno != ENOTDIR)
2594                                 e = errno;
2595                         goto loop;
2596                 }
2597                 e = EACCES;     /* if we fail, this will be the error */
2598                 if (!S_ISREG(statb.st_mode))
2599                         continue;
2600                 if (pathopt) {          /* this is a %func directory */
2601                         stalloc(strlen(fullname) + 1);
2602                         readcmdfile(fullname);
2603                         if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
2604                                 error("%s not defined in %s", name, fullname);
2605                         stunalloc(fullname);
2606                         goto success;
2607                 }
2608 #ifdef notdef
2609                 if (statb.st_uid == geteuid()) {
2610                         if ((statb.st_mode & 0100) == 0)
2611                                 goto loop;
2612                 } else if (statb.st_gid == getegid()) {
2613                         if ((statb.st_mode & 010) == 0)
2614                                 goto loop;
2615                 } else {
2616                         if ((statb.st_mode & 01) == 0)
2617                                 goto loop;
2618                 }
2619 #endif
2620                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
2621                 /* If we aren't called with DO_BRUTE and cmdp is set, it must
2622                    be a function and we're being called with DO_NOFUN */
2623                 if (!updatetbl) {
2624                         entry->cmdtype = CMDNORMAL;
2625                         entry->u.index = idx;
2626                         return;
2627                 }
2628                 INTOFF;
2629                 cmdp = cmdlookup(name, 1);
2630                 cmdp->cmdtype = CMDNORMAL;
2631                 cmdp->param.index = idx;
2632                 INTON;
2633                 goto success;
2634         }
2635
2636         /* We failed.  If there was an entry for this command, delete it */
2637         if (cmdp && updatetbl)
2638                 delete_cmd_entry();
2639         if (act & DO_ERR)
2640                 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
2641         entry->cmdtype = CMDUNKNOWN;
2642         return;
2643
2644 success:
2645         cmdp->rehash = 0;
2646         entry->cmdtype = cmdp->cmdtype;
2647         entry->u = cmdp->param;
2648 }
2649
2650
2651
2652 /*
2653  * Search the table of builtin commands.
2654  */
2655
2656 struct builtincmd *
2657 find_builtin(name)
2658         char *name;
2659 {
2660         struct builtincmd *bp;
2661
2662         bp = bsearch( &name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
2663                 pstrcmp
2664         );
2665         return bp;
2666 }
2667
2668
2669 /*
2670  * Called when a cd is done.  Marks all commands so the next time they
2671  * are executed they will be rehashed.
2672  */
2673
2674 static void
2675 hashcd() {
2676         struct tblentry **pp;
2677         struct tblentry *cmdp;
2678
2679         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
2680                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2681                         if (cmdp->cmdtype == CMDNORMAL
2682                          || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
2683                                 cmdp->rehash = 1;
2684                 }
2685         }
2686 }
2687
2688
2689
2690 /*
2691  * Called before PATH is changed.  The argument is the new value of PATH;
2692  * pathval() still returns the old value at this point.  Called with
2693  * interrupts off.
2694  */
2695
2696 static void
2697 changepath(newval)
2698         const char *newval;
2699 {
2700         int firstchange;
2701         int bltin;
2702
2703         firstchange = path_change(newval, &bltin);
2704         if (builtinloc < 0 && bltin >= 0)
2705                 builtinloc = bltin;             /* zap builtins */
2706         clearcmdentry(firstchange);
2707         builtinloc = bltin;
2708 }
2709
2710
2711 /*
2712  * Clear out command entries.  The argument specifies the first entry in
2713  * PATH which has changed.
2714  */
2715
2716 static void
2717 clearcmdentry(firstchange)
2718         int firstchange;
2719 {
2720         struct tblentry **tblp;
2721         struct tblentry **pp;
2722         struct tblentry *cmdp;
2723
2724         INTOFF;
2725         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2726                 pp = tblp;
2727                 while ((cmdp = *pp) != NULL) {
2728                         if ((cmdp->cmdtype == CMDNORMAL &&
2729                              cmdp->param.index >= firstchange)
2730                          || (cmdp->cmdtype == CMDBUILTIN &&
2731                              builtinloc >= firstchange)) {
2732                                 *pp = cmdp->next;
2733                                 ckfree(cmdp);
2734                         } else {
2735                                 pp = &cmdp->next;
2736                         }
2737                 }
2738         }
2739         INTON;
2740 }
2741
2742
2743 /*
2744  * Delete all functions.
2745  */
2746
2747 #ifdef mkinit
2748 static void deletefuncs __P((void));
2749
2750 SHELLPROC {
2751         deletefuncs();
2752 }
2753 #endif
2754
2755 static void
2756 deletefuncs() {
2757         struct tblentry **tblp;
2758         struct tblentry **pp;
2759         struct tblentry *cmdp;
2760
2761         INTOFF;
2762         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
2763                 pp = tblp;
2764                 while ((cmdp = *pp) != NULL) {
2765                         if (cmdp->cmdtype == CMDFUNCTION) {
2766                                 *pp = cmdp->next;
2767                                 freefunc(cmdp->param.func);
2768                                 ckfree(cmdp);
2769                         } else {
2770                                 pp = &cmdp->next;
2771                         }
2772                 }
2773         }
2774         INTON;
2775 }
2776
2777
2778
2779 /*
2780  * Locate a command in the command hash table.  If "add" is nonzero,
2781  * add the command to the table if it is not already present.  The
2782  * variable "lastcmdentry" is set to point to the address of the link
2783  * pointing to the entry, so that delete_cmd_entry can delete the
2784  * entry.
2785  */
2786
2787 struct tblentry **lastcmdentry;
2788
2789
2790 static struct tblentry *
2791 cmdlookup(name, add)
2792         char *name;
2793         int add;
2794 {
2795         int hashval;
2796         char *p;
2797         struct tblentry *cmdp;
2798         struct tblentry **pp;
2799
2800         p = name;
2801         hashval = *p << 4;
2802         while (*p)
2803                 hashval += *p++;
2804         hashval &= 0x7FFF;
2805         pp = &cmdtable[hashval % CMDTABLESIZE];
2806         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
2807                 if (equal(cmdp->cmdname, name))
2808                         break;
2809                 pp = &cmdp->next;
2810         }
2811         if (add && cmdp == NULL) {
2812                 INTOFF;
2813                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
2814                                         + strlen(name) + 1);
2815                 cmdp->next = NULL;
2816                 cmdp->cmdtype = CMDUNKNOWN;
2817                 cmdp->rehash = 0;
2818                 strcpy(cmdp->cmdname, name);
2819                 INTON;
2820         }
2821         lastcmdentry = pp;
2822         return cmdp;
2823 }
2824
2825 /*
2826  * Delete the command entry returned on the last lookup.
2827  */
2828
2829 static void
2830 delete_cmd_entry() {
2831         struct tblentry *cmdp;
2832
2833         INTOFF;
2834         cmdp = *lastcmdentry;
2835         *lastcmdentry = cmdp->next;
2836         ckfree(cmdp);
2837         INTON;
2838 }
2839
2840
2841
2842 #ifdef notdef
2843 static void
2844 getcmdentry(name, entry)
2845         char *name;
2846         struct cmdentry *entry;
2847         {
2848         struct tblentry *cmdp = cmdlookup(name, 0);
2849
2850         if (cmdp) {
2851                 entry->u = cmdp->param;
2852                 entry->cmdtype = cmdp->cmdtype;
2853         } else {
2854                 entry->cmdtype = CMDUNKNOWN;
2855                 entry->u.index = 0;
2856         }
2857 }
2858 #endif
2859
2860
2861 /*
2862  * Add a new command entry, replacing any existing command entry for
2863  * the same name.
2864  */
2865
2866 static void
2867 addcmdentry(name, entry)
2868         char *name;
2869         struct cmdentry *entry;
2870         {
2871         struct tblentry *cmdp;
2872
2873         INTOFF;
2874         cmdp = cmdlookup(name, 1);
2875         if (cmdp->cmdtype == CMDFUNCTION) {
2876                 freefunc(cmdp->param.func);
2877         }
2878         cmdp->cmdtype = entry->cmdtype;
2879         cmdp->param = entry->u;
2880         INTON;
2881 }
2882
2883
2884 /*
2885  * Define a shell function.
2886  */
2887
2888 static void
2889 defun(name, func)
2890         char *name;
2891         union node *func;
2892         {
2893         struct cmdentry entry;
2894
2895         entry.cmdtype = CMDFUNCTION;
2896         entry.u.func = copyfunc(func);
2897         addcmdentry(name, &entry);
2898 }
2899
2900
2901 /*
2902  * Delete a function if it exists.
2903  */
2904
2905 static void
2906 unsetfunc(name)
2907         char *name;
2908         {
2909         struct tblentry *cmdp;
2910
2911         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
2912                 freefunc(cmdp->param.func);
2913                 delete_cmd_entry();
2914         }
2915 }
2916
2917 #ifdef ASH_TYPE
2918 /*
2919  * Locate and print what a word is...
2920  */
2921
2922 static int
2923 typecmd(argc, argv)
2924         int argc;
2925         char **argv;
2926 {
2927         int i;
2928         int err = 0;
2929
2930         for (i = 1; i < argc; i++) {
2931                 err |= describe_command(argv[i], 1);
2932         }
2933         return err;
2934 }
2935
2936 static int
2937 describe_command(command, verbose)
2938         char *command;
2939         int verbose;
2940 {
2941         struct cmdentry entry;
2942         struct tblentry *cmdp;
2943         const struct alias *ap;
2944         const char *path = pathval();
2945
2946         if (verbose) {
2947                 out1str(command);
2948         }
2949
2950         /* First look at the keywords */
2951         if (findkwd(command)) {
2952                 out1str(verbose ? " is a shell keyword" : command);
2953                 goto out;
2954         }
2955
2956         /* Then look at the aliases */
2957         if ((ap = lookupalias(command, 0)) != NULL) {
2958                 if (verbose) {
2959                         out1fmt(" is an alias for %s", ap->val);
2960                 } else {
2961                         printalias(ap);
2962                 }
2963                 goto out;
2964         }
2965
2966         /* Then check if it is a tracked alias */
2967         if ((cmdp = cmdlookup(command, 0)) != NULL) {
2968                 entry.cmdtype = cmdp->cmdtype;
2969                 entry.u = cmdp->param;
2970         } else {
2971                 /* Finally use brute force */
2972                 find_command(command, &entry, DO_ABS, path);
2973         }
2974
2975         switch (entry.cmdtype) {
2976         case CMDNORMAL: {
2977                 int j = entry.u.index;
2978                 char *p;
2979                 if (j == -1) {
2980                         p = command;
2981                 } else {
2982                         do {
2983                                 p = padvance(&path, command);
2984                                 stunalloc(p);
2985                         } while (--j >= 0);
2986                 }
2987                 if (verbose) {
2988                         out1fmt(
2989                                 " is%s %s",
2990                                 cmdp ? " a tracked alias for" : nullstr, p
2991                         );
2992                 } else {
2993                         out1str(p);
2994                 }
2995                 break;
2996         }
2997
2998         case CMDFUNCTION:
2999                 if (verbose) {
3000                         out1str(" is a shell function");
3001                 } else {
3002                         out1str(command);
3003                 }
3004                 break;
3005
3006         case CMDBUILTIN:
3007                 if (verbose) {
3008                         out1fmt(
3009                                 " is a %sshell builtin",
3010                                 entry.u.cmd->flags & BUILTIN_SPECIAL ?
3011                                         "special " : nullstr
3012                         );
3013                 } else {
3014                         out1str(command);
3015                 }
3016                 break;
3017
3018         default:
3019                 if (verbose) {
3020                         out1str(": not found\n");
3021                 }
3022                 return 127;
3023         }
3024
3025 out:
3026         out1c('\n');
3027         return 0;
3028 }
3029 #endif  
3030
3031 static int
3032 commandcmd(argc, argv)
3033         int argc;
3034         char **argv;
3035 {
3036         int c;
3037         int default_path = 0;
3038         int verify_only = 0;
3039         int verbose_verify_only = 0;
3040
3041         while ((c = nextopt("pvV")) != '\0')
3042                 switch (c) {
3043                 case 'p':
3044                         default_path = 1;
3045                         break;
3046                 case 'v':
3047                         verify_only = 1;
3048                         break;
3049                 case 'V':
3050                         verbose_verify_only = 1;
3051                         break;
3052                 default:
3053                         outfmt(out2,
3054 "command: nextopt returned character code 0%o\n", c);
3055                         return EX_SOFTWARE;
3056                 }
3057
3058         if (default_path + verify_only + verbose_verify_only > 1 ||
3059             !*argptr) {
3060                         outfmt(out2,
3061 "command [-p] command [arg ...]\n");
3062                         outfmt(out2,
3063 "command {-v|-V} command\n");
3064                         return EX_USAGE;
3065         }
3066
3067 #ifdef ASH_TYPE
3068         if (verify_only || verbose_verify_only) {
3069                 return describe_command(*argptr, verbose_verify_only);
3070         }
3071 #endif  
3072
3073         return 0;
3074 }
3075
3076 static int
3077 path_change(newval, bltin)
3078         const char *newval;
3079         int *bltin;
3080 {
3081         const char *old, *new;
3082         int idx;
3083         int firstchange;
3084
3085         old = pathval();
3086         new = newval;
3087         firstchange = 9999;     /* assume no change */
3088         idx = 0;
3089         *bltin = -1;
3090         for (;;) {
3091                 if (*old != *new) {
3092                         firstchange = idx;
3093                         if ((*old == '\0' && *new == ':')
3094                          || (*old == ':' && *new == '\0'))
3095                                 firstchange++;
3096                         old = new;      /* ignore subsequent differences */
3097                 }
3098                 if (*new == '\0')
3099                         break;
3100                 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
3101                         *bltin = idx;
3102                 if (*new == ':') {
3103                         idx++;
3104                 }
3105                 new++, old++;
3106         }
3107         if (builtinloc >= 0 && *bltin < 0)
3108                 firstchange = 0;
3109         return firstchange;
3110 }
3111 /*      $NetBSD: expand.c,v 1.50 2001/02/04 19:52:06 christos Exp $     */
3112
3113 /*
3114  * Routines to expand arguments to commands.  We have to deal with
3115  * backquotes, shell variables, and file metacharacters.
3116  */
3117 /*
3118  * _rmescape() flags
3119  */
3120 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
3121 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
3122
3123 /*
3124  * Structure specifying which parts of the string should be searched
3125  * for IFS characters.
3126  */
3127
3128 struct ifsregion {
3129         struct ifsregion *next; /* next region in list */
3130         int begoff;             /* offset of start of region */
3131         int endoff;             /* offset of end of region */
3132         int nulonly;            /* search for nul bytes only */
3133 };
3134
3135
3136 static char *expdest;                   /* output of current string */
3137 struct nodelist *argbackq;      /* list of back quote expressions */
3138 struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
3139 struct ifsregion *ifslastp;     /* last struct in list */
3140 struct arglist exparg;          /* holds expanded arg list */
3141
3142 static void argstr __P((char *, int));
3143 static char *exptilde __P((char *, int));
3144 static void expbackq __P((union node *, int, int));
3145 static int subevalvar __P((char *, char *, int, int, int, int, int));
3146 static char *evalvar __P((char *, int));
3147 static int varisset __P((char *, int));
3148 static void strtodest __P((const char *, const char *, int));
3149 static void varvalue __P((char *, int, int));
3150 static void recordregion __P((int, int, int));
3151 static void removerecordregions __P((int)); 
3152 static void ifsbreakup __P((char *, struct arglist *));
3153 static void ifsfree __P((void));
3154 static void expandmeta __P((struct strlist *, int));
3155 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3156 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
3157 #if !defined(GLOB_BROKEN)
3158 static void addglob __P((const glob_t *));
3159 #endif
3160 #endif
3161 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3162 static void expmeta __P((char *, char *));
3163 #endif
3164 static void addfname __P((char *));
3165 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
3166 static struct strlist *expsort __P((struct strlist *));
3167 static struct strlist *msort __P((struct strlist *, int));
3168 #endif
3169 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
3170 static int patmatch __P((char *, char *, int));
3171 static int patmatch2 __P((char *, char *, int));
3172 #else
3173 static int pmatch __P((char *, char *, int));
3174 #define patmatch2 patmatch
3175 #endif
3176 static char *cvtnum __P((int, char *));
3177
3178 extern int oexitstatus;
3179
3180 /*
3181  * Expand shell variables and backquotes inside a here document.
3182  */
3183
3184 static void
3185 expandhere(arg, fd)
3186         union node *arg;        /* the document */
3187         int fd;                 /* where to write the expanded version */
3188         {
3189         herefd = fd;
3190         expandarg(arg, (struct arglist *)NULL, 0);
3191         xwrite(fd, stackblock(), expdest - stackblock());
3192 }
3193
3194
3195 /*
3196  * Perform variable substitution and command substitution on an argument,
3197  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
3198  * perform splitting and file name expansion.  When arglist is NULL, perform
3199  * here document expansion.
3200  */
3201
3202 static void
3203 expandarg(arg, arglist, flag)
3204         union node *arg;
3205         struct arglist *arglist;
3206         int flag;
3207 {
3208         struct strlist *sp;
3209         char *p;
3210
3211         argbackq = arg->narg.backquote;
3212         STARTSTACKSTR(expdest);
3213         ifsfirst.next = NULL;
3214         ifslastp = NULL;
3215         argstr(arg->narg.text, flag);
3216         if (arglist == NULL) {
3217                 return;                 /* here document expanded */
3218         }
3219         STPUTC('\0', expdest);
3220         p = grabstackstr(expdest);
3221         exparg.lastp = &exparg.list;
3222         /*
3223          * TODO - EXP_REDIR
3224          */
3225         if (flag & EXP_FULL) {
3226                 ifsbreakup(p, &exparg);
3227                 *exparg.lastp = NULL;
3228                 exparg.lastp = &exparg.list;
3229                 expandmeta(exparg.list, flag);
3230         } else {
3231                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
3232                         rmescapes(p);
3233                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
3234                 sp->text = p;
3235                 *exparg.lastp = sp;
3236                 exparg.lastp = &sp->next;
3237         }
3238         ifsfree();
3239         *exparg.lastp = NULL;
3240         if (exparg.list) {
3241                 *arglist->lastp = exparg.list;
3242                 arglist->lastp = exparg.lastp;
3243         }
3244 }
3245
3246
3247
3248 /*
3249  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
3250  * characters to allow for further processing.  Otherwise treat
3251  * $@ like $* since no splitting will be performed.
3252  */
3253
3254 static void
3255 argstr(p, flag)
3256         char *p;
3257         int flag;
3258 {
3259         char c;
3260         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
3261         int firsteq = 1;
3262
3263         if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
3264                 p = exptilde(p, flag);
3265         for (;;) {
3266                 switch (c = *p++) {
3267                 case '\0':
3268                 case CTLENDVAR: /* ??? */
3269                         goto breakloop;
3270                 case CTLQUOTEMARK:
3271                         /* "$@" syntax adherence hack */
3272                         if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
3273                                 break;
3274                         if ((flag & EXP_FULL) != 0)
3275                                 STPUTC(c, expdest);
3276                         break;
3277                 case CTLESC:
3278                         if (quotes)
3279                                 STPUTC(c, expdest);
3280                         c = *p++;
3281                         STPUTC(c, expdest);
3282                         break;
3283                 case CTLVAR:
3284                         p = evalvar(p, flag);
3285                         break;
3286                 case CTLBACKQ:
3287                 case CTLBACKQ|CTLQUOTE:
3288                         expbackq(argbackq->n, c & CTLQUOTE, flag);
3289                         argbackq = argbackq->next;
3290                         break;
3291 #ifdef ASH_MATH_SUPPORT
3292                 case CTLENDARI:
3293                         expari(flag);
3294                         break;
3295 #endif  
3296                 case ':':
3297                 case '=':
3298                         /*
3299                          * sort of a hack - expand tildes in variable
3300                          * assignments (after the first '=' and after ':'s).
3301                          */
3302                         STPUTC(c, expdest);
3303                         if (flag & EXP_VARTILDE && *p == '~') {
3304                                 if (c == '=') {
3305                                         if (firsteq)
3306                                                 firsteq = 0;
3307                                         else
3308                                                 break;
3309                                 }
3310                                 p = exptilde(p, flag);
3311                         }
3312                         break;
3313                 default:
3314                         STPUTC(c, expdest);
3315                 }
3316         }
3317 breakloop:;
3318         return;
3319 }
3320
3321 static char *
3322 exptilde(p, flag)
3323         char *p;
3324         int flag;
3325 {
3326         char c, *startp = p;
3327         struct passwd *pw;
3328         const char *home;
3329         int quotes = flag & (EXP_FULL | EXP_CASE);
3330
3331         while ((c = *p) != '\0') {
3332                 switch(c) {
3333                 case CTLESC:
3334                         return (startp);
3335                 case CTLQUOTEMARK:
3336                         return (startp);
3337                 case ':':
3338                         if (flag & EXP_VARTILDE)
3339                                 goto done;
3340                         break;
3341                 case '/':
3342                         goto done;
3343                 }
3344                 p++;
3345         }
3346 done:
3347         *p = '\0';
3348         if (*(startp+1) == '\0') {
3349                 if ((home = lookupvar("HOME")) == NULL)
3350                         goto lose;
3351         } else {
3352                 if ((pw = getpwnam(startp+1)) == NULL)
3353                         goto lose;
3354                 home = pw->pw_dir;
3355         }
3356         if (*home == '\0')
3357                 goto lose;
3358         *p = c;
3359         strtodest(home, SQSYNTAX, quotes);
3360         return (p);
3361 lose:
3362         *p = c;
3363         return (startp);
3364 }
3365
3366
3367 static void 
3368 removerecordregions(endoff)
3369         int endoff;
3370 {
3371         if (ifslastp == NULL)
3372                 return;
3373
3374         if (ifsfirst.endoff > endoff) {
3375                 while (ifsfirst.next != NULL) {
3376                         struct ifsregion *ifsp;
3377                         INTOFF;
3378                         ifsp = ifsfirst.next->next;
3379                         ckfree(ifsfirst.next);
3380                         ifsfirst.next = ifsp;
3381                         INTON;
3382                 }
3383                 if (ifsfirst.begoff > endoff)
3384                         ifslastp = NULL;
3385                 else {
3386                         ifslastp = &ifsfirst;
3387                         ifsfirst.endoff = endoff;
3388                 }
3389                 return;
3390         }
3391         
3392         ifslastp = &ifsfirst;
3393         while (ifslastp->next && ifslastp->next->begoff < endoff)
3394                 ifslastp=ifslastp->next;
3395         while (ifslastp->next != NULL) {
3396                 struct ifsregion *ifsp;
3397                 INTOFF;
3398                 ifsp = ifslastp->next->next;
3399                 ckfree(ifslastp->next);
3400                 ifslastp->next = ifsp;
3401                 INTON;
3402         }
3403         if (ifslastp->endoff > endoff)
3404                 ifslastp->endoff = endoff;
3405 }
3406
3407
3408 #ifdef ASH_MATH_SUPPORT
3409 /*
3410  * Expand arithmetic expression.  Backup to start of expression,
3411  * evaluate, place result in (backed up) result, adjust string position.
3412  */
3413 static void
3414 expari(flag)
3415         int flag;
3416 {
3417         char *p, *start;
3418         int result;
3419         int begoff;
3420         int quotes = flag & (EXP_FULL | EXP_CASE);
3421         int quoted;
3422
3423         /*      ifsfree(); */
3424
3425         /*
3426          * This routine is slightly over-complicated for
3427          * efficiency.  First we make sure there is
3428          * enough space for the result, which may be bigger
3429          * than the expression if we add exponentation.  Next we
3430          * scan backwards looking for the start of arithmetic.  If the
3431          * next previous character is a CTLESC character, then we
3432          * have to rescan starting from the beginning since CTLESC
3433          * characters have to be processed left to right.
3434          */
3435         CHECKSTRSPACE(10, expdest);
3436         USTPUTC('\0', expdest);
3437         start = stackblock();
3438         p = expdest - 1;
3439         while (*p != CTLARI && p >= start)
3440                 --p;
3441         if (*p != CTLARI)
3442                 error("missing CTLARI (shouldn't happen)");
3443         if (p > start && *(p-1) == CTLESC)
3444                 for (p = start; *p != CTLARI; p++)
3445                         if (*p == CTLESC)
3446                                 p++;
3447
3448         if (p[1] == '"')
3449                 quoted=1;
3450         else
3451                 quoted=0;
3452         begoff = p - start;
3453         removerecordregions(begoff);
3454         if (quotes)
3455                 rmescapes(p+2);
3456         result = arith(p+2);
3457         fmtstr(p, 12, "%d", result);
3458
3459         while (*p++)
3460                 ;
3461
3462         if (quoted == 0)
3463                 recordregion(begoff, p - 1 - start, 0);
3464         result = expdest - p + 1;
3465         STADJUST(-result, expdest);
3466 }
3467 #endif  
3468
3469
3470 /*
3471  * Expand stuff in backwards quotes.
3472  */
3473
3474 static void
3475 expbackq(cmd, quoted, flag)
3476         union node *cmd;
3477         int quoted;
3478         int flag;
3479 {
3480         volatile struct backcmd in;
3481         int i;
3482         char buf[128];
3483         char *p;
3484         char *dest = expdest;
3485         volatile struct ifsregion saveifs;
3486         struct ifsregion *volatile savelastp;
3487         struct nodelist *volatile saveargbackq;
3488         char lastc;
3489         int startloc = dest - stackblock();
3490         char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
3491         volatile int saveherefd;
3492         int quotes = flag & (EXP_FULL | EXP_CASE);
3493         struct jmploc jmploc;
3494         struct jmploc *volatile savehandler;
3495         int ex;
3496
3497 #if __GNUC__
3498         /* Avoid longjmp clobbering */
3499         (void) &dest;
3500         (void) &syntax;
3501 #endif
3502
3503         in.fd = -1;
3504         in.buf = 0;
3505         in.jp = 0;
3506
3507         INTOFF;
3508         saveifs = ifsfirst;
3509         savelastp = ifslastp;
3510         saveargbackq = argbackq;
3511         saveherefd = herefd;
3512         herefd = -1;
3513         if ((ex = setjmp(jmploc.loc))) {
3514                 goto err1;
3515         }
3516         savehandler = handler;
3517         handler = &jmploc;
3518         INTON;
3519         p = grabstackstr(dest);
3520         evalbackcmd(cmd, (struct backcmd *) &in);
3521         ungrabstackstr(p, dest);
3522 err1:
3523         INTOFF;
3524         ifsfirst = saveifs;
3525         ifslastp = savelastp;
3526         argbackq = saveargbackq;
3527         herefd = saveherefd;
3528         if (ex) {
3529                 goto err2;
3530         }
3531
3532         p = in.buf;
3533         lastc = '\0';
3534         for (;;) {
3535                 if (--in.nleft < 0) {
3536                         if (in.fd < 0)
3537                                 break;
3538                         while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
3539                         TRACE(("expbackq: read returns %d\n", i));
3540                         if (i <= 0)
3541                                 break;
3542                         p = buf;
3543                         in.nleft = i - 1;
3544                 }
3545                 lastc = *p++;
3546                 if (lastc != '\0') {
3547                         if (quotes && syntax[(int)lastc] == CCTL)
3548                                 STPUTC(CTLESC, dest);
3549                         STPUTC(lastc, dest);
3550                 }
3551         }
3552
3553         /* Eat all trailing newlines */
3554         for (; dest > stackblock() && dest[-1] == '\n';)
3555                 STUNPUTC(dest);
3556
3557 err2:
3558         if (in.fd >= 0)
3559                 close(in.fd);
3560         if (in.buf)
3561                 ckfree(in.buf);
3562         if (in.jp)
3563                 exitstatus = waitforjob(in.jp);
3564         handler = savehandler;
3565         if (ex) {
3566                 longjmp(handler->loc, 1);
3567         }
3568         if (quoted == 0)
3569                 recordregion(startloc, dest - stackblock(), 0);
3570         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
3571                 (dest - stackblock()) - startloc,
3572                 (dest - stackblock()) - startloc,
3573                 stackblock() + startloc));
3574         expdest = dest;
3575         INTON;
3576 }
3577
3578
3579
3580 static int
3581 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
3582         char *p;
3583         char *str;
3584         int strloc;
3585         int subtype;
3586         int startloc;
3587         int varflags;
3588         int quotes;
3589 {
3590         char *startp;
3591         char *loc = NULL;
3592         char *q;
3593         int c = 0;
3594         int saveherefd = herefd;
3595         struct nodelist *saveargbackq = argbackq;
3596         int amount;
3597
3598         herefd = -1;
3599         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
3600         STACKSTRNUL(expdest);
3601         herefd = saveherefd;
3602         argbackq = saveargbackq;
3603         startp = stackblock() + startloc;
3604         if (str == NULL)
3605             str = stackblock() + strloc;
3606
3607         switch (subtype) {
3608         case VSASSIGN:
3609                 setvar(str, startp, 0);
3610                 amount = startp - expdest;
3611                 STADJUST(amount, expdest);
3612                 varflags &= ~VSNUL;
3613                 if (c != 0)
3614                         *loc = c;
3615                 return 1;
3616
3617         case VSQUESTION:
3618                 if (*p != CTLENDVAR) {
3619                         outfmt(&errout, snlfmt, startp);
3620                         error((char *)NULL);
3621                 }
3622                 error("%.*s: parameter %snot set", p - str - 1,
3623                       str, (varflags & VSNUL) ? "null or "
3624                                               : nullstr);
3625                 /* NOTREACHED */
3626
3627         case VSTRIMLEFT:
3628                 for (loc = startp; loc < str; loc++) {
3629                         c = *loc;
3630                         *loc = '\0';
3631                         if (patmatch2(str, startp, quotes))
3632                                 goto recordleft;
3633                         *loc = c;
3634                         if (quotes && *loc == CTLESC)
3635                                 loc++;
3636                 }
3637                 return 0;
3638
3639         case VSTRIMLEFTMAX:
3640                 for (loc = str - 1; loc >= startp;) {
3641                         c = *loc;
3642                         *loc = '\0';
3643                         if (patmatch2(str, startp, quotes))
3644                                 goto recordleft;
3645                         *loc = c;
3646                         loc--;
3647                         if (quotes && loc > startp && *(loc - 1) == CTLESC) {
3648                                 for (q = startp; q < loc; q++)
3649                                         if (*q == CTLESC)
3650                                                 q++;
3651                                 if (q > loc)
3652                                         loc--;
3653                         }
3654                 }
3655                 return 0;
3656
3657         case VSTRIMRIGHT:
3658                 for (loc = str - 1; loc >= startp;) {
3659                         if (patmatch2(str, loc, quotes))
3660                                 goto recordright;
3661                         loc--;
3662                         if (quotes && loc > startp && *(loc - 1) == CTLESC) { 
3663                                 for (q = startp; q < loc; q++)
3664                                         if (*q == CTLESC)
3665                                                 q++;
3666                                 if (q > loc)
3667                                         loc--;
3668                         }
3669                 }
3670                 return 0;
3671
3672         case VSTRIMRIGHTMAX:
3673                 for (loc = startp; loc < str - 1; loc++) {
3674                         if (patmatch2(str, loc, quotes))
3675                                 goto recordright;
3676                         if (quotes && *loc == CTLESC)
3677                                 loc++;
3678                 }
3679                 return 0;
3680
3681 #ifdef DEBUG
3682         default:
3683                 abort();
3684 #endif
3685         }
3686
3687 recordleft:
3688         *loc = c;
3689         amount = ((str - 1) - (loc - startp)) - expdest;
3690         STADJUST(amount, expdest);
3691         while (loc != str - 1)
3692                 *startp++ = *loc++;
3693         return 1;
3694
3695 recordright:
3696         amount = loc - expdest;
3697         STADJUST(amount, expdest);
3698         STPUTC('\0', expdest);
3699         STADJUST(-1, expdest);
3700         return 1;
3701 }
3702
3703
3704 /*
3705  * Expand a variable, and return a pointer to the next character in the
3706  * input string.
3707  */
3708
3709 static char *
3710 evalvar(p, flag)
3711         char *p;
3712         int flag;
3713 {
3714         int subtype;
3715         int varflags;
3716         char *var;
3717         char *val;
3718         int patloc;
3719         int c;
3720         int set;
3721         int special;
3722         int startloc;
3723         int varlen;
3724         int easy;
3725         int quotes = flag & (EXP_FULL | EXP_CASE);
3726
3727         varflags = *p++;
3728         subtype = varflags & VSTYPE;
3729         var = p;
3730         special = 0;
3731         if (! is_name(*p))
3732                 special = 1;
3733         p = strchr(p, '=') + 1;
3734 again: /* jump here after setting a variable with ${var=text} */
3735         if (special) {
3736                 set = varisset(var, varflags & VSNUL);
3737                 val = NULL;
3738         } else {
3739                 val = lookupvar(var);
3740                 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
3741                         val = NULL;
3742                         set = 0;
3743                 } else
3744                         set = 1;
3745         }
3746         varlen = 0;
3747         startloc = expdest - stackblock();
3748         if (set && subtype != VSPLUS) {
3749                 /* insert the value of the variable */
3750                 if (special) {
3751                         varvalue(var, varflags & VSQUOTE, flag);
3752                         if (subtype == VSLENGTH) {
3753                                 varlen = expdest - stackblock() - startloc;
3754                                 STADJUST(-varlen, expdest);
3755                         }
3756                 } else {
3757                         if (subtype == VSLENGTH) {
3758                                 varlen = strlen(val);
3759                         } else {
3760                                 strtodest(
3761                                         val,
3762                                         varflags & VSQUOTE ?
3763                                                 DQSYNTAX : BASESYNTAX,
3764                                         quotes
3765                                 );
3766                         }
3767                 }
3768         }
3769
3770         if (subtype == VSPLUS)
3771                 set = ! set;
3772
3773         easy = ((varflags & VSQUOTE) == 0 ||
3774                 (*var == '@' && shellparam.nparam != 1));
3775
3776
3777         switch (subtype) {
3778         case VSLENGTH:
3779                 expdest = cvtnum(varlen, expdest);
3780                 goto record;
3781
3782         case VSNORMAL:
3783                 if (!easy)
3784                         break;
3785 record:
3786                 recordregion(startloc, expdest - stackblock(),
3787                              varflags & VSQUOTE);
3788                 break;
3789
3790         case VSPLUS:
3791         case VSMINUS:
3792                 if (!set) {
3793                         argstr(p, flag);
3794                         break;
3795                 }
3796                 if (easy)
3797                         goto record;
3798                 break;
3799
3800         case VSTRIMLEFT:
3801         case VSTRIMLEFTMAX:
3802         case VSTRIMRIGHT:
3803         case VSTRIMRIGHTMAX:
3804                 if (!set)
3805                         break;
3806                 /*
3807                  * Terminate the string and start recording the pattern
3808                  * right after it
3809                  */
3810                 STPUTC('\0', expdest);
3811                 patloc = expdest - stackblock();
3812                 if (subevalvar(p, NULL, patloc, subtype,
3813                                startloc, varflags, quotes) == 0) {
3814                         int amount = (expdest - stackblock() - patloc) + 1;
3815                         STADJUST(-amount, expdest);
3816                 }
3817                 /* Remove any recorded regions beyond start of variable */
3818                 removerecordregions(startloc);
3819                 goto record;
3820
3821         case VSASSIGN:
3822         case VSQUESTION:
3823                 if (!set) {
3824                         if (subevalvar(p, var, 0, subtype, startloc,
3825                                        varflags, quotes)) {
3826                                 varflags &= ~VSNUL;
3827                                 /* 
3828                                  * Remove any recorded regions beyond 
3829                                  * start of variable 
3830                                  */
3831                                 removerecordregions(startloc);
3832                                 goto again;
3833                         }
3834                         break;
3835                 }
3836                 if (easy)
3837                         goto record;
3838                 break;
3839
3840 #ifdef DEBUG
3841         default:
3842                 abort();
3843 #endif
3844         }
3845
3846         if (subtype != VSNORMAL) {      /* skip to end of alternative */
3847                 int nesting = 1;
3848                 for (;;) {
3849                         if ((c = *p++) == CTLESC)
3850                                 p++;
3851                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
3852                                 if (set)
3853                                         argbackq = argbackq->next;
3854                         } else if (c == CTLVAR) {
3855                                 if ((*p++ & VSTYPE) != VSNORMAL)
3856                                         nesting++;
3857                         } else if (c == CTLENDVAR) {
3858                                 if (--nesting == 0)
3859                                         break;
3860                         }
3861                 }
3862         }
3863         return p;
3864 }
3865
3866
3867
3868 /*
3869  * Test whether a specialized variable is set.
3870  */
3871
3872 static int
3873 varisset(name, nulok)
3874         char *name;
3875         int nulok;
3876 {
3877         if (*name == '!')
3878                 return backgndpid != -1;
3879         else if (*name == '@' || *name == '*') {
3880                 if (*shellparam.p == NULL)
3881                         return 0;
3882
3883                 if (nulok) {
3884                         char **av;
3885
3886                         for (av = shellparam.p; *av; av++)
3887                                 if (**av != '\0')
3888                                         return 1;
3889                         return 0;
3890                 }
3891         } else if (is_digit(*name)) {
3892                 char *ap;
3893                 int num = atoi(name);
3894
3895                 if (num > shellparam.nparam)
3896                         return 0;
3897
3898                 if (num == 0)
3899                         ap = arg0;
3900                 else
3901                         ap = shellparam.p[num - 1];
3902
3903                 if (nulok && (ap == NULL || *ap == '\0'))
3904                         return 0;
3905         }
3906         return 1;
3907 }
3908
3909
3910
3911 /*
3912  * Put a string on the stack.
3913  */
3914
3915 static void
3916 strtodest(p, syntax, quotes)
3917         const char *p;
3918         const char *syntax;
3919         int quotes;
3920 {
3921         while (*p) {
3922                 if (quotes && syntax[(int) *p] == CCTL)
3923                         STPUTC(CTLESC, expdest);
3924                 STPUTC(*p++, expdest);
3925         }
3926 }
3927
3928
3929
3930 /*
3931  * Add the value of a specialized variable to the stack string.
3932  */
3933
3934 static void
3935 varvalue(name, quoted, flags)
3936         char *name;
3937         int quoted;
3938         int flags;
3939 {
3940         int num;
3941         char *p;
3942         int i;
3943         int sep;
3944         int sepq = 0;
3945         char **ap;
3946         char const *syntax;
3947         int allow_split = flags & EXP_FULL;
3948         int quotes = flags & (EXP_FULL | EXP_CASE);
3949
3950         syntax = quoted ? DQSYNTAX : BASESYNTAX;
3951         switch (*name) {
3952         case '$':
3953                 num = rootpid;
3954                 goto numvar;
3955         case '?':
3956                 num = oexitstatus;
3957                 goto numvar;
3958         case '#':
3959                 num = shellparam.nparam;
3960                 goto numvar;
3961         case '!':
3962                 num = backgndpid;
3963 numvar:
3964                 expdest = cvtnum(num, expdest);
3965                 break;
3966         case '-':
3967                 for (i = 0 ; i < NOPTS ; i++) {
3968                         if (optlist[i].val)
3969                                 STPUTC(optlist[i].letter, expdest);
3970                 }
3971                 break;
3972         case '@':
3973                 if (allow_split && quoted) {
3974                         sep = 1 << CHAR_BIT;
3975                         goto param;
3976                 }
3977                 /* fall through */
3978         case '*':
3979                 sep = ifsset() ? ifsval()[0] : ' ';
3980                 if (quotes) {
3981                         sepq = syntax[(int) sep] == CCTL;
3982                 }
3983 param:
3984                 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
3985                         strtodest(p, syntax, quotes);
3986                         if (*ap && sep) {
3987                                 if (sepq)
3988                                         STPUTC(CTLESC, expdest);
3989                                 STPUTC(sep, expdest);
3990                         }
3991                 }
3992                 break;
3993         case '0':
3994                 strtodest(arg0, syntax, quotes);
3995                 break;
3996         default:
3997                 num = atoi(name);
3998                 if (num > 0 && num <= shellparam.nparam) {
3999                         strtodest(shellparam.p[num - 1], syntax, quotes);
4000                 }
4001                 break;
4002         }
4003 }
4004
4005
4006
4007 /*
4008  * Record the fact that we have to scan this region of the
4009  * string for IFS characters.
4010  */
4011
4012 static void
4013 recordregion(start, end, nulonly)
4014         int start;
4015         int end;
4016         int nulonly;
4017 {
4018         struct ifsregion *ifsp;
4019
4020         if (ifslastp == NULL) {
4021                 ifsp = &ifsfirst;
4022         } else {
4023                 INTOFF;
4024                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
4025                 ifsp->next = NULL;
4026                 ifslastp->next = ifsp;
4027                 INTON;
4028         }
4029         ifslastp = ifsp;
4030         ifslastp->begoff = start;
4031         ifslastp->endoff = end;
4032         ifslastp->nulonly = nulonly;
4033 }
4034
4035
4036
4037 /*
4038  * Break the argument string into pieces based upon IFS and add the
4039  * strings to the argument list.  The regions of the string to be
4040  * searched for IFS characters have been stored by recordregion.
4041  */
4042 static void
4043 ifsbreakup(string, arglist)
4044         char *string;
4045         struct arglist *arglist;
4046         {
4047         struct ifsregion *ifsp;
4048         struct strlist *sp;
4049         char *start;
4050         char *p;
4051         char *q;
4052         const char *ifs, *realifs;
4053         int ifsspc;
4054         int nulonly;
4055
4056
4057         start = string;
4058         ifsspc = 0;
4059         nulonly = 0;
4060         realifs = ifsset() ? ifsval() : defifs;
4061         if (ifslastp != NULL) {
4062                 ifsp = &ifsfirst;
4063                 do {
4064                         p = string + ifsp->begoff;
4065                         nulonly = ifsp->nulonly;
4066                         ifs = nulonly ? nullstr : realifs;
4067                         ifsspc = 0;
4068                         while (p < string + ifsp->endoff) {
4069                                 q = p;
4070                                 if (*p == CTLESC)
4071                                         p++;
4072                                 if (strchr(ifs, *p)) {
4073                                         if (!nulonly)
4074                                                 ifsspc = (strchr(defifs, *p) != NULL);
4075                                         /* Ignore IFS whitespace at start */
4076                                         if (q == start && ifsspc) {
4077                                                 p++;
4078                                                 start = p;
4079                                                 continue;
4080                                         }
4081                                         *q = '\0';
4082                                         sp = (struct strlist *)stalloc(sizeof *sp);
4083                                         sp->text = start;
4084                                         *arglist->lastp = sp;
4085                                         arglist->lastp = &sp->next;
4086                                         p++;
4087                                         if (!nulonly) {
4088                                                 for (;;) {
4089                                                         if (p >= string + ifsp->endoff) {
4090                                                                 break;
4091                                                         }
4092                                                         q = p;
4093                                                         if (*p == CTLESC)
4094                                                                 p++;
4095                                                         if (strchr(ifs, *p) == NULL ) {
4096                                                                 p = q;
4097                                                                 break;
4098                                                         } else if (strchr(defifs, *p) == NULL) {
4099                                                                 if (ifsspc) {
4100                                                                         p++;
4101                                                                         ifsspc = 0;
4102                                                                 } else {
4103                                                                         p = q;
4104                                                                         break;
4105                                                                 }
4106                                                         } else
4107                                                                 p++;
4108                                                 }
4109                                         }
4110                                         start = p;
4111                                 } else
4112                                         p++;
4113                         }
4114                 } while ((ifsp = ifsp->next) != NULL);
4115                 if (!(*start || (!ifsspc && start > string && nulonly))) {
4116                         return;
4117                 }
4118         }
4119
4120         sp = (struct strlist *)stalloc(sizeof *sp);
4121         sp->text = start;
4122         *arglist->lastp = sp;
4123         arglist->lastp = &sp->next;
4124 }
4125
4126 static void
4127 ifsfree()
4128 {
4129         while (ifsfirst.next != NULL) {
4130                 struct ifsregion *ifsp;
4131                 INTOFF;
4132                 ifsp = ifsfirst.next->next;
4133                 ckfree(ifsfirst.next);
4134                 ifsfirst.next = ifsp;
4135                 INTON;
4136         }
4137         ifslastp = NULL;
4138         ifsfirst.next = NULL;
4139 }
4140
4141
4142
4143 /*
4144  * Expand shell metacharacters.  At this point, the only control characters
4145  * should be escapes.  The results are stored in the list exparg.
4146  */
4147
4148 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
4149 static void
4150 expandmeta(str, flag)
4151         struct strlist *str;
4152         int flag;
4153 {
4154         const char *p;
4155         glob_t pglob;
4156         /* TODO - EXP_REDIR */
4157
4158         while (str) {
4159                 if (fflag)
4160                         goto nometa;
4161                 p = preglob(str->text);
4162                 INTOFF;
4163                 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
4164                 case 0:
4165                         if (!(pglob.gl_flags & GLOB_MAGCHAR))
4166                                 goto nometa2;
4167                         addglob(&pglob);
4168                         globfree(&pglob);
4169                         INTON;
4170                         break;
4171                 case GLOB_NOMATCH:
4172 nometa2:
4173                         globfree(&pglob);
4174                         INTON;
4175 nometa:
4176                         *exparg.lastp = str;
4177                         rmescapes(str->text);
4178                         exparg.lastp = &str->next;
4179                         break;
4180                 default:        /* GLOB_NOSPACE */
4181                         error("Out of space");
4182                 }
4183                 str = str->next;
4184         }
4185 }
4186
4187
4188 /*
4189  * Add the result of glob(3) to the list.
4190  */
4191
4192 static void
4193 addglob(pglob)
4194         const glob_t *pglob;
4195 {
4196         char **p = pglob->gl_pathv;
4197
4198         do {
4199                 addfname(*p);
4200         } while (*++p);
4201 }
4202
4203
4204 #else   /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4205 static char *expdir;
4206
4207
4208 static void
4209 expandmeta(str, flag)
4210         struct strlist *str;
4211         int flag;
4212 {
4213         char *p;
4214         struct strlist **savelastp;
4215         struct strlist *sp;
4216         char c;
4217         /* TODO - EXP_REDIR */
4218
4219         while (str) {
4220                 if (fflag)
4221                         goto nometa;
4222                 p = str->text;
4223                 for (;;) {                      /* fast check for meta chars */
4224                         if ((c = *p++) == '\0')
4225                                 goto nometa;
4226                         if (c == '*' || c == '?' || c == '[' || c == '!')
4227                                 break;
4228                 }
4229                 savelastp = exparg.lastp;
4230                 INTOFF;
4231                 if (expdir == NULL) {
4232                         int i = strlen(str->text);
4233                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
4234                 }
4235
4236                 expmeta(expdir, str->text);
4237                 ckfree(expdir);
4238                 expdir = NULL;
4239                 INTON;
4240                 if (exparg.lastp == savelastp) {
4241                         /*
4242                          * no matches
4243                          */
4244 nometa:
4245                         *exparg.lastp = str;
4246                         rmescapes(str->text);
4247                         exparg.lastp = &str->next;
4248                 } else {
4249                         *exparg.lastp = NULL;
4250                         *savelastp = sp = expsort(*savelastp);
4251                         while (sp->next != NULL)
4252                                 sp = sp->next;
4253                         exparg.lastp = &sp->next;
4254                 }
4255                 str = str->next;
4256         }
4257 }
4258
4259
4260 /*
4261  * Do metacharacter (i.e. *, ?, [...]) expansion.
4262  */
4263
4264 static void
4265 expmeta(enddir, name)
4266         char *enddir;
4267         char *name;
4268         {
4269         char *p;
4270         const char *cp;
4271         char *q;
4272         char *start;
4273         char *endname;
4274         int metaflag;
4275         struct stat statb;
4276         DIR *dirp;
4277         struct dirent *dp;
4278         int atend;
4279         int matchdot;
4280
4281         metaflag = 0;
4282         start = name;
4283         for (p = name ; ; p++) {
4284                 if (*p == '*' || *p == '?')
4285                         metaflag = 1;
4286                 else if (*p == '[') {
4287                         q = p + 1;
4288                         if (*q == '!')
4289                                 q++;
4290                         for (;;) {
4291                                 while (*q == CTLQUOTEMARK)
4292                                         q++;
4293                                 if (*q == CTLESC)
4294                                         q++;
4295                                 if (*q == '/' || *q == '\0')
4296                                         break;
4297                                 if (*++q == ']') {
4298                                         metaflag = 1;
4299                                         break;
4300                                 }
4301                         }
4302                 } else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
4303                         metaflag = 1;
4304                 } else if (*p == '\0')
4305                         break;
4306                 else if (*p == CTLQUOTEMARK)
4307                         continue;
4308                 else if (*p == CTLESC)
4309                         p++;
4310                 if (*p == '/') {
4311                         if (metaflag)
4312                                 break;
4313                         start = p + 1;
4314                 }
4315         }
4316         if (metaflag == 0) {    /* we've reached the end of the file name */
4317                 if (enddir != expdir)
4318                         metaflag++;
4319                 for (p = name ; ; p++) {
4320                         if (*p == CTLQUOTEMARK)
4321                                 continue;
4322                         if (*p == CTLESC)
4323                                 p++;
4324                         *enddir++ = *p;
4325                         if (*p == '\0')
4326                                 break;
4327                 }
4328                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
4329                         addfname(expdir);
4330                 return;
4331         }
4332         endname = p;
4333         if (start != name) {
4334                 p = name;
4335                 while (p < start) {
4336                         while (*p == CTLQUOTEMARK)
4337                                 p++;
4338                         if (*p == CTLESC)
4339                                 p++;
4340                         *enddir++ = *p++;
4341                 }
4342         }
4343         if (enddir == expdir) {
4344                 cp = ".";
4345         } else if (enddir == expdir + 1 && *expdir == '/') {
4346                 cp = "/";
4347         } else {
4348                 cp = expdir;
4349                 enddir[-1] = '\0';
4350         }
4351         if ((dirp = opendir(cp)) == NULL)
4352                 return;
4353         if (enddir != expdir)
4354                 enddir[-1] = '/';
4355         if (*endname == 0) {
4356                 atend = 1;
4357         } else {
4358                 atend = 0;
4359                 *endname++ = '\0';
4360         }
4361         matchdot = 0;
4362         p = start;
4363         while (*p == CTLQUOTEMARK)
4364                 p++;
4365         if (*p == CTLESC)
4366                 p++;
4367         if (*p == '.')
4368                 matchdot++;
4369         while (! int_pending() && (dp = readdir(dirp)) != NULL) {
4370                 if (dp->d_name[0] == '.' && ! matchdot)
4371                         continue;
4372                 if (patmatch(start, dp->d_name, 0)) {
4373                         if (atend) {
4374                                 scopy(dp->d_name, enddir);
4375                                 addfname(expdir);
4376                         } else {
4377                                 for (p = enddir, cp = dp->d_name;
4378                                      (*p++ = *cp++) != '\0';)
4379                                         continue;
4380                                 p[-1] = '/';
4381                                 expmeta(p, endname);
4382                         }
4383                 }
4384         }
4385         closedir(dirp);
4386         if (! atend)
4387                 endname[-1] = '/';
4388 }
4389 #endif  /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
4390
4391
4392 /*
4393  * Add a file name to the list.
4394  */
4395
4396 static void
4397 addfname(name)
4398         char *name;
4399         {
4400         char *p;
4401         struct strlist *sp;
4402
4403         p = sstrdup(name);
4404         sp = (struct strlist *)stalloc(sizeof *sp);
4405         sp->text = p;
4406         *exparg.lastp = sp;
4407         exparg.lastp = &sp->next;
4408 }
4409
4410
4411 #if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4412 /*
4413  * Sort the results of file name expansion.  It calculates the number of
4414  * strings to sort and then calls msort (short for merge sort) to do the
4415  * work.
4416  */
4417
4418 static struct strlist *
4419 expsort(str)
4420         struct strlist *str;
4421         {
4422         int len;
4423         struct strlist *sp;
4424
4425         len = 0;
4426         for (sp = str ; sp ; sp = sp->next)
4427                 len++;
4428         return msort(str, len);
4429 }
4430
4431
4432 static struct strlist *
4433 msort(list, len)
4434         struct strlist *list;
4435         int len;
4436 {
4437         struct strlist *p, *q = NULL;
4438         struct strlist **lpp;
4439         int half;
4440         int n;
4441
4442         if (len <= 1)
4443                 return list;
4444         half = len >> 1;
4445         p = list;
4446         for (n = half ; --n >= 0 ; ) {
4447                 q = p;
4448                 p = p->next;
4449         }
4450         q->next = NULL;                 /* terminate first half of list */
4451         q = msort(list, half);          /* sort first half of list */
4452         p = msort(p, len - half);               /* sort second half */
4453         lpp = &list;
4454         for (;;) {
4455                 if (strcmp(p->text, q->text) < 0) {
4456                         *lpp = p;
4457                         lpp = &p->next;
4458                         if ((p = *lpp) == NULL) {
4459                                 *lpp = q;
4460                                 break;
4461                         }
4462                 } else {
4463                         *lpp = q;
4464                         lpp = &q->next;
4465                         if ((q = *lpp) == NULL) {
4466                                 *lpp = p;
4467                                 break;
4468                         }
4469                 }
4470         }
4471         return list;
4472 }
4473 #endif
4474
4475
4476
4477 /*
4478  * Returns true if the pattern matches the string.
4479  */
4480
4481 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4482 static int
4483 patmatch(pattern, string, squoted)
4484         char *pattern;
4485         char *string;
4486         int squoted;    /* string might have quote chars */
4487         {
4488         const char *p;
4489         char *q;
4490
4491         p = preglob(pattern);
4492         q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
4493
4494         return !fnmatch(p, q, 0);
4495 }
4496
4497
4498 static int
4499 patmatch2(pattern, string, squoted)
4500         char *pattern;
4501         char *string;
4502         int squoted;    /* string might have quote chars */
4503         {
4504         char *p;
4505         int res;
4506
4507         sstrnleft--;
4508         p = grabstackstr(expdest);
4509         res = patmatch(pattern, string, squoted);
4510         ungrabstackstr(p, expdest);
4511         return res;
4512 }
4513 #else
4514 static int
4515 patmatch(pattern, string, squoted)
4516         char *pattern;
4517         char *string;
4518         int squoted;    /* string might have quote chars */
4519         {
4520 #ifdef notdef
4521         if (pattern[0] == '!' && pattern[1] == '!')
4522                 return 1 - pmatch(pattern + 2, string);
4523         else
4524 #endif
4525                 return pmatch(pattern, string, squoted);
4526 }
4527
4528
4529 static int
4530 pmatch(pattern, string, squoted)
4531         char *pattern;
4532         char *string;
4533         int squoted;
4534         {
4535         char *p, *q;
4536         char c;
4537
4538         p = pattern;
4539         q = string;
4540         for (;;) {
4541                 switch (c = *p++) {
4542                 case '\0':
4543                         goto breakloop;
4544                 case CTLESC:
4545                         if (squoted && *q == CTLESC)
4546                                 q++;
4547                         if (*q++ != *p++)
4548                                 return 0;
4549                         break;
4550                 case CTLQUOTEMARK:
4551                         continue;
4552                 case '?':
4553                         if (squoted && *q == CTLESC)
4554                                 q++;
4555                         if (*q++ == '\0')
4556                                 return 0;
4557                         break;
4558                 case '*':
4559                         c = *p;
4560                         while (c == CTLQUOTEMARK || c == '*')
4561                                 c = *++p;
4562                         if (c != CTLESC &&  c != CTLQUOTEMARK &&
4563                             c != '?' && c != '*' && c != '[') {
4564                                 while (*q != c) {
4565                                         if (squoted && *q == CTLESC &&
4566                                             q[1] == c)
4567                                                 break;
4568                                         if (*q == '\0')
4569                                                 return 0;
4570                                         if (squoted && *q == CTLESC)
4571                                                 q++;
4572                                         q++;
4573                                 }
4574                         }
4575                         do {
4576                                 if (pmatch(p, q, squoted))
4577                                         return 1;
4578                                 if (squoted && *q == CTLESC)
4579                                         q++;
4580                         } while (*q++ != '\0');
4581                         return 0;
4582                 case '[': {
4583                         char *endp;
4584                         int invert, found;
4585                         char chr;
4586
4587                         endp = p;
4588                         if (*endp == '!')
4589                                 endp++;
4590                         for (;;) {
4591                                 while (*endp == CTLQUOTEMARK)
4592                                         endp++;
4593                                 if (*endp == '\0')
4594                                         goto dft;               /* no matching ] */
4595                                 if (*endp == CTLESC)
4596                                         endp++;
4597                                 if (*++endp == ']')
4598                                         break;
4599                         }
4600                         invert = 0;
4601                         if (*p == '!') {
4602                                 invert++;
4603                                 p++;
4604                         }
4605                         found = 0;
4606                         chr = *q++;
4607                         if (squoted && chr == CTLESC)
4608                                 chr = *q++;
4609                         if (chr == '\0')
4610                                 return 0;
4611                         c = *p++;
4612                         do {
4613                                 if (c == CTLQUOTEMARK)
4614                                         continue;
4615                                 if (c == CTLESC)
4616                                         c = *p++;
4617                                 if (*p == '-' && p[1] != ']') {
4618                                         p++;
4619                                         while (*p == CTLQUOTEMARK)
4620                                                 p++;
4621                                         if (*p == CTLESC)
4622                                                 p++;
4623                                         if (chr >= c && chr <= *p)
4624                                                 found = 1;
4625                                         p++;
4626                                 } else {
4627                                         if (chr == c)
4628                                                 found = 1;
4629                                 }
4630                         } while ((c = *p++) != ']');
4631                         if (found == invert)
4632                                 return 0;
4633                         break;
4634                 }
4635 dft:            default:
4636                         if (squoted && *q == CTLESC)
4637                                 q++;
4638                         if (*q++ != c)
4639                                 return 0;
4640                         break;
4641                 }
4642         }
4643 breakloop:
4644         if (*q != '\0')
4645                 return 0;
4646         return 1;
4647 }
4648 #endif
4649
4650
4651
4652 /*
4653  * Remove any CTLESC characters from a string.
4654  */
4655
4656 #if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4657 static char *
4658 _rmescapes(str, flag)
4659         char *str;
4660         int flag;
4661 {
4662         char *p, *q, *r;
4663         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
4664
4665         p = strpbrk(str, qchars);
4666         if (!p) {
4667                 return str;
4668         }
4669         q = p;
4670         r = str;
4671         if (flag & RMESCAPE_ALLOC) {
4672                 size_t len = p - str;
4673                 q = r = stalloc(strlen(p) + len + 1);
4674                 if (len > 0) {
4675 #ifdef _GNU_SOURCE
4676                         q = mempcpy(q, str, len);
4677 #else
4678                         memcpy(q, str, len);
4679                         q += len;
4680 #endif
4681                 }
4682         }
4683         while (*p) {
4684                 if (*p == CTLQUOTEMARK) {
4685                         p++;
4686                         continue;
4687                 }
4688                 if (*p == CTLESC) {
4689                         p++;
4690                         if (flag & RMESCAPE_GLOB && *p != '/') {
4691                                 *q++ = '\\';
4692                         }
4693                 }
4694                 *q++ = *p++;
4695         }
4696         *q = '\0';
4697         return r;
4698 }
4699 #else
4700 static void
4701 rmescapes(str)
4702         char *str;
4703 {
4704         char *p, *q;
4705
4706         p = str;
4707         while (*p != CTLESC && *p != CTLQUOTEMARK) {
4708                 if (*p++ == '\0')
4709                         return;
4710         }
4711         q = p;
4712         while (*p) {
4713                 if (*p == CTLQUOTEMARK) {
4714                         p++;
4715                         continue;
4716                 }
4717                 if (*p == CTLESC)
4718                         p++;
4719                 *q++ = *p++;
4720         }
4721         *q = '\0';
4722 }
4723 #endif
4724
4725
4726
4727 /*
4728  * See if a pattern matches in a case statement.
4729  */
4730
4731 static int
4732 casematch(pattern, val)
4733         union node *pattern;
4734         char *val;
4735         {
4736         struct stackmark smark;
4737         int result;
4738         char *p;
4739
4740         setstackmark(&smark);
4741         argbackq = pattern->narg.backquote;
4742         STARTSTACKSTR(expdest);
4743         ifslastp = NULL;
4744         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
4745         STPUTC('\0', expdest);
4746         p = grabstackstr(expdest);
4747         result = patmatch(p, val, 0);
4748         popstackmark(&smark);
4749         return result;
4750 }
4751
4752 /*
4753  * Our own itoa().
4754  */
4755
4756 static char *
4757 cvtnum(num, buf)
4758         int num;
4759         char *buf;
4760         {
4761         int len;
4762
4763         CHECKSTRSPACE(32, buf);
4764         len = sprintf(buf, "%d", num);
4765         STADJUST(len, buf);
4766         return buf;
4767 }
4768 /*      $NetBSD: histedit.c,v 1.25 2001/02/04 19:52:06 christos Exp $   */
4769
4770 /*
4771  * Editline and history functions (and glue).
4772  */
4773 static int histcmd(argc, argv)
4774         int argc;
4775         char **argv;
4776 {
4777         error("not compiled with history support");
4778         /* NOTREACHED */
4779 }
4780
4781
4782 /*
4783  * This file was generated by the mkinit program.
4784  */
4785
4786 extern void rmaliases __P((void));
4787
4788 extern int loopnest;            /* current loop nesting level */
4789
4790 extern void deletefuncs __P((void));
4791
4792 struct strpush {
4793         struct strpush *prev;   /* preceding string on stack */
4794         char *prevstring;
4795         int prevnleft;
4796         struct alias *ap;       /* if push was associated with an alias */
4797         char *string;           /* remember the string since it may change */
4798 };
4799
4800 struct parsefile {
4801         struct parsefile *prev; /* preceding file on stack */
4802         int linno;              /* current line */
4803         int fd;                 /* file descriptor (or -1 if string) */
4804         int nleft;              /* number of chars left in this line */
4805         int lleft;              /* number of chars left in this buffer */
4806         char *nextc;            /* next char in buffer */
4807         char *buf;              /* input buffer */
4808         struct strpush *strpush; /* for pushing strings at this level */
4809         struct strpush basestrpush; /* so pushing one is fast */
4810 };
4811
4812 extern int parselleft;          /* copy of parsefile->lleft */
4813 extern struct parsefile basepf; /* top level input file */
4814 extern char basebuf[BUFSIZ];    /* buffer for top level input file */
4815
4816 extern short backgndpid;        /* pid of last background process */
4817 extern int jobctl;
4818
4819 extern int tokpushback;         /* last token pushed back */
4820 extern int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
4821
4822 struct redirtab {
4823         struct redirtab *next;
4824         short renamed[10];
4825 };
4826
4827 extern struct redirtab *redirlist;
4828
4829 extern char sigmode[NSIG - 1];  /* current value of signal */
4830
4831 extern char **environ;
4832
4833
4834
4835 /*
4836  * Initialization code.
4837  */
4838
4839 static void
4840 init() {
4841
4842       /* from cd.c: */
4843       {
4844               setpwd(0, 0);
4845       }
4846
4847       /* from input.c: */
4848       {
4849               basepf.nextc = basepf.buf = basebuf;
4850       }
4851
4852       /* from output.c: */
4853       {
4854 #ifdef USE_GLIBC_STDIO
4855               initstreams();
4856 #endif
4857       }
4858
4859       /* from var.c: */
4860       {
4861               char **envp;
4862               char ppid[32];
4863
4864               initvar();
4865               for (envp = environ ; *envp ; envp++) {
4866                       if (strchr(*envp, '=')) {
4867                               setvareq(*envp, VEXPORT|VTEXTFIXED);
4868                       }
4869               }
4870
4871               fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
4872               setvar("PPID", ppid, 0);
4873       }
4874 }
4875
4876
4877
4878 /*
4879  * This routine is called when an error or an interrupt occurs in an
4880  * interactive shell and control is returned to the main command loop.
4881  */
4882
4883 static void
4884 reset() {
4885
4886       /* from eval.c: */
4887       {
4888               evalskip = 0;
4889               loopnest = 0;
4890               funcnest = 0;
4891       }
4892
4893       /* from input.c: */
4894       {
4895               if (exception != EXSHELLPROC)
4896                       parselleft = parsenleft = 0;      /* clear input buffer */
4897               popallfiles();
4898       }
4899
4900       /* from parser.c: */
4901       {
4902               tokpushback = 0;
4903               checkkwd = 0;
4904               checkalias = 0;
4905       }
4906
4907       /* from redir.c: */
4908       {
4909               while (redirlist)
4910                       popredir();
4911       }
4912
4913       /* from output.c: */
4914       {
4915               out1 = &output;
4916               out2 = &errout;
4917 #ifdef USE_GLIBC_STDIO
4918               if (memout.stream != NULL)
4919                       __closememout();
4920 #endif
4921               if (memout.buf != NULL) {
4922                       ckfree(memout.buf);
4923                       memout.buf = NULL;
4924               }
4925       }
4926 }
4927
4928
4929
4930 /*
4931  * This routine is called to initialize the shell to run a shell procedure.
4932  */
4933
4934 static void
4935 initshellproc() {
4936
4937       /* from alias.c: */
4938       {
4939               rmaliases();
4940       }
4941
4942       /* from eval.c: */
4943       {
4944               exitstatus = 0;
4945       }
4946
4947       /* from exec.c: */
4948       {
4949               deletefuncs();
4950       }
4951
4952       /* from jobs.c: */
4953       {
4954               backgndpid = -1;
4955 #if JOBS
4956               jobctl = 0;
4957 #endif
4958       }
4959
4960       /* from options.c: */
4961       {
4962               int i;
4963
4964               for (i = 0; i < NOPTS; i++)
4965                       optlist[i].val = 0;
4966               optschanged();
4967
4968       }
4969
4970       /* from redir.c: */
4971       {
4972               clearredir();
4973       }
4974
4975       /* from trap.c: */
4976       {
4977               char *sm;
4978
4979               clear_traps();
4980               for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
4981                       if (*sm == S_IGN)
4982                               *sm = S_HARD_IGN;
4983               }
4984       }
4985
4986       /* from var.c: */
4987       {
4988               shprocvar();
4989       }
4990 }
4991 /*      $NetBSD: input.c,v 1.35 2001/02/04 19:52:06 christos Exp $      */
4992
4993 /*
4994  * This file implements the input routines used by the parser.
4995  */
4996
4997 #ifdef BB_FEATURE_COMMAND_EDITING
4998 unsigned int shell_context;
4999 static const char * cmdedit_prompt;
5000 static inline void putprompt(const char *s) {
5001     cmdedit_prompt = s;
5002 }
5003 #else
5004 static inline void putprompt(const char *s) {
5005     out2str(s);
5006 }
5007 #endif
5008
5009 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
5010
5011 static int plinno = 1;                  /* input line number */
5012 static int parsenleft;                  /* copy of parsefile->nleft */
5013 static int parselleft;          /* copy of parsefile->lleft */
5014 static char *parsenextc;                /* copy of parsefile->nextc */
5015 struct parsefile basepf;        /* top level input file */
5016 static char basebuf[BUFSIZ];    /* buffer for top level input file */
5017 struct parsefile *parsefile = &basepf;  /* current input file */
5018 static int whichprompt;         /* 1 == PS1, 2 == PS2 */
5019
5020 static void pushfile __P((void));
5021 static int preadfd __P((void));
5022
5023 #ifdef mkinit
5024 INCLUDE <stdio.h>
5025 INCLUDE "input.h"
5026 INCLUDE "error.h"
5027
5028 INIT {
5029         basepf.nextc = basepf.buf = basebuf;
5030 }
5031
5032 RESET {
5033         if (exception != EXSHELLPROC)
5034                 parselleft = parsenleft = 0;    /* clear input buffer */
5035         popallfiles();
5036 }
5037 #endif
5038
5039
5040 /*
5041  * Read a line from the script.
5042  */
5043
5044 static char *
5045 pfgets(line, len)
5046         char *line;
5047         int len;
5048 {
5049         char *p = line;
5050         int nleft = len;
5051         int c;
5052
5053         while (--nleft > 0) {
5054                 c = pgetc2();
5055                 if (c == PEOF) {
5056                         if (p == line)
5057                                 return NULL;
5058                         break;
5059                 }
5060                 *p++ = c;
5061                 if (c == '\n')
5062                         break;
5063         }
5064         *p = '\0';
5065         return line;
5066 }
5067
5068
5069 /*
5070  * Read a character from the script, returning PEOF on end of file.
5071  * Nul characters in the input are silently discarded.
5072  */
5073
5074 static int
5075 pgetc()
5076 {
5077         return pgetc_macro();
5078 }
5079
5080
5081 /*
5082  * Same as pgetc(), but ignores PEOA.
5083  */
5084
5085 static int
5086 pgetc2()
5087 {
5088         int c;
5089         do {
5090                 c = pgetc_macro();
5091         } while (c == PEOA);
5092         return c;
5093 }
5094
5095
5096 static int
5097 preadfd()
5098 {
5099     int nr;
5100     char *buf =  parsefile->buf;
5101     parsenextc = buf;
5102
5103 retry:
5104 #ifdef BB_FEATURE_COMMAND_EDITING
5105         {
5106             if (parsefile->fd)
5107                 nr = read(parsefile->fd, buf, BUFSIZ - 1);
5108             else { 
5109                 do {
5110                     cmdedit_read_input((char*)cmdedit_prompt, buf);
5111                     nr = strlen(buf);
5112                 } while (nr <=0 || shell_context);
5113                 cmdedit_terminate();
5114             }
5115         }
5116 #else
5117         nr = read(parsefile->fd, buf, BUFSIZ - 1);
5118 #endif
5119
5120         if (nr < 0) {
5121                 if (errno == EINTR)
5122                         goto retry;
5123                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5124                         int flags = fcntl(0, F_GETFL, 0);
5125                         if (flags >= 0 && flags & O_NONBLOCK) {
5126                                 flags &=~ O_NONBLOCK;
5127                                 if (fcntl(0, F_SETFL, flags) >= 0) {
5128                                         out2str("sh: turning off NDELAY mode\n");
5129                                         goto retry;
5130                                 }
5131                         }
5132                 }
5133         }
5134         return nr;
5135 }
5136
5137 /*
5138  * Refill the input buffer and return the next input character:
5139  *
5140  * 1) If a string was pushed back on the input, pop it;
5141  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5142  *    from a string so we can't refill the buffer, return EOF.
5143  * 3) If the is more stuff in this buffer, use it else call read to fill it.
5144  * 4) Process input up to the next newline, deleting nul characters.
5145  */
5146
5147 static int
5148 preadbuffer()
5149 {
5150         char *p, *q;
5151         int more;
5152         char savec;
5153
5154         while (parsefile->strpush) {
5155                 if (
5156                         parsenleft == -1 && parsefile->strpush->ap &&
5157                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
5158                 ) {
5159                         return PEOA;
5160                 }
5161                 popstring();
5162                 if (--parsenleft >= 0)
5163                         return (*parsenextc++);
5164         }
5165         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5166                 return PEOF;
5167         flushout(&output);
5168 #ifdef FLUSHERR
5169         flushout(&errout);
5170 #endif
5171
5172 again:
5173         if (parselleft <= 0) {
5174                 if ((parselleft = preadfd()) <= 0) {
5175                         parselleft = parsenleft = EOF_NLEFT;
5176                         return PEOF;
5177                 }
5178         }
5179
5180         q = p = parsenextc;
5181
5182         /* delete nul characters */
5183         for (more = 1; more;) {
5184                 switch (*p) {
5185                 case '\0':
5186                         p++;    /* Skip nul */
5187                         goto check;
5188
5189
5190                 case '\n':
5191                         parsenleft = q - parsenextc;
5192                         more = 0; /* Stop processing here */
5193                         break;
5194                 }
5195
5196                 *q++ = *p++;
5197 check:
5198                 if (--parselleft <= 0 && more) {
5199                         parsenleft = q - parsenextc - 1;
5200                         if (parsenleft < 0)
5201                                 goto again;
5202                         more = 0;
5203                 }
5204         }
5205
5206         savec = *q;
5207         *q = '\0';
5208
5209         if (vflag) {
5210                 out2str(parsenextc);
5211 #ifdef FLUSHERR
5212                 flushout(out2);
5213 #endif
5214         }
5215
5216         *q = savec;
5217
5218         return *parsenextc++;
5219 }
5220
5221 /*
5222  * Undo the last call to pgetc.  Only one character may be pushed back.
5223  * PEOF may be pushed back.
5224  */
5225
5226 static void
5227 pungetc() {
5228         parsenleft++;
5229         parsenextc--;
5230 }
5231
5232 /*
5233  * Push a string back onto the input at this current parsefile level.
5234  * We handle aliases this way.
5235  */
5236 static void
5237 pushstring(s, len, ap)
5238         char *s;
5239         int len;
5240         void *ap;
5241         {
5242         struct strpush *sp;
5243
5244         INTOFF;
5245 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
5246         if (parsefile->strpush) {
5247                 sp = ckmalloc(sizeof (struct strpush));
5248                 sp->prev = parsefile->strpush;
5249                 parsefile->strpush = sp;
5250         } else
5251                 sp = parsefile->strpush = &(parsefile->basestrpush);
5252         sp->prevstring = parsenextc;
5253         sp->prevnleft = parsenleft;
5254         sp->ap = (struct alias *)ap;
5255         if (ap) {
5256                 ((struct alias *)ap)->flag |= ALIASINUSE;
5257                 sp->string = s;
5258         }
5259         parsenextc = s;
5260         parsenleft = len;
5261         INTON;
5262 }
5263
5264 static void
5265 popstring()
5266 {
5267         struct strpush *sp = parsefile->strpush;
5268
5269         INTOFF;
5270         if (sp->ap) {
5271                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
5272                         if (!checkalias) {
5273                                 checkalias = 1;
5274                         }
5275                 }
5276                 if (sp->string != sp->ap->val) {
5277                         ckfree(sp->string);
5278                 }
5279                 sp->ap->flag &= ~ALIASINUSE;
5280                 if (sp->ap->flag & ALIASDEAD) {
5281                         unalias(sp->ap->name);
5282                 }
5283         }
5284         parsenextc = sp->prevstring;
5285         parsenleft = sp->prevnleft;
5286 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
5287         parsefile->strpush = sp->prev;
5288         if (sp != &(parsefile->basestrpush))
5289                 ckfree(sp);
5290         INTON;
5291 }
5292
5293 /*
5294  * Set the input to take input from a file.  If push is set, push the
5295  * old input onto the stack first.
5296  */
5297
5298 static void
5299 setinputfile(fname, push)
5300         const char *fname;
5301         int push;
5302 {
5303         int fd;
5304         int myfileno2;
5305
5306         INTOFF;
5307         if ((fd = open(fname, O_RDONLY)) < 0)
5308                 error("Can't open %s", fname);
5309         if (fd < 10) {
5310                 myfileno2 = dup_as_newfd(fd, 10);
5311                 close(fd);
5312                 if (myfileno2 < 0)
5313                         error("Out of file descriptors");
5314                 fd = myfileno2;
5315         }
5316         setinputfd(fd, push);
5317         INTON;
5318 }
5319
5320
5321 /*
5322  * Like setinputfile, but takes an open file descriptor.  Call this with
5323  * interrupts off.
5324  */
5325
5326 static void
5327 setinputfd(fd, push)
5328         int fd, push;
5329 {
5330         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
5331         if (push) {
5332                 pushfile();
5333                 parsefile->buf = 0;
5334         } else {
5335                 closescript();
5336                 while (parsefile->strpush)
5337                         popstring();
5338         }
5339         parsefile->fd = fd;
5340         if (parsefile->buf == NULL)
5341                 parsefile->buf = ckmalloc(BUFSIZ);
5342         parselleft = parsenleft = 0;
5343         plinno = 1;
5344 }
5345
5346
5347 /*
5348  * Like setinputfile, but takes input from a string.
5349  */
5350
5351 static void
5352 setinputstring(string)
5353         char *string;
5354         {
5355         INTOFF;
5356         pushfile();
5357         parsenextc = string;
5358         parsenleft = strlen(string);
5359         parsefile->buf = NULL;
5360         plinno = 1;
5361         INTON;
5362 }
5363
5364
5365
5366 /*
5367  * To handle the "." command, a stack of input files is used.  Pushfile
5368  * adds a new entry to the stack and popfile restores the previous level.
5369  */
5370
5371 static void
5372 pushfile() {
5373         struct parsefile *pf;
5374
5375         parsefile->nleft = parsenleft;
5376         parsefile->lleft = parselleft;
5377         parsefile->nextc = parsenextc;
5378         parsefile->linno = plinno;
5379         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
5380         pf->prev = parsefile;
5381         pf->fd = -1;
5382         pf->strpush = NULL;
5383         pf->basestrpush.prev = NULL;
5384         parsefile = pf;
5385 }
5386
5387
5388 static void
5389 popfile() {
5390         struct parsefile *pf = parsefile;
5391
5392         INTOFF;
5393         if (pf->fd >= 0)
5394                 close(pf->fd);
5395         if (pf->buf)
5396                 ckfree(pf->buf);
5397         while (pf->strpush)
5398                 popstring();
5399         parsefile = pf->prev;
5400         ckfree(pf);
5401         parsenleft = parsefile->nleft;
5402         parselleft = parsefile->lleft;
5403         parsenextc = parsefile->nextc;
5404         plinno = parsefile->linno;
5405         INTON;
5406 }
5407
5408
5409 /*
5410  * Return to top level.
5411  */
5412
5413 static void
5414 popallfiles() {
5415         while (parsefile != &basepf)
5416                 popfile();
5417 }
5418
5419
5420
5421 /*
5422  * Close the file(s) that the shell is reading commands from.  Called
5423  * after a fork is done.
5424  */
5425
5426 static void
5427 closescript() {
5428         popallfiles();
5429         if (parsefile->fd > 0) {
5430                 close(parsefile->fd);
5431                 parsefile->fd = 0;
5432         }
5433 }
5434 /*      $NetBSD: jobs.c,v 1.36 2000/05/22 10:18:47 elric Exp $  */
5435
5436
5437 struct job *jobtab;             /* array of jobs */
5438 static int njobs;                       /* size of array */
5439 short backgndpid = -1;  /* pid of last background process */
5440 #if JOBS
5441 static int initialpgrp;         /* pgrp of shell on invocation */
5442 short curjob;                   /* current job */
5443 #endif
5444 static int intreceived;
5445
5446 static void restartjob __P((struct job *));
5447 static void freejob __P((struct job *));
5448 static struct job *getjob __P((char *));
5449 static int dowait __P((int, struct job *));
5450 #ifdef SYSV
5451 static int onsigchild __P((void));
5452 #endif
5453 static int waitproc __P((int, int *));
5454 static void cmdtxt __P((union node *));
5455 static void cmdputs __P((const char *));
5456 static void waitonint(int);
5457
5458
5459 #if JOBS
5460 /*
5461  * Turn job control on and off.
5462  *
5463  * Note:  This code assumes that the third arg to ioctl is a character
5464  * pointer, which is true on Berkeley systems but not System V.  Since
5465  * System V doesn't have job control yet, this isn't a problem now.
5466  */
5467
5468 static int jobctl;
5469
5470 static void setjobctl(int enable)
5471 {
5472 #ifdef OLD_TTY_DRIVER
5473         int ldisc;
5474 #endif
5475
5476         if (enable == jobctl || rootshell == 0)
5477                 return;
5478         if (enable) {
5479                 do { /* while we are in the background */
5480 #ifdef OLD_TTY_DRIVER
5481                         if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
5482 #else
5483                         initialpgrp = tcgetpgrp(fileno2);
5484                         if (initialpgrp < 0) {
5485 #endif
5486                                 out2str("sh: can't access tty; job cenabletrol turned off\n");
5487                                 mflag = 0;
5488                                 return;
5489                         }
5490                         if (initialpgrp == -1)
5491                                 initialpgrp = getpgrp();
5492                         else if (initialpgrp != getpgrp()) {
5493                                 killpg(initialpgrp, SIGTTIN);
5494                                 continue;
5495                         }
5496                 } while (0);
5497 #ifdef OLD_TTY_DRIVER
5498                 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
5499                         out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
5500                         mflag = 0;
5501                         return;
5502                 }
5503 #endif
5504                 setsignal(SIGTSTP);
5505                 setsignal(SIGTTOU);
5506                 setsignal(SIGTTIN);
5507                 setpgid(0, rootpid);
5508 #ifdef OLD_TTY_DRIVER
5509                 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
5510 #else
5511                 tcsetpgrp(fileno2, rootpid);
5512 #endif
5513         } else { /* turning job cenabletrol off */
5514                 setpgid(0, initialpgrp);
5515 #ifdef OLD_TTY_DRIVER
5516                 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
5517 #else
5518                 tcsetpgrp(fileno2, initialpgrp);
5519 #endif
5520                 setsignal(SIGTSTP);
5521                 setsignal(SIGTTOU);
5522                 setsignal(SIGTTIN);
5523         }
5524         jobctl = enable;
5525 }
5526 #endif
5527
5528
5529 #ifdef mkinit
5530 INCLUDE <stdlib.h>
5531
5532 SHELLPROC {
5533         backgndpid = -1;
5534 #if JOBS
5535         jobctl = 0;
5536 #endif
5537 }
5538
5539 #endif
5540
5541
5542 /* This file was automatically created by ./mksignames.
5543    Do not edit.  Edit support/mksignames.c instead. */
5544
5545 /* A translation list so we can be polite to our users. */
5546 static char *signal_names[NSIG + 2] = {
5547     "EXIT",
5548     "SIGHUP",
5549     "SIGINT",
5550     "SIGQUIT",
5551     "SIGILL",
5552     "SIGTRAP",
5553     "SIGABRT",
5554     "SIGBUS",
5555     "SIGFPE",
5556     "SIGKILL",
5557     "SIGUSR1",
5558     "SIGSEGV",
5559     "SIGUSR2",
5560     "SIGPIPE",
5561     "SIGALRM",
5562     "SIGTERM",
5563     "SIGJUNK(16)",
5564     "SIGCHLD",
5565     "SIGCONT",
5566     "SIGSTOP",
5567     "SIGTSTP",
5568     "SIGTTIN",
5569     "SIGTTOU",
5570     "SIGURG",
5571     "SIGXCPU",
5572     "SIGXFSZ",
5573     "SIGVTALRM",
5574     "SIGPROF",
5575     "SIGWINCH",
5576     "SIGIO",
5577     "SIGPWR",
5578     "SIGSYS",
5579     "SIGRTMIN",
5580     "SIGRTMIN+1",
5581     "SIGRTMIN+2",
5582     "SIGRTMIN+3",
5583     "SIGRTMIN+4",
5584     "SIGRTMIN+5",
5585     "SIGRTMIN+6",
5586     "SIGRTMIN+7",
5587     "SIGRTMIN+8",
5588     "SIGRTMIN+9",
5589     "SIGRTMIN+10",
5590     "SIGRTMIN+11",
5591     "SIGRTMIN+12",
5592     "SIGRTMIN+13",
5593     "SIGRTMIN+14",
5594     "SIGRTMIN+15",
5595     "SIGRTMAX-15",
5596     "SIGRTMAX-14",
5597     "SIGRTMAX-13",
5598     "SIGRTMAX-12",
5599     "SIGRTMAX-11",
5600     "SIGRTMAX-10",
5601     "SIGRTMAX-9",
5602     "SIGRTMAX-8",
5603     "SIGRTMAX-7",
5604     "SIGRTMAX-6",
5605     "SIGRTMAX-5",
5606     "SIGRTMAX-4",
5607     "SIGRTMAX-3",
5608     "SIGRTMAX-2",
5609     "SIGRTMAX-1",
5610     "SIGRTMAX",
5611     "DEBUG",
5612     (char *)0x0,
5613 };
5614
5615
5616
5617 #if JOBS
5618 static int
5619 killcmd(argc, argv)
5620         int argc;
5621         char **argv;
5622 {
5623         int signo = -1;
5624         int list = 0;
5625         int i;
5626         pid_t pid;
5627         struct job *jp;
5628
5629         if (argc <= 1) {
5630 usage:
5631                 error(
5632 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
5633 "kill -l [exitstatus]"
5634                 );
5635         }
5636
5637         if (*argv[1] == '-') {
5638                 signo = decode_signal(argv[1] + 1, 1);
5639                 if (signo < 0) {
5640                         int c;
5641
5642                         while ((c = nextopt("ls:")) != '\0')
5643                                 switch (c) {
5644                                 case 'l':
5645                                         list = 1;
5646                                         break;
5647                                 case 's':
5648                                         signo = decode_signal(optionarg, 1);
5649                                         if (signo < 0) {
5650                                                 error(
5651                                                         "invalid signal number or name: %s",
5652                                                         optionarg
5653                                                 );
5654                                         }
5655                                         break;
5656 #ifdef DEBUG
5657                                 default:
5658                                         error(
5659         "nextopt returned character code 0%o", c);
5660 #endif
5661                         }
5662                 } else
5663                         argptr++;
5664         }
5665
5666         if (!list && signo < 0)
5667                 signo = SIGTERM;
5668
5669         if ((signo < 0 || !*argptr) ^ list) {
5670                 goto usage;
5671         }
5672
5673         if (list) {
5674                 if (!*argptr) {
5675                         out1str("0\n");
5676                         for (i = 1; i < NSIG; i++) {
5677                                 out1fmt(snlfmt, signal_names[i] + 3);
5678                         }
5679                         return 0;
5680                 }
5681                 signo = atoi(*argptr);
5682                 if (signo > 128)
5683                         signo -= 128;
5684                 if (0 < signo && signo < NSIG)
5685                                 out1fmt(snlfmt, signal_names[signo] + 3);
5686                 else
5687                         error("invalid signal number or exit status: %s",
5688                               *argptr);
5689                 return 0;
5690         }
5691
5692         do {
5693                 if (**argptr == '%') {
5694                         jp = getjob(*argptr);
5695                         if (jp->jobctl == 0)
5696                                 error("job %s not created under job control",
5697                                       *argptr);
5698                         pid = -jp->ps[0].pid;
5699                 } else
5700                         pid = atoi(*argptr);
5701                 if (kill(pid, signo) != 0)
5702                         error("%s: %s", *argptr, strerror(errno));
5703         } while (*++argptr);
5704
5705         return 0;
5706 }
5707
5708 static int
5709 fgcmd(argc, argv)
5710         int argc;
5711         char **argv;
5712 {
5713         struct job *jp;
5714         int pgrp;
5715         int status;
5716
5717         jp = getjob(argv[1]);
5718         if (jp->jobctl == 0)
5719                 error("job not created under job control");
5720         pgrp = jp->ps[0].pid;
5721 #ifdef OLD_TTY_DRIVER
5722         ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
5723 #else
5724         tcsetpgrp(fileno2, pgrp);
5725 #endif
5726         restartjob(jp);
5727         INTOFF;
5728         status = waitforjob(jp);
5729         INTON;
5730         return status;
5731 }
5732
5733
5734 static int
5735 bgcmd(argc, argv)
5736         int argc;
5737         char **argv;
5738 {
5739         struct job *jp;
5740
5741         do {
5742                 jp = getjob(*++argv);
5743                 if (jp->jobctl == 0)
5744                         error("job not created under job control");
5745                 restartjob(jp);
5746         } while (--argc > 1);
5747         return 0;
5748 }
5749
5750
5751 static void
5752 restartjob(jp)
5753         struct job *jp;
5754 {
5755         struct procstat *ps;
5756         int i;
5757
5758         if (jp->state == JOBDONE)
5759                 return;
5760         INTOFF;
5761         killpg(jp->ps[0].pid, SIGCONT);
5762         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
5763                 if (WIFSTOPPED(ps->status)) {
5764                         ps->status = -1;
5765                         jp->state = 0;
5766                 }
5767         }
5768         INTON;
5769 }
5770 #endif
5771
5772
5773 static int
5774 jobscmd(argc, argv)
5775         int argc;
5776         char **argv;
5777 {
5778         showjobs(0);
5779         return 0;
5780 }
5781
5782
5783 /*
5784  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
5785  * statuses have changed since the last call to showjobs.
5786  *
5787  * If the shell is interrupted in the process of creating a job, the
5788  * result may be a job structure containing zero processes.  Such structures
5789  * will be freed here.
5790  */
5791
5792 static void
5793 showjobs(change)
5794         int change;
5795 {
5796         int jobno;
5797         int procno;
5798         int i;
5799         struct job *jp;
5800         struct procstat *ps;
5801         int col;
5802         char s[64];
5803
5804         TRACE(("showjobs(%d) called\n", change));
5805         while (dowait(0, (struct job *)NULL) > 0);
5806         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
5807                 if (! jp->used)
5808                         continue;
5809                 if (jp->nprocs == 0) {
5810                         freejob(jp);
5811                         continue;
5812                 }
5813                 if (change && ! jp->changed)
5814                         continue;
5815                 procno = jp->nprocs;
5816                 for (ps = jp->ps ; ; ps++) {    /* for each process */
5817                         if (ps == jp->ps)
5818                                 fmtstr(s, 64, "[%d] %ld ", jobno, 
5819                                     (long)ps->pid);
5820                         else
5821                                 fmtstr(s, 64, "    %ld ", 
5822                                     (long)ps->pid);
5823                         out1str(s);
5824                         col = strlen(s);
5825                         s[0] = '\0';
5826                         if (ps->status == -1) {
5827                                 /* don't print anything */
5828                         } else if (WIFEXITED(ps->status)) {
5829                                 fmtstr(s, 64, "Exit %d", 
5830                                        WEXITSTATUS(ps->status));
5831                         } else {
5832 #if JOBS
5833                                 if (WIFSTOPPED(ps->status)) 
5834                                         i = WSTOPSIG(ps->status);
5835                                 else /* WIFSIGNALED(ps->status) */
5836 #endif
5837                                         i = WTERMSIG(ps->status);
5838                                 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
5839                                         scopy(sys_siglist[i & 0x7F], s);
5840                                 else
5841                                         fmtstr(s, 64, "Signal %d", i & 0x7F);
5842                                 if (WCOREDUMP(ps->status))
5843                                         strcat(s, " (core dumped)");
5844                         }
5845                         out1str(s);
5846                         col += strlen(s);
5847                         out1fmt(
5848                                 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
5849                                 ps->cmd
5850                         );
5851                         if (--procno <= 0)
5852                                 break;
5853                 }
5854                 jp->changed = 0;
5855                 if (jp->state == JOBDONE) {
5856                         freejob(jp);
5857                 }
5858         }
5859 }
5860
5861
5862 /*
5863  * Mark a job structure as unused.
5864  */
5865
5866 static void
5867 freejob(jp)
5868         struct job *jp;
5869         {
5870         struct procstat *ps;
5871         int i;
5872
5873         INTOFF;
5874         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
5875                 if (ps->cmd != nullstr)
5876                         ckfree(ps->cmd);
5877         }
5878         if (jp->ps != &jp->ps0)
5879                 ckfree(jp->ps);
5880         jp->used = 0;
5881 #if JOBS
5882         if (curjob == jp - jobtab + 1)
5883                 curjob = 0;
5884 #endif
5885         INTON;
5886 }
5887
5888
5889
5890 static int
5891 waitcmd(argc, argv)
5892         int argc;
5893         char **argv;
5894 {
5895         struct job *job;
5896         int status, retval;
5897         struct job *jp;
5898
5899         if (--argc > 0) {
5900 start:
5901                 job = getjob(*++argv);
5902         } else {
5903                 job = NULL;
5904         }
5905         for (;;) {      /* loop until process terminated or stopped */
5906                 if (job != NULL) {
5907                         if (job->state) {
5908                                 status = job->ps[job->nprocs - 1].status;
5909                                 if (! iflag)
5910                                         freejob(job);
5911                                 if (--argc) {
5912                                         goto start;
5913                                 }
5914                                 if (WIFEXITED(status))
5915                                         retval = WEXITSTATUS(status);
5916 #if JOBS
5917                                 else if (WIFSTOPPED(status))
5918                                         retval = WSTOPSIG(status) + 128;
5919 #endif
5920                                 else {
5921                                         /* XXX: limits number of signals */
5922                                         retval = WTERMSIG(status) + 128;
5923                                 }
5924                                 return retval;
5925                         }
5926                 } else {
5927                         for (jp = jobtab ; ; jp++) {
5928                                 if (jp >= jobtab + njobs) {     /* no running procs */
5929                                         return 0;
5930                                 }
5931                                 if (jp->used && jp->state == 0)
5932                                         break;
5933                         }
5934                 }
5935                 if (dowait(2, 0) < 0 && errno == EINTR) {
5936                         return 129;
5937                 }
5938         }
5939 }
5940
5941
5942
5943 /*
5944  * Convert a job name to a job structure.
5945  */
5946
5947 static struct job *
5948 getjob(name)
5949         char *name;
5950         {
5951         int jobno;
5952         struct job *jp;
5953         int pid;
5954         int i;
5955
5956         if (name == NULL) {
5957 #if JOBS
5958 currentjob:
5959                 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
5960                         error("No current job");
5961                 return &jobtab[jobno - 1];
5962 #else
5963                 error("No current job");
5964 #endif
5965         } else if (name[0] == '%') {
5966                 if (is_digit(name[1])) {
5967                         jobno = number(name + 1);
5968                         if (jobno > 0 && jobno <= njobs
5969                          && jobtab[jobno - 1].used != 0)
5970                                 return &jobtab[jobno - 1];
5971 #if JOBS
5972                 } else if (name[1] == '%' && name[2] == '\0') {
5973                         goto currentjob;
5974 #endif
5975                 } else {
5976                         struct job *found = NULL;
5977                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5978                                 if (jp->used && jp->nprocs > 0
5979                                  && prefix(name + 1, jp->ps[0].cmd)) {
5980                                         if (found)
5981                                                 error("%s: ambiguous", name);
5982                                         found = jp;
5983                                 }
5984                         }
5985                         if (found)
5986                                 return found;
5987                 }
5988         } else if (is_number(name)) {
5989                 pid = number(name);
5990                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
5991                         if (jp->used && jp->nprocs > 0
5992                          && jp->ps[jp->nprocs - 1].pid == pid)
5993                                 return jp;
5994                 }
5995         }
5996         error("No such job: %s", name);
5997         /* NOTREACHED */
5998 }
5999
6000
6001
6002 /*
6003  * Return a new job structure,
6004  */
6005
6006 struct job *
6007 makejob(node, nprocs)
6008         union node *node;
6009         int nprocs;
6010 {
6011         int i;
6012         struct job *jp;
6013
6014         for (i = njobs, jp = jobtab ; ; jp++) {
6015                 if (--i < 0) {
6016                         INTOFF;
6017                         if (njobs == 0) {
6018                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6019                         } else {
6020                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6021                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6022                                 /* Relocate `ps' pointers */
6023                                 for (i = 0; i < njobs; i++)
6024                                         if (jp[i].ps == &jobtab[i].ps0)
6025                                                 jp[i].ps = &jp[i].ps0;
6026                                 ckfree(jobtab);
6027                                 jobtab = jp;
6028                         }
6029                         jp = jobtab + njobs;
6030                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6031                         INTON;
6032                         break;
6033                 }
6034                 if (jp->used == 0)
6035                         break;
6036         }
6037         INTOFF;
6038         jp->state = 0;
6039         jp->used = 1;
6040         jp->changed = 0;
6041         jp->nprocs = 0;
6042 #if JOBS
6043         jp->jobctl = jobctl;
6044 #endif
6045         if (nprocs > 1) {
6046                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6047         } else {
6048                 jp->ps = &jp->ps0;
6049         }
6050         INTON;
6051         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6052             jp - jobtab + 1));
6053         return jp;
6054 }
6055
6056
6057 /*
6058  * Fork of a subshell.  If we are doing job control, give the subshell its
6059  * own process group.  Jp is a job structure that the job is to be added to.
6060  * N is the command that will be evaluated by the child.  Both jp and n may
6061  * be NULL.  The mode parameter can be one of the following:
6062  *      FORK_FG - Fork off a foreground process.
6063  *      FORK_BG - Fork off a background process.
6064  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
6065  *                   process group even if job control is on.
6066  *
6067  * When job control is turned off, background processes have their standard
6068  * input redirected to /dev/null (except for the second and later processes
6069  * in a pipeline).
6070  */
6071
6072 static int
6073 forkshell(jp, n, mode)
6074         union node *n;
6075         struct job *jp;
6076         int mode;
6077 {
6078         int pid;
6079         int pgrp;
6080         const char *devnull = _PATH_DEVNULL;
6081         const char *nullerr = "Can't open %s";
6082
6083         TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6084             mode));
6085         INTOFF;
6086         pid = fork();
6087         if (pid == -1) {
6088                 TRACE(("Fork failed, errno=%d\n", errno));
6089                 INTON;
6090                 error("Cannot fork");
6091         }
6092         if (pid == 0) {
6093                 struct job *p;
6094                 int wasroot;
6095                 int i;
6096
6097                 TRACE(("Child shell %d\n", getpid()));
6098                 wasroot = rootshell;
6099                 rootshell = 0;
6100                 closescript();
6101                 INTON;
6102                 clear_traps();
6103 #if JOBS
6104                 jobctl = 0;             /* do job control only in root shell */
6105                 if (wasroot && mode != FORK_NOJOB && mflag) {
6106                         if (jp == NULL || jp->nprocs == 0)
6107                                 pgrp = getpid();
6108                         else
6109                                 pgrp = jp->ps[0].pid;
6110                         setpgid(0, pgrp);
6111                         if (mode == FORK_FG) {
6112                                 /*** this causes superfluous TIOCSPGRPS ***/
6113 #ifdef OLD_TTY_DRIVER
6114                                 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
6115                                         error("TIOCSPGRP failed, errno=%d", errno);
6116 #else
6117                                 if (tcsetpgrp(fileno2, pgrp) < 0)
6118                                         error("tcsetpgrp failed, errno=%d", errno);
6119 #endif
6120                         }
6121                         setsignal(SIGTSTP);
6122                         setsignal(SIGTTOU);
6123                 } else if (mode == FORK_BG) {
6124                         ignoresig(SIGINT);
6125                         ignoresig(SIGQUIT);
6126                         if ((jp == NULL || jp->nprocs == 0) &&
6127                             ! fd0_redirected_p ()) {
6128                                 close(0);
6129                                 if (open(devnull, O_RDONLY) != 0)
6130                                         error(nullerr, devnull);
6131                         }
6132                 }
6133 #else
6134                 if (mode == FORK_BG) {
6135                         ignoresig(SIGINT);
6136                         ignoresig(SIGQUIT);
6137                         if ((jp == NULL || jp->nprocs == 0) &&
6138                             ! fd0_redirected_p ()) {
6139                                 close(0);
6140                                 if (open(devnull, O_RDONLY) != 0)
6141                                         error(nullerr, devnull);
6142                         }
6143                 }
6144 #endif
6145                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6146                         if (p->used)
6147                                 freejob(p);
6148                 if (wasroot && iflag) {
6149                         setsignal(SIGINT);
6150                         setsignal(SIGQUIT);
6151                         setsignal(SIGTERM);
6152                 }
6153                 return pid;
6154         }
6155         if (rootshell && mode != FORK_NOJOB && mflag) {
6156                 if (jp == NULL || jp->nprocs == 0)
6157                         pgrp = pid;
6158                 else
6159                         pgrp = jp->ps[0].pid;
6160                 setpgid(pid, pgrp);
6161         }
6162         if (mode == FORK_BG)
6163                 backgndpid = pid;               /* set $! */
6164         if (jp) {
6165                 struct procstat *ps = &jp->ps[jp->nprocs++];
6166                 ps->pid = pid;
6167                 ps->status = -1;
6168                 ps->cmd = nullstr;
6169                 if (iflag && rootshell && n)
6170                         ps->cmd = commandtext(n);
6171         }
6172         INTON;
6173         TRACE(("In parent shell:  child = %d\n", pid));
6174         return pid;
6175 }
6176
6177
6178
6179 /*
6180  * Wait for job to finish.
6181  *
6182  * Under job control we have the problem that while a child process is
6183  * running interrupts generated by the user are sent to the child but not
6184  * to the shell.  This means that an infinite loop started by an inter-
6185  * active user may be hard to kill.  With job control turned off, an
6186  * interactive user may place an interactive program inside a loop.  If
6187  * the interactive program catches interrupts, the user doesn't want
6188  * these interrupts to also abort the loop.  The approach we take here
6189  * is to have the shell ignore interrupt signals while waiting for a
6190  * forground process to terminate, and then send itself an interrupt
6191  * signal if the child process was terminated by an interrupt signal.
6192  * Unfortunately, some programs want to do a bit of cleanup and then
6193  * exit on interrupt; unless these processes terminate themselves by
6194  * sending a signal to themselves (instead of calling exit) they will
6195  * confuse this approach.
6196  */
6197
6198 static int
6199 waitforjob(jp)
6200         struct job *jp;
6201         {
6202 #if JOBS
6203         int mypgrp = getpgrp();
6204 #endif
6205         int status;
6206         int st;
6207         struct sigaction act, oact;
6208
6209         INTOFF;
6210         intreceived = 0;
6211 #if JOBS
6212         if (!jobctl) {
6213 #else
6214         if (!iflag) {
6215 #endif
6216                 sigaction(SIGINT, 0, &act);
6217                 act.sa_handler = waitonint;
6218                 sigaction(SIGINT, &act, &oact);
6219         }
6220         TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
6221         while (jp->state == 0) {
6222                 dowait(1, jp);
6223         }
6224 #if JOBS
6225         if (!jobctl) {
6226 #else
6227         if (!iflag) {
6228 #endif
6229                 sigaction(SIGINT, &oact, 0);
6230                 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
6231         }
6232 #if JOBS
6233         if (jp->jobctl) {
6234 #ifdef OLD_TTY_DRIVER
6235                 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
6236                         error("TIOCSPGRP failed, errno=%d\n", errno);
6237 #else
6238                 if (tcsetpgrp(fileno2, mypgrp) < 0)
6239                         error("tcsetpgrp failed, errno=%d\n", errno);
6240 #endif
6241         }
6242         if (jp->state == JOBSTOPPED)
6243                 curjob = jp - jobtab + 1;
6244 #endif
6245         status = jp->ps[jp->nprocs - 1].status;
6246         /* convert to 8 bits */
6247         if (WIFEXITED(status))
6248                 st = WEXITSTATUS(status);
6249 #if JOBS
6250         else if (WIFSTOPPED(status))
6251                 st = WSTOPSIG(status) + 128;
6252 #endif
6253         else
6254                 st = WTERMSIG(status) + 128;
6255 #if JOBS
6256         if (jp->jobctl) {
6257                 /*
6258                  * This is truly gross.
6259                  * If we're doing job control, then we did a TIOCSPGRP which
6260                  * caused us (the shell) to no longer be in the controlling
6261                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
6262                  * intuit from the subprocess exit status whether a SIGINT
6263                  * occured, and if so interrupt ourselves.  Yuck.  - mycroft
6264                  */
6265                 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
6266                         raise(SIGINT);
6267         }
6268 #endif
6269         if (! JOBS || jp->state == JOBDONE)
6270                 freejob(jp);
6271         INTON;
6272         return st;
6273 }
6274
6275
6276
6277 /*
6278  * Wait for a process to terminate.
6279  */
6280
6281 static int
6282 dowait(block, job)
6283         int block;
6284         struct job *job;
6285 {
6286         int pid;
6287         int status;
6288         struct procstat *sp;
6289         struct job *jp;
6290         struct job *thisjob;
6291         int done;
6292         int stopped;
6293         int core;
6294         int sig;
6295
6296         TRACE(("dowait(%d) called\n", block));
6297         do {
6298                 pid = waitproc(block, &status);
6299                 TRACE(("wait returns %d, status=%d\n", pid, status));
6300         } while (!(block & 2) && pid == -1 && errno == EINTR);
6301         if (pid <= 0)
6302                 return pid;
6303         INTOFF;
6304         thisjob = NULL;
6305         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
6306                 if (jp->used) {
6307                         done = 1;
6308                         stopped = 1;
6309                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
6310                                 if (sp->pid == -1)
6311                                         continue;
6312                                 if (sp->pid == pid) {
6313                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
6314                                         sp->status = status;
6315                                         thisjob = jp;
6316                                 }
6317                                 if (sp->status == -1)
6318                                         stopped = 0;
6319                                 else if (WIFSTOPPED(sp->status))
6320                                         done = 0;
6321                         }
6322                         if (stopped) {          /* stopped or done */
6323                                 int state = done? JOBDONE : JOBSTOPPED;
6324                                 if (jp->state != state) {
6325                                         TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
6326                                         jp->state = state;
6327 #if JOBS
6328                                         if (done && curjob == jp - jobtab + 1)
6329                                                 curjob = 0;             /* no current job */
6330 #endif
6331                                 }
6332                         }
6333                 }
6334         }
6335         INTON;
6336         if (! rootshell || ! iflag || (job && thisjob == job)) {
6337                 core = WCOREDUMP(status);
6338 #if JOBS
6339                 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
6340                 else
6341 #endif
6342                 if (WIFEXITED(status)) sig = 0;
6343                 else sig = WTERMSIG(status);
6344
6345                 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
6346                         if (thisjob != job)
6347                                 outfmt(out2, "%d: ", pid);
6348 #if JOBS
6349                         if (sig == SIGTSTP && rootshell && iflag)
6350                                 outfmt(out2, "%%%ld ",
6351                                     (long)(job - jobtab + 1));
6352 #endif
6353                         if (sig < NSIG && sys_siglist[sig])
6354                                 out2str(sys_siglist[sig]);
6355                         else
6356                                 outfmt(out2, "Signal %d", sig);
6357                         if (core)
6358                                 out2str(" - core dumped");
6359                         out2c('\n');
6360 #ifdef FLUSHERR
6361                         flushout(&errout);
6362 #endif
6363                 } else {
6364                         TRACE(("Not printing status: status=%d, sig=%d\n", 
6365                                status, sig));
6366                 }
6367         } else {
6368                 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
6369                 if (thisjob)
6370                         thisjob->changed = 1;
6371         }
6372         return pid;
6373 }
6374
6375
6376
6377 /*
6378  * Do a wait system call.  If job control is compiled in, we accept
6379  * stopped processes.  If block is zero, we return a value of zero
6380  * rather than blocking.
6381  *
6382  * System V doesn't have a non-blocking wait system call.  It does
6383  * have a SIGCLD signal that is sent to a process when one of it's
6384  * children dies.  The obvious way to use SIGCLD would be to install
6385  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
6386  * was received, and have waitproc bump another counter when it got
6387  * the status of a process.  Waitproc would then know that a wait
6388  * system call would not block if the two counters were different.
6389  * This approach doesn't work because if a process has children that
6390  * have not been waited for, System V will send it a SIGCLD when it
6391  * installs a signal handler for SIGCLD.  What this means is that when
6392  * a child exits, the shell will be sent SIGCLD signals continuously
6393  * until is runs out of stack space, unless it does a wait call before
6394  * restoring the signal handler.  The code below takes advantage of
6395  * this (mis)feature by installing a signal handler for SIGCLD and
6396  * then checking to see whether it was called.  If there are any
6397  * children to be waited for, it will be.
6398  *
6399  * If neither SYSV nor BSD is defined, we don't implement nonblocking
6400  * waits at all.  In this case, the user will not be informed when
6401  * a background process until the next time she runs a real program
6402  * (as opposed to running a builtin command or just typing return),
6403  * and the jobs command may give out of date information.
6404  */
6405
6406 #ifdef SYSV
6407 static int gotsigchild;
6408
6409 static int onsigchild() {
6410         gotsigchild = 1;
6411 }
6412 #endif
6413
6414
6415 static int
6416 waitproc(block, status)
6417         int block;
6418         int *status;
6419 {
6420 #ifdef BSD
6421         int flags;
6422
6423         flags = 0;
6424 #if JOBS
6425         if (jobctl)
6426                 flags |= WUNTRACED;
6427 #endif
6428         if (block == 0)
6429                 flags |= WNOHANG;
6430         return wait3(status, flags, (struct rusage *)NULL);
6431 #else
6432 #ifdef SYSV
6433         int (*save)();
6434
6435         if (block == 0) {
6436                 gotsigchild = 0;
6437                 save = signal(SIGCLD, onsigchild);
6438                 signal(SIGCLD, save);
6439                 if (gotsigchild == 0)
6440                         return 0;
6441         }
6442         return wait(status);
6443 #else
6444         if (block == 0)
6445                 return 0;
6446         return wait(status);
6447 #endif
6448 #endif
6449 }
6450
6451 /*
6452  * return 1 if there are stopped jobs, otherwise 0
6453  */
6454 static int job_warning = 0;
6455 static int
6456 stoppedjobs()
6457 {
6458         int jobno;
6459         struct job *jp;
6460
6461         if (job_warning)
6462                 return (0);
6463         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
6464                 if (jp->used == 0)
6465                         continue;
6466                 if (jp->state == JOBSTOPPED) {
6467                         out2str("You have stopped jobs.\n");
6468                         job_warning = 2;
6469                         return (1);
6470                 }
6471         }
6472
6473         return (0);
6474 }
6475
6476 /*
6477  * Return a string identifying a command (to be printed by the
6478  * jobs command.
6479  */
6480
6481 static char *cmdnextc;
6482 static int cmdnleft;
6483 #define MAXCMDTEXT      200
6484
6485 static char *
6486 commandtext(n)
6487         union node *n;
6488         {
6489         char *name;
6490
6491         cmdnextc = name = ckmalloc(MAXCMDTEXT);
6492         cmdnleft = MAXCMDTEXT - 4;
6493         cmdtxt(n);
6494         *cmdnextc = '\0';
6495         return name;
6496 }
6497
6498
6499 static void
6500 cmdtxt(n)
6501         union node *n;
6502         {
6503         union node *np;
6504         struct nodelist *lp;
6505         const char *p;
6506         int i;
6507         char s[2];
6508
6509         if (n == NULL)
6510                 return;
6511         switch (n->type) {
6512         case NSEMI:
6513                 cmdtxt(n->nbinary.ch1);
6514                 cmdputs("; ");
6515                 cmdtxt(n->nbinary.ch2);
6516                 break;
6517         case NAND:
6518                 cmdtxt(n->nbinary.ch1);
6519                 cmdputs(" && ");
6520                 cmdtxt(n->nbinary.ch2);
6521                 break;
6522         case NOR:
6523                 cmdtxt(n->nbinary.ch1);
6524                 cmdputs(" || ");
6525                 cmdtxt(n->nbinary.ch2);
6526                 break;
6527         case NPIPE:
6528                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
6529                         cmdtxt(lp->n);
6530                         if (lp->next)
6531                                 cmdputs(" | ");
6532                 }
6533                 break;
6534         case NSUBSHELL:
6535                 cmdputs("(");
6536                 cmdtxt(n->nredir.n);
6537                 cmdputs(")");
6538                 break;
6539         case NREDIR:
6540         case NBACKGND:
6541                 cmdtxt(n->nredir.n);
6542                 break;
6543         case NIF:
6544                 cmdputs("if ");
6545                 cmdtxt(n->nif.test);
6546                 cmdputs("; then ");
6547                 cmdtxt(n->nif.ifpart);
6548                 cmdputs("...");
6549                 break;
6550         case NWHILE:
6551                 cmdputs("while ");
6552                 goto until;
6553         case NUNTIL:
6554                 cmdputs("until ");
6555 until:
6556                 cmdtxt(n->nbinary.ch1);
6557                 cmdputs("; do ");
6558                 cmdtxt(n->nbinary.ch2);
6559                 cmdputs("; done");
6560                 break;
6561         case NFOR:
6562                 cmdputs("for ");
6563                 cmdputs(n->nfor.var);
6564                 cmdputs(" in ...");
6565                 break;
6566         case NCASE:
6567                 cmdputs("case ");
6568                 cmdputs(n->ncase.expr->narg.text);
6569                 cmdputs(" in ...");
6570                 break;
6571         case NDEFUN:
6572                 cmdputs(n->narg.text);
6573                 cmdputs("() ...");
6574                 break;
6575         case NCMD:
6576                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
6577                         cmdtxt(np);
6578                         if (np->narg.next)
6579                                 cmdputs(spcstr);
6580                 }
6581                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
6582                         cmdputs(spcstr);
6583                         cmdtxt(np);
6584                 }
6585                 break;
6586         case NARG:
6587                 cmdputs(n->narg.text);
6588                 break;
6589         case NTO:
6590                 p = ">";  i = 1;  goto redir;
6591         case NAPPEND:
6592                 p = ">>";  i = 1;  goto redir;
6593         case NTOFD:
6594                 p = ">&";  i = 1;  goto redir;
6595         case NTOOV:
6596                 p = ">|";  i = 1;  goto redir;
6597         case NFROM:
6598                 p = "<";  i = 0;  goto redir;
6599         case NFROMFD:
6600                 p = "<&";  i = 0;  goto redir;
6601         case NFROMTO:
6602                 p = "<>";  i = 0;  goto redir;
6603 redir:
6604                 if (n->nfile.fd != i) {
6605                         s[0] = n->nfile.fd + '0';
6606                         s[1] = '\0';
6607                         cmdputs(s);
6608                 }
6609                 cmdputs(p);
6610                 if (n->type == NTOFD || n->type == NFROMFD) {
6611                         s[0] = n->ndup.dupfd + '0';
6612                         s[1] = '\0';
6613                         cmdputs(s);
6614                 } else {
6615                         cmdtxt(n->nfile.fname);
6616                 }
6617                 break;
6618         case NHERE:
6619         case NXHERE:
6620                 cmdputs("<<...");
6621                 break;
6622         default:
6623                 cmdputs("???");
6624                 break;
6625         }
6626 }
6627
6628
6629
6630 static void
6631 cmdputs(s)
6632         const char *s;
6633         {
6634         const char *p;
6635         char *q;
6636         char c;
6637         int subtype = 0;
6638
6639         if (cmdnleft <= 0)
6640                 return;
6641         p = s;
6642         q = cmdnextc;
6643         while ((c = *p++) != '\0') {
6644                 if (c == CTLESC)
6645                         *q++ = *p++;
6646                 else if (c == CTLVAR) {
6647                         *q++ = '$';
6648                         if (--cmdnleft > 0)
6649                                 *q++ = '{';
6650                         subtype = *p++;
6651                 } else if (c == '=' && subtype != 0) {
6652                         *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
6653                         subtype = 0;
6654                 } else if (c == CTLENDVAR) {
6655                         *q++ = '}';
6656                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
6657                         cmdnleft++;             /* ignore it */
6658                 else
6659                         *q++ = c;
6660                 if (--cmdnleft <= 0) {
6661                         *q++ = '.';
6662                         *q++ = '.';
6663                         *q++ = '.';
6664                         break;
6665                 }
6666         }
6667         cmdnextc = q;
6668 }
6669
6670 static void waitonint(int sig) {
6671         intreceived = 1;
6672         return;
6673 }
6674 /*      $NetBSD: mail.c,v 1.14 2000/07/03 03:26:19 matt Exp $   */
6675
6676 /*
6677  * Routines to check for mail.  (Perhaps make part of main.c?)
6678  */
6679
6680
6681 #define MAXMBOXES 10
6682
6683
6684 static int nmboxes;                     /* number of mailboxes */
6685 static time_t mailtime[MAXMBOXES];      /* times of mailboxes */
6686
6687
6688
6689 /*
6690  * Print appropriate message(s) if mail has arrived.  If the argument is
6691  * nozero, then the value of MAIL has changed, so we just update the
6692  * values.
6693  */
6694
6695 static void
6696 chkmail(silent)
6697         int silent;
6698 {
6699         int i;
6700         const char *mpath;
6701         char *p;
6702         char *q;
6703         struct stackmark smark;
6704         struct stat statb;
6705
6706         if (silent)
6707                 nmboxes = 10;
6708         if (nmboxes == 0)
6709                 return;
6710         setstackmark(&smark);
6711         mpath = mpathset()? mpathval() : mailval();
6712         for (i = 0 ; i < nmboxes ; i++) {
6713                 p = padvance(&mpath, nullstr);
6714                 if (p == NULL)
6715                         break;
6716                 if (*p == '\0')
6717                         continue;
6718                 for (q = p ; *q ; q++);
6719 #ifdef DEBUG
6720                 if (q[-1] != '/')
6721                         abort();
6722 #endif
6723                 q[-1] = '\0';                   /* delete trailing '/' */
6724 #ifdef notdef /* this is what the System V shell claims to do (it lies) */
6725                 if (stat(p, &statb) < 0)
6726                         statb.st_mtime = 0;
6727                 if (statb.st_mtime > mailtime[i] && ! silent) {
6728                         outfmt(
6729                                 &errout, snlfmt,
6730                                 pathopt? pathopt : "you have mail"
6731                         );
6732                 }
6733                 mailtime[i] = statb.st_mtime;
6734 #else /* this is what it should do */
6735                 if (stat(p, &statb) < 0)
6736                         statb.st_size = 0;
6737                 if (statb.st_size > mailtime[i] && ! silent) {
6738                         outfmt(
6739                                 &errout, snlfmt,
6740                                 pathopt? pathopt : "you have mail"
6741                         );
6742                 }
6743                 mailtime[i] = statb.st_size;
6744 #endif
6745         }
6746         nmboxes = i;
6747         popstackmark(&smark);
6748 }
6749 /*      $NetBSD: main.c,v 1.40 2001/02/04 19:52:06 christos Exp $       */
6750
6751
6752 #define PROFILE 0
6753
6754 static int rootpid;
6755 static int rootshell;
6756 #if PROFILE
6757 short profile_buf[16384];
6758 extern int etext();
6759 #endif
6760
6761 static void read_profile __P((const char *));
6762 static char *find_dot_file __P((char *));
6763 int shell_main __P((int, char **));
6764
6765 extern int oexitstatus;
6766 /*
6767  * Main routine.  We initialize things, parse the arguments, execute
6768  * profiles if we're a login shell, and then call cmdloop to execute
6769  * commands.  The setjmp call sets up the location to jump to when an
6770  * exception occurs.  When an exception occurs the variable "state"
6771  * is used to figure out how far we had gotten.
6772  */
6773
6774 int
6775 shell_main(argc, argv)
6776         int argc;
6777         char **argv;
6778 {
6779         struct jmploc jmploc;
6780         struct stackmark smark;
6781         volatile int state;
6782         char *shinit;
6783
6784         DOTCMD = find_builtin(".");
6785         BLTINCMD = find_builtin("builtin");
6786         COMMANDCMD = find_builtin("command");
6787         EXECCMD = find_builtin("exec");
6788         EVALCMD = find_builtin("eval");
6789
6790 #if PROFILE
6791         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
6792 #endif
6793 #if defined(linux) || defined(__GNU__)
6794         signal(SIGCHLD, SIG_DFL);
6795 #endif
6796         state = 0;
6797         if (setjmp(jmploc.loc)) {
6798                 INTOFF;
6799                 /*
6800                  * When a shell procedure is executed, we raise the
6801                  * exception EXSHELLPROC to clean up before executing
6802                  * the shell procedure.
6803                  */
6804                 switch (exception) {
6805                 case EXSHELLPROC:
6806                         rootpid = getpid();
6807                         rootshell = 1;
6808                         minusc = NULL;
6809                         state = 3;
6810                         break;
6811
6812                 case EXEXEC:
6813                         exitstatus = exerrno;
6814                         break;
6815
6816                 case EXERROR:
6817                         exitstatus = 2;
6818                         break;
6819
6820                 default:
6821                         break;
6822                 }
6823
6824                 if (exception != EXSHELLPROC) {
6825                     if (state == 0 || iflag == 0 || ! rootshell)
6826                             exitshell(exitstatus);
6827                 }
6828                 reset();
6829                 if (exception == EXINT
6830 #if ATTY
6831                  && (! attyset() || equal(termval(), "emacs"))
6832 #endif
6833                  ) {
6834                         out2c('\n');
6835 #ifdef FLUSHERR
6836                         flushout(out2);
6837 #endif
6838                 }
6839                 popstackmark(&smark);
6840                 FORCEINTON;                             /* enable interrupts */
6841                 if (state == 1)
6842                         goto state1;
6843                 else if (state == 2)
6844                         goto state2;
6845                 else if (state == 3)
6846                         goto state3;
6847                 else
6848                         goto state4;
6849         }
6850         handler = &jmploc;
6851 #ifdef DEBUG
6852         opentrace();
6853         trputs("Shell args:  ");  trargs(argv);
6854 #endif
6855         rootpid = getpid();
6856         rootshell = 1;
6857         init();
6858         setstackmark(&smark);
6859         procargs(argc, argv);
6860         if (argv[0] && argv[0][0] == '-') {
6861                 state = 1;
6862                 read_profile("/etc/profile");
6863 state1:
6864                 state = 2;
6865                 read_profile(".profile");
6866         }
6867 state2:
6868         state = 3;
6869 #ifndef linux
6870         if (getuid() == geteuid() && getgid() == getegid()) {
6871 #endif
6872                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
6873                         state = 3;
6874                         read_profile(shinit);
6875                 }
6876 #ifndef linux
6877         }
6878 #endif
6879 state3:
6880         state = 4;
6881         if (sflag == 0 || minusc) {
6882                 static int sigs[] =  {
6883                     SIGINT, SIGQUIT, SIGHUP, 
6884 #ifdef SIGTSTP
6885                     SIGTSTP,
6886 #endif
6887                     SIGPIPE
6888                 };
6889 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
6890                 int i;
6891
6892                 for (i = 0; i < SIGSSIZE; i++)
6893                     setsignal(sigs[i]);
6894         }
6895
6896         if (minusc)
6897                 evalstring(minusc, 0);
6898
6899         if (sflag || minusc == NULL) {
6900 state4: /* XXX ??? - why isn't this before the "if" statement */
6901                 cmdloop(1);
6902         }
6903 #if PROFILE
6904         monitor(0);
6905 #endif
6906         exitshell(exitstatus);
6907         /* NOTREACHED */
6908 }
6909
6910
6911 /*
6912  * Read and execute commands.  "Top" is nonzero for the top level command
6913  * loop; it turns on prompting if the shell is interactive.
6914  */
6915
6916 static void
6917 cmdloop(top)
6918         int top;
6919 {
6920         union node *n;
6921         struct stackmark smark;
6922         int inter;
6923         int numeof = 0;
6924
6925         TRACE(("cmdloop(%d) called\n", top));
6926         setstackmark(&smark);
6927         for (;;) {
6928                 if (pendingsigs)
6929                         dotrap();
6930                 inter = 0;
6931                 if (iflag && top) {
6932                         inter++;
6933                         showjobs(1);
6934                         chkmail(0);
6935                         flushout(&output);
6936                 }
6937                 n = parsecmd(inter);
6938                 /* showtree(n); DEBUG */
6939                 if (n == NEOF) {
6940                         if (!top || numeof >= 50)
6941                                 break;
6942                         if (!stoppedjobs()) {
6943                                 if (!Iflag)
6944                                         break;
6945                                 out2str("\nUse \"exit\" to leave shell.\n");
6946                         }
6947                         numeof++;
6948                 } else if (n != NULL && nflag == 0) {
6949                         job_warning = (job_warning == 2) ? 1 : 0;
6950                         numeof = 0;
6951                         evaltree(n, 0);
6952                 }
6953                 popstackmark(&smark);
6954                 setstackmark(&smark);
6955                 if (evalskip == SKIPFILE) {
6956                         evalskip = 0;
6957                         break;
6958                 }
6959         }
6960         popstackmark(&smark);
6961 }
6962
6963
6964
6965 /*
6966  * Read /etc/profile or .profile.  Return on error.
6967  */
6968
6969 static void
6970 read_profile(name)
6971         const char *name;
6972 {
6973         int fd;
6974         int xflag_set = 0;
6975         int vflag_set = 0;
6976
6977         INTOFF;
6978         if ((fd = open(name, O_RDONLY)) >= 0)
6979                 setinputfd(fd, 1);
6980         INTON;
6981         if (fd < 0)
6982                 return;
6983         /* -q turns off -x and -v just when executing init files */
6984         if (qflag)  {
6985             if (xflag)
6986                     xflag = 0, xflag_set = 1;
6987             if (vflag)
6988                     vflag = 0, vflag_set = 1;
6989         }
6990         cmdloop(0);
6991         if (qflag)  {
6992             if (xflag_set)
6993                     xflag = 1;
6994             if (vflag_set)
6995                     vflag = 1;
6996         }
6997         popfile();
6998 }
6999
7000
7001
7002 /*
7003  * Read a file containing shell functions.
7004  */
7005
7006 static void
7007 readcmdfile(name)
7008         char *name;
7009 {
7010         int fd;
7011
7012         INTOFF;
7013         if ((fd = open(name, O_RDONLY)) >= 0)
7014                 setinputfd(fd, 1);
7015         else
7016                 error("Can't open %s", name);
7017         INTON;
7018         cmdloop(0);
7019         popfile();
7020 }
7021
7022
7023
7024 /*
7025  * Take commands from a file.  To be compatable we should do a path
7026  * search for the file, which is necessary to find sub-commands.
7027  */
7028
7029
7030 static char *
7031 find_dot_file(mybasename)
7032         char *mybasename;
7033 {
7034         char *fullname;
7035         const char *path = pathval();
7036         struct stat statb;
7037
7038         /* don't try this for absolute or relative paths */
7039         if (strchr(mybasename, '/'))
7040                 return mybasename;
7041
7042         while ((fullname = padvance(&path, mybasename)) != NULL) {
7043                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7044                         /*
7045                          * Don't bother freeing here, since it will
7046                          * be freed by the caller.
7047                          */
7048                         return fullname;
7049                 }
7050                 stunalloc(fullname);
7051         }
7052
7053         /* not found in the PATH */
7054         error("%s: not found", mybasename);
7055         /* NOTREACHED */
7056 }
7057
7058 static int
7059 dotcmd(argc, argv)
7060         int argc;
7061         char **argv;
7062 {
7063         struct strlist *sp;
7064         exitstatus = 0;
7065
7066         for (sp = cmdenviron; sp ; sp = sp->next)
7067                 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7068
7069         if (argc >= 2) {                /* That's what SVR2 does */
7070                 char *fullname;
7071                 struct stackmark smark;
7072
7073                 setstackmark(&smark);
7074                 fullname = find_dot_file(argv[1]);
7075                 setinputfile(fullname, 1);
7076                 commandname = fullname;
7077                 cmdloop(0);
7078                 popfile();
7079                 popstackmark(&smark);
7080         }
7081         return exitstatus;
7082 }
7083
7084
7085 static int
7086 exitcmd(argc, argv)
7087         int argc;
7088         char **argv;
7089 {
7090         if (stoppedjobs())
7091                 return 0;
7092         if (argc > 1)
7093                 exitstatus = number(argv[1]);
7094         else
7095                 exitstatus = oexitstatus;
7096         exitshell(exitstatus);
7097         /* NOTREACHED */
7098 }
7099 /*      $NetBSD: memalloc.c,v 1.23 2000/11/01 19:56:01 christos Exp $   */
7100
7101 /*
7102  * Parse trees for commands are allocated in lifo order, so we use a stack
7103  * to make this more efficient, and also to avoid all sorts of exception
7104  * handling code to handle interrupts in the middle of a parse.
7105  *
7106  * The size 504 was chosen because the Ultrix malloc handles that size
7107  * well.
7108  */
7109
7110 #define MINSIZE 504             /* minimum size of a block */
7111
7112
7113 struct stack_block {
7114         struct stack_block *prev;
7115         char space[MINSIZE];
7116 };
7117
7118 struct stack_block stackbase;
7119 struct stack_block *stackp = &stackbase;
7120 struct stackmark *markp;
7121 static char *stacknxt = stackbase.space;
7122 static int stacknleft = MINSIZE;
7123 static int sstrnleft;
7124 static int herefd = -1;
7125
7126
7127
7128 pointer
7129 stalloc(nbytes)
7130         int nbytes;
7131 {
7132         char *p;
7133
7134         nbytes = ALIGN(nbytes);
7135         if (nbytes > stacknleft) {
7136                 int blocksize;
7137                 struct stack_block *sp;
7138
7139                 blocksize = nbytes;
7140                 if (blocksize < MINSIZE)
7141                         blocksize = MINSIZE;
7142                 INTOFF;
7143                 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
7144                 sp->prev = stackp;
7145                 stacknxt = sp->space;
7146                 stacknleft = blocksize;
7147                 stackp = sp;
7148                 INTON;
7149         }
7150         p = stacknxt;
7151         stacknxt += nbytes;
7152         stacknleft -= nbytes;
7153         return p;
7154 }
7155
7156
7157 static void
7158 stunalloc(p)
7159         pointer p;
7160         {
7161 #ifdef DEBUG
7162         if (p == NULL) {                /*DEBUG */
7163                 write(2, "stunalloc\n", 10);
7164                 abort();
7165         }
7166 #endif
7167         if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
7168                 p = stackp->space;
7169         }
7170         stacknleft += stacknxt - (char *)p;
7171         stacknxt = p;
7172 }
7173
7174
7175
7176 static void
7177 setstackmark(mark)
7178         struct stackmark *mark;
7179         {
7180         mark->stackp = stackp;
7181         mark->stacknxt = stacknxt;
7182         mark->stacknleft = stacknleft;
7183         mark->marknext = markp;
7184         markp = mark;
7185 }
7186
7187
7188 static void
7189 popstackmark(mark)
7190         struct stackmark *mark;
7191         {
7192         struct stack_block *sp;
7193
7194         INTOFF;
7195         markp = mark->marknext;
7196         while (stackp != mark->stackp) {
7197                 sp = stackp;
7198                 stackp = sp->prev;
7199                 ckfree(sp);
7200         }
7201         stacknxt = mark->stacknxt;
7202         stacknleft = mark->stacknleft;
7203         INTON;
7204 }
7205
7206
7207 /*
7208  * When the parser reads in a string, it wants to stick the string on the
7209  * stack and only adjust the stack pointer when it knows how big the
7210  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
7211  * of space on top of the stack and stackblocklen returns the length of
7212  * this block.  Growstackblock will grow this space by at least one byte,
7213  * possibly moving it (like realloc).  Grabstackblock actually allocates the
7214  * part of the block that has been used.
7215  */
7216
7217 static void
7218 growstackblock() {
7219         char *p;
7220         int newlen = ALIGN(stacknleft * 2 + 100);
7221         char *oldspace = stacknxt;
7222         int oldlen = stacknleft;
7223         struct stack_block *sp;
7224         struct stack_block *oldstackp;
7225
7226         if (stacknxt == stackp->space && stackp != &stackbase) {
7227                 INTOFF;
7228                 oldstackp = stackp;
7229                 sp = stackp;
7230                 stackp = sp->prev;
7231                 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
7232                 sp->prev = stackp;
7233                 stackp = sp;
7234                 stacknxt = sp->space;
7235                 stacknleft = newlen;
7236                 {
7237                   /* Stack marks pointing to the start of the old block
7238                    * must be relocated to point to the new block 
7239                    */
7240                   struct stackmark *xmark;
7241                   xmark = markp;
7242                   while (xmark != NULL && xmark->stackp == oldstackp) {
7243                     xmark->stackp = stackp;
7244                     xmark->stacknxt = stacknxt;
7245                     xmark->stacknleft = stacknleft;
7246                     xmark = xmark->marknext;
7247                   }
7248                 }
7249                 INTON;
7250         } else {
7251                 p = stalloc(newlen);
7252                 memcpy(p, oldspace, oldlen);
7253                 stacknxt = p;                   /* free the space */
7254                 stacknleft += newlen;           /* we just allocated */
7255         }
7256 }
7257
7258
7259
7260 static void
7261 grabstackblock(len)
7262         int len;
7263 {
7264         len = ALIGN(len);
7265         stacknxt += len;
7266         stacknleft -= len;
7267 }
7268
7269
7270
7271 /*
7272  * The following routines are somewhat easier to use that the above.
7273  * The user declares a variable of type STACKSTR, which may be declared
7274  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
7275  * the user uses the macro STPUTC to add characters to the string.  In
7276  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
7277  * grown as necessary.  When the user is done, she can just leave the
7278  * string there and refer to it using stackblock().  Or she can allocate
7279  * the space for it using grabstackstr().  If it is necessary to allow
7280  * someone else to use the stack temporarily and then continue to grow
7281  * the string, the user should use grabstack to allocate the space, and
7282  * then call ungrabstr(p) to return to the previous mode of operation.
7283  *
7284  * USTPUTC is like STPUTC except that it doesn't check for overflow.
7285  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
7286  * is space for at least one character.
7287  */
7288
7289
7290 static char *
7291 growstackstr() {
7292         int len = stackblocksize();
7293         if (herefd >= 0 && len >= 1024) {
7294                 xwrite(herefd, stackblock(), len);
7295                 sstrnleft = len - 1;
7296                 return stackblock();
7297         }
7298         growstackblock();
7299         sstrnleft = stackblocksize() - len - 1;
7300         return stackblock() + len;
7301 }
7302
7303
7304 /*
7305  * Called from CHECKSTRSPACE.
7306  */
7307
7308 static char *
7309 makestrspace(size_t newlen) {
7310         int len = stackblocksize() - sstrnleft;
7311         do {
7312                 growstackblock();
7313                 sstrnleft = stackblocksize() - len;
7314         } while (sstrnleft < newlen);
7315         return stackblock() + len;
7316 }
7317
7318
7319
7320 static void
7321 ungrabstackstr(s, p)
7322         char *s;
7323         char *p;
7324         {
7325         stacknleft += stacknxt - s;
7326         stacknxt = s;
7327         sstrnleft = stacknleft - (p - s);
7328 }
7329 /*      $NetBSD: miscbltin.c,v 1.30 2001/02/04 19:52:06 christos Exp $  */
7330
7331 /*
7332  * Miscelaneous builtins.
7333  */
7334
7335
7336 #undef rflag
7337
7338 #ifdef __GLIBC__
7339 mode_t getmode(const void *, mode_t);
7340 static void *setmode(const char *);
7341
7342 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
7343 typedef enum __rlimit_resource rlim_t;
7344 #endif
7345 #endif
7346
7347
7348
7349 /*
7350  * The read builtin.  The -e option causes backslashes to escape the
7351  * following character.
7352  *
7353  * This uses unbuffered input, which may be avoidable in some cases.
7354  */
7355
7356 static int
7357 readcmd(argc, argv)
7358         int argc;
7359         char **argv;
7360 {
7361         char **ap;
7362         int backslash;
7363         char c;
7364         int rflag;
7365         char *prompt;
7366         const char *ifs;
7367         char *p;
7368         int startword;
7369         int status;
7370         int i;
7371
7372         rflag = 0;
7373         prompt = NULL;
7374         while ((i = nextopt("p:r")) != '\0') {
7375                 if (i == 'p')
7376                         prompt = optionarg;
7377                 else
7378                         rflag = 1;
7379         }
7380         if (prompt && isatty(0)) {
7381                 putprompt(prompt);
7382                 flushall();
7383         }
7384         if (*(ap = argptr) == NULL)
7385                 error("arg count");
7386         if ((ifs = bltinlookup("IFS")) == NULL)
7387                 ifs = defifs;
7388         status = 0;
7389         startword = 1;
7390         backslash = 0;
7391         STARTSTACKSTR(p);
7392         for (;;) {
7393                 if (read(0, &c, 1) != 1) {
7394                         status = 1;
7395                         break;
7396                 }
7397                 if (c == '\0')
7398                         continue;
7399                 if (backslash) {
7400                         backslash = 0;
7401                         if (c != '\n')
7402                                 STPUTC(c, p);
7403                         continue;
7404                 }
7405                 if (!rflag && c == '\\') {
7406                         backslash++;
7407                         continue;
7408                 }
7409                 if (c == '\n')
7410                         break;
7411                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
7412                         continue;
7413                 }
7414                 startword = 0;
7415                 if (backslash && c == '\\') {
7416                         if (read(0, &c, 1) != 1) {
7417                                 status = 1;
7418                                 break;
7419                         }
7420                         STPUTC(c, p);
7421                 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
7422                         STACKSTRNUL(p);
7423                         setvar(*ap, stackblock(), 0);
7424                         ap++;
7425                         startword = 1;
7426                         STARTSTACKSTR(p);
7427                 } else {
7428                         STPUTC(c, p);
7429                 }
7430         }
7431         STACKSTRNUL(p);
7432         /* Remove trailing blanks */
7433         while (stackblock() <= --p && strchr(ifs, *p) != NULL)
7434                 *p = '\0';
7435         setvar(*ap, stackblock(), 0);
7436         while (*++ap != NULL)
7437                 setvar(*ap, nullstr, 0);
7438         return status;
7439 }
7440
7441
7442
7443 static int
7444 umaskcmd(argc, argv)
7445         int argc;
7446         char **argv;
7447 {
7448         char *ap;
7449         int mask;
7450         int i;
7451         int symbolic_mode = 0;
7452
7453         while ((i = nextopt("S")) != '\0') {
7454                 symbolic_mode = 1;
7455         }
7456
7457         INTOFF;
7458         mask = umask(0);
7459         umask(mask);
7460         INTON;
7461
7462         if ((ap = *argptr) == NULL) {
7463                 if (symbolic_mode) {
7464                         char u[4], g[4], o[4];
7465
7466                         i = 0;
7467                         if ((mask & S_IRUSR) == 0)
7468                                 u[i++] = 'r';
7469                         if ((mask & S_IWUSR) == 0)
7470                                 u[i++] = 'w';
7471                         if ((mask & S_IXUSR) == 0)
7472                                 u[i++] = 'x';
7473                         u[i] = '\0';
7474
7475                         i = 0;
7476                         if ((mask & S_IRGRP) == 0)
7477                                 g[i++] = 'r';
7478                         if ((mask & S_IWGRP) == 0)
7479                                 g[i++] = 'w';
7480                         if ((mask & S_IXGRP) == 0)
7481                                 g[i++] = 'x';
7482                         g[i] = '\0';
7483
7484                         i = 0;
7485                         if ((mask & S_IROTH) == 0)
7486                                 o[i++] = 'r';
7487                         if ((mask & S_IWOTH) == 0)
7488                                 o[i++] = 'w';
7489                         if ((mask & S_IXOTH) == 0)
7490                                 o[i++] = 'x';
7491                         o[i] = '\0';
7492
7493                         out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
7494                 } else {
7495                         out1fmt("%.4o\n", mask);
7496                 }
7497         } else {
7498                 if (isdigit((unsigned char)*ap)) {
7499                         mask = 0;
7500                         do {
7501                                 if (*ap >= '8' || *ap < '0')
7502                                         error("Illegal number: %s", argv[1]);
7503                                 mask = (mask << 3) + (*ap - '0');
7504                         } while (*++ap != '\0');
7505                         umask(mask);
7506                 } else {
7507                         void *set;
7508
7509                         INTOFF;
7510                         if ((set = setmode(ap)) != 0) {
7511                                 mask = getmode(set, ~mask & 0777);
7512                                 ckfree(set);
7513                         }
7514                         INTON;
7515                         if (!set)
7516                                 error("Illegal mode: %s", ap);
7517
7518                         umask(~mask & 0777);
7519                 }
7520         }
7521         return 0;
7522 }
7523
7524 /*
7525  * ulimit builtin
7526  *
7527  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
7528  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
7529  * ash by J.T. Conklin.
7530  *
7531  * Public domain.
7532  */
7533
7534 struct limits {
7535         const char *name;
7536         int     cmd;
7537         int     factor; /* multiply by to get rlim_{cur,max} values */
7538         char    option;
7539 };
7540
7541 static const struct limits limits[] = {
7542 #ifdef RLIMIT_CPU
7543         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
7544 #endif
7545 #ifdef RLIMIT_FSIZE
7546         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
7547 #endif
7548 #ifdef RLIMIT_DATA
7549         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
7550 #endif
7551 #ifdef RLIMIT_STACK
7552         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
7553 #endif
7554 #ifdef  RLIMIT_CORE
7555         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
7556 #endif
7557 #ifdef RLIMIT_RSS
7558         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
7559 #endif
7560 #ifdef RLIMIT_MEMLOCK
7561         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
7562 #endif
7563 #ifdef RLIMIT_NPROC
7564         { "process(processes)",         RLIMIT_NPROC,      1, 'p' },
7565 #endif
7566 #ifdef RLIMIT_NOFILE
7567         { "nofiles(descriptors)",       RLIMIT_NOFILE,     1, 'n' },
7568 #endif
7569 #ifdef RLIMIT_VMEM
7570         { "vmemory(kbytes)",            RLIMIT_VMEM,    1024, 'v' },
7571 #endif
7572 #ifdef RLIMIT_SWAP
7573         { "swap(kbytes)",               RLIMIT_SWAP,    1024, 'w' },
7574 #endif
7575         { (char *) 0,                   0,                 0,  '\0' }
7576 };
7577
7578 static int
7579 ulimitcmd(argc, argv)
7580         int argc;
7581         char **argv;
7582 {
7583         int     c;
7584         rlim_t val = 0;
7585         enum { SOFT = 0x1, HARD = 0x2 }
7586                         how = SOFT | HARD;
7587         const struct limits     *l;
7588         int             set, all = 0;
7589         int             optc, what;
7590         struct rlimit   limit;
7591
7592         what = 'f';
7593         while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
7594                 switch (optc) {
7595                 case 'H':
7596                         how = HARD;
7597                         break;
7598                 case 'S':
7599                         how = SOFT;
7600                         break;
7601                 case 'a':
7602                         all = 1;
7603                         break;
7604                 default:
7605                         what = optc;
7606                 }
7607
7608         for (l = limits; l->name && l->option != what; l++)
7609                 ;
7610         if (!l->name)
7611                 error("internal error (%c)", what);
7612
7613         set = *argptr ? 1 : 0;
7614         if (set) {
7615                 char *p = *argptr;
7616
7617                 if (all || argptr[1])
7618                         error("too many arguments");
7619                 if (strcmp(p, "unlimited") == 0)
7620                         val = RLIM_INFINITY;
7621                 else {
7622                         val = (rlim_t) 0;
7623
7624                         while ((c = *p++) >= '0' && c <= '9')
7625                         {
7626                                 val = (val * 10) + (long)(c - '0');
7627                                 if (val < (rlim_t) 0)
7628                                         break;
7629                         }
7630                         if (c)
7631                                 error("bad number");
7632                         val *= l->factor;
7633                 }
7634         }
7635         if (all) {
7636                 for (l = limits; l->name; l++) {
7637                         getrlimit(l->cmd, &limit);
7638                         if (how & SOFT)
7639                                 val = limit.rlim_cur;
7640                         else if (how & HARD)
7641                                 val = limit.rlim_max;
7642
7643                         out1fmt("%-20s ", l->name);
7644                         if (val == RLIM_INFINITY)
7645                                 out1fmt("unlimited\n");
7646                         else
7647                         {
7648                                 val /= l->factor;
7649 #ifdef BSD4_4
7650                                 out1fmt("%lld\n", (long long) val);
7651 #else
7652                                 out1fmt("%ld\n", (long) val);
7653 #endif
7654                         }
7655                 }
7656                 return 0;
7657         }
7658
7659         getrlimit(l->cmd, &limit);
7660         if (set) {
7661                 if (how & HARD)
7662                         limit.rlim_max = val;
7663                 if (how & SOFT)
7664                         limit.rlim_cur = val;
7665                 if (setrlimit(l->cmd, &limit) < 0)
7666                         error("error setting limit (%s)", strerror(errno));
7667         } else {
7668                 if (how & SOFT)
7669                         val = limit.rlim_cur;
7670                 else if (how & HARD)
7671                         val = limit.rlim_max;
7672
7673                 if (val == RLIM_INFINITY)
7674                         out1fmt("unlimited\n");
7675                 else
7676                 {
7677                         val /= l->factor;
7678 #ifdef BSD4_4
7679                         out1fmt("%lld\n", (long long) val);
7680 #else
7681                         out1fmt("%ld\n", (long) val);
7682 #endif
7683                 }
7684         }
7685         return 0;
7686 }
7687 /*      $NetBSD: mystring.c,v 1.14 1999/07/09 03:05:50 christos Exp $   */
7688
7689 /*
7690  * String functions.
7691  *
7692  *      equal(s1, s2)           Return true if strings are equal.
7693  *      scopy(from, to)         Copy a string.
7694  *      scopyn(from, to, n)     Like scopy, but checks for overflow.
7695  *      number(s)               Convert a string of digits to an integer.
7696  *      is_number(s)            Return true if s is a string of digits.
7697  */
7698
7699 static char nullstr[1];         /* zero length string */
7700 static const char spcstr[] = " ";
7701 static const char snlfmt[] = "%s\n";
7702
7703 /*
7704  * equal - #defined in mystring.h
7705  */
7706
7707 /*
7708  * scopy - #defined in mystring.h
7709  */
7710
7711
7712 #if 0
7713 /*
7714  * scopyn - copy a string from "from" to "to", truncating the string
7715  *              if necessary.  "To" is always nul terminated, even if
7716  *              truncation is performed.  "Size" is the size of "to".
7717  */
7718
7719 static void
7720 scopyn(from, to, size)
7721         char const *from;
7722         char *to;
7723         int size;
7724         {
7725
7726         while (--size > 0) {
7727                 if ((*to++ = *from++) == '\0')
7728                         return;
7729         }
7730         *to = '\0';
7731 }
7732 #endif
7733
7734
7735 /*
7736  * prefix -- see if pfx is a prefix of string.
7737  */
7738
7739 static int
7740 prefix(pfx, string)
7741         char const *pfx;
7742         char const *string;
7743         {
7744         while (*pfx) {
7745                 if (*pfx++ != *string++)
7746                         return 0;
7747         }
7748         return 1;
7749 }
7750
7751
7752 /*
7753  * Convert a string of digits to an integer, printing an error message on
7754  * failure.
7755  */
7756
7757 static int
7758 number(s)
7759         const char *s;
7760         {
7761
7762         if (! is_number(s))
7763                 error("Illegal number: %s", s);
7764         return atoi(s);
7765 }
7766
7767
7768
7769 /*
7770  * Check for a valid number.  This should be elsewhere.
7771  */
7772
7773 static int
7774 is_number(p)
7775         const char *p;
7776         {
7777         do {
7778                 if (! is_digit(*p))
7779                         return 0;
7780         } while (*++p != '\0');
7781         return 1;
7782 }
7783
7784
7785 /*
7786  * Produce a possibly single quoted string suitable as input to the shell.
7787  * The return string is allocated on the stack.
7788  */
7789
7790 static char *
7791 single_quote(const char *s) {
7792         char *p;
7793
7794         STARTSTACKSTR(p);
7795
7796         do {
7797                 char *q = p;
7798                 size_t len1, len1p, len2, len2p;
7799
7800                 len1 = strcspn(s, "'");
7801                 len2 = strspn(s + len1, "'");
7802
7803                 len1p = len1 ? len1 + 2 : len1;
7804                 switch (len2) {
7805                 case 0:
7806                         len2p = 0;
7807                         break;
7808                 case 1:
7809                         len2p = 2;
7810                         break;
7811                 default:
7812                         len2p = len2 + 2;
7813                 }
7814
7815                 CHECKSTRSPACE(len1p + len2p + 1, p);
7816
7817                 if (len1) {
7818                         *p = '\'';
7819 #ifdef _GNU_SOURCE
7820                         q = mempcpy(p + 1, s, len1);
7821 #else
7822                         q = p + 1 + len1;
7823                         memcpy(p + 1, s, len1);
7824 #endif
7825                         *q++ = '\'';
7826                         s += len1;
7827                 }
7828
7829                 switch (len2) {
7830                 case 0:
7831                         break;
7832                 case 1:
7833                         *q++ = '\\';
7834                         *q = '\'';
7835                         s++;
7836                         break;
7837                 default:
7838                         *q = '"';
7839 #ifdef _GNU_SOURCE
7840                         *(char *) mempcpy(q + 1, s, len2) = '"';
7841 #else
7842                         q += 1 + len2;
7843                         memcpy(q + 1, s, len2);
7844                         *q = '"';
7845 #endif
7846                         s += len2;
7847                 }
7848
7849                 STADJUST(len1p + len2p, p);
7850         } while (*s);
7851
7852         USTPUTC(0, p);
7853
7854         return grabstackstr(p);
7855 }
7856
7857 /*
7858  * Like strdup but works with the ash stack.
7859  */
7860
7861 static char *
7862 sstrdup(const char *p)
7863 {
7864         size_t len = strlen(p) + 1;
7865         return memcpy(stalloc(len), p, len);
7866 }
7867
7868 /*
7869  * Wrapper around strcmp for qsort/bsearch/...
7870  */
7871 static int
7872 pstrcmp(const void *a, const void *b)
7873 {
7874         return strcmp(*(const char *const *) a, *(const char *const *) b);
7875 }
7876
7877 /*
7878  * Find a string is in a sorted array.
7879  */
7880 static const char *const *
7881 findstring(const char *s, const char *const *array, size_t nmemb)
7882 {
7883         return bsearch(&s, array, nmemb, sizeof(const char *), pstrcmp);
7884 }
7885 /*
7886  * This file was generated by the mknodes program.
7887  */
7888
7889 /*      $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 christos Exp $   */
7890
7891 /*
7892  * Routine for dealing with parsed shell commands.
7893  */
7894
7895
7896 static int     funcblocksize;           /* size of structures in function */
7897 static int     funcstringsize;          /* size of strings in node */
7898 pointer funcblock;              /* block to allocate function from */
7899 static char   *funcstring;              /* block to allocate strings from */
7900
7901 static const short nodesize[26] = {
7902       ALIGN(sizeof (struct nbinary)),
7903       ALIGN(sizeof (struct ncmd)),
7904       ALIGN(sizeof (struct npipe)),
7905       ALIGN(sizeof (struct nredir)),
7906       ALIGN(sizeof (struct nredir)),
7907       ALIGN(sizeof (struct nredir)),
7908       ALIGN(sizeof (struct nbinary)),
7909       ALIGN(sizeof (struct nbinary)),
7910       ALIGN(sizeof (struct nif)),
7911       ALIGN(sizeof (struct nbinary)),
7912       ALIGN(sizeof (struct nbinary)),
7913       ALIGN(sizeof (struct nfor)),
7914       ALIGN(sizeof (struct ncase)),
7915       ALIGN(sizeof (struct nclist)),
7916       ALIGN(sizeof (struct narg)),
7917       ALIGN(sizeof (struct narg)),
7918       ALIGN(sizeof (struct nfile)),
7919       ALIGN(sizeof (struct nfile)),
7920       ALIGN(sizeof (struct nfile)),
7921       ALIGN(sizeof (struct nfile)),
7922       ALIGN(sizeof (struct nfile)),
7923       ALIGN(sizeof (struct ndup)),
7924       ALIGN(sizeof (struct ndup)),
7925       ALIGN(sizeof (struct nhere)),
7926       ALIGN(sizeof (struct nhere)),
7927       ALIGN(sizeof (struct nnot)),
7928 };
7929
7930
7931 static void calcsize __P((union node *));
7932 static void sizenodelist __P((struct nodelist *));
7933 static union node *copynode __P((union node *));
7934 static struct nodelist *copynodelist __P((struct nodelist *));
7935 static char *nodesavestr __P((char *));
7936
7937
7938
7939 /*
7940  * Make a copy of a parse tree.
7941  */
7942
7943 union node *
7944 copyfunc(n)
7945         union node *n;
7946 {
7947         if (n == NULL)
7948                 return NULL;
7949         funcblocksize = 0;
7950         funcstringsize = 0;
7951         calcsize(n);
7952         funcblock = ckmalloc(funcblocksize + funcstringsize);
7953         funcstring = (char *) funcblock + funcblocksize;
7954         return copynode(n);
7955 }
7956
7957
7958
7959 static void
7960 calcsize(n)
7961         union node *n;
7962 {
7963       if (n == NULL)
7964             return;
7965       funcblocksize += nodesize[n->type];
7966       switch (n->type) {
7967       case NSEMI:
7968       case NAND:
7969       case NOR:
7970       case NWHILE:
7971       case NUNTIL:
7972             calcsize(n->nbinary.ch2);
7973             calcsize(n->nbinary.ch1);
7974             break;
7975       case NCMD:
7976             calcsize(n->ncmd.redirect);
7977             calcsize(n->ncmd.args);
7978             calcsize(n->ncmd.assign);
7979             break;
7980       case NPIPE:
7981             sizenodelist(n->npipe.cmdlist);
7982             break;
7983       case NREDIR:
7984       case NBACKGND:
7985       case NSUBSHELL:
7986             calcsize(n->nredir.redirect);
7987             calcsize(n->nredir.n);
7988             break;
7989       case NIF:
7990             calcsize(n->nif.elsepart);
7991             calcsize(n->nif.ifpart);
7992             calcsize(n->nif.test);
7993             break;
7994       case NFOR:
7995             funcstringsize += strlen(n->nfor.var) + 1;
7996             calcsize(n->nfor.body);
7997             calcsize(n->nfor.args);
7998             break;
7999       case NCASE:
8000             calcsize(n->ncase.cases);
8001             calcsize(n->ncase.expr);
8002             break;
8003       case NCLIST:
8004             calcsize(n->nclist.body);
8005             calcsize(n->nclist.pattern);
8006             calcsize(n->nclist.next);
8007             break;
8008       case NDEFUN:
8009       case NARG:
8010             sizenodelist(n->narg.backquote);
8011             funcstringsize += strlen(n->narg.text) + 1;
8012             calcsize(n->narg.next);
8013             break;
8014       case NTO:
8015       case NFROM:
8016       case NFROMTO:
8017       case NAPPEND:
8018       case NTOOV:
8019             calcsize(n->nfile.fname);
8020             calcsize(n->nfile.next);
8021             break;
8022       case NTOFD:
8023       case NFROMFD:
8024             calcsize(n->ndup.vname);
8025             calcsize(n->ndup.next);
8026             break;
8027       case NHERE:
8028       case NXHERE:
8029             calcsize(n->nhere.doc);
8030             calcsize(n->nhere.next);
8031             break;
8032       case NNOT:
8033             calcsize(n->nnot.com);
8034             break;
8035       };
8036 }
8037
8038
8039
8040 static void
8041 sizenodelist(lp)
8042         struct nodelist *lp;
8043 {
8044         while (lp) {
8045                 funcblocksize += ALIGN(sizeof(struct nodelist));
8046                 calcsize(lp->n);
8047                 lp = lp->next;
8048         }
8049 }
8050
8051
8052
8053 static union node *
8054 copynode(n)
8055         union node *n;
8056 {
8057         union node *new;
8058
8059       if (n == NULL)
8060             return NULL;
8061       new = funcblock;
8062       funcblock = (char *) funcblock + nodesize[n->type];
8063       switch (n->type) {
8064       case NSEMI:
8065       case NAND:
8066       case NOR:
8067       case NWHILE:
8068       case NUNTIL:
8069             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8070             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8071             break;
8072       case NCMD:
8073             new->ncmd.redirect = copynode(n->ncmd.redirect);
8074             new->ncmd.args = copynode(n->ncmd.args);
8075             new->ncmd.assign = copynode(n->ncmd.assign);
8076             new->ncmd.backgnd = n->ncmd.backgnd;
8077             break;
8078       case NPIPE:
8079             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8080             new->npipe.backgnd = n->npipe.backgnd;
8081             break;
8082       case NREDIR:
8083       case NBACKGND:
8084       case NSUBSHELL:
8085             new->nredir.redirect = copynode(n->nredir.redirect);
8086             new->nredir.n = copynode(n->nredir.n);
8087             break;
8088       case NIF:
8089             new->nif.elsepart = copynode(n->nif.elsepart);
8090             new->nif.ifpart = copynode(n->nif.ifpart);
8091             new->nif.test = copynode(n->nif.test);
8092             break;
8093       case NFOR:
8094             new->nfor.var = nodesavestr(n->nfor.var);
8095             new->nfor.body = copynode(n->nfor.body);
8096             new->nfor.args = copynode(n->nfor.args);
8097             break;
8098       case NCASE:
8099             new->ncase.cases = copynode(n->ncase.cases);
8100             new->ncase.expr = copynode(n->ncase.expr);
8101             break;
8102       case NCLIST:
8103             new->nclist.body = copynode(n->nclist.body);
8104             new->nclist.pattern = copynode(n->nclist.pattern);
8105             new->nclist.next = copynode(n->nclist.next);
8106             break;
8107       case NDEFUN:
8108       case NARG:
8109             new->narg.backquote = copynodelist(n->narg.backquote);
8110             new->narg.text = nodesavestr(n->narg.text);
8111             new->narg.next = copynode(n->narg.next);
8112             break;
8113       case NTO:
8114       case NFROM:
8115       case NFROMTO:
8116       case NAPPEND:
8117       case NTOOV:
8118             new->nfile.fname = copynode(n->nfile.fname);
8119             new->nfile.fd = n->nfile.fd;
8120             new->nfile.next = copynode(n->nfile.next);
8121             break;
8122       case NTOFD:
8123       case NFROMFD:
8124             new->ndup.vname = copynode(n->ndup.vname);
8125             new->ndup.dupfd = n->ndup.dupfd;
8126             new->ndup.fd = n->ndup.fd;
8127             new->ndup.next = copynode(n->ndup.next);
8128             break;
8129       case NHERE:
8130       case NXHERE:
8131             new->nhere.doc = copynode(n->nhere.doc);
8132             new->nhere.fd = n->nhere.fd;
8133             new->nhere.next = copynode(n->nhere.next);
8134             break;
8135       case NNOT:
8136             new->nnot.com = copynode(n->nnot.com);
8137             break;
8138       };
8139       new->type = n->type;
8140         return new;
8141 }
8142
8143
8144 static struct nodelist *
8145 copynodelist(lp)
8146         struct nodelist *lp;
8147 {
8148         struct nodelist *start;
8149         struct nodelist **lpp;
8150
8151         lpp = &start;
8152         while (lp) {
8153                 *lpp = funcblock;
8154                 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
8155                 (*lpp)->n = copynode(lp->n);
8156                 lp = lp->next;
8157                 lpp = &(*lpp)->next;
8158         }
8159         *lpp = NULL;
8160         return start;
8161 }
8162
8163
8164
8165 static char *
8166 nodesavestr(s)
8167         char   *s;
8168 {
8169 #ifdef _GNU_SOURCE
8170         char   *rtn = funcstring;
8171
8172         funcstring = stpcpy(funcstring, s) + 1;
8173         return rtn;
8174 #else
8175         register char *p = s;
8176         register char *q = funcstring;
8177         char   *rtn = funcstring;
8178
8179         while ((*q++ = *p++) != '\0')
8180                 continue;
8181         funcstring = q;
8182         return rtn;
8183 #endif
8184 }
8185
8186
8187
8188 /*
8189  * Free a parse tree.
8190  */
8191
8192 static void
8193 freefunc(n)
8194         union node *n;
8195 {
8196         if (n)
8197                 ckfree(n);
8198 }
8199 /*      $NetBSD: options.c,v 1.31 2001/02/26 13:06:43 wiz Exp $ */
8200
8201
8202 struct optent optlist[NOPTS] = {
8203         { "errexit",    'e',    0 },
8204         { "noglob",     'f',    0 },
8205         { "ignoreeof",  'I',    0 },
8206         { "interactive",'i',    0 },
8207         { "monitor",    'm',    0 },
8208         { "noexec",     'n',    0 },
8209         { "stdin",      's',    0 },
8210         { "xtrace",     'x',    0 },
8211         { "verbose",    'v',    0 },
8212         { "vi",         'V',    0 },
8213         { "emacs",      'E',    0 },
8214         { "noclobber",  'C',    0 },
8215         { "allexport",  'a',    0 },
8216         { "notify",     'b',    0 },
8217         { "nounset",    'u',    0 },
8218         { "quietprofile", 'q',  0 },
8219 };
8220 static char *arg0;                      /* value of $0 */
8221 struct shparam shellparam;      /* current positional parameters */
8222 static char **argptr;                   /* argument list for builtin commands */
8223 static char *optionarg;         /* set by nextopt (like getopt) */
8224 static char *optptr;                    /* used by nextopt */
8225
8226 static char *minusc;                    /* argument to -c option */
8227
8228
8229 static void options __P((int));
8230 static void minus_o __P((char *, int));
8231 static void setoption __P((int, int));
8232 #ifdef ASH_GETOPTS
8233 static int getopts __P((char *, char *, char **, int *, int *));
8234 #endif
8235
8236
8237 /*
8238  * Process the shell command line arguments.
8239  */
8240
8241 static void
8242 procargs(argc, argv)
8243         int argc;
8244         char **argv;
8245 {
8246         int i;
8247
8248         argptr = argv;
8249         if (argc > 0)
8250                 argptr++;
8251         for (i = 0; i < NOPTS; i++)
8252                 optlist[i].val = 2;
8253         options(1);
8254         if (*argptr == NULL && minusc == NULL)
8255                 sflag = 1;
8256         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8257                 iflag = 1;
8258         if (mflag == 2)
8259                 mflag = iflag;
8260         for (i = 0; i < NOPTS; i++)
8261                 if (optlist[i].val == 2)
8262                         optlist[i].val = 0;
8263         arg0 = argv[0];
8264         if (sflag == 0 && minusc == NULL) {
8265                 commandname = argv[0];
8266                 arg0 = *argptr++;
8267                 setinputfile(arg0, 0);
8268                 commandname = arg0;
8269         }
8270         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8271         if (argptr && minusc && *argptr)
8272                 arg0 = *argptr++;
8273
8274         shellparam.p = argptr;
8275         shellparam.optind = 1;
8276         shellparam.optoff = -1;
8277         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8278         while (*argptr) {
8279                 shellparam.nparam++;
8280                 argptr++;
8281         }
8282         optschanged();
8283 }
8284
8285
8286 static void
8287 optschanged()
8288 {
8289         setinteractive(iflag);
8290         setjobctl(mflag);
8291 }
8292
8293 /*
8294  * Process shell options.  The global variable argptr contains a pointer
8295  * to the argument list; we advance it past the options.
8296  */
8297
8298 static void
8299 options(cmdline)
8300         int cmdline;
8301 {
8302         char *p;
8303         int val;
8304         int c;
8305
8306         if (cmdline)
8307                 minusc = NULL;
8308         while ((p = *argptr) != NULL) {
8309                 argptr++;
8310                 if ((c = *p++) == '-') {
8311                         val = 1;
8312                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8313                                 if (!cmdline) {
8314                                         /* "-" means turn off -x and -v */
8315                                         if (p[0] == '\0')
8316                                                 xflag = vflag = 0;
8317                                         /* "--" means reset params */
8318                                         else if (*argptr == NULL)
8319                                                 setparam(argptr);
8320                                 }
8321                                 break;    /* "-" or  "--" terminates options */
8322                         }
8323                 } else if (c == '+') {
8324                         val = 0;
8325                 } else {
8326                         argptr--;
8327                         break;
8328                 }
8329                 while ((c = *p++) != '\0') {
8330                         if (c == 'c' && cmdline) {
8331                                 char *q;
8332 #ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
8333                                 if (*p == '\0')
8334 #endif
8335                                         q = *argptr++;
8336                                 if (q == NULL || minusc != NULL)
8337                                         error("Bad -c option");
8338                                 minusc = q;
8339 #ifdef NOHACK
8340                                 break;
8341 #endif
8342                         } else if (c == 'o') {
8343                                 minus_o(*argptr, val);
8344                                 if (*argptr)
8345                                         argptr++;
8346                         } else {
8347                                 setoption(c, val);
8348                         }
8349                 }
8350         }
8351 }
8352
8353 static void
8354 minus_o(name, val)
8355         char *name;
8356         int val;
8357 {
8358         int i;
8359
8360         if (name == NULL) {
8361                 out1str("Current option settings\n");
8362                 for (i = 0; i < NOPTS; i++)
8363                         out1fmt("%-16s%s\n", optlist[i].name,
8364                                 optlist[i].val ? "on" : "off");
8365         } else {
8366                 for (i = 0; i < NOPTS; i++)
8367                         if (equal(name, optlist[i].name)) {
8368                                 setoption(optlist[i].letter, val);
8369                                 return;
8370                         }
8371                 error("Illegal option -o %s", name);
8372         }
8373 }
8374
8375
8376 static void
8377 setoption(flag, val)
8378         char flag;
8379         int val;
8380         {
8381         int i;
8382
8383         for (i = 0; i < NOPTS; i++)
8384                 if (optlist[i].letter == flag) {
8385                         optlist[i].val = val;
8386                         if (val) {
8387                                 /* #%$ hack for ksh semantics */
8388                                 if (flag == 'V')
8389                                         Eflag = 0;
8390                                 else if (flag == 'E')
8391                                         Vflag = 0;
8392                         }
8393                         return;
8394                 }
8395         error("Illegal option -%c", flag);
8396         /* NOTREACHED */
8397 }
8398
8399
8400
8401 #ifdef mkinit
8402 SHELLPROC {
8403         int i;
8404
8405         for (i = 0; i < NOPTS; i++)
8406                 optlist[i].val = 0;
8407         optschanged();
8408
8409 }
8410 #endif
8411
8412
8413 /*
8414  * Set the shell parameters.
8415  */
8416
8417 static void
8418 setparam(argv)
8419         char **argv;
8420         {
8421         char **newparam;
8422         char **ap;
8423         int nparam;
8424
8425         for (nparam = 0 ; argv[nparam] ; nparam++);
8426         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8427         while (*argv) {
8428                 *ap++ = savestr(*argv++);
8429         }
8430         *ap = NULL;
8431         freeparam(&shellparam);
8432         shellparam.malloc = 1;
8433         shellparam.nparam = nparam;
8434         shellparam.p = newparam;
8435         shellparam.optind = 1;
8436         shellparam.optoff = -1;
8437 }
8438
8439
8440 /*
8441  * Free the list of positional parameters.
8442  */
8443
8444 static void
8445 freeparam(param)
8446         volatile struct shparam *param;
8447         {
8448         char **ap;
8449
8450         if (param->malloc) {
8451                 for (ap = param->p ; *ap ; ap++)
8452                         ckfree(*ap);
8453                 ckfree(param->p);
8454         }
8455 }
8456
8457
8458
8459 /*
8460  * The shift builtin command.
8461  */
8462
8463 static int
8464 shiftcmd(argc, argv)
8465         int argc;
8466         char **argv;
8467 {
8468         int n;
8469         char **ap1, **ap2;
8470
8471         n = 1;
8472         if (argc > 1)
8473                 n = number(argv[1]);
8474         if (n > shellparam.nparam)
8475                 error("can't shift that many");
8476         INTOFF;
8477         shellparam.nparam -= n;
8478         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8479                 if (shellparam.malloc)
8480                         ckfree(*ap1);
8481         }
8482         ap2 = shellparam.p;
8483         while ((*ap2++ = *ap1++) != NULL);
8484         shellparam.optind = 1;
8485         shellparam.optoff = -1;
8486         INTON;
8487         return 0;
8488 }
8489
8490
8491
8492 /*
8493  * The set command builtin.
8494  */
8495
8496 static int
8497 setcmd(argc, argv)
8498         int argc;
8499         char **argv;
8500 {
8501         if (argc == 1)
8502                 return showvarscmd(argc, argv);
8503         INTOFF;
8504         options(0);
8505         optschanged();
8506         if (*argptr != NULL) {
8507                 setparam(argptr);
8508         }
8509         INTON;
8510         return 0;
8511 }
8512
8513
8514 static void
8515 getoptsreset(value)
8516         const char *value;
8517 {
8518         shellparam.optind = number(value);
8519         shellparam.optoff = -1;
8520 }
8521
8522 #ifdef ASH_GETOPTS
8523 /*
8524  * The getopts builtin.  Shellparam.optnext points to the next argument
8525  * to be processed.  Shellparam.optptr points to the next character to
8526  * be processed in the current argument.  If shellparam.optnext is NULL,
8527  * then it's the first time getopts has been called.
8528  */
8529
8530 static int
8531 getoptscmd(argc, argv)
8532         int argc;
8533         char **argv;
8534 {
8535         char **optbase;
8536
8537         if (argc < 3)
8538                 error("Usage: getopts optstring var [arg]");
8539         else if (argc == 3) {
8540                 optbase = shellparam.p;
8541                 if (shellparam.optind > shellparam.nparam + 1) {
8542                         shellparam.optind = 1;
8543                         shellparam.optoff = -1;
8544                 }
8545         }
8546         else {
8547                 optbase = &argv[3];
8548                 if (shellparam.optind > argc - 2) {
8549                         shellparam.optind = 1;
8550                         shellparam.optoff = -1;
8551                 }
8552         }
8553
8554         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
8555                        &shellparam.optoff);
8556 }
8557
8558 /*
8559  * Safe version of setvar, returns 1 on success 0 on failure.
8560  */
8561
8562 static int
8563 setvarsafe(name, val, flags)
8564         const char *name, *val;
8565         int flags;
8566 {
8567         struct jmploc jmploc;
8568         struct jmploc *volatile savehandler = handler;
8569         int err = 0;
8570 #ifdef __GNUC__
8571         (void) &err;
8572 #endif
8573
8574         if (setjmp(jmploc.loc))
8575                 err = 1;
8576         else {
8577                 handler = &jmploc;
8578                 setvar(name, val, flags);
8579         }
8580         handler = savehandler;
8581         return err;
8582 }
8583
8584 static int
8585 getopts(optstr, optvar, optfirst, myoptind, optoff)
8586         char *optstr;
8587         char *optvar;
8588         char **optfirst;
8589         int *myoptind;
8590         int *optoff;
8591 {
8592         char *p, *q;
8593         char c = '?';
8594         int done = 0;
8595         int err = 0;
8596         char s[10];
8597         char **optnext = optfirst + *myoptind - 1;
8598
8599         if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8600             strlen(*(optnext - 1)) < *optoff)
8601                 p = NULL;
8602         else
8603                 p = *(optnext - 1) + *optoff;
8604         if (p == NULL || *p == '\0') {
8605                 /* Current word is done, advance */
8606                 if (optnext == NULL)
8607                         return 1;
8608                 p = *optnext;
8609                 if (p == NULL || *p != '-' || *++p == '\0') {
8610 atend:
8611                         *myoptind = optnext - optfirst + 1;
8612                         p = NULL;
8613                         done = 1;
8614                         goto out;
8615                 }
8616                 optnext++;
8617                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
8618                         goto atend;
8619         }
8620
8621         c = *p++;
8622         for (q = optstr; *q != c; ) {
8623                 if (*q == '\0') {
8624                         if (optstr[0] == ':') {
8625                                 s[0] = c;
8626                                 s[1] = '\0';
8627                                 err |= setvarsafe("OPTARG", s, 0);
8628                         }
8629                         else {
8630                                 outfmt(&errout, "Illegal option -%c\n", c);
8631                                 (void) unsetvar("OPTARG");
8632                         }
8633                         c = '?';
8634                         goto bad;
8635                 }
8636                 if (*++q == ':')
8637                         q++;
8638         }
8639
8640         if (*++q == ':') {
8641                 if (*p == '\0' && (p = *optnext) == NULL) {
8642                         if (optstr[0] == ':') {
8643                                 s[0] = c;
8644                                 s[1] = '\0';
8645                                 err |= setvarsafe("OPTARG", s, 0);
8646                                 c = ':';
8647                         }
8648                         else {
8649                                 outfmt(&errout, "No arg for -%c option\n", c);
8650                                 (void) unsetvar("OPTARG");
8651                                 c = '?';
8652                         }
8653                         goto bad;
8654                 }
8655
8656                 if (p == *optnext)
8657                         optnext++;
8658                 setvarsafe("OPTARG", p, 0);
8659                 p = NULL;
8660         }
8661         else
8662                 setvarsafe("OPTARG", "", 0);
8663         *myoptind = optnext - optfirst + 1;
8664         goto out;
8665
8666 bad:
8667         *myoptind = 1;
8668         p = NULL;
8669 out:
8670         *optoff = p ? p - *(optnext - 1) : -1;
8671         fmtstr(s, sizeof(s), "%d", *myoptind);
8672         err |= setvarsafe("OPTIND", s, VNOFUNC);
8673         s[0] = c;
8674         s[1] = '\0';
8675         err |= setvarsafe(optvar, s, 0);
8676         if (err) {
8677                 *myoptind = 1;
8678                 *optoff = -1;
8679                 flushall();
8680                 exraise(EXERROR);
8681         }
8682         return done;
8683 }
8684 #endif  
8685
8686 /*
8687  * XXX - should get rid of.  have all builtins use getopt(3).  the
8688  * library getopt must have the BSD extension static variable "optreset"
8689  * otherwise it can't be used within the shell safely.
8690  *
8691  * Standard option processing (a la getopt) for builtin routines.  The
8692  * only argument that is passed to nextopt is the option string; the
8693  * other arguments are unnecessary.  It return the character, or '\0' on
8694  * end of input.
8695  */
8696
8697 static int
8698 nextopt(optstring)
8699         const char *optstring;
8700         {
8701         char *p;
8702         const char *q;
8703         char c;
8704
8705         if ((p = optptr) == NULL || *p == '\0') {
8706                 p = *argptr;
8707                 if (p == NULL || *p != '-' || *++p == '\0')
8708                         return '\0';
8709                 argptr++;
8710                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
8711                         return '\0';
8712         }
8713         c = *p++;
8714         for (q = optstring ; *q != c ; ) {
8715                 if (*q == '\0')
8716                         error("Illegal option -%c", c);
8717                 if (*++q == ':')
8718                         q++;
8719         }
8720         if (*++q == ':') {
8721                 if (*p == '\0' && (p = *argptr++) == NULL)
8722                         error("No arg for -%c option", c);
8723                 optionarg = p;
8724                 p = NULL;
8725         }
8726         optptr = p;
8727         return c;
8728 }
8729
8730
8731 /*      $NetBSD: output.c,v 1.23 2001/01/07 23:39:07 lukem Exp $        */
8732
8733 /*
8734  * Shell output routines.  We use our own output routines because:
8735  *      When a builtin command is interrupted we have to discard
8736  *              any pending output.
8737  *      When a builtin command appears in back quotes, we want to
8738  *              save the output of the command in a region obtained
8739  *              via malloc, rather than doing a fork and reading the
8740  *              output of the command via a pipe.
8741  *      Our output routines may be smaller than the stdio routines.
8742  */
8743
8744
8745 #define OUTBUFSIZ BUFSIZ
8746 #define MEM_OUT -3              /* output to dynamically allocated memory */
8747
8748
8749 #ifdef USE_GLIBC_STDIO
8750 struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
8751 struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
8752 struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
8753 #else
8754 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
8755 struct output errout = {NULL, 0, NULL, 0, 2, 0};
8756 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
8757 #endif
8758 struct output *out1 = &output;
8759 struct output *out2 = &errout;
8760
8761
8762 #ifndef USE_GLIBC_STDIO
8763 static void __outstr __P((const char *, size_t, struct output*));
8764 #endif
8765
8766
8767 #ifdef mkinit
8768
8769 INCLUDE "output.h"
8770 INCLUDE "memalloc.h"
8771
8772 INIT {
8773 #ifdef USE_GLIBC_STDIO
8774         initstreams();
8775 #endif
8776 }
8777
8778 RESET {
8779         out1 = &output;
8780         out2 = &errout;
8781 #ifdef USE_GLIBC_STDIO
8782         if (memout.stream != NULL)
8783                 __closememout();
8784 #endif
8785         if (memout.buf != NULL) {
8786                 ckfree(memout.buf);
8787                 memout.buf = NULL;
8788         }
8789 }
8790
8791 #endif
8792
8793
8794 #ifndef USE_GLIBC_STDIO
8795 static void
8796 __outstr(const char *p, size_t len, struct output *dest) {
8797         if (!dest->bufsize) {
8798                 dest->nleft = 0;
8799         } else if (dest->buf == NULL) {
8800                 if (len > dest->bufsize && dest->fd == MEM_OUT) {
8801                         dest->bufsize = len;
8802                 }
8803                 INTOFF;
8804                 dest->buf = ckmalloc(dest->bufsize);
8805                 dest->nextc = dest->buf;
8806                 dest->nleft = dest->bufsize;
8807                 INTON;
8808         } else if (dest->fd == MEM_OUT) {
8809                 int offset;
8810
8811                 offset = dest->bufsize;
8812                 INTOFF;
8813                 if (dest->bufsize >= len) {
8814                         dest->bufsize <<= 1;
8815                 } else {
8816                         dest->bufsize += len;
8817                 }
8818                 dest->buf = ckrealloc(dest->buf, dest->bufsize);
8819                 dest->nleft = dest->bufsize - offset;
8820                 dest->nextc = dest->buf + offset;
8821                 INTON;
8822         } else {
8823                 flushout(dest);
8824         }
8825
8826         if (len < dest->nleft) {
8827                 dest->nleft -= len;
8828                 memcpy(dest->nextc, p, len);
8829                 dest->nextc += len;
8830                 return;
8831         }
8832
8833         if (xwrite(dest->fd, p, len) < len)
8834                 dest->flags |= OUTPUT_ERR;
8835 }
8836 #endif
8837
8838
8839 static void
8840 outstr(p, file)
8841         const char *p;
8842         struct output *file;
8843         {
8844 #ifdef USE_GLIBC_STDIO
8845         INTOFF;
8846         fputs(p, file->stream);
8847         INTON;
8848 #else
8849         size_t len;
8850
8851         if (!*p) {
8852                 return;
8853         }
8854         len = strlen(p);
8855         if ((file->nleft -= len) > 0) {
8856                 memcpy(file->nextc, p, len);
8857                 file->nextc += len;
8858                 return;
8859         }
8860         __outstr(p, len, file);
8861 #endif
8862 }
8863
8864
8865 #ifndef USE_GLIBC_STDIO
8866
8867
8868 static void
8869 outcslow(c, dest)
8870         char c;
8871         struct output *dest;
8872         {
8873         __outstr(&c, 1, dest);
8874 }
8875 #endif
8876
8877
8878 static void
8879 flushall() {
8880         flushout(&output);
8881 #ifdef FLUSHERR
8882         flushout(&errout);
8883 #endif
8884 }
8885
8886
8887 static void
8888 flushout(dest)
8889         struct output *dest;
8890         {
8891 #ifdef USE_GLIBC_STDIO
8892         INTOFF;
8893         fflush(dest->stream);
8894         INTON;
8895 #else
8896         size_t len;
8897
8898         len = dest->nextc - dest->buf;
8899         if (dest->buf == NULL || !len || dest->fd < 0)
8900                 return;
8901         dest->nextc = dest->buf;
8902         dest->nleft = dest->bufsize;
8903         if (xwrite(dest->fd, dest->buf, len) < len)
8904                 dest->flags |= OUTPUT_ERR;
8905 #endif
8906 }
8907
8908
8909 static void
8910 freestdout() {
8911         if (output.buf) {
8912                 INTOFF;
8913                 ckfree(output.buf);
8914                 output.buf = NULL;
8915                 output.nleft = 0;
8916                 INTON;
8917         }
8918         output.flags = 0;
8919 }
8920
8921
8922 static void
8923 #ifdef __STDC__
8924 outfmt(struct output *file, const char *fmt, ...)
8925 #else
8926 static void
8927 outfmt(va_alist)
8928         va_dcl
8929 #endif
8930 {
8931         va_list ap;
8932 #ifndef __STDC__
8933         struct output *file;
8934         const char *fmt;
8935
8936         va_start(ap);
8937         file = va_arg(ap, struct output *);
8938         fmt = va_arg(ap, const char *);
8939 #else
8940         va_start(ap, fmt);
8941 #endif
8942         doformat(file, fmt, ap);
8943         va_end(ap);
8944 }
8945
8946
8947 static void
8948 #ifdef __STDC__
8949 out1fmt(const char *fmt, ...)
8950 #else
8951 out1fmt(va_alist)
8952         va_dcl
8953 #endif
8954 {
8955         va_list ap;
8956 #ifndef __STDC__
8957         const char *fmt;
8958
8959         va_start(ap);
8960         fmt = va_arg(ap, const char *);
8961 #else
8962         va_start(ap, fmt);
8963 #endif
8964         doformat(out1, fmt, ap);
8965         va_end(ap);
8966 }
8967
8968 static void
8969 #ifdef __STDC__
8970 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
8971 #else
8972 fmtstr(va_alist)
8973         va_dcl
8974 #endif
8975 {
8976         va_list ap;
8977 #ifndef __STDC__
8978         char *outbuf;
8979         size_t length;
8980         const char *fmt;
8981
8982         va_start(ap);
8983         outbuf = va_arg(ap, char *);
8984         length = va_arg(ap, size_t);
8985         fmt = va_arg(ap, const char *);
8986 #else
8987         va_start(ap, fmt);
8988 #endif
8989         INTOFF;
8990         vsnprintf(outbuf, length, fmt, ap);
8991         INTON;
8992 }
8993
8994 #ifndef USE_GLIBC_STDIO
8995 /*
8996  * Formatted output.  This routine handles a subset of the printf formats:
8997  * - Formats supported: d, u, o, p, X, s, and c.
8998  * - The x format is also accepted but is treated like X.
8999  * - The l, ll and q modifiers are accepted.
9000  * - The - and # flags are accepted; # only works with the o format.
9001  * - Width and precision may be specified with any format except c.
9002  * - An * may be given for the width or precision.
9003  * - The obsolete practice of preceding the width with a zero to get
9004  *   zero padding is not supported; use the precision field.
9005  * - A % may be printed by writing %% in the format string.
9006  */
9007
9008 #define TEMPSIZE 24
9009
9010 #ifdef BSD4_4
9011 #define HAVE_VASPRINTF 1
9012 #endif
9013
9014 #if     !HAVE_VASPRINTF
9015 static const char digit[] = "0123456789ABCDEF";
9016 #endif
9017
9018
9019 static void
9020 doformat(dest, f, ap)
9021         struct output *dest;
9022         const char *f;          /* format string */
9023         va_list ap;
9024 {
9025 #if     HAVE_VASPRINTF
9026         char *s, *t;
9027         int len;
9028
9029         INTOFF;
9030         len = vasprintf(&t, f, ap);
9031         if (len < 0) {
9032                 return;
9033         }
9034         s = stalloc(++len);
9035         memcpy(s, t, len);
9036         free(t);
9037         INTON;
9038         outstr(s, dest);
9039         stunalloc(s);
9040 #else   /* !HAVE_VASPRINTF */
9041         char c;
9042         char temp[TEMPSIZE];
9043         int flushleft;
9044         int sharp;
9045         int width;
9046         int prec;
9047         int islong;
9048         int isquad;
9049         char *p;
9050         int sign;
9051 #ifdef BSD4_4
9052         quad_t l;
9053         u_quad_t num;
9054 #else
9055         long l;
9056         u_long num;
9057 #endif
9058         unsigned base;
9059         int len;
9060         int size;
9061         int pad;
9062
9063         while ((c = *f++) != '\0') {
9064                 if (c != '%') {
9065                         outc(c, dest);
9066                         continue;
9067                 }
9068                 flushleft = 0;
9069                 sharp = 0;
9070                 width = 0;
9071                 prec = -1;
9072                 islong = 0;
9073                 isquad = 0;
9074                 for (;;) {
9075                         if (*f == '-')
9076                                 flushleft++;
9077                         else if (*f == '#')
9078                                 sharp++;
9079                         else
9080                                 break;
9081                         f++;
9082                 }
9083                 if (*f == '*') {
9084                         width = va_arg(ap, int);
9085                         f++;
9086                 } else {
9087                         while (is_digit(*f)) {
9088                                 width = 10 * width + digit_val(*f++);
9089                         }
9090                 }
9091                 if (*f == '.') {
9092                         if (*++f == '*') {
9093                                 prec = va_arg(ap, int);
9094                                 f++;
9095                         } else {
9096                                 prec = 0;
9097                                 while (is_digit(*f)) {
9098                                         prec = 10 * prec + digit_val(*f++);
9099                                 }
9100                         }
9101                 }
9102                 if (*f == 'l') {
9103                         f++;
9104                         if (*f == 'l') {
9105                                 isquad++;
9106                                 f++;
9107                         } else
9108                                 islong++;
9109                 } else if (*f == 'q') {
9110                         isquad++;
9111                         f++;
9112                 }
9113                 switch (*f) {
9114                 case 'd':
9115 #ifdef BSD4_4
9116                         if (isquad)
9117                                 l = va_arg(ap, quad_t);
9118                         else
9119 #endif
9120                         if (islong)
9121                                 l = va_arg(ap, long);
9122                         else
9123                                 l = va_arg(ap, int);
9124                         sign = 0;
9125                         num = l;
9126                         if (l < 0) {
9127                                 num = -l;
9128                                 sign = 1;
9129                         }
9130                         base = 10;
9131                         goto number;
9132                 case 'u':
9133                         base = 10;
9134                         goto uns_number;
9135                 case 'o':
9136                         base = 8;
9137                         goto uns_number;
9138                 case 'p':
9139                         outc('0', dest);
9140                         outc('x', dest);
9141                         /*FALLTHROUGH*/
9142                 case 'x':
9143                         /* we don't implement 'x'; treat like 'X' */
9144                 case 'X':
9145                         base = 16;
9146 uns_number:       /* an unsigned number */
9147                         sign = 0;
9148 #ifdef BSD4_4
9149                         if (isquad)
9150                                 num = va_arg(ap, u_quad_t);
9151                         else
9152 #endif
9153                         if (islong)
9154                                 num = va_arg(ap, unsigned long);
9155                         else
9156                                 num = va_arg(ap, unsigned int);
9157 number:           /* process a number */
9158                         p = temp + TEMPSIZE - 1;
9159                         *p = '\0';
9160                         while (num) {
9161                                 *--p = digit[num % base];
9162                                 num /= base;
9163                         }
9164                         len = (temp + TEMPSIZE - 1) - p;
9165                         if (prec < 0)
9166                                 prec = 1;
9167                         if (sharp && *f == 'o' && prec <= len)
9168                                 prec = len + 1;
9169                         pad = 0;
9170                         if (width) {
9171                                 size = len;
9172                                 if (size < prec)
9173                                         size = prec;
9174                                 size += sign;
9175                                 pad = width - size;
9176                                 if (flushleft == 0) {
9177                                         while (--pad >= 0)
9178                                                 outc(' ', dest);
9179                                 }
9180                         }
9181                         if (sign)
9182                                 outc('-', dest);
9183                         prec -= len;
9184                         while (--prec >= 0)
9185                                 outc('0', dest);
9186                         while (*p)
9187                                 outc(*p++, dest);
9188                         while (--pad >= 0)
9189                                 outc(' ', dest);
9190                         break;
9191                 case 's':
9192                         p = va_arg(ap, char *);
9193                         pad = 0;
9194                         if (width) {
9195                                 len = strlen(p);
9196                                 if (prec >= 0 && len > prec)
9197                                         len = prec;
9198                                 pad = width - len;
9199                                 if (flushleft == 0) {
9200                                         while (--pad >= 0)
9201                                                 outc(' ', dest);
9202                                 }
9203                         }
9204                         prec++;
9205                         while (--prec != 0 && *p)
9206                                 outc(*p++, dest);
9207                         while (--pad >= 0)
9208                                 outc(' ', dest);
9209                         break;
9210                 case 'c':
9211                         c = va_arg(ap, int);
9212                         outc(c, dest);
9213                         break;
9214                 default:
9215                         outc(*f, dest);
9216                         break;
9217                 }
9218                 f++;
9219         }
9220 #endif  /* !HAVE_VASPRINTF */
9221 }
9222 #endif
9223
9224
9225
9226 /*
9227  * Version of write which resumes after a signal is caught.
9228  */
9229
9230 static int
9231 xwrite(fd, buf, nbytes)
9232         int fd;
9233         const char *buf;
9234         int nbytes;
9235         {
9236         int ntry;
9237         int i;
9238         int n;
9239
9240         n = nbytes;
9241         ntry = 0;
9242         for (;;) {
9243                 i = write(fd, buf, n);
9244                 if (i > 0) {
9245                         if ((n -= i) <= 0)
9246                                 return nbytes;
9247                         buf += i;
9248                         ntry = 0;
9249                 } else if (i == 0) {
9250                         if (++ntry > 10)
9251                                 return nbytes - n;
9252                 } else if (errno != EINTR) {
9253                         return -1;
9254                 }
9255         }
9256 }
9257
9258
9259 #ifdef notdef
9260 /*
9261  * Version of ioctl that retries after a signal is caught.
9262  * XXX unused function
9263  */
9264
9265 static int
9266 xioctl(fd, request, arg)
9267         int fd;
9268         unsigned long request;
9269         char * arg;
9270 {
9271         int i;
9272
9273         while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
9274         return i;
9275 }
9276 #endif
9277
9278
9279 #ifdef USE_GLIBC_STDIO
9280 static void initstreams() {
9281         output.stream = stdout;
9282         errout.stream = stderr;
9283 }
9284
9285
9286 static void
9287 openmemout() {
9288         INTOFF;
9289         memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9290         INTON;
9291 }
9292
9293
9294 static int
9295 __closememout() {
9296         int error;
9297         error = fclose(memout.stream);
9298         memout.stream = NULL;
9299         return error;
9300 }
9301 #endif
9302 /*      $NetBSD: parser.c,v 1.46 2001/02/04 19:52:06 christos Exp $     */
9303
9304 /*
9305  * Shell command parser.
9306  */
9307
9308 #define EOFMARKLEN 79
9309
9310
9311
9312 struct heredoc {
9313         struct heredoc *next;   /* next here document in list */
9314         union node *here;               /* redirection node */
9315         char *eofmark;          /* string indicating end of input */
9316         int striptabs;          /* if set, strip leading tabs */
9317 };
9318
9319
9320
9321 struct heredoc *heredoclist;    /* list of here documents to read */
9322 static int parsebackquote;              /* nonzero if we are inside backquotes */
9323 static int doprompt;                    /* if set, prompt the user */
9324 static int needprompt;                  /* true if interactive and at start of line */
9325 static int lasttoken;                   /* last token read */
9326 static int tokpushback;         /* last token pushed back */
9327 static char *wordtext;                  /* text of last word returned by readtoken */
9328 static int checkkwd;            /* 1 == check for kwds, 2 == also eat newlines */
9329 /* 1 == check for aliases, 2 == also check for assignments */
9330 static int checkalias;
9331 struct nodelist *backquotelist;
9332 union node *redirnode;
9333 struct heredoc *heredoc;
9334 static int quoteflag;                   /* set if (part of) last token was quoted */
9335 static int startlinno;                  /* line # where last token started */
9336
9337
9338 static union node *list __P((int));
9339 static union node *andor __P((void));
9340 static union node *pipeline __P((void));
9341 static union node *command __P((void));
9342 static union node *simplecmd __P((void));
9343 static union node *makename __P((void));
9344 static void parsefname __P((void));
9345 static void parseheredoc __P((void));
9346 static int peektoken __P((void));
9347 static int readtoken __P((void));
9348 static int xxreadtoken __P((void));
9349 static int readtoken1 __P((int, char const *, char *, int));
9350 static int noexpand __P((char *));
9351 static void synexpect __P((int)) __attribute__((noreturn));
9352 static void synerror __P((const char *)) __attribute__((noreturn));
9353 static void setprompt __P((int));
9354
9355
9356 /*
9357  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9358  * valid parse tree indicating a blank line.)
9359  */
9360
9361 union node *
9362 parsecmd(int interact)
9363 {
9364         int t;
9365
9366         tokpushback = 0;
9367         doprompt = interact;
9368         if (doprompt)
9369                 setprompt(1);
9370         else
9371                 setprompt(0);
9372         needprompt = 0;
9373         t = readtoken();
9374         if (t == TEOF)
9375                 return NEOF;
9376         if (t == TNL)
9377                 return NULL;
9378         tokpushback++;
9379         return list(1);
9380 }
9381
9382
9383 static union node *
9384 list(nlflag)
9385         int nlflag;
9386 {
9387         union node *n1, *n2, *n3;
9388         int tok;
9389
9390         checkkwd = 2;
9391         if (nlflag == 0 && tokendlist[peektoken()])
9392                 return NULL;
9393         n1 = NULL;
9394         for (;;) {
9395                 n2 = andor();
9396                 tok = readtoken();
9397                 if (tok == TBACKGND) {
9398                         if (n2->type == NCMD || n2->type == NPIPE) {
9399                                 n2->ncmd.backgnd = 1;
9400                         } else if (n2->type == NREDIR) {
9401                                 n2->type = NBACKGND;
9402                         } else {
9403                                 n3 = (union node *)stalloc(sizeof (struct nredir));
9404                                 n3->type = NBACKGND;
9405                                 n3->nredir.n = n2;
9406                                 n3->nredir.redirect = NULL;
9407                                 n2 = n3;
9408                         }
9409                 }
9410                 if (n1 == NULL) {
9411                         n1 = n2;
9412                 }
9413                 else {
9414                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9415                         n3->type = NSEMI;
9416                         n3->nbinary.ch1 = n1;
9417                         n3->nbinary.ch2 = n2;
9418                         n1 = n3;
9419                 }
9420                 switch (tok) {
9421                 case TBACKGND:
9422                 case TSEMI:
9423                         tok = readtoken();
9424                         /* fall through */
9425                 case TNL:
9426                         if (tok == TNL) {
9427                                 parseheredoc();
9428                                 if (nlflag)
9429                                         return n1;
9430                         } else {
9431                                 tokpushback++;
9432                         }
9433                         checkkwd = 2;
9434                         if (tokendlist[peektoken()])
9435                                 return n1;
9436                         break;
9437                 case TEOF:
9438                         if (heredoclist)
9439                                 parseheredoc();
9440                         else
9441                                 pungetc();              /* push back EOF on input */
9442                         return n1;
9443                 default:
9444                         if (nlflag)
9445                                 synexpect(-1);
9446                         tokpushback++;
9447                         return n1;
9448                 }
9449         }
9450 }
9451
9452
9453
9454 static union node *
9455 andor() {
9456         union node *n1, *n2, *n3;
9457         int t;
9458
9459         checkkwd = 1;
9460         n1 = pipeline();
9461         for (;;) {
9462                 if ((t = readtoken()) == TAND) {
9463                         t = NAND;
9464                 } else if (t == TOR) {
9465                         t = NOR;
9466                 } else {
9467                         tokpushback++;
9468                         return n1;
9469                 }
9470                 checkkwd = 2;
9471                 n2 = pipeline();
9472                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9473                 n3->type = t;
9474                 n3->nbinary.ch1 = n1;
9475                 n3->nbinary.ch2 = n2;
9476                 n1 = n3;
9477         }
9478 }
9479
9480
9481
9482 static union node *
9483 pipeline() {
9484         union node *n1, *n2, *pipenode;
9485         struct nodelist *lp, *prev;
9486         int negate;
9487
9488         negate = 0;
9489         TRACE(("pipeline: entered\n"));
9490         if (readtoken() == TNOT) {
9491                 negate = !negate;
9492                 checkkwd = 1;
9493         } else
9494                 tokpushback++;
9495         n1 = command();
9496         if (readtoken() == TPIPE) {
9497                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9498                 pipenode->type = NPIPE;
9499                 pipenode->npipe.backgnd = 0;
9500                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9501                 pipenode->npipe.cmdlist = lp;
9502                 lp->n = n1;
9503                 do {
9504                         prev = lp;
9505                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9506                         checkkwd = 2;
9507                         lp->n = command();
9508                         prev->next = lp;
9509                 } while (readtoken() == TPIPE);
9510                 lp->next = NULL;
9511                 n1 = pipenode;
9512         }
9513         tokpushback++;
9514         if (negate) {
9515                 n2 = (union node *)stalloc(sizeof (struct nnot));
9516                 n2->type = NNOT;
9517                 n2->nnot.com = n1;
9518                 return n2;
9519         } else
9520                 return n1;
9521 }
9522
9523
9524
9525 static union node *
9526 command() {
9527         union node *n1, *n2;
9528         union node *ap, **app;
9529         union node *cp, **cpp;
9530         union node *redir, **rpp;
9531         int t;
9532
9533         redir = NULL;
9534         n1 = NULL;
9535         rpp = &redir;
9536
9537         switch (readtoken()) {
9538         case TIF:
9539                 n1 = (union node *)stalloc(sizeof (struct nif));
9540                 n1->type = NIF;
9541                 n1->nif.test = list(0);
9542                 if (readtoken() != TTHEN)
9543                         synexpect(TTHEN);
9544                 n1->nif.ifpart = list(0);
9545                 n2 = n1;
9546                 while (readtoken() == TELIF) {
9547                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9548                         n2 = n2->nif.elsepart;
9549                         n2->type = NIF;
9550                         n2->nif.test = list(0);
9551                         if (readtoken() != TTHEN)
9552                                 synexpect(TTHEN);
9553                         n2->nif.ifpart = list(0);
9554                 }
9555                 if (lasttoken == TELSE)
9556                         n2->nif.elsepart = list(0);
9557                 else {
9558                         n2->nif.elsepart = NULL;
9559                         tokpushback++;
9560                 }
9561                 if (readtoken() != TFI)
9562                         synexpect(TFI);
9563                 checkkwd = 1;
9564                 break;
9565         case TWHILE:
9566         case TUNTIL: {
9567                 int got;
9568                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9569                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9570                 n1->nbinary.ch1 = list(0);
9571                 if ((got=readtoken()) != TDO) {
9572 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9573                         synexpect(TDO);
9574                 }
9575                 n1->nbinary.ch2 = list(0);
9576                 if (readtoken() != TDONE)
9577                         synexpect(TDONE);
9578                 checkkwd = 1;
9579                 break;
9580         }
9581         case TFOR:
9582                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9583                         synerror("Bad for loop variable");
9584                 n1 = (union node *)stalloc(sizeof (struct nfor));
9585                 n1->type = NFOR;
9586                 n1->nfor.var = wordtext;
9587                 checkkwd = 1;
9588                 if (readtoken() == TIN) {
9589                         app = &ap;
9590                         while (readtoken() == TWORD) {
9591                                 n2 = (union node *)stalloc(sizeof (struct narg));
9592                                 n2->type = NARG;
9593                                 n2->narg.text = wordtext;
9594                                 n2->narg.backquote = backquotelist;
9595                                 *app = n2;
9596                                 app = &n2->narg.next;
9597                         }
9598                         *app = NULL;
9599                         n1->nfor.args = ap;
9600                         if (lasttoken != TNL && lasttoken != TSEMI)
9601                                 synexpect(-1);
9602                 } else {
9603                         static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9604                                                                    '@', '=', '\0'};
9605                         n2 = (union node *)stalloc(sizeof (struct narg));
9606                         n2->type = NARG;
9607                         n2->narg.text = argvars;
9608                         n2->narg.backquote = NULL;
9609                         n2->narg.next = NULL;
9610                         n1->nfor.args = n2;
9611                         /*
9612                          * Newline or semicolon here is optional (but note
9613                          * that the original Bourne shell only allowed NL).
9614                          */
9615                         if (lasttoken != TNL && lasttoken != TSEMI)
9616                                 tokpushback++;
9617                 }
9618                 checkkwd = 2;
9619                 if (readtoken() != TDO)
9620                         synexpect(TDO);
9621                 n1->nfor.body = list(0);
9622                 if (readtoken() != TDONE)
9623                         synexpect(TDONE);
9624                 checkkwd = 1;
9625                 break;
9626         case TCASE:
9627                 n1 = (union node *)stalloc(sizeof (struct ncase));
9628                 n1->type = NCASE;
9629                 if (readtoken() != TWORD)
9630                         synexpect(TWORD);
9631                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9632                 n2->type = NARG;
9633                 n2->narg.text = wordtext;
9634                 n2->narg.backquote = backquotelist;
9635                 n2->narg.next = NULL;
9636                 do {
9637                         checkkwd = 1;
9638                 } while (readtoken() == TNL);
9639                 if (lasttoken != TIN)
9640                         synerror("expecting \"in\"");
9641                 cpp = &n1->ncase.cases;
9642                 checkkwd = 2, readtoken();
9643                 do {
9644                         if (lasttoken == TLP)
9645                                 readtoken();
9646                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9647                         cp->type = NCLIST;
9648                         app = &cp->nclist.pattern;
9649                         for (;;) {
9650                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9651                                 ap->type = NARG;
9652                                 ap->narg.text = wordtext;
9653                                 ap->narg.backquote = backquotelist;
9654                                 if (checkkwd = 2, readtoken() != TPIPE)
9655                                         break;
9656                                 app = &ap->narg.next;
9657                                 readtoken();
9658                         }
9659                         ap->narg.next = NULL;
9660                         if (lasttoken != TRP)
9661                                 synexpect(TRP);
9662                         cp->nclist.body = list(0);
9663
9664                         checkkwd = 2;
9665                         if ((t = readtoken()) != TESAC) {
9666                                 if (t != TENDCASE)
9667                                         synexpect(TENDCASE);
9668                                 else
9669                                         checkkwd = 2, readtoken();
9670                         }
9671                         cpp = &cp->nclist.next;
9672                 } while(lasttoken != TESAC);
9673                 *cpp = NULL;
9674                 checkkwd = 1;
9675                 break;
9676         case TLP:
9677                 n1 = (union node *)stalloc(sizeof (struct nredir));
9678                 n1->type = NSUBSHELL;
9679                 n1->nredir.n = list(0);
9680                 n1->nredir.redirect = NULL;
9681                 if (readtoken() != TRP)
9682                         synexpect(TRP);
9683                 checkkwd = 1;
9684                 break;
9685         case TBEGIN:
9686                 n1 = list(0);
9687                 if (readtoken() != TEND)
9688                         synexpect(TEND);
9689                 checkkwd = 1;
9690                 break;
9691         /* Handle an empty command like other simple commands.  */
9692         case TSEMI:
9693         case TAND:
9694         case TOR:
9695         case TNL:
9696         case TEOF:
9697         case TRP:
9698         case TBACKGND:
9699                 /*
9700                  * An empty command before a ; doesn't make much sense, and
9701                  * should certainly be disallowed in the case of `if ;'.
9702                  */
9703                 if (!redir)
9704                         synexpect(-1);
9705         case TWORD:
9706         case TREDIR:
9707                 tokpushback++;
9708                 n1 = simplecmd();
9709                 return n1;
9710         default:
9711                 synexpect(-1);
9712                 /* NOTREACHED */
9713         }
9714
9715         /* Now check for redirection which may follow command */
9716         while (readtoken() == TREDIR) {
9717                 *rpp = n2 = redirnode;
9718                 rpp = &n2->nfile.next;
9719                 parsefname();
9720         }
9721         tokpushback++;
9722         *rpp = NULL;
9723         if (redir) {
9724                 if (n1->type != NSUBSHELL) {
9725                         n2 = (union node *)stalloc(sizeof (struct nredir));
9726                         n2->type = NREDIR;
9727                         n2->nredir.n = n1;
9728                         n1 = n2;
9729                 }
9730                 n1->nredir.redirect = redir;
9731         }
9732
9733         return n1;
9734 }
9735
9736
9737 static union node *
9738 simplecmd() {
9739         union node *args, **app;
9740         union node *n = NULL;
9741         union node *vars, **vpp;
9742         union node **rpp, *redir;
9743
9744         args = NULL;
9745         app = &args;
9746         vars = NULL;
9747         vpp = &vars;
9748         redir = NULL;
9749         rpp = &redir;
9750
9751         checkalias = 2;
9752         for (;;) {
9753                 switch (readtoken()) {
9754                 case TWORD:
9755                 case TASSIGN:
9756                         n = (union node *)stalloc(sizeof (struct narg));
9757                         n->type = NARG;
9758                         n->narg.text = wordtext;
9759                         n->narg.backquote = backquotelist;
9760                         if (lasttoken == TWORD) {
9761                                 *app = n;
9762                                 app = &n->narg.next;
9763                         } else {
9764                                 *vpp = n;
9765                                 vpp = &n->narg.next;
9766                         }
9767                         break;
9768                 case TREDIR:
9769                         *rpp = n = redirnode;
9770                         rpp = &n->nfile.next;
9771                         parsefname();   /* read name of redirection file */
9772                         break;
9773                 case TLP:
9774                         if (
9775                                 args && app == &args->narg.next &&
9776                                 !vars && !redir
9777                         ) {
9778                                 /* We have a function */
9779                                 if (readtoken() != TRP)
9780                                         synexpect(TRP);
9781 #ifdef notdef
9782                                 if (! goodname(n->narg.text))
9783                                         synerror("Bad function name");
9784 #endif
9785                                 n->type = NDEFUN;
9786                                 checkkwd = 2;
9787                                 n->narg.next = command();
9788                                 return n;
9789                         }
9790                         /* fall through */
9791                 default:
9792                         tokpushback++;
9793                         goto out;
9794                 }
9795         }
9796 out:
9797         *app = NULL;
9798         *vpp = NULL;
9799         *rpp = NULL;
9800         n = (union node *)stalloc(sizeof (struct ncmd));
9801         n->type = NCMD;
9802         n->ncmd.backgnd = 0;
9803         n->ncmd.args = args;
9804         n->ncmd.assign = vars;
9805         n->ncmd.redirect = redir;
9806         return n;
9807 }
9808
9809 static union node *
9810 makename() {
9811         union node *n;
9812
9813         n = (union node *)stalloc(sizeof (struct narg));
9814         n->type = NARG;
9815         n->narg.next = NULL;
9816         n->narg.text = wordtext;
9817         n->narg.backquote = backquotelist;
9818         return n;
9819 }
9820
9821 static void fixredir(union node *n, const char *text, int err)
9822         {
9823         TRACE(("Fix redir %s %d\n", text, err));
9824         if (!err)
9825                 n->ndup.vname = NULL;
9826
9827         if (is_digit(text[0]) && text[1] == '\0')
9828                 n->ndup.dupfd = digit_val(text[0]);
9829         else if (text[0] == '-' && text[1] == '\0')
9830                 n->ndup.dupfd = -1;
9831         else {
9832
9833                 if (err)
9834                         synerror("Bad fd number");
9835                 else
9836                         n->ndup.vname = makename();
9837         }
9838 }
9839
9840
9841 static void
9842 parsefname() {
9843         union node *n = redirnode;
9844
9845         if (readtoken() != TWORD)
9846                 synexpect(-1);
9847         if (n->type == NHERE) {
9848                 struct heredoc *here = heredoc;
9849                 struct heredoc *p;
9850                 int i;
9851
9852                 if (quoteflag == 0)
9853                         n->type = NXHERE;
9854                 TRACE(("Here document %d\n", n->type));
9855                 if (here->striptabs) {
9856                         while (*wordtext == '\t')
9857                                 wordtext++;
9858                 }
9859                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9860                         synerror("Illegal eof marker for << redirection");
9861                 rmescapes(wordtext);
9862                 here->eofmark = wordtext;
9863                 here->next = NULL;
9864                 if (heredoclist == NULL)
9865                         heredoclist = here;
9866                 else {
9867                         for (p = heredoclist ; p->next ; p = p->next);
9868                         p->next = here;
9869                 }
9870         } else if (n->type == NTOFD || n->type == NFROMFD) {
9871                 fixredir(n, wordtext, 0);
9872         } else {
9873                 n->nfile.fname = makename();
9874         }
9875 }
9876
9877
9878 /*
9879  * Input any here documents.
9880  */
9881
9882 static void
9883 parseheredoc() {
9884         struct heredoc *here;
9885         union node *n;
9886
9887         while (heredoclist) {
9888                 here = heredoclist;
9889                 heredoclist = here->next;
9890                 if (needprompt) {
9891                         setprompt(2);
9892                         needprompt = 0;
9893                 }
9894                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9895                                 here->eofmark, here->striptabs);
9896                 n = (union node *)stalloc(sizeof (struct narg));
9897                 n->narg.type = NARG;
9898                 n->narg.next = NULL;
9899                 n->narg.text = wordtext;
9900                 n->narg.backquote = backquotelist;
9901                 here->here->nhere.doc = n;
9902         }
9903 }
9904
9905 static int
9906 peektoken() {
9907         int t;
9908
9909         t = readtoken();
9910         tokpushback++;
9911         return (t);
9912 }
9913
9914 static int
9915 readtoken() {
9916         int t;
9917         int savecheckkwd = checkkwd;
9918         int savecheckalias = checkalias;
9919         struct alias *ap;
9920 #ifdef DEBUG
9921         int alreadyseen = tokpushback;
9922 #endif
9923
9924 top:
9925         t = xxreadtoken();
9926         checkalias = savecheckalias;
9927
9928         if (checkkwd) {
9929                 /*
9930                  * eat newlines
9931                  */
9932                 if (checkkwd == 2) {
9933                         checkkwd = 0;
9934                         while (t == TNL) {
9935                                 parseheredoc();
9936                                 t = xxreadtoken();
9937                         }
9938                 }
9939                 checkkwd = 0;
9940                 /*
9941                  * check for keywords
9942                  */
9943                 if (t == TWORD && !quoteflag)
9944                 {
9945                         const char *const *pp;
9946
9947                         if ((pp = findkwd(wordtext))) {
9948                                 lasttoken = t = pp - parsekwd + KWDOFFSET;
9949                                 TRACE(("keyword %s recognized\n", tokname[t]));
9950                                 goto out;
9951                         }
9952                 }
9953         }
9954
9955         if (t != TWORD) {
9956                 if (t != TREDIR) {
9957                         checkalias = 0;
9958                 }
9959         } else if (checkalias == 2 && isassignment(wordtext)) {
9960                 lasttoken = t = TASSIGN;
9961         } else if (checkalias) {
9962                 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
9963                         if (*ap->val) {
9964                                 pushstring(ap->val, strlen(ap->val), ap);
9965                         }
9966                         checkkwd = savecheckkwd;
9967                         goto top;
9968                 }
9969                 checkalias = 0;
9970         }
9971 out:
9972 #ifdef DEBUG
9973         if (!alreadyseen)
9974             TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9975         else
9976             TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
9977 #endif
9978         return (t);
9979 }
9980
9981
9982 /*
9983  * Read the next input token.
9984  * If the token is a word, we set backquotelist to the list of cmds in
9985  *      backquotes.  We set quoteflag to true if any part of the word was
9986  *      quoted.
9987  * If the token is TREDIR, then we set redirnode to a structure containing
9988  *      the redirection.
9989  * In all cases, the variable startlinno is set to the number of the line
9990  *      on which the token starts.
9991  *
9992  * [Change comment:  here documents and internal procedures]
9993  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
9994  *  word parsing code into a separate routine.  In this case, readtoken
9995  *  doesn't need to have any internal procedures, but parseword does.
9996  *  We could also make parseoperator in essence the main routine, and
9997  *  have parseword (readtoken1?) handle both words and redirection.]
9998  */
9999
10000 #define RETURN(token)   return lasttoken = token
10001
10002 static int
10003 xxreadtoken() {
10004         int c;
10005
10006         if (tokpushback) {
10007                 tokpushback = 0;
10008                 return lasttoken;
10009         }
10010         if (needprompt) {
10011                 setprompt(2);
10012                 needprompt = 0;
10013         }
10014         startlinno = plinno;
10015         for (;;) {      /* until token or start of word found */
10016                 c = pgetc_macro();
10017                 switch (c) {
10018                 case ' ': case '\t':
10019                 case PEOA:
10020                         continue;
10021                 case '#':
10022                         while ((c = pgetc()) != '\n' && c != PEOF);
10023                         pungetc();
10024                         continue;
10025                 case '\\':
10026                         if (pgetc() == '\n') {
10027                                 startlinno = ++plinno;
10028                                 if (doprompt)
10029                                         setprompt(2);
10030                                 else
10031                                         setprompt(0);
10032                                 continue;
10033                         }
10034                         pungetc();
10035                         goto breakloop;
10036                 case '\n':
10037                         plinno++;
10038                         needprompt = doprompt;
10039                         RETURN(TNL);
10040                 case PEOF:
10041                         RETURN(TEOF);
10042                 case '&':
10043                         if (pgetc() == '&')
10044                                 RETURN(TAND);
10045                         pungetc();
10046                         RETURN(TBACKGND);
10047                 case '|':
10048                         if (pgetc() == '|')
10049                                 RETURN(TOR);
10050                         pungetc();
10051                         RETURN(TPIPE);
10052                 case ';':
10053                         if (pgetc() == ';')
10054                                 RETURN(TENDCASE);
10055                         pungetc();
10056                         RETURN(TSEMI);
10057                 case '(':
10058                         RETURN(TLP);
10059                 case ')':
10060                         RETURN(TRP);
10061                 default:
10062                         goto breakloop;
10063                 }
10064         }
10065 breakloop:
10066         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10067 #undef RETURN
10068 }
10069
10070
10071
10072 /*
10073  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10074  * is not NULL, read a here document.  In the latter case, eofmark is the
10075  * word which marks the end of the document and striptabs is true if
10076  * leading tabs should be stripped from the document.  The argument firstc
10077  * is the first character of the input token or document.
10078  *
10079  * Because C does not have internal subroutines, I have simulated them
10080  * using goto's to implement the subroutine linkage.  The following macros
10081  * will run code that appears at the end of readtoken1.
10082  */
10083
10084 #define CHECKEND()      {goto checkend; checkend_return:;}
10085 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10086 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10087 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10088 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10089 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10090
10091 static int
10092 readtoken1(firstc, syntax, eofmark, striptabs)
10093         int firstc;
10094         char const *syntax;
10095         char *eofmark;
10096         int striptabs;
10097         {
10098         int c = firstc;
10099         char *out;
10100         int len;
10101         char line[EOFMARKLEN + 1];
10102         struct nodelist *bqlist;
10103         int quotef;
10104         int dblquote;
10105         int varnest;    /* levels of variables expansion */
10106         int arinest;    /* levels of arithmetic expansion */
10107         int parenlevel; /* levels of parens in arithmetic */
10108         int dqvarnest;  /* levels of variables expansion within double quotes */
10109         int oldstyle;
10110         char const *prevsyntax; /* syntax before arithmetic */
10111 #if __GNUC__
10112         /* Avoid longjmp clobbering */
10113         (void) &out;
10114         (void) &quotef;
10115         (void) &dblquote;
10116         (void) &varnest;
10117         (void) &arinest;
10118         (void) &parenlevel;
10119         (void) &dqvarnest;
10120         (void) &oldstyle;
10121         (void) &prevsyntax;
10122         (void) &syntax;
10123 #endif
10124
10125         startlinno = plinno;
10126         dblquote = 0;
10127         if (syntax == DQSYNTAX)
10128                 dblquote = 1;
10129         quotef = 0;
10130         bqlist = NULL;
10131         varnest = 0;
10132         arinest = 0;
10133         parenlevel = 0;
10134         dqvarnest = 0;
10135
10136         STARTSTACKSTR(out);
10137         loop: { /* for each line, until end of word */
10138 #if ATTY
10139                 if (c == '\034' && doprompt
10140                  && attyset() && ! equal(termval(), "emacs")) {
10141                         attyline();
10142                         if (syntax == BASESYNTAX)
10143                                 return readtoken();
10144                         c = pgetc();
10145                         goto loop;
10146                 }
10147 #endif
10148                 CHECKEND();     /* set c to PEOF if at end of here document */
10149                 for (;;) {      /* until end of line or end of word */
10150                         CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
10151                         switch(syntax[c]) {
10152                         case CNL:       /* '\n' */
10153                                 if (syntax == BASESYNTAX)
10154                                         goto endword;   /* exit outer loop */
10155                                 USTPUTC(c, out);
10156                                 plinno++;
10157                                 if (doprompt)
10158                                         setprompt(2);
10159                                 else
10160                                         setprompt(0);
10161                                 c = pgetc();
10162                                 goto loop;              /* continue outer loop */
10163                         case CWORD:
10164                                 USTPUTC(c, out);
10165                                 break;
10166                         case CCTL:
10167                                 if ((eofmark == NULL || dblquote) &&
10168                                     dqvarnest == 0)
10169                                         USTPUTC(CTLESC, out);
10170                                 USTPUTC(c, out);
10171                                 break;
10172                         case CBACK:     /* backslash */
10173                                 c = pgetc2();
10174                                 if (c == PEOF) {
10175                                         USTPUTC('\\', out);
10176                                         pungetc();
10177                                 } else if (c == '\n') {
10178                                         if (doprompt)
10179                                                 setprompt(2);
10180                                         else
10181                                                 setprompt(0);
10182                                 } else {
10183                                         if (dblquote && c != '\\' && c != '`' && c != '$'
10184                                                          && (c != '"' || eofmark != NULL))
10185                                                 USTPUTC('\\', out);
10186                                         if (SQSYNTAX[c] == CCTL)
10187                                                 USTPUTC(CTLESC, out);
10188                                         else if (eofmark == NULL)
10189                                                 USTPUTC(CTLQUOTEMARK, out);
10190                                         USTPUTC(c, out);
10191                                         quotef++;
10192                                 }
10193                                 break;
10194                         case CSQUOTE:
10195                                 if (eofmark == NULL)
10196                                         USTPUTC(CTLQUOTEMARK, out);
10197                                 syntax = SQSYNTAX;
10198                                 break;
10199                         case CDQUOTE:
10200                                 if (eofmark == NULL)
10201                                         USTPUTC(CTLQUOTEMARK, out);
10202                                 syntax = DQSYNTAX;
10203                                 dblquote = 1;
10204                                 break;
10205                         case CENDQUOTE:
10206                                 if (eofmark != NULL && arinest == 0 &&
10207                                     varnest == 0) {
10208                                         USTPUTC(c, out);
10209                                 } else {
10210                                         if (arinest) {
10211                                                 syntax = ARISYNTAX;
10212                                                 dblquote = 0;
10213                                         } else if (eofmark == NULL &&
10214                                                    dqvarnest == 0) {
10215                                                 syntax = BASESYNTAX;
10216                                                 dblquote = 0;
10217                                         }
10218                                         quotef++;
10219                                 }
10220                                 break;
10221                         case CVAR:      /* '$' */
10222                                 PARSESUB();             /* parse substitution */
10223                                 break;
10224                         case CENDVAR:   /* '}' */
10225                                 if (varnest > 0) {
10226                                         varnest--;
10227                                         if (dqvarnest > 0) {
10228                                                 dqvarnest--;
10229                                         }
10230                                         USTPUTC(CTLENDVAR, out);
10231                                 } else {
10232                                         USTPUTC(c, out);
10233                                 }
10234                                 break;
10235 #ifdef ASH_MATH_SUPPORT
10236                         case CLP:       /* '(' in arithmetic */
10237                                 parenlevel++;
10238                                 USTPUTC(c, out);
10239                                 break;
10240                         case CRP:       /* ')' in arithmetic */
10241                                 if (parenlevel > 0) {
10242                                         USTPUTC(c, out);
10243                                         --parenlevel;
10244                                 } else {
10245                                         if (pgetc() == ')') {
10246                                                 if (--arinest == 0) {
10247                                                         USTPUTC(CTLENDARI, out);
10248                                                         syntax = prevsyntax;
10249                                                         if (syntax == DQSYNTAX)
10250                                                                 dblquote = 1;
10251                                                         else
10252                                                                 dblquote = 0;
10253                                                 } else
10254                                                         USTPUTC(')', out);
10255                                         } else {
10256                                                 /*
10257                                                  * unbalanced parens
10258                                                  *  (don't 2nd guess - no error)
10259                                                  */
10260                                                 pungetc();
10261                                                 USTPUTC(')', out);
10262                                         }
10263                                 }
10264                                 break;
10265 #endif
10266                         case CBQUOTE:   /* '`' */
10267                                 PARSEBACKQOLD();
10268                                 break;
10269                         case CEOF:
10270                                 goto endword;           /* exit outer loop */
10271                         case CIGN:
10272                                 break;
10273                         default:
10274                                 if (varnest == 0)
10275                                         goto endword;   /* exit outer loop */
10276                                 if (c != PEOA) {
10277                                         USTPUTC(c, out);
10278                                 }
10279                         }
10280                         c = pgetc_macro();
10281                 }
10282         }
10283 endword:
10284         if (syntax == ARISYNTAX)
10285                 synerror("Missing '))'");
10286         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10287                 synerror("Unterminated quoted string");
10288         if (varnest != 0) {
10289                 startlinno = plinno;
10290                 synerror("Missing '}'");
10291         }
10292         USTPUTC('\0', out);
10293         len = out - stackblock();
10294         out = stackblock();
10295         if (eofmark == NULL) {
10296                 if ((c == '>' || c == '<')
10297                  && quotef == 0
10298                  && len <= 2
10299                  && (*out == '\0' || is_digit(*out))) {
10300                         PARSEREDIR();
10301                         return lasttoken = TREDIR;
10302                 } else {
10303                         pungetc();
10304                 }
10305         }
10306         quoteflag = quotef;
10307         backquotelist = bqlist;
10308         grabstackblock(len);
10309         wordtext = out;
10310         return lasttoken = TWORD;
10311 /* end of readtoken routine */
10312
10313
10314
10315 /*
10316  * Check to see whether we are at the end of the here document.  When this
10317  * is called, c is set to the first character of the next input line.  If
10318  * we are at the end of the here document, this routine sets the c to PEOF.
10319  */
10320
10321 checkend: {
10322         if (eofmark) {
10323                 if (c == PEOA) {
10324                         c = pgetc2();
10325                 }
10326                 if (striptabs) {
10327                         while (c == '\t') {
10328                                 c = pgetc2();
10329                         }
10330                 }
10331                 if (c == *eofmark) {
10332                         if (pfgets(line, sizeof line) != NULL) {
10333                                 char *p, *q;
10334
10335                                 p = line;
10336                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10337                                 if (*p == '\n' && *q == '\0') {
10338                                         c = PEOF;
10339                                         plinno++;
10340                                         needprompt = doprompt;
10341                                 } else {
10342                                         pushstring(line, strlen(line), NULL);
10343                                 }
10344                         }
10345                 }
10346         }
10347         goto checkend_return;
10348 }
10349
10350
10351 /*
10352  * Parse a redirection operator.  The variable "out" points to a string
10353  * specifying the fd to be redirected.  The variable "c" contains the
10354  * first character of the redirection operator.
10355  */
10356
10357 parseredir: {
10358         char fd = *out;
10359         union node *np;
10360
10361         np = (union node *)stalloc(sizeof (struct nfile));
10362         if (c == '>') {
10363                 np->nfile.fd = 1;
10364                 c = pgetc();
10365                 if (c == '>')
10366                         np->type = NAPPEND;
10367                 else if (c == '&')
10368                         np->type = NTOFD;
10369                 else if (c == '|')
10370                         np->type = NTOOV;
10371                 else {
10372                         np->type = NTO;
10373                         pungetc();
10374                 }
10375         } else {        /* c == '<' */
10376                 np->nfile.fd = 0;
10377                 switch (c = pgetc()) {
10378                 case '<':
10379                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10380                                 np = (union node *)stalloc(sizeof (struct nhere));
10381                                 np->nfile.fd = 0;
10382                         }
10383                         np->type = NHERE;
10384                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10385                         heredoc->here = np;
10386                         if ((c = pgetc()) == '-') {
10387                                 heredoc->striptabs = 1;
10388                         } else {
10389                                 heredoc->striptabs = 0;
10390                                 pungetc();
10391                         }
10392                         break;
10393
10394                 case '&':
10395                         np->type = NFROMFD;
10396                         break;
10397
10398                 case '>':
10399                         np->type = NFROMTO;
10400                         break;
10401
10402                 default:
10403                         np->type = NFROM;
10404                         pungetc();
10405                         break;
10406                 }
10407         }
10408         if (fd != '\0')
10409                 np->nfile.fd = digit_val(fd);
10410         redirnode = np;
10411         goto parseredir_return;
10412 }
10413
10414
10415 /*
10416  * Parse a substitution.  At this point, we have read the dollar sign
10417  * and nothing else.
10418  */
10419
10420 parsesub: {
10421         int subtype;
10422         int typeloc;
10423         int flags;
10424         char *p;
10425         static const char types[] = "}-+?=";
10426
10427         c = pgetc();
10428         if (
10429                 c <= PEOA  ||
10430                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10431         ) {
10432                 USTPUTC('$', out);
10433                 pungetc();
10434         } else if (c == '(') {  /* $(command) or $((arith)) */
10435                 if (pgetc() == '(') {
10436                         PARSEARITH();
10437                 } else {
10438                         pungetc();
10439                         PARSEBACKQNEW();
10440                 }
10441         } else {
10442                 USTPUTC(CTLVAR, out);
10443                 typeloc = out - stackblock();
10444                 USTPUTC(VSNORMAL, out);
10445                 subtype = VSNORMAL;
10446                 if (c == '{') {
10447                         c = pgetc();
10448                         if (c == '#') {
10449                                 if ((c = pgetc()) == '}')
10450                                         c = '#';
10451                                 else
10452                                         subtype = VSLENGTH;
10453                         }
10454                         else
10455                                 subtype = 0;
10456                 }
10457                 if (c > PEOA && is_name(c)) {
10458                         do {
10459                                 STPUTC(c, out);
10460                                 c = pgetc();
10461                         } while (c > PEOA && is_in_name(c));
10462                 } else if (is_digit(c)) {
10463                         do {
10464                                 USTPUTC(c, out);
10465                                 c = pgetc();
10466                         } while (is_digit(c));
10467                 }
10468                 else if (is_special(c)) {
10469                         USTPUTC(c, out);
10470                         c = pgetc();
10471                 }
10472                 else
10473 badsub:                 synerror("Bad substitution");
10474
10475                 STPUTC('=', out);
10476                 flags = 0;
10477                 if (subtype == 0) {
10478                         switch (c) {
10479                         case ':':
10480                                 flags = VSNUL;
10481                                 c = pgetc();
10482                                 /*FALLTHROUGH*/
10483                         default:
10484                                 p = strchr(types, c);
10485                                 if (p == NULL)
10486                                         goto badsub;
10487                                 subtype = p - types + VSNORMAL;
10488                                 break;
10489                         case '%':
10490                         case '#':
10491                                 {
10492                                         int cc = c;
10493                                         subtype = c == '#' ? VSTRIMLEFT :
10494                                                              VSTRIMRIGHT;
10495                                         c = pgetc();
10496                                         if (c == cc)
10497                                                 subtype++;
10498                                         else
10499                                                 pungetc();
10500                                         break;
10501                                 }
10502                         }
10503                 } else {
10504                         pungetc();
10505                 }
10506                 if (dblquote || arinest)
10507                         flags |= VSQUOTE;
10508                 *(stackblock() + typeloc) = subtype | flags;
10509                 if (subtype != VSNORMAL) {
10510                         varnest++;
10511                         if (dblquote) {
10512                                 dqvarnest++;
10513                         }
10514                 }
10515         }
10516         goto parsesub_return;
10517 }
10518
10519
10520 /*
10521  * Called to parse command substitutions.  Newstyle is set if the command
10522  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10523  * list of commands (passed by reference), and savelen is the number of
10524  * characters on the top of the stack which must be preserved.
10525  */
10526
10527 parsebackq: {
10528         struct nodelist **nlpp;
10529         int savepbq;
10530         union node *n;
10531         char *volatile str;
10532         struct jmploc jmploc;
10533         struct jmploc *volatile savehandler;
10534         int savelen;
10535         int saveprompt;
10536 #ifdef __GNUC__
10537         (void) &saveprompt;
10538 #endif
10539
10540         savepbq = parsebackquote;
10541         if (setjmp(jmploc.loc)) {
10542                 if (str)
10543                         ckfree(str);
10544                 parsebackquote = 0;
10545                 handler = savehandler;
10546                 longjmp(handler->loc, 1);
10547         }
10548         INTOFF;
10549         str = NULL;
10550         savelen = out - stackblock();
10551         if (savelen > 0) {
10552                 str = ckmalloc(savelen);
10553                 memcpy(str, stackblock(), savelen);
10554         }
10555         savehandler = handler;
10556         handler = &jmploc;
10557         INTON;
10558         if (oldstyle) {
10559                 /* We must read until the closing backquote, giving special
10560                    treatment to some slashes, and then push the string and
10561                    reread it as input, interpreting it normally.  */
10562                 char *pout;
10563                 int pc;
10564                 int psavelen;
10565                 char *pstr;
10566
10567
10568                 STARTSTACKSTR(pout);
10569                 for (;;) {
10570                         if (needprompt) {
10571                                 setprompt(2);
10572                                 needprompt = 0;
10573                         }
10574                         switch (pc = pgetc()) {
10575                         case '`':
10576                                 goto done;
10577
10578                         case '\\':
10579                                 if ((pc = pgetc()) == '\n') {
10580                                         plinno++;
10581                                         if (doprompt)
10582                                                 setprompt(2);
10583                                         else
10584                                                 setprompt(0);
10585                                         /*
10586                                          * If eating a newline, avoid putting
10587                                          * the newline into the new character
10588                                          * stream (via the STPUTC after the
10589                                          * switch).
10590                                          */
10591                                         continue;
10592                                 }
10593                                 if (pc != '\\' && pc != '`' && pc != '$'
10594                                     && (!dblquote || pc != '"'))
10595                                         STPUTC('\\', pout);
10596                                 if (pc > PEOA) {
10597                                         break;
10598                                 }
10599                                 /* fall through */
10600
10601                         case PEOF:
10602                         case PEOA:
10603                                 startlinno = plinno;
10604                                 synerror("EOF in backquote substitution");
10605
10606                         case '\n':
10607                                 plinno++;
10608                                 needprompt = doprompt;
10609                                 break;
10610
10611                         default:
10612                                 break;
10613                         }
10614                         STPUTC(pc, pout);
10615                 }
10616 done:
10617                 STPUTC('\0', pout);
10618                 psavelen = pout - stackblock();
10619                 if (psavelen > 0) {
10620                         pstr = grabstackstr(pout);
10621                         setinputstring(pstr);
10622                 }
10623         }
10624         nlpp = &bqlist;
10625         while (*nlpp)
10626                 nlpp = &(*nlpp)->next;
10627         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10628         (*nlpp)->next = NULL;
10629         parsebackquote = oldstyle;
10630
10631         if (oldstyle) {
10632                 saveprompt = doprompt;
10633                 doprompt = 0;
10634         }
10635
10636         n = list(0);
10637
10638         if (oldstyle)
10639                 doprompt = saveprompt;
10640         else {
10641                 if (readtoken() != TRP)
10642                         synexpect(TRP);
10643         }
10644
10645         (*nlpp)->n = n;
10646         if (oldstyle) {
10647                 /*
10648                  * Start reading from old file again, ignoring any pushed back
10649                  * tokens left from the backquote parsing
10650                  */
10651                 popfile();
10652                 tokpushback = 0;
10653         }
10654         while (stackblocksize() <= savelen)
10655                 growstackblock();
10656         STARTSTACKSTR(out);
10657         if (str) {
10658                 memcpy(out, str, savelen);
10659                 STADJUST(savelen, out);
10660                 INTOFF;
10661                 ckfree(str);
10662                 str = NULL;
10663                 INTON;
10664         }
10665         parsebackquote = savepbq;
10666         handler = savehandler;
10667         if (arinest || dblquote)
10668                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10669         else
10670                 USTPUTC(CTLBACKQ, out);
10671         if (oldstyle)
10672                 goto parsebackq_oldreturn;
10673         else
10674                 goto parsebackq_newreturn;
10675 }
10676
10677 /*
10678  * Parse an arithmetic expansion (indicate start of one and set state)
10679  */
10680 parsearith: {
10681
10682         if (++arinest == 1) {
10683                 prevsyntax = syntax;
10684                 syntax = ARISYNTAX;
10685                 USTPUTC(CTLARI, out);
10686                 if (dblquote)
10687                         USTPUTC('"',out);
10688                 else
10689                         USTPUTC(' ',out);
10690         } else {
10691                 /*
10692                  * we collapse embedded arithmetic expansion to
10693                  * parenthesis, which should be equivalent
10694                  */
10695                 USTPUTC('(', out);
10696         }
10697         goto parsearith_return;
10698 }
10699
10700 } /* end of readtoken */
10701
10702
10703
10704 #ifdef mkinit
10705 INCLUDE "parser.h"
10706 RESET {
10707         tokpushback = 0;
10708         checkkwd = 0;
10709         checkalias = 0;
10710 }
10711 #endif
10712
10713 /*
10714  * Returns true if the text contains nothing to expand (no dollar signs
10715  * or backquotes).
10716  */
10717
10718 static int
10719 noexpand(text)
10720         char *text;
10721         {
10722         char *p;
10723         char c;
10724
10725         p = text;
10726         while ((c = *p++) != '\0') {
10727                 if (c == CTLQUOTEMARK)
10728                         continue;
10729                 if (c == CTLESC)
10730                         p++;
10731                 else if (BASESYNTAX[(int)c] == CCTL)
10732                         return 0;
10733         }
10734         return 1;
10735 }
10736
10737
10738 /*
10739  * Return true if the argument is a legal variable name (a letter or
10740  * underscore followed by zero or more letters, underscores, and digits).
10741  */
10742
10743 static int
10744 goodname(char *name)
10745         {
10746         char *p;
10747
10748         p = name;
10749         if (! is_name(*p))
10750                 return 0;
10751         while (*++p) {
10752                 if (! is_in_name(*p))
10753                         return 0;
10754         }
10755         return 1;
10756 }
10757
10758
10759 /*
10760  * Called when an unexpected token is read during the parse.  The argument
10761  * is the token that is expected, or -1 if more than one type of token can
10762  * occur at this point.
10763  */
10764
10765 static void
10766 synexpect(token)
10767         int token;
10768 {
10769         char msg[64];
10770
10771         if (token >= 0) {
10772                 fmtstr(msg, 64, "%s unexpected (expecting %s)",
10773                         tokname[lasttoken], tokname[token]);
10774         } else {
10775                 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
10776         }
10777         synerror(msg);
10778         /* NOTREACHED */
10779 }
10780
10781
10782 static void
10783 synerror(msg)
10784         const char *msg;
10785         {
10786         if (commandname)
10787                 outfmt(&errout, "%s: %d: ", commandname, startlinno);
10788         outfmt(&errout, "Syntax error: %s\n", msg);
10789         error((char *)NULL);
10790         /* NOTREACHED */
10791 }
10792
10793 static void
10794 setprompt(int which)
10795 {
10796     whichprompt = which;
10797     putprompt(getprompt(NULL));
10798 }
10799
10800 /*
10801  * called by editline -- any expansions to the prompt
10802  *    should be added here.
10803  */
10804 static const char *
10805 getprompt(void *unused)
10806         {
10807         switch (whichprompt) {
10808         case 0:
10809                 return "";
10810         case 1:
10811                 return ps1val();
10812         case 2:
10813                 return ps2val();
10814         default:
10815                 return "<internal prompt error>";
10816         }
10817 }
10818
10819 static int
10820 isassignment(const char *word) {
10821         if (!is_name(*word)) {
10822                 return 0;
10823         }
10824         do {
10825                 word++;
10826         } while (is_in_name(*word));
10827         return *word == '=';
10828 }
10829
10830 static const char *const *
10831 findkwd(const char *s) {
10832         return findstring(
10833                 s, parsekwd, sizeof(parsekwd) / sizeof(const char *)
10834         );
10835 }
10836 /*      $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $ */
10837
10838 /*
10839  * Code for dealing with input/output redirection.
10840  */
10841
10842 #define EMPTY -2                /* marks an unused slot in redirtab */
10843 #ifndef PIPE_BUF
10844 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10845 #else
10846 # define PIPESIZE PIPE_BUF
10847 #endif
10848
10849
10850 struct redirtab *redirlist;
10851
10852 /*
10853  * We keep track of whether or not fd0 has been redirected.  This is for
10854  * background commands, where we want to redirect fd0 to /dev/null only
10855  * if it hasn't already been redirected.
10856 */
10857 static int fd0_redirected = 0;
10858
10859 /*
10860  * We also keep track of where fileno2 goes.
10861  */
10862 static int fileno2 = 2;
10863
10864 static int openredirect __P((union node *));
10865 static void dupredirect __P((union node *, int, char[10 ]));
10866 static int openhere __P((union node *));
10867 static int noclobberopen __P((const char *));
10868
10869
10870 /*
10871  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
10872  * old file descriptors are stashed away so that the redirection can be
10873  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
10874  * standard output, and the standard error if it becomes a duplicate of
10875  * stdout, is saved in memory.
10876  */
10877
10878 static void
10879 redirect(redir, flags)
10880         union node *redir;
10881         int flags;
10882         {
10883         union node *n;
10884         struct redirtab *sv = NULL;
10885         int i;
10886         int fd;
10887         int newfd;
10888         int try;
10889         char memory[10];        /* file descriptors to write to memory */
10890
10891         for (i = 10 ; --i >= 0 ; )
10892                 memory[i] = 0;
10893         memory[1] = flags & REDIR_BACKQ;
10894         if (flags & REDIR_PUSH) {
10895                 sv = ckmalloc(sizeof (struct redirtab));
10896                 for (i = 0 ; i < 10 ; i++)
10897                         sv->renamed[i] = EMPTY;
10898                 sv->next = redirlist;
10899                 redirlist = sv;
10900         }
10901         for (n = redir ; n ; n = n->nfile.next) {
10902                 fd = n->nfile.fd;
10903                 try = 0;
10904                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10905                     n->ndup.dupfd == fd)
10906                         continue; /* redirect from/to same file descriptor */
10907
10908                 INTOFF;
10909                 newfd = openredirect(n);
10910                 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
10911                     (fd == fileno2)) {
10912                         if (newfd == fd) {
10913                                 try++;
10914                         } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
10915                                 switch (errno) {
10916                                 case EBADF:
10917                                         if (!try) {
10918                                                 dupredirect(n, newfd, memory);
10919                                                 try++;
10920                                                 break;
10921                                         }
10922                                         /* FALLTHROUGH*/
10923                                 default:
10924                                         if (newfd >= 0) {
10925                                                 close(newfd);
10926                                         }
10927                                         INTON;
10928                                         error("%d: %s", fd, strerror(errno));
10929                                         /* NOTREACHED */
10930                                 }
10931                         }
10932                         if (!try) {
10933                                 close(fd);
10934                                 if (flags & REDIR_PUSH) {
10935                                         sv->renamed[fd] = i;
10936                                 }
10937                                 if (fd == fileno2) {
10938                                         fileno2 = i;
10939                                 }
10940                         }
10941                 } else if (fd != newfd) {
10942                         close(fd);
10943                 }
10944                 if (fd == 0)
10945                         fd0_redirected++;
10946                 if (!try)
10947                         dupredirect(n, newfd, memory);
10948                 INTON;
10949         }
10950         if (memory[1])
10951                 out1 = &memout;
10952         if (memory[2])
10953                 out2 = &memout;
10954 }
10955
10956
10957 static int
10958 openredirect(redir)
10959         union node *redir;
10960         {
10961         char *fname;
10962         int f;
10963
10964         switch (redir->nfile.type) {
10965         case NFROM:
10966                 fname = redir->nfile.expfname;
10967                 if ((f = open(fname, O_RDONLY)) < 0)
10968                         goto eopen;
10969                 break;
10970         case NFROMTO:
10971                 fname = redir->nfile.expfname;
10972                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10973                         goto ecreate;
10974                 break;
10975         case NTO:
10976                 /* Take care of noclobber mode. */
10977                 if (Cflag) {
10978                         fname = redir->nfile.expfname;
10979                         if ((f = noclobberopen(fname)) < 0)
10980                                 goto ecreate;
10981                         break;
10982                 }
10983         case NTOOV:
10984                 fname = redir->nfile.expfname;
10985 #ifdef O_CREAT
10986                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10987                         goto ecreate;
10988 #else
10989                 if ((f = creat(fname, 0666)) < 0)
10990                         goto ecreate;
10991 #endif
10992                 break;
10993         case NAPPEND:
10994                 fname = redir->nfile.expfname;
10995 #ifdef O_APPEND
10996                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10997                         goto ecreate;
10998 #else
10999                 if ((f = open(fname, O_WRONLY)) < 0
11000                  && (f = creat(fname, 0666)) < 0)
11001                         goto ecreate;
11002                 lseek(f, (off_t)0, 2);
11003 #endif
11004                 break;
11005         default:
11006 #ifdef DEBUG
11007                 abort();
11008 #endif
11009                 /* Fall through to eliminate warning. */
11010         case NTOFD:
11011         case NFROMFD:
11012                 f = -1;
11013                 break;
11014         case NHERE:
11015         case NXHERE:
11016                 f = openhere(redir);
11017                 break;
11018         }
11019
11020         return f;
11021 ecreate:
11022         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11023 eopen:
11024         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11025 }
11026
11027
11028 static void
11029 dupredirect(redir, f, memory)
11030         union node *redir;
11031         int f;
11032         char memory[10];
11033         {
11034         int fd = redir->nfile.fd;
11035
11036         memory[fd] = 0;
11037         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11038                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11039                         if (memory[redir->ndup.dupfd])
11040                                 memory[fd] = 1;
11041                         else
11042                                 dup_as_newfd(redir->ndup.dupfd, fd);
11043                 }
11044                 return;
11045         }
11046
11047         if (f != fd) {
11048                 dup_as_newfd(f, fd);
11049                 close(f);
11050         }
11051         return;
11052 }
11053
11054
11055 /*
11056  * Handle here documents.  Normally we fork off a process to write the
11057  * data to a pipe.  If the document is short, we can stuff the data in
11058  * the pipe without forking.
11059  */
11060
11061 static int
11062 openhere(redir)
11063         union node *redir;
11064         {
11065         int pip[2];
11066         int len = 0;
11067
11068         if (pipe(pip) < 0)
11069                 error("Pipe call failed");
11070         if (redir->type == NHERE) {
11071                 len = strlen(redir->nhere.doc->narg.text);
11072                 if (len <= PIPESIZE) {
11073                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11074                         goto out;
11075                 }
11076         }
11077         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11078                 close(pip[0]);
11079                 signal(SIGINT, SIG_IGN);
11080                 signal(SIGQUIT, SIG_IGN);
11081                 signal(SIGHUP, SIG_IGN);
11082 #ifdef SIGTSTP
11083                 signal(SIGTSTP, SIG_IGN);
11084 #endif
11085                 signal(SIGPIPE, SIG_DFL);
11086                 if (redir->type == NHERE)
11087                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11088                 else
11089                         expandhere(redir->nhere.doc, pip[1]);
11090                 _exit(0);
11091         }
11092 out:
11093         close(pip[1]);
11094         return pip[0];
11095 }
11096
11097
11098
11099 /*
11100  * Undo the effects of the last redirection.
11101  */
11102
11103 static void
11104 popredir() {
11105         struct redirtab *rp = redirlist;
11106         int i;
11107
11108         INTOFF;
11109         for (i = 0 ; i < 10 ; i++) {
11110                 if (rp->renamed[i] != EMPTY) {
11111                         if (i == 0)
11112                                 fd0_redirected--;
11113                         close(i);
11114                         if (rp->renamed[i] >= 0) {
11115                                 dup_as_newfd(rp->renamed[i], i);
11116                                 close(rp->renamed[i]);
11117                         }
11118                         if (rp->renamed[i] == fileno2) {
11119                                 fileno2 = i;
11120                         }
11121                 }
11122         }
11123         redirlist = rp->next;
11124         ckfree(rp);
11125         INTON;
11126 }
11127
11128 /*
11129  * Undo all redirections.  Called on error or interrupt.
11130  */
11131
11132 #ifdef mkinit
11133
11134 INCLUDE "redir.h"
11135
11136 RESET {
11137         while (redirlist)
11138                 popredir();
11139 }
11140
11141 SHELLPROC {
11142         clearredir();
11143 }
11144
11145 #endif
11146
11147 /* Return true if fd 0 has already been redirected at least once.  */
11148 static int
11149 fd0_redirected_p () {
11150         return fd0_redirected != 0;
11151 }
11152
11153 /*
11154  * Discard all saved file descriptors.
11155  */
11156
11157 static void
11158 clearredir() {
11159         struct redirtab *rp;
11160         int i;
11161
11162         for (rp = redirlist ; rp ; rp = rp->next) {
11163                 for (i = 0 ; i < 10 ; i++) {
11164                         if (rp->renamed[i] >= 0) {
11165                                 close(rp->renamed[i]);
11166                                 if (rp->renamed[i] == fileno2) {
11167                                         fileno2 = -1;
11168                                 }
11169                         }
11170                         rp->renamed[i] = EMPTY;
11171                 }
11172         }
11173         if (fileno2 != 2 && fileno2 >= 0) {
11174                 close(fileno2);
11175                 fileno2 = -1;
11176         }
11177 }
11178
11179
11180
11181 /*
11182  * Copy a file descriptor to be >= to.  Returns -1
11183  * if the source file descriptor is closed, EMPTY if there are no unused
11184  * file descriptors left.
11185  */
11186
11187 static int
11188 dup_as_newfd(from, to)
11189         int from;
11190         int to;
11191 {
11192         int newfd;
11193
11194         newfd = fcntl(from, F_DUPFD, to);
11195         if (newfd < 0) {
11196                 if (errno == EMFILE)
11197                         return EMPTY;
11198                 else
11199                         error("%d: %s", from, strerror(errno));
11200         }
11201         return newfd;
11202 }
11203
11204 /*
11205  * Open a file in noclobber mode.
11206  * The code was copied from bash.
11207  */
11208 static int
11209 noclobberopen(fname)
11210         const char *fname;
11211 {
11212         int r, fd;
11213         struct stat finfo, finfo2;
11214
11215         /*
11216          * If the file exists and is a regular file, return an error
11217          * immediately.
11218          */
11219         r = stat(fname, &finfo);
11220         if (r == 0 && S_ISREG(finfo.st_mode)) {
11221                 errno = EEXIST;
11222                 return -1;
11223         }
11224
11225         /*
11226          * If the file was not present (r != 0), make sure we open it
11227          * exclusively so that if it is created before we open it, our open
11228          * will fail.  Make sure that we do not truncate an existing file.
11229          * Note that we don't turn on O_EXCL unless the stat failed -- if the
11230          * file was not a regular file, we leave O_EXCL off.
11231          */
11232         if (r != 0)
11233                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11234         fd = open(fname, O_WRONLY|O_CREAT, 0666);
11235
11236         /* If the open failed, return the file descriptor right away. */
11237         if (fd < 0)
11238                 return fd;
11239
11240         /*
11241          * OK, the open succeeded, but the file may have been changed from a
11242          * non-regular file to a regular file between the stat and the open.
11243          * We are assuming that the O_EXCL open handles the case where FILENAME
11244          * did not exist and is symlinked to an existing file between the stat
11245          * and open.
11246          */
11247
11248         /*
11249          * If we can open it and fstat the file descriptor, and neither check
11250          * revealed that it was a regular file, and the file has not been
11251          * replaced, return the file descriptor.
11252          */
11253          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11254              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11255                 return fd;
11256
11257         /* The file has been replaced.  badness. */
11258         close(fd);
11259         errno = EEXIST;
11260         return -1;
11261 }
11262 /*      $NetBSD: setmode.c,v 1.28 2000/01/25 15:43:43 enami Exp $       */
11263
11264 #ifdef __weak_alias
11265 __weak_alias(getmode,_getmode)
11266 __weak_alias(setmode,_setmode)
11267 #endif
11268
11269 #ifdef __GLIBC__
11270 #define S_ISTXT __S_ISVTX
11271 #endif
11272
11273 #define SET_LEN 6               /* initial # of bitcmd struct to malloc */
11274 #define SET_LEN_INCR 4          /* # of bitcmd structs to add as needed */
11275
11276 typedef struct bitcmd {
11277         char    cmd;
11278         char    cmd2;
11279         mode_t  bits;
11280 } BITCMD;
11281
11282 #define CMD2_CLR        0x01
11283 #define CMD2_SET        0x02
11284 #define CMD2_GBITS      0x04
11285 #define CMD2_OBITS      0x08
11286 #define CMD2_UBITS      0x10
11287
11288 static BITCMD   *addcmd __P((BITCMD *, int, int, int, u_int));
11289 static void      compress_mode __P((BITCMD *));
11290 #ifdef SETMODE_DEBUG
11291 static void      dumpmode __P((BITCMD *));
11292 #endif
11293
11294 /*
11295  * Given the old mode and an array of bitcmd structures, apply the operations
11296  * described in the bitcmd structures to the old mode, and return the new mode.
11297  * Note that there is no '=' command; a strict assignment is just a '-' (clear
11298  * bits) followed by a '+' (set bits).
11299  */
11300 mode_t
11301 getmode(bbox, omode)
11302         const void *bbox;
11303         mode_t omode;
11304 {
11305         const BITCMD *set;
11306         mode_t clrval, newmode, value;
11307
11308         _DIAGASSERT(bbox != NULL);
11309
11310         set = (const BITCMD *)bbox;
11311         newmode = omode;
11312         for (value = 0;; set++)
11313                 switch(set->cmd) {
11314                 /*
11315                  * When copying the user, group or other bits around, we "know"
11316                  * where the bits are in the mode so that we can do shifts to
11317                  * copy them around.  If we don't use shifts, it gets real
11318                  * grundgy with lots of single bit checks and bit sets.
11319                  */
11320                 case 'u':
11321                         value = (newmode & S_IRWXU) >> 6;
11322                         goto common;
11323
11324                 case 'g':
11325                         value = (newmode & S_IRWXG) >> 3;
11326                         goto common;
11327
11328                 case 'o':
11329                         value = newmode & S_IRWXO;
11330 common:                 if (set->cmd2 & CMD2_CLR) {
11331                                 clrval =
11332                                     (set->cmd2 & CMD2_SET) ?  S_IRWXO : value;
11333                                 if (set->cmd2 & CMD2_UBITS)
11334                                         newmode &= ~((clrval<<6) & set->bits);
11335                                 if (set->cmd2 & CMD2_GBITS)
11336                                         newmode &= ~((clrval<<3) & set->bits);
11337                                 if (set->cmd2 & CMD2_OBITS)
11338                                         newmode &= ~(clrval & set->bits);
11339                         }
11340                         if (set->cmd2 & CMD2_SET) {
11341                                 if (set->cmd2 & CMD2_UBITS)
11342                                         newmode |= (value<<6) & set->bits;
11343                                 if (set->cmd2 & CMD2_GBITS)
11344                                         newmode |= (value<<3) & set->bits;
11345                                 if (set->cmd2 & CMD2_OBITS)
11346                                         newmode |= value & set->bits;
11347                         }
11348                         break;
11349
11350                 case '+':
11351                         newmode |= set->bits;
11352                         break;
11353
11354                 case '-':
11355                         newmode &= ~set->bits;
11356                         break;
11357
11358                 case 'X':
11359                         if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11360                                 newmode |= set->bits;
11361                         break;
11362
11363                 case '\0':
11364                 default:
11365 #ifdef SETMODE_DEBUG
11366                         (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11367 #endif
11368                         return (newmode);
11369                 }
11370 }
11371
11372 #define ADDCMD(a, b, c, d) do {                                         \
11373         if (set >= endset) {                                            \
11374                 BITCMD *newset;                                         \
11375                 setlen += SET_LEN_INCR;                                 \
11376                 newset = realloc(saveset, sizeof(BITCMD) * setlen);     \
11377                 if (newset == NULL) {                                   \
11378                         free(saveset);                                  \
11379                         return (NULL);                                  \
11380                 }                                                       \
11381                 set = newset + (set - saveset);                         \
11382                 saveset = newset;                                       \
11383                 endset = newset + (setlen - 2);                         \
11384         }                                                               \
11385         set = addcmd(set, (a), (b), (c), (d));                          \
11386 } while (/*CONSTCOND*/0)
11387
11388 #define STANDARD_BITS   (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
11389
11390 static void *
11391 setmode(p)
11392         const char *p;
11393 {
11394         int perm, who;
11395         char op, *ep;
11396         BITCMD *set, *saveset, *endset;
11397         sigset_t mysigset, sigoset;
11398         mode_t mask;
11399         int equalopdone = 0;    /* pacify gcc */
11400         int permXbits, setlen;
11401
11402         if (!*p)
11403                 return (NULL);
11404
11405         /*
11406          * Get a copy of the mask for the permissions that are mask relative.
11407          * Flip the bits, we want what's not set.  Since it's possible that
11408          * the caller is opening files inside a signal handler, protect them
11409          * as best we can.
11410          */
11411         sigfillset(&mysigset);
11412         (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11413         (void)umask(mask = umask(0));
11414         mask = ~mask;
11415         (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11416
11417         setlen = SET_LEN + 2;
11418         
11419         if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11420                 return (NULL);
11421         saveset = set;
11422         endset = set + (setlen - 2);
11423
11424         /*
11425          * If an absolute number, get it and return; disallow non-octal digits
11426          * or illegal bits.
11427          */
11428         if (isdigit((unsigned char)*p)) {
11429                 perm = (mode_t)strtol(p, &ep, 8);
11430                 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11431                         free(saveset);
11432                         return (NULL);
11433                 }
11434                 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11435                 set->cmd = 0;
11436                 return (saveset);
11437         }
11438
11439         /*
11440          * Build list of structures to set/clear/copy bits as described by
11441          * each clause of the symbolic mode.
11442          */
11443         for (;;) {
11444                 /* First, find out which bits might be modified. */
11445                 for (who = 0;; ++p) {
11446                         switch (*p) {
11447                         case 'a':
11448                                 who |= STANDARD_BITS;
11449                                 break;
11450                         case 'u':
11451                                 who |= S_ISUID|S_IRWXU;
11452                                 break;
11453                         case 'g':
11454                                 who |= S_ISGID|S_IRWXG;
11455                                 break;
11456                         case 'o':
11457                                 who |= S_IRWXO;
11458                                 break;
11459                         default:
11460                                 goto getop;
11461                         }
11462                 }
11463
11464 getop:          if ((op = *p++) != '+' && op != '-' && op != '=') {
11465                         free(saveset);
11466                         return (NULL);
11467                 }
11468                 if (op == '=')
11469                         equalopdone = 0;
11470
11471                 who &= ~S_ISTXT;
11472                 for (perm = 0, permXbits = 0;; ++p) {
11473                         switch (*p) {
11474                         case 'r':
11475                                 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11476                                 break;
11477                         case 's':
11478                                 /*
11479                                  * If specific bits where requested and 
11480                                  * only "other" bits ignore set-id. 
11481                                  */
11482                                 if (who == 0 || (who & ~S_IRWXO))
11483                                         perm |= S_ISUID|S_ISGID;
11484                                 break;
11485                         case 't':
11486                                 /*
11487                                  * If specific bits where requested and 
11488                                  * only "other" bits ignore set-id. 
11489                                  */
11490                                 if (who == 0 || (who & ~S_IRWXO)) {
11491                                         who |= S_ISTXT;
11492                                         perm |= S_ISTXT;
11493                                 }
11494                                 break;
11495                         case 'w':
11496                                 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11497                                 break;
11498                         case 'X':
11499                                 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11500                                 break;
11501                         case 'x':
11502                                 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11503                                 break;
11504                         case 'u':
11505                         case 'g':
11506                         case 'o':
11507                                 /*
11508                                  * When ever we hit 'u', 'g', or 'o', we have
11509                                  * to flush out any partial mode that we have,
11510                                  * and then do the copying of the mode bits.
11511                                  */
11512                                 if (perm) {
11513                                         ADDCMD(op, who, perm, mask);
11514                                         perm = 0;
11515                                 }
11516                                 if (op == '=')
11517                                         equalopdone = 1;
11518                                 if (op == '+' && permXbits) {
11519                                         ADDCMD('X', who, permXbits, mask);
11520                                         permXbits = 0;
11521                                 }
11522                                 ADDCMD(*p, who, op, mask);
11523                                 break;
11524
11525                         default:
11526                                 /*
11527                                  * Add any permissions that we haven't already
11528                                  * done.
11529                                  */
11530                                 if (perm || (op == '=' && !equalopdone)) {
11531                                         if (op == '=')
11532                                                 equalopdone = 1;
11533                                         ADDCMD(op, who, perm, mask);
11534                                         perm = 0;
11535                                 }
11536                                 if (permXbits) {
11537                                         ADDCMD('X', who, permXbits, mask);
11538                                         permXbits = 0;
11539                                 }
11540                                 goto apply;
11541                         }
11542                 }
11543
11544 apply:          if (!*p)
11545                         break;
11546                 if (*p != ',')
11547                         goto getop;
11548                 ++p;
11549         }
11550         set->cmd = 0;
11551 #ifdef SETMODE_DEBUG
11552         (void)printf("Before compress_mode()\n");
11553         dumpmode(saveset);
11554 #endif
11555         compress_mode(saveset);
11556 #ifdef SETMODE_DEBUG
11557         (void)printf("After compress_mode()\n");
11558         dumpmode(saveset);
11559 #endif
11560         return (saveset);
11561 }
11562
11563 static BITCMD *
11564 addcmd(set, op, who, oparg, mask)
11565         BITCMD *set;
11566         int oparg, who;
11567         int op;
11568         u_int mask;
11569 {
11570
11571         _DIAGASSERT(set != NULL);
11572
11573         switch (op) {
11574         case '=':
11575                 set->cmd = '-';
11576                 set->bits = who ? who : STANDARD_BITS;
11577                 set++;
11578
11579                 op = '+';
11580                 /* FALLTHROUGH */
11581         case '+':
11582         case '-':
11583         case 'X':
11584                 set->cmd = op;
11585                 set->bits = (who ? who : mask) & oparg;
11586                 break;
11587
11588         case 'u':
11589         case 'g':
11590         case 'o':
11591                 set->cmd = op;
11592                 if (who) {
11593                         set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11594                                     ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11595                                     ((who & S_IROTH) ? CMD2_OBITS : 0);
11596                         set->bits = (mode_t)~0;
11597                 } else {
11598                         set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11599                         set->bits = mask;
11600                 }
11601         
11602                 if (oparg == '+')
11603                         set->cmd2 |= CMD2_SET;
11604                 else if (oparg == '-')
11605                         set->cmd2 |= CMD2_CLR;
11606                 else if (oparg == '=')
11607                         set->cmd2 |= CMD2_SET|CMD2_CLR;
11608                 break;
11609         }
11610         return (set + 1);
11611 }
11612
11613 #ifdef SETMODE_DEBUG
11614 static void
11615 dumpmode(set)
11616         BITCMD *set;
11617 {
11618
11619         _DIAGASSERT(set != NULL);
11620
11621         for (; set->cmd; ++set)
11622                 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11623                     set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11624                     set->cmd2 & CMD2_CLR ? " CLR" : "",
11625                     set->cmd2 & CMD2_SET ? " SET" : "",
11626                     set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11627                     set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11628                     set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11629 }
11630 #endif
11631
11632 /*
11633  * Given an array of bitcmd structures, compress by compacting consecutive
11634  * '+', '-' and 'X' commands into at most 3 commands, one of each.  The 'u',
11635  * 'g' and 'o' commands continue to be separate.  They could probably be 
11636  * compacted, but it's not worth the effort.
11637  */
11638 static void
11639 compress_mode(set)
11640         BITCMD *set;
11641 {
11642         BITCMD *nset;
11643         int setbits, clrbits, Xbits, op;
11644
11645         _DIAGASSERT(set != NULL);
11646
11647         for (nset = set;;) {
11648                 /* Copy over any 'u', 'g' and 'o' commands. */
11649                 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11650                         *set++ = *nset++;
11651                         if (!op)
11652                                 return;
11653                 }
11654
11655                 for (setbits = clrbits = Xbits = 0;; nset++) {
11656                         if ((op = nset->cmd) == '-') {
11657                                 clrbits |= nset->bits;
11658                                 setbits &= ~nset->bits;
11659                                 Xbits &= ~nset->bits;
11660                         } else if (op == '+') {
11661                                 setbits |= nset->bits;
11662                                 clrbits &= ~nset->bits;
11663                                 Xbits &= ~nset->bits;
11664                         } else if (op == 'X')
11665                                 Xbits |= nset->bits & ~setbits;
11666                         else
11667                                 break;
11668                 }
11669                 if (clrbits) {
11670                         set->cmd = '-';
11671                         set->cmd2 = 0;
11672                         set->bits = clrbits;
11673                         set++;
11674                 }
11675                 if (setbits) {
11676                         set->cmd = '+';
11677                         set->cmd2 = 0;
11678                         set->bits = setbits;
11679                         set++;
11680                 }
11681                 if (Xbits) {
11682                         set->cmd = 'X';
11683                         set->cmd2 = 0;
11684                         set->bits = Xbits;
11685                         set++;
11686                 }
11687         }
11688 }
11689 /*      $NetBSD: show.c,v 1.18 1999/10/08 21:10:44 pk Exp $     */
11690
11691
11692 #ifdef DEBUG
11693 static void shtree __P((union node *, int, char *, FILE*));
11694 static void shcmd __P((union node *, FILE *));
11695 static void sharg __P((union node *, FILE *));
11696 static void indent __P((int, char *, FILE *));
11697 static void trstring __P((char *));
11698
11699
11700 static void
11701 showtree(n)
11702         union node *n;
11703 {
11704         trputs("showtree called\n");
11705         shtree(n, 1, NULL, stdout);
11706 }
11707
11708
11709 static void
11710 shtree(n, ind, pfx, fp)
11711         union node *n;
11712         int ind;
11713         char *pfx;
11714         FILE *fp;
11715 {
11716         struct nodelist *lp;
11717         const char *s;
11718
11719         if (n == NULL)
11720                 return;
11721
11722         indent(ind, pfx, fp);
11723         switch(n->type) {
11724         case NSEMI:
11725                 s = "; ";
11726                 goto binop;
11727         case NAND:
11728                 s = " && ";
11729                 goto binop;
11730         case NOR:
11731                 s = " || ";
11732 binop:
11733                 shtree(n->nbinary.ch1, ind, NULL, fp);
11734            /*    if (ind < 0) */
11735                         fputs(s, fp);
11736                 shtree(n->nbinary.ch2, ind, NULL, fp);
11737                 break;
11738         case NCMD:
11739                 shcmd(n, fp);
11740                 if (ind >= 0)
11741                         putc('\n', fp);
11742                 break;
11743         case NPIPE:
11744                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11745                         shcmd(lp->n, fp);
11746                         if (lp->next)
11747                                 fputs(" | ", fp);
11748                 }
11749                 if (n->npipe.backgnd)
11750                         fputs(" &", fp);
11751                 if (ind >= 0)
11752                         putc('\n', fp);
11753                 break;
11754         default:
11755                 fprintf(fp, "<node type %d>", n->type);
11756                 if (ind >= 0)
11757                         putc('\n', fp);
11758                 break;
11759         }
11760 }
11761
11762
11763
11764 static void
11765 shcmd(cmd, fp)
11766         union node *cmd;
11767         FILE *fp;
11768 {
11769         union node *np;
11770         int first;
11771         const char *s;
11772         int dftfd;
11773
11774         first = 1;
11775         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11776                 if (! first)
11777                         putchar(' ');
11778                 sharg(np, fp);
11779                 first = 0;
11780         }
11781         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11782                 if (! first)
11783                         putchar(' ');
11784                 switch (np->nfile.type) {
11785                         case NTO:       s = ">";  dftfd = 1; break;
11786                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11787                         case NTOFD:     s = ">&"; dftfd = 1; break;
11788                         case NTOOV:     s = ">|"; dftfd = 1; break;
11789                         case NFROM:     s = "<";  dftfd = 0; break;
11790                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11791                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11792                         default:        s = "*error*"; dftfd = 0; break;
11793                 }
11794                 if (np->nfile.fd != dftfd)
11795                         fprintf(fp, "%d", np->nfile.fd);
11796                 fputs(s, fp);
11797                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11798                         fprintf(fp, "%d", np->ndup.dupfd);
11799                 } else {
11800                         sharg(np->nfile.fname, fp);
11801                 }
11802                 first = 0;
11803         }
11804 }
11805
11806
11807
11808 static void
11809 sharg(arg, fp)
11810         union node *arg;
11811         FILE *fp;
11812         {
11813         char *p;
11814         struct nodelist *bqlist;
11815         int subtype;
11816
11817         if (arg->type != NARG) {
11818                 printf("<node type %d>\n", arg->type);
11819                 fflush(stdout);
11820                 abort();
11821         }
11822         bqlist = arg->narg.backquote;
11823         for (p = arg->narg.text ; *p ; p++) {
11824                 switch (*p) {
11825                 case CTLESC:
11826                         putc(*++p, fp);
11827                         break;
11828                 case CTLVAR:
11829                         putc('$', fp);
11830                         putc('{', fp);
11831                         subtype = *++p;
11832                         if (subtype == VSLENGTH)
11833                                 putc('#', fp);
11834
11835                         while (*p != '=')
11836                                 putc(*p++, fp);
11837
11838                         if (subtype & VSNUL)
11839                                 putc(':', fp);
11840
11841                         switch (subtype & VSTYPE) {
11842                         case VSNORMAL:
11843                                 putc('}', fp);
11844                                 break;
11845                         case VSMINUS:
11846                                 putc('-', fp);
11847                                 break;
11848                         case VSPLUS:
11849                                 putc('+', fp);
11850                                 break;
11851                         case VSQUESTION:
11852                                 putc('?', fp);
11853                                 break;
11854                         case VSASSIGN:
11855                                 putc('=', fp);
11856                                 break;
11857                         case VSTRIMLEFT:
11858                                 putc('#', fp);
11859                                 break;
11860                         case VSTRIMLEFTMAX:
11861                                 putc('#', fp);
11862                                 putc('#', fp);
11863                                 break;
11864                         case VSTRIMRIGHT:
11865                                 putc('%', fp);
11866                                 break;
11867                         case VSTRIMRIGHTMAX:
11868                                 putc('%', fp);
11869                                 putc('%', fp);
11870                                 break;
11871                         case VSLENGTH:
11872                                 break;
11873                         default:
11874                                 printf("<subtype %d>", subtype);
11875                         }
11876                         break;
11877                 case CTLENDVAR:
11878                      putc('}', fp);
11879                      break;
11880                 case CTLBACKQ:
11881                 case CTLBACKQ|CTLQUOTE:
11882                         putc('$', fp);
11883                         putc('(', fp);
11884                         shtree(bqlist->n, -1, NULL, fp);
11885                         putc(')', fp);
11886                         break;
11887                 default:
11888                         putc(*p, fp);
11889                         break;
11890                 }
11891         }
11892 }
11893
11894
11895 static void
11896 indent(amount, pfx, fp)
11897         int amount;
11898         char *pfx;
11899         FILE *fp;
11900 {
11901         int i;
11902
11903         for (i = 0 ; i < amount ; i++) {
11904                 if (pfx && i == amount - 1)
11905                         fputs(pfx, fp);
11906                 putc('\t', fp);
11907         }
11908 }
11909 #endif
11910
11911
11912
11913 /*
11914  * Debugging stuff.
11915  */
11916
11917
11918 #ifdef DEBUG
11919 FILE *tracefile;
11920
11921 #if DEBUG == 2
11922 static int debug = 1;
11923 #else
11924 static int debug = 0;
11925 #endif
11926
11927
11928 static void
11929 trputc(c)
11930         int c;
11931 {
11932         if (tracefile == NULL)
11933                 return;
11934         putc(c, tracefile);
11935         if (c == '\n')
11936                 fflush(tracefile);
11937 }
11938
11939 static void
11940 trace(const char *fmt, ...)
11941 {
11942         va_list va;
11943 #ifdef __STDC__
11944         va_start(va, fmt);
11945 #else
11946         char *fmt;
11947         va_start(va);
11948         fmt = va_arg(va, char *);
11949 #endif
11950         if (tracefile != NULL) {
11951                 (void) vfprintf(tracefile, fmt, va);
11952                 if (strchr(fmt, '\n'))
11953                         (void) fflush(tracefile);
11954         }
11955         va_end(va);
11956 }
11957
11958
11959 static void
11960 trputs(s)
11961         const char *s;
11962 {
11963         if (tracefile == NULL)
11964                 return;
11965         fputs(s, tracefile);
11966         if (strchr(s, '\n'))
11967                 fflush(tracefile);
11968 }
11969
11970
11971 static void
11972 trstring(s)
11973         char *s;
11974 {
11975         char *p;
11976         char c;
11977
11978         if (tracefile == NULL)
11979                 return;
11980         putc('"', tracefile);
11981         for (p = s ; *p ; p++) {
11982                 switch (*p) {
11983                 case '\n':  c = 'n';  goto backslash;
11984                 case '\t':  c = 't';  goto backslash;
11985                 case '\r':  c = 'r';  goto backslash;
11986                 case '"':  c = '"';  goto backslash;
11987                 case '\\':  c = '\\';  goto backslash;
11988                 case CTLESC:  c = 'e';  goto backslash;
11989                 case CTLVAR:  c = 'v';  goto backslash;
11990                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11991                 case CTLBACKQ:  c = 'q';  goto backslash;
11992                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11993 backslash:        putc('\\', tracefile);
11994                         putc(c, tracefile);
11995                         break;
11996                 default:
11997                         if (*p >= ' ' && *p <= '~')
11998                                 putc(*p, tracefile);
11999                         else {
12000                                 putc('\\', tracefile);
12001                                 putc(*p >> 6 & 03, tracefile);
12002                                 putc(*p >> 3 & 07, tracefile);
12003                                 putc(*p & 07, tracefile);
12004                         }
12005                         break;
12006                 }
12007         }
12008         putc('"', tracefile);
12009 }
12010
12011
12012 static void
12013 trargs(ap)
12014         char **ap;
12015 {
12016         if (tracefile == NULL)
12017                 return;
12018         while (*ap) {
12019                 trstring(*ap++);
12020                 if (*ap)
12021                         putc(' ', tracefile);
12022                 else
12023                         putc('\n', tracefile);
12024         }
12025         fflush(tracefile);
12026 }
12027
12028
12029 static void
12030 opentrace() {
12031         char s[100];
12032 #ifdef O_APPEND
12033         int flags;
12034 #endif
12035
12036         if (!debug)
12037                 return;
12038 #ifdef not_this_way
12039         {
12040                 char *p;
12041                 if ((p = getenv("HOME")) == NULL) {
12042                         if (geteuid() == 0)
12043                                 p = "/";
12044                         else
12045                                 p = "/tmp";
12046                 }
12047                 scopy(p, s);
12048                 strcat(s, "/trace");
12049         }
12050 #else
12051         scopy("./trace", s);
12052 #endif /* not_this_way */
12053         if ((tracefile = fopen(s, "a")) == NULL) {
12054                 fprintf(stderr, "Can't open %s\n", s);
12055                 return;
12056         }
12057 #ifdef O_APPEND
12058         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12059                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12060 #endif
12061         fputs("\nTracing started.\n", tracefile);
12062         fflush(tracefile);
12063 }
12064 #endif /* DEBUG */
12065
12066
12067 /*
12068  * This file was generated by the mksyntax program.
12069  */
12070
12071 /* syntax table used when not in quotes */
12072 static const char basesyntax[257] = {
12073       CEOF,    CSPCL,   CWORD,   CCTL,
12074       CCTL,    CCTL,    CCTL,    CCTL,
12075       CCTL,    CCTL,    CCTL,    CWORD,
12076       CWORD,   CWORD,   CWORD,   CWORD,
12077       CWORD,   CWORD,   CWORD,   CWORD,
12078       CWORD,   CWORD,   CWORD,   CWORD,
12079       CWORD,   CWORD,   CWORD,   CWORD,
12080       CWORD,   CWORD,   CWORD,   CWORD,
12081       CWORD,   CWORD,   CWORD,   CWORD,
12082       CWORD,   CWORD,   CWORD,   CWORD,
12083       CWORD,   CWORD,   CWORD,   CWORD,
12084       CWORD,   CWORD,   CWORD,   CWORD,
12085       CWORD,   CWORD,   CWORD,   CWORD,
12086       CWORD,   CWORD,   CWORD,   CWORD,
12087       CWORD,   CWORD,   CWORD,   CWORD,
12088       CWORD,   CWORD,   CWORD,   CWORD,
12089       CWORD,   CWORD,   CWORD,   CWORD,
12090       CWORD,   CWORD,   CWORD,   CWORD,
12091       CWORD,   CWORD,   CWORD,   CWORD,
12092       CWORD,   CWORD,   CWORD,   CWORD,
12093       CWORD,   CWORD,   CWORD,   CWORD,
12094       CWORD,   CWORD,   CWORD,   CWORD,
12095       CWORD,   CWORD,   CWORD,   CWORD,
12096       CWORD,   CWORD,   CWORD,   CWORD,
12097       CWORD,   CWORD,   CWORD,   CWORD,
12098       CWORD,   CWORD,   CWORD,   CWORD,
12099       CWORD,   CWORD,   CWORD,   CWORD,
12100       CWORD,   CWORD,   CWORD,   CWORD,
12101       CWORD,   CWORD,   CWORD,   CWORD,
12102       CWORD,   CWORD,   CWORD,   CWORD,
12103       CWORD,   CWORD,   CWORD,   CWORD,
12104       CWORD,   CWORD,   CWORD,   CWORD,
12105       CWORD,   CWORD,   CWORD,   CWORD,
12106       CWORD,   CWORD,   CWORD,   CWORD,
12107       CWORD,   CWORD,   CWORD,   CSPCL,
12108       CNL,     CWORD,   CWORD,   CWORD,
12109       CWORD,   CWORD,   CWORD,   CWORD,
12110       CWORD,   CWORD,   CWORD,   CWORD,
12111       CWORD,   CWORD,   CWORD,   CWORD,
12112       CWORD,   CWORD,   CWORD,   CWORD,
12113       CWORD,   CWORD,   CSPCL,   CWORD,
12114       CDQUOTE, CWORD,   CVAR,    CWORD,
12115       CSPCL,   CSQUOTE, CSPCL,   CSPCL,
12116       CWORD,   CWORD,   CWORD,   CWORD,
12117       CWORD,   CWORD,   CWORD,   CWORD,
12118       CWORD,   CWORD,   CWORD,   CWORD,
12119       CWORD,   CWORD,   CWORD,   CWORD,
12120       CWORD,   CSPCL,   CSPCL,   CWORD,
12121       CSPCL,   CWORD,   CWORD,   CWORD,
12122       CWORD,   CWORD,   CWORD,   CWORD,
12123       CWORD,   CWORD,   CWORD,   CWORD,
12124       CWORD,   CWORD,   CWORD,   CWORD,
12125       CWORD,   CWORD,   CWORD,   CWORD,
12126       CWORD,   CWORD,   CWORD,   CWORD,
12127       CWORD,   CWORD,   CWORD,   CWORD,
12128       CWORD,   CWORD,   CBACK,   CWORD,
12129       CWORD,   CWORD,   CBQUOTE, CWORD,
12130       CWORD,   CWORD,   CWORD,   CWORD,
12131       CWORD,   CWORD,   CWORD,   CWORD,
12132       CWORD,   CWORD,   CWORD,   CWORD,
12133       CWORD,   CWORD,   CWORD,   CWORD,
12134       CWORD,   CWORD,   CWORD,   CWORD,
12135       CWORD,   CWORD,   CWORD,   CWORD,
12136       CWORD,   CWORD,   CSPCL,   CENDVAR,
12137       CWORD
12138 };
12139
12140 /* syntax table used when in double quotes */
12141 static const char dqsyntax[257] = {
12142       CEOF,    CIGN,    CWORD,   CCTL,
12143       CCTL,    CCTL,    CCTL,    CCTL,
12144       CCTL,    CCTL,    CCTL,    CWORD,
12145       CWORD,   CWORD,   CWORD,   CWORD,
12146       CWORD,   CWORD,   CWORD,   CWORD,
12147       CWORD,   CWORD,   CWORD,   CWORD,
12148       CWORD,   CWORD,   CWORD,   CWORD,
12149       CWORD,   CWORD,   CWORD,   CWORD,
12150       CWORD,   CWORD,   CWORD,   CWORD,
12151       CWORD,   CWORD,   CWORD,   CWORD,
12152       CWORD,   CWORD,   CWORD,   CWORD,
12153       CWORD,   CWORD,   CWORD,   CWORD,
12154       CWORD,   CWORD,   CWORD,   CWORD,
12155       CWORD,   CWORD,   CWORD,   CWORD,
12156       CWORD,   CWORD,   CWORD,   CWORD,
12157       CWORD,   CWORD,   CWORD,   CWORD,
12158       CWORD,   CWORD,   CWORD,   CWORD,
12159       CWORD,   CWORD,   CWORD,   CWORD,
12160       CWORD,   CWORD,   CWORD,   CWORD,
12161       CWORD,   CWORD,   CWORD,   CWORD,
12162       CWORD,   CWORD,   CWORD,   CWORD,
12163       CWORD,   CWORD,   CWORD,   CWORD,
12164       CWORD,   CWORD,   CWORD,   CWORD,
12165       CWORD,   CWORD,   CWORD,   CWORD,
12166       CWORD,   CWORD,   CWORD,   CWORD,
12167       CWORD,   CWORD,   CWORD,   CWORD,
12168       CWORD,   CWORD,   CWORD,   CWORD,
12169       CWORD,   CWORD,   CWORD,   CWORD,
12170       CWORD,   CWORD,   CWORD,   CWORD,
12171       CWORD,   CWORD,   CWORD,   CWORD,
12172       CWORD,   CWORD,   CWORD,   CWORD,
12173       CWORD,   CWORD,   CWORD,   CWORD,
12174       CWORD,   CWORD,   CWORD,   CWORD,
12175       CWORD,   CWORD,   CWORD,   CWORD,
12176       CWORD,   CWORD,   CWORD,   CWORD,
12177       CNL,     CWORD,   CWORD,   CWORD,
12178       CWORD,   CWORD,   CWORD,   CWORD,
12179       CWORD,   CWORD,   CWORD,   CWORD,
12180       CWORD,   CWORD,   CWORD,   CWORD,
12181       CWORD,   CWORD,   CWORD,   CWORD,
12182       CWORD,   CWORD,   CWORD,   CCTL,
12183       CENDQUOTE,CWORD,  CVAR,    CWORD,
12184       CWORD,   CWORD,   CWORD,   CWORD,
12185       CCTL,    CWORD,   CWORD,   CCTL,
12186       CWORD,   CCTL,    CWORD,   CWORD,
12187       CWORD,   CWORD,   CWORD,   CWORD,
12188       CWORD,   CWORD,   CWORD,   CWORD,
12189       CCTL,    CWORD,   CWORD,   CCTL,
12190       CWORD,   CCTL,    CWORD,   CWORD,
12191       CWORD,   CWORD,   CWORD,   CWORD,
12192       CWORD,   CWORD,   CWORD,   CWORD,
12193       CWORD,   CWORD,   CWORD,   CWORD,
12194       CWORD,   CWORD,   CWORD,   CWORD,
12195       CWORD,   CWORD,   CWORD,   CWORD,
12196       CWORD,   CWORD,   CWORD,   CWORD,
12197       CWORD,   CCTL,    CBACK,   CCTL,
12198       CWORD,   CWORD,   CBQUOTE, CWORD,
12199       CWORD,   CWORD,   CWORD,   CWORD,
12200       CWORD,   CWORD,   CWORD,   CWORD,
12201       CWORD,   CWORD,   CWORD,   CWORD,
12202       CWORD,   CWORD,   CWORD,   CWORD,
12203       CWORD,   CWORD,   CWORD,   CWORD,
12204       CWORD,   CWORD,   CWORD,   CWORD,
12205       CWORD,   CWORD,   CWORD,   CENDVAR,
12206       CCTL
12207 };
12208
12209 /* syntax table used when in single quotes */
12210 static const char sqsyntax[257] = {
12211       CEOF,    CIGN,    CWORD,   CCTL,
12212       CCTL,    CCTL,    CCTL,    CCTL,
12213       CCTL,    CCTL,    CCTL,    CWORD,
12214       CWORD,   CWORD,   CWORD,   CWORD,
12215       CWORD,   CWORD,   CWORD,   CWORD,
12216       CWORD,   CWORD,   CWORD,   CWORD,
12217       CWORD,   CWORD,   CWORD,   CWORD,
12218       CWORD,   CWORD,   CWORD,   CWORD,
12219       CWORD,   CWORD,   CWORD,   CWORD,
12220       CWORD,   CWORD,   CWORD,   CWORD,
12221       CWORD,   CWORD,   CWORD,   CWORD,
12222       CWORD,   CWORD,   CWORD,   CWORD,
12223       CWORD,   CWORD,   CWORD,   CWORD,
12224       CWORD,   CWORD,   CWORD,   CWORD,
12225       CWORD,   CWORD,   CWORD,   CWORD,
12226       CWORD,   CWORD,   CWORD,   CWORD,
12227       CWORD,   CWORD,   CWORD,   CWORD,
12228       CWORD,   CWORD,   CWORD,   CWORD,
12229       CWORD,   CWORD,   CWORD,   CWORD,
12230       CWORD,   CWORD,   CWORD,   CWORD,
12231       CWORD,   CWORD,   CWORD,   CWORD,
12232       CWORD,   CWORD,   CWORD,   CWORD,
12233       CWORD,   CWORD,   CWORD,   CWORD,
12234       CWORD,   CWORD,   CWORD,   CWORD,
12235       CWORD,   CWORD,   CWORD,   CWORD,
12236       CWORD,   CWORD,   CWORD,   CWORD,
12237       CWORD,   CWORD,   CWORD,   CWORD,
12238       CWORD,   CWORD,   CWORD,   CWORD,
12239       CWORD,   CWORD,   CWORD,   CWORD,
12240       CWORD,   CWORD,   CWORD,   CWORD,
12241       CWORD,   CWORD,   CWORD,   CWORD,
12242       CWORD,   CWORD,   CWORD,   CWORD,
12243       CWORD,   CWORD,   CWORD,   CWORD,
12244       CWORD,   CWORD,   CWORD,   CWORD,
12245       CWORD,   CWORD,   CWORD,   CWORD,
12246       CNL,     CWORD,   CWORD,   CWORD,
12247       CWORD,   CWORD,   CWORD,   CWORD,
12248       CWORD,   CWORD,   CWORD,   CWORD,
12249       CWORD,   CWORD,   CWORD,   CWORD,
12250       CWORD,   CWORD,   CWORD,   CWORD,
12251       CWORD,   CWORD,   CWORD,   CCTL,
12252       CWORD,   CWORD,   CWORD,   CWORD,
12253       CWORD,   CENDQUOTE,CWORD,  CWORD,
12254       CCTL,    CWORD,   CWORD,   CCTL,
12255       CWORD,   CCTL,    CWORD,   CWORD,
12256       CWORD,   CWORD,   CWORD,   CWORD,
12257       CWORD,   CWORD,   CWORD,   CWORD,
12258       CCTL,    CWORD,   CWORD,   CCTL,
12259       CWORD,   CCTL,    CWORD,   CWORD,
12260       CWORD,   CWORD,   CWORD,   CWORD,
12261       CWORD,   CWORD,   CWORD,   CWORD,
12262       CWORD,   CWORD,   CWORD,   CWORD,
12263       CWORD,   CWORD,   CWORD,   CWORD,
12264       CWORD,   CWORD,   CWORD,   CWORD,
12265       CWORD,   CWORD,   CWORD,   CWORD,
12266       CWORD,   CCTL,    CCTL,    CCTL,
12267       CWORD,   CWORD,   CWORD,   CWORD,
12268       CWORD,   CWORD,   CWORD,   CWORD,
12269       CWORD,   CWORD,   CWORD,   CWORD,
12270       CWORD,   CWORD,   CWORD,   CWORD,
12271       CWORD,   CWORD,   CWORD,   CWORD,
12272       CWORD,   CWORD,   CWORD,   CWORD,
12273       CWORD,   CWORD,   CWORD,   CWORD,
12274       CWORD,   CWORD,   CWORD,   CWORD,
12275       CCTL
12276 };
12277
12278 /* syntax table used when in arithmetic */
12279 static const char arisyntax[257] = {
12280       CEOF,    CIGN,    CWORD,   CCTL,
12281       CCTL,    CCTL,    CCTL,    CCTL,
12282       CCTL,    CCTL,    CCTL,    CWORD,
12283       CWORD,   CWORD,   CWORD,   CWORD,
12284       CWORD,   CWORD,   CWORD,   CWORD,
12285       CWORD,   CWORD,   CWORD,   CWORD,
12286       CWORD,   CWORD,   CWORD,   CWORD,
12287       CWORD,   CWORD,   CWORD,   CWORD,
12288       CWORD,   CWORD,   CWORD,   CWORD,
12289       CWORD,   CWORD,   CWORD,   CWORD,
12290       CWORD,   CWORD,   CWORD,   CWORD,
12291       CWORD,   CWORD,   CWORD,   CWORD,
12292       CWORD,   CWORD,   CWORD,   CWORD,
12293       CWORD,   CWORD,   CWORD,   CWORD,
12294       CWORD,   CWORD,   CWORD,   CWORD,
12295       CWORD,   CWORD,   CWORD,   CWORD,
12296       CWORD,   CWORD,   CWORD,   CWORD,
12297       CWORD,   CWORD,   CWORD,   CWORD,
12298       CWORD,   CWORD,   CWORD,   CWORD,
12299       CWORD,   CWORD,   CWORD,   CWORD,
12300       CWORD,   CWORD,   CWORD,   CWORD,
12301       CWORD,   CWORD,   CWORD,   CWORD,
12302       CWORD,   CWORD,   CWORD,   CWORD,
12303       CWORD,   CWORD,   CWORD,   CWORD,
12304       CWORD,   CWORD,   CWORD,   CWORD,
12305       CWORD,   CWORD,   CWORD,   CWORD,
12306       CWORD,   CWORD,   CWORD,   CWORD,
12307       CWORD,   CWORD,   CWORD,   CWORD,
12308       CWORD,   CWORD,   CWORD,   CWORD,
12309       CWORD,   CWORD,   CWORD,   CWORD,
12310       CWORD,   CWORD,   CWORD,   CWORD,
12311       CWORD,   CWORD,   CWORD,   CWORD,
12312       CWORD,   CWORD,   CWORD,   CWORD,
12313       CWORD,   CWORD,   CWORD,   CWORD,
12314       CWORD,   CWORD,   CWORD,   CWORD,
12315       CNL,     CWORD,   CWORD,   CWORD,
12316       CWORD,   CWORD,   CWORD,   CWORD,
12317       CWORD,   CWORD,   CWORD,   CWORD,
12318       CWORD,   CWORD,   CWORD,   CWORD,
12319       CWORD,   CWORD,   CWORD,   CWORD,
12320       CWORD,   CWORD,   CWORD,   CWORD,
12321       CDQUOTE, CWORD,   CVAR,    CWORD,
12322       CWORD,   CSQUOTE, CLP,     CRP,
12323       CWORD,   CWORD,   CWORD,   CWORD,
12324       CWORD,   CWORD,   CWORD,   CWORD,
12325       CWORD,   CWORD,   CWORD,   CWORD,
12326       CWORD,   CWORD,   CWORD,   CWORD,
12327       CWORD,   CWORD,   CWORD,   CWORD,
12328       CWORD,   CWORD,   CWORD,   CWORD,
12329       CWORD,   CWORD,   CWORD,   CWORD,
12330       CWORD,   CWORD,   CWORD,   CWORD,
12331       CWORD,   CWORD,   CWORD,   CWORD,
12332       CWORD,   CWORD,   CWORD,   CWORD,
12333       CWORD,   CWORD,   CWORD,   CWORD,
12334       CWORD,   CWORD,   CWORD,   CWORD,
12335       CWORD,   CWORD,   CBACK,   CWORD,
12336       CWORD,   CWORD,   CBQUOTE, CWORD,
12337       CWORD,   CWORD,   CWORD,   CWORD,
12338       CWORD,   CWORD,   CWORD,   CWORD,
12339       CWORD,   CWORD,   CWORD,   CWORD,
12340       CWORD,   CWORD,   CWORD,   CWORD,
12341       CWORD,   CWORD,   CWORD,   CWORD,
12342       CWORD,   CWORD,   CWORD,   CWORD,
12343       CWORD,   CWORD,   CWORD,   CENDVAR,
12344       CWORD
12345 };
12346
12347 /* character classification table */
12348 static const char is_type[257] = {
12349       0,       0,       0,       0,
12350       0,       0,       0,       0,
12351       0,       0,       0,       0,
12352       0,       0,       0,       0,
12353       0,       0,       0,       0,
12354       0,       0,       0,       0,
12355       0,       0,       0,       0,
12356       0,       0,       0,       0,
12357       0,       0,       0,       0,
12358       0,       0,       0,       0,
12359       0,       0,       0,       0,
12360       0,       0,       0,       0,
12361       0,       0,       0,       0,
12362       0,       0,       0,       0,
12363       0,       0,       0,       0,
12364       0,       0,       0,       0,
12365       0,       0,       0,       0,
12366       0,       0,       0,       0,
12367       0,       0,       0,       0,
12368       0,       0,       0,       0,
12369       0,       0,       0,       0,
12370       0,       0,       0,       0,
12371       0,       0,       0,       0,
12372       0,       0,       0,       0,
12373       0,       0,       0,       0,
12374       0,       0,       0,       0,
12375       0,       0,       0,       0,
12376       0,       0,       0,       0,
12377       0,       0,       0,       0,
12378       0,       0,       0,       0,
12379       0,       0,       0,       0,
12380       0,       0,       0,       0,
12381       0,       0,       0,       0,
12382       0,       0,       0,       0,
12383       0,       0,       0,       0,
12384       0,       0,       0,       0,
12385       0,       0,       0,       0,
12386       0,       0,       0,       0,
12387       0,       0,       0,       0,
12388       0,       0,       0,       0,
12389       0,       0,       0,       ISSPECL,
12390       0,       ISSPECL, ISSPECL, 0,
12391       0,       0,       0,       0,
12392       ISSPECL, 0,       0,       ISSPECL,
12393       0,       0,       ISDIGIT, ISDIGIT,
12394       ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12395       ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
12396       0,       0,       0,       0,
12397       0,       ISSPECL, ISSPECL, ISUPPER,
12398       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12399       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12400       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12401       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12402       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12403       ISUPPER, ISUPPER, ISUPPER, ISUPPER,
12404       ISUPPER, 0,       0,       0,
12405       0,       ISUNDER, 0,       ISLOWER,
12406       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12407       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12408       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12409       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12410       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12411       ISLOWER, ISLOWER, ISLOWER, ISLOWER,
12412       ISLOWER, 0,       0,       0,
12413       0
12414 };
12415 /*      $NetBSD: trap.c,v 1.25 2001/02/04 19:52:07 christos Exp $       */
12416
12417 /*
12418  * The trap builtin.
12419  */
12420
12421 static int
12422 trapcmd(argc, argv)
12423         int argc;
12424         char **argv;
12425 {
12426         char *action;
12427         char **ap;
12428         int signo;
12429
12430         if (argc <= 1) {
12431                 for (signo = 0 ; signo < NSIG ; signo++) {
12432                         if (trap[signo] != NULL) {
12433                                 char *p;
12434
12435                                 p = single_quote(trap[signo]);
12436                                 out1fmt("trap -- %s %s\n", p,
12437                                         signal_names[signo] + (signo ? 3 : 0)
12438                                 );
12439                                 stunalloc(p);
12440                         }
12441                 }
12442                 return 0;
12443         }
12444         ap = argv + 1;
12445         if (argc == 2)
12446                 action = NULL;
12447         else
12448                 action = *ap++;
12449         while (*ap) {
12450                 if ((signo = decode_signal(*ap, 0)) < 0)
12451                         error("%s: bad trap", *ap);
12452                 INTOFF;
12453                 if (action) {
12454                         if (action[0] == '-' && action[1] == '\0')
12455                                 action = NULL;
12456                         else
12457                                 action = savestr(action);
12458                 }
12459                 if (trap[signo])
12460                         ckfree(trap[signo]);
12461                 trap[signo] = action;
12462                 if (signo != 0)
12463                         setsignal(signo);
12464                 INTON;
12465                 ap++;
12466         }
12467         return 0;
12468 }
12469
12470
12471
12472 /*
12473  * Clear traps on a fork.
12474  */
12475
12476 static void
12477 clear_traps() {
12478         char **tp;
12479
12480         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
12481                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
12482                         INTOFF;
12483                         ckfree(*tp);
12484                         *tp = NULL;
12485                         if (tp != &trap[0])
12486                                 setsignal(tp - trap);
12487                         INTON;
12488                 }
12489         }
12490 }
12491
12492
12493
12494 /*
12495  * Set the signal handler for the specified signal.  The routine figures
12496  * out what it should be set to.
12497  */
12498
12499 static void
12500 setsignal(signo)
12501         int signo;
12502 {
12503         int action;
12504         char *t;
12505         struct sigaction act;
12506
12507         if ((t = trap[signo]) == NULL)
12508                 action = S_DFL;
12509         else if (*t != '\0')
12510                 action = S_CATCH;
12511         else
12512                 action = S_IGN;
12513         if (rootshell && action == S_DFL) {
12514                 switch (signo) {
12515                 case SIGINT:
12516                         if (iflag || minusc || sflag == 0)
12517                                 action = S_CATCH;
12518                         break;
12519                 case SIGQUIT:
12520 #ifdef DEBUG
12521                         {
12522                         extern int debug;
12523
12524                         if (debug)
12525                                 break;
12526                         }
12527 #endif
12528                         /* FALLTHROUGH */
12529                 case SIGTERM:
12530                         if (iflag)
12531                                 action = S_IGN;
12532                         break;
12533 #if JOBS
12534                 case SIGTSTP:
12535                 case SIGTTOU:
12536                         if (mflag)
12537                                 action = S_IGN;
12538                         break;
12539 #endif
12540                 }
12541         }
12542
12543         t = &sigmode[signo - 1];
12544         if (*t == 0) {
12545                 /*
12546                  * current setting unknown
12547                  */
12548                 if (sigaction(signo, 0, &act) == -1) {
12549                         /*
12550                          * Pretend it worked; maybe we should give a warning
12551                          * here, but other shells don't. We don't alter
12552                          * sigmode, so that we retry every time.
12553                          */
12554                         return;
12555                 }
12556                 if (act.sa_handler == SIG_IGN) {
12557                         if (mflag && (signo == SIGTSTP ||
12558                              signo == SIGTTIN || signo == SIGTTOU)) {
12559                                 *t = S_IGN;     /* don't hard ignore these */
12560                         } else
12561                                 *t = S_HARD_IGN;
12562                 } else {
12563                         *t = S_RESET;   /* force to be set */
12564                 }
12565         }
12566         if (*t == S_HARD_IGN || *t == action)
12567                 return;
12568         switch (action) {
12569         case S_CATCH:
12570                 act.sa_handler = onsig;
12571                 break;
12572         case S_IGN:
12573                 act.sa_handler = SIG_IGN;
12574                 break;
12575         default:
12576                 act.sa_handler = SIG_DFL;
12577         }
12578         *t = action;
12579         act.sa_flags = 0;
12580         sigemptyset(&act.sa_mask);
12581         sigaction(signo, &act, 0);
12582 }
12583
12584 /*
12585  * Ignore a signal.
12586  */
12587
12588 static void
12589 ignoresig(signo)
12590         int signo;
12591 {
12592         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12593                 signal(signo, SIG_IGN);
12594         }
12595         sigmode[signo - 1] = S_HARD_IGN;
12596 }
12597
12598
12599 #ifdef mkinit
12600 INCLUDE <signal.h>
12601 INCLUDE "trap.h"
12602
12603 SHELLPROC {
12604         char *sm;
12605
12606         clear_traps();
12607         for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
12608                 if (*sm == S_IGN)
12609                         *sm = S_HARD_IGN;
12610         }
12611 }
12612 #endif
12613
12614
12615
12616 /*
12617  * Signal handler.
12618  */
12619
12620 static void
12621 onsig(signo)
12622         int signo;
12623 {
12624         if (signo == SIGINT && trap[SIGINT] == NULL) {
12625                 onint();
12626                 return;
12627         }
12628         gotsig[signo - 1] = 1;
12629         pendingsigs++;
12630 }
12631
12632
12633
12634 /*
12635  * Called to execute a trap.  Perhaps we should avoid entering new trap
12636  * handlers while we are executing a trap handler.
12637  */
12638
12639 static void
12640 dotrap() {
12641         int i;
12642         int savestatus;
12643
12644         for (;;) {
12645                 for (i = 1 ; ; i++) {
12646                         if (gotsig[i - 1])
12647                                 break;
12648                         if (i >= NSIG - 1)
12649                                 goto done;
12650                 }
12651                 gotsig[i - 1] = 0;
12652                 savestatus=exitstatus;
12653                 evalstring(trap[i], 0);
12654                 exitstatus=savestatus;
12655         }
12656 done:
12657         pendingsigs = 0;
12658 }
12659
12660
12661
12662 /*
12663  * Controls whether the shell is interactive or not.
12664  */
12665
12666
12667 static void
12668 setinteractive(on)
12669         int on;
12670 {
12671         static int is_interactive;
12672
12673         if (on == is_interactive)
12674                 return;
12675         setsignal(SIGINT);
12676         setsignal(SIGQUIT);
12677         setsignal(SIGTERM);
12678         chkmail(1);
12679         is_interactive = on;
12680 }
12681
12682
12683
12684 /*
12685  * Called to exit the shell.
12686  */
12687
12688 static void
12689 exitshell(status)
12690         int status;
12691 {
12692         struct jmploc loc1, loc2;
12693         char *p;
12694
12695         TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12696         if (setjmp(loc1.loc)) {
12697                 goto l1;
12698         }
12699         if (setjmp(loc2.loc)) {
12700                 goto l2;
12701         }
12702         handler = &loc1;
12703         if ((p = trap[0]) != NULL && *p != '\0') {
12704                 trap[0] = NULL;
12705                 evalstring(p, 0);
12706         }
12707 l1:   handler = &loc2;                  /* probably unnecessary */
12708         flushall();
12709 #if JOBS
12710         setjobctl(0);
12711 #endif
12712 l2:   _exit(status);
12713         /* NOTREACHED */
12714 }
12715
12716 static int decode_signal(const char *string, int minsig)
12717 {
12718         int signo;
12719
12720         if (is_number(string)) {
12721                 signo = atoi(string);
12722                 if (signo >= NSIG) {
12723                         return -1;
12724                 }
12725                 return signo;
12726         }
12727
12728         signo = minsig;
12729         if (!signo) {
12730                 goto zero;
12731         }
12732         for (; signo < NSIG; signo++) {
12733                 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12734                         return signo;
12735                 }
12736 zero:
12737                 if (!strcasecmp(string, signal_names[signo])) {
12738                         return signo;
12739                 }
12740         }
12741
12742         return -1;
12743 }
12744 /*      $NetBSD: var.c,v 1.27 2001/02/04 19:52:07 christos Exp $        */
12745
12746 #define VTABSIZE 39
12747
12748
12749 struct varinit {
12750         struct var *var;
12751         int flags;
12752         const char *text;
12753         void (*func) __P((const char *));
12754 };
12755
12756 struct localvar *localvars;
12757
12758 #if ATTY
12759 struct var vatty;
12760 #endif
12761 struct var vifs;
12762 struct var vmail;
12763 struct var vmpath;
12764 struct var vpath;
12765 struct var vps1;
12766 struct var vps2;
12767 struct var vvers;
12768 struct var voptind;
12769
12770 static const char defpathvar[] =
12771         "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
12772 #ifdef IFS_BROKEN
12773 static const char defifsvar[] = "IFS= \t\n";
12774 #else
12775 static const char defifs[] = " \t\n";
12776 #endif
12777
12778 static const struct varinit varinit[] = {
12779 #if ATTY
12780         { &vatty,       VSTRFIXED|VTEXTFIXED|VUNSET,    "ATTY=",
12781           NULL },
12782 #endif
12783 #ifdef IFS_BROKEN
12784         { &vifs,        VSTRFIXED|VTEXTFIXED,           defifsvar,
12785 #else
12786         { &vifs,        VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS=",
12787 #endif
12788           NULL },
12789         { &vmail,       VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL=",
12790           NULL },
12791         { &vmpath,      VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH=",
12792           NULL },
12793         { &vpath,       VSTRFIXED|VTEXTFIXED,           defpathvar,
12794           changepath },
12795         /*
12796          * vps1 depends on uid
12797          */
12798         { &vps2,        VSTRFIXED|VTEXTFIXED,           "PS2=> ",
12799           NULL },
12800         { &voptind,     VSTRFIXED|VTEXTFIXED,           "OPTIND=1",
12801           getoptsreset },
12802         { NULL, 0,                              NULL,
12803           NULL }
12804 };
12805
12806 struct var *vartab[VTABSIZE];
12807
12808 static struct var **hashvar __P((const char *));
12809 static void showvars __P((const char *, int, int));
12810 static struct var **findvar __P((struct var **, const char *));
12811
12812 /*
12813  * Initialize the varable symbol tables and import the environment
12814  */
12815
12816 #ifdef mkinit
12817 INCLUDE <unistd.h>
12818 INCLUDE "output.h"
12819 INCLUDE "var.h"
12820 static char **environ;
12821 INIT {
12822         char **envp;
12823         char ppid[32];
12824
12825         initvar();
12826         for (envp = environ ; *envp ; envp++) {
12827                 if (strchr(*envp, '=')) {
12828                         setvareq(*envp, VEXPORT|VTEXTFIXED);
12829                 }
12830         }
12831
12832         fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
12833         setvar("PPID", ppid, 0);
12834 }
12835 #endif
12836
12837
12838 /*
12839  * This routine initializes the builtin variables.  It is called when the
12840  * shell is initialized and again when a shell procedure is spawned.
12841  */
12842
12843 static void
12844 initvar() {
12845         const struct varinit *ip;
12846         struct var *vp;
12847         struct var **vpp;
12848
12849         for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12850                 if ((vp->flags & VEXPORT) == 0) {
12851                         vpp = hashvar(ip->text);
12852                         vp->next = *vpp;
12853                         *vpp = vp;
12854                         vp->text = strdup(ip->text);
12855                         vp->flags = ip->flags;
12856                         vp->func = ip->func;
12857                 }
12858         }
12859         /*
12860          * PS1 depends on uid
12861          */
12862         if ((vps1.flags & VEXPORT) == 0) {
12863                 vpp = hashvar("PS1=");
12864                 vps1.next = *vpp;
12865                 *vpp = &vps1;
12866                 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12867                 vps1.flags = VSTRFIXED|VTEXTFIXED;
12868         }
12869 }
12870
12871 /*
12872  * Set the value of a variable.  The flags argument is ored with the
12873  * flags of the variable.  If val is NULL, the variable is unset.
12874  */
12875
12876 static void
12877 setvar(name, val, flags)
12878         const char *name, *val;
12879         int flags;
12880 {
12881         const char *p;
12882         int len;
12883         int namelen;
12884         char *nameeq;
12885         int isbad;
12886         int vallen = 0;
12887
12888         isbad = 0;
12889         p = name;
12890         if (! is_name(*p))
12891                 isbad = 1;
12892         p++;
12893         for (;;) {
12894                 if (! is_in_name(*p)) {
12895                         if (*p == '\0' || *p == '=')
12896                                 break;
12897                         isbad = 1;
12898                 }
12899                 p++;
12900         }
12901         namelen = p - name;
12902         if (isbad)
12903                 error("%.*s: bad variable name", namelen, name);
12904         len = namelen + 2;              /* 2 is space for '=' and '\0' */
12905         if (val == NULL) {
12906                 flags |= VUNSET;
12907         } else {
12908                 len += vallen = strlen(val);
12909         }
12910         INTOFF;
12911         nameeq = ckmalloc(len);
12912         memcpy(nameeq, name, namelen);
12913         nameeq[namelen] = '=';
12914         if (val) {
12915                 memcpy(nameeq + namelen + 1, val, vallen + 1);
12916         } else {
12917                 nameeq[namelen + 1] = '\0';
12918         }
12919         setvareq(nameeq, flags);
12920         INTON;
12921 }
12922
12923
12924
12925 /*
12926  * Same as setvar except that the variable and value are passed in
12927  * the first argument as name=value.  Since the first argument will
12928  * be actually stored in the table, it should not be a string that
12929  * will go away.
12930  */
12931
12932 static void
12933 setvareq(s, flags)
12934         char *s;
12935         int flags;
12936 {
12937         struct var *vp, **vpp;
12938
12939         vpp = hashvar(s);
12940         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12941         if ((vp = *findvar(vpp, s))) {
12942                 if (vp->flags & VREADONLY) {
12943                         size_t len = strchr(s, '=') - s;
12944                         error("%.*s: is read only", len, s);
12945                 }
12946                 INTOFF;
12947
12948                 if (vp->func && (flags & VNOFUNC) == 0)
12949                         (*vp->func)(strchr(s, '=') + 1);
12950
12951                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12952                         ckfree(vp->text);
12953
12954                 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12955                 vp->flags |= flags;
12956                 vp->text = s;
12957
12958                 /*
12959                  * We could roll this to a function, to handle it as
12960                  * a regular variable function callback, but why bother?
12961                  */
12962                 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12963                         chkmail(1);
12964                 INTON;
12965                 return;
12966         }
12967         /* not found */
12968         vp = ckmalloc(sizeof (*vp));
12969         vp->flags = flags;
12970         vp->text = s;
12971         vp->next = *vpp;
12972         vp->func = NULL;
12973         *vpp = vp;
12974 }
12975
12976
12977
12978 /*
12979  * Process a linked list of variable assignments.
12980  */
12981
12982 static void
12983 listsetvar(mylist)
12984         struct strlist *mylist;
12985         {
12986         struct strlist *lp;
12987
12988         INTOFF;
12989         for (lp = mylist ; lp ; lp = lp->next) {
12990                 setvareq(savestr(lp->text), 0);
12991         }
12992         INTON;
12993 }
12994
12995
12996
12997 /*
12998  * Find the value of a variable.  Returns NULL if not set.
12999  */
13000
13001 static char *
13002 lookupvar(name)
13003         const char *name;
13004         {
13005         struct var *v;
13006
13007         if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13008                 return strchr(v->text, '=') + 1;
13009         }
13010         return NULL;
13011 }
13012
13013
13014
13015 /*
13016  * Search the environment of a builtin command.
13017  */
13018
13019 static char *
13020 bltinlookup(name)
13021         const char *name;
13022 {
13023         struct strlist *sp;
13024
13025         for (sp = cmdenviron ; sp ; sp = sp->next) {
13026                 if (varequal(sp->text, name))
13027                         return strchr(sp->text, '=') + 1;
13028         }
13029         return lookupvar(name);
13030 }
13031
13032
13033
13034 /*
13035  * Generate a list of exported variables.  This routine is used to construct
13036  * the third argument to execve when executing a program.
13037  */
13038
13039 static char **
13040 environment() {
13041         int nenv;
13042         struct var **vpp;
13043         struct var *vp;
13044         char **env;
13045         char **ep;
13046
13047         nenv = 0;
13048         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13049                 for (vp = *vpp ; vp ; vp = vp->next)
13050                         if (vp->flags & VEXPORT)
13051                                 nenv++;
13052         }
13053         ep = env = stalloc((nenv + 1) * sizeof *env);
13054         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13055                 for (vp = *vpp ; vp ; vp = vp->next)
13056                         if (vp->flags & VEXPORT)
13057                                 *ep++ = vp->text;
13058         }
13059         *ep = NULL;
13060         return env;
13061 }
13062
13063
13064 /*
13065  * Called when a shell procedure is invoked to clear out nonexported
13066  * variables.  It is also necessary to reallocate variables of with
13067  * VSTACK set since these are currently allocated on the stack.
13068  */
13069
13070 #ifdef mkinit
13071 static void shprocvar __P((void));
13072
13073 SHELLPROC {
13074         shprocvar();
13075 }
13076 #endif
13077
13078 static void
13079 shprocvar() {
13080         struct var **vpp;
13081         struct var *vp, **prev;
13082
13083         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13084                 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13085                         if ((vp->flags & VEXPORT) == 0) {
13086                                 *prev = vp->next;
13087                                 if ((vp->flags & VTEXTFIXED) == 0)
13088                                         ckfree(vp->text);
13089                                 if ((vp->flags & VSTRFIXED) == 0)
13090                                         ckfree(vp);
13091                         } else {
13092                                 if (vp->flags & VSTACK) {
13093                                         vp->text = savestr(vp->text);
13094                                         vp->flags &=~ VSTACK;
13095                                 }
13096                                 prev = &vp->next;
13097                         }
13098                 }
13099         }
13100         initvar();
13101 }
13102
13103
13104
13105 /*
13106  * Command to list all variables which are set.  Currently this command
13107  * is invoked from the set command when the set command is called without
13108  * any variables.
13109  */
13110
13111 static int
13112 showvarscmd(argc, argv)
13113         int argc;
13114         char **argv;
13115 {
13116         showvars(nullstr, VUNSET, VUNSET);
13117         return 0;
13118 }
13119
13120
13121
13122 /*
13123  * The export and readonly commands.
13124  */
13125
13126 static int
13127 exportcmd(argc, argv)
13128         int argc;
13129         char **argv;
13130 {
13131         struct var *vp;
13132         char *name;
13133         const char *p;
13134         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13135         int pflag;
13136
13137         listsetvar(cmdenviron);
13138         pflag = (nextopt("p") == 'p');
13139         if (argc > 1 && !pflag) {
13140                 while ((name = *argptr++) != NULL) {
13141                         if ((p = strchr(name, '=')) != NULL) {
13142                                 p++;
13143                         } else {
13144                                 if ((vp = *findvar(hashvar(name), name))) {
13145                                         vp->flags |= flag;
13146                                         goto found;
13147                                 }
13148                         }
13149                         setvar(name, p, flag);
13150 found:;
13151                 }
13152         } else {
13153                 showvars(argv[0], flag, 0);
13154         }
13155         return 0;
13156 }
13157
13158
13159 /*
13160  * The "local" command.
13161  */
13162
13163 static int
13164 localcmd(argc, argv)
13165         int argc;
13166         char **argv;
13167 {
13168         char *name;
13169
13170         if (! in_function())
13171                 error("Not in a function");
13172         while ((name = *argptr++) != NULL) {
13173                 mklocal(name);
13174         }
13175         return 0;
13176 }
13177
13178
13179 /*
13180  * Make a variable a local variable.  When a variable is made local, it's
13181  * value and flags are saved in a localvar structure.  The saved values
13182  * will be restored when the shell function returns.  We handle the name
13183  * "-" as a special case.
13184  */
13185
13186 static void
13187 mklocal(name)
13188         char *name;
13189         {
13190         struct localvar *lvp;
13191         struct var **vpp;
13192         struct var *vp;
13193
13194         INTOFF;
13195         lvp = ckmalloc(sizeof (struct localvar));
13196         if (name[0] == '-' && name[1] == '\0') {
13197                 char *p;
13198                 p = ckmalloc(sizeof optlist);
13199                 lvp->text = memcpy(p, optlist, sizeof optlist);
13200                 vp = NULL;
13201         } else {
13202                 vpp = hashvar(name);
13203                 vp = *findvar(vpp, name);
13204                 if (vp == NULL) {
13205                         if (strchr(name, '='))
13206                                 setvareq(savestr(name), VSTRFIXED);
13207                         else
13208                                 setvar(name, NULL, VSTRFIXED);
13209                         vp = *vpp;      /* the new variable */
13210                         lvp->text = NULL;
13211                         lvp->flags = VUNSET;
13212                 } else {
13213                         lvp->text = vp->text;
13214                         lvp->flags = vp->flags;
13215                         vp->flags |= VSTRFIXED|VTEXTFIXED;
13216                         if (strchr(name, '='))
13217                                 setvareq(savestr(name), 0);
13218                 }
13219         }
13220         lvp->vp = vp;
13221         lvp->next = localvars;
13222         localvars = lvp;
13223         INTON;
13224 }
13225
13226
13227 /*
13228  * Called after a function returns.
13229  */
13230
13231 static void
13232 poplocalvars() {
13233         struct localvar *lvp;
13234         struct var *vp;
13235
13236         while ((lvp = localvars) != NULL) {
13237                 localvars = lvp->next;
13238                 vp = lvp->vp;
13239                 if (vp == NULL) {       /* $- saved */
13240                         memcpy(optlist, lvp->text, sizeof optlist);
13241                         ckfree(lvp->text);
13242                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13243                         (void)unsetvar(vp->text);
13244                 } else {
13245                         if ((vp->flags & VTEXTFIXED) == 0)
13246                                 ckfree(vp->text);
13247                         vp->flags = lvp->flags;
13248                         vp->text = lvp->text;
13249                 }
13250                 ckfree(lvp);
13251         }
13252 }
13253
13254
13255 static int
13256 setvarcmd(argc, argv)
13257         int argc;
13258         char **argv;
13259 {
13260         if (argc <= 2)
13261                 return unsetcmd(argc, argv);
13262         else if (argc == 3)
13263                 setvar(argv[1], argv[2], 0);
13264         else
13265                 error("List assignment not implemented");
13266         return 0;
13267 }
13268
13269
13270 /*
13271  * The unset builtin command.  We unset the function before we unset the
13272  * variable to allow a function to be unset when there is a readonly variable
13273  * with the same name.
13274  */
13275
13276 static int
13277 unsetcmd(argc, argv)
13278         int argc;
13279         char **argv;
13280 {
13281         char **ap;
13282         int i;
13283         int flg_func = 0;
13284         int flg_var = 0;
13285         int ret = 0;
13286
13287         while ((i = nextopt("vf")) != '\0') {
13288                 if (i == 'f')
13289                         flg_func = 1;
13290                 else
13291                         flg_var = 1;
13292         }
13293         if (flg_func == 0 && flg_var == 0)
13294                 flg_var = 1;
13295
13296         for (ap = argptr; *ap ; ap++) {
13297                 if (flg_func)
13298                         unsetfunc(*ap);
13299                 if (flg_var)
13300                         ret |= unsetvar(*ap);
13301         }
13302         return ret;
13303 }
13304
13305
13306 /*
13307  * Unset the specified variable.
13308  */
13309
13310 static int
13311 unsetvar(s)
13312         const char *s;
13313         {
13314         struct var **vpp;
13315         struct var *vp;
13316
13317         vpp = findvar(hashvar(s), s);
13318         vp = *vpp;
13319         if (vp) {
13320                 if (vp->flags & VREADONLY)
13321                         return (1);
13322                 INTOFF;
13323                 if (*(strchr(vp->text, '=') + 1) != '\0')
13324                         setvar(s, nullstr, 0);
13325                 vp->flags &= ~VEXPORT;
13326                 vp->flags |= VUNSET;
13327                 if ((vp->flags & VSTRFIXED) == 0) {
13328                         if ((vp->flags & VTEXTFIXED) == 0)
13329                                 ckfree(vp->text);
13330                         *vpp = vp->next;
13331                         ckfree(vp);
13332                 }
13333                 INTON;
13334                 return (0);
13335         }
13336
13337         return (0);
13338 }
13339
13340
13341
13342 /*
13343  * Find the appropriate entry in the hash table from the name.
13344  */
13345
13346 static struct var **
13347 hashvar(p)
13348         const char *p;
13349         {
13350         unsigned int hashval;
13351
13352         hashval = ((unsigned char) *p) << 4;
13353         while (*p && *p != '=')
13354                 hashval += (unsigned char) *p++;
13355         return &vartab[hashval % VTABSIZE];
13356 }
13357
13358
13359
13360 /*
13361  * Returns true if the two strings specify the same varable.  The first
13362  * variable name is terminated by '='; the second may be terminated by
13363  * either '=' or '\0'.
13364  */
13365
13366 static int
13367 varequal(p, q)
13368         const char *p, *q;
13369         {
13370         while (*p == *q++) {
13371                 if (*p++ == '=')
13372                         return 1;
13373         }
13374         if (*p == '=' && *(q - 1) == '\0')
13375                 return 1;
13376         return 0;
13377 }
13378
13379 static void
13380 showvars(const char *myprefix, int mask, int xor)
13381 {
13382         struct var **vpp;
13383         struct var *vp;
13384         const char *sep = myprefix == nullstr ? myprefix : spcstr;
13385
13386         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13387                 for (vp = *vpp ; vp ; vp = vp->next) {
13388                         if ((vp->flags & mask) ^ xor) {
13389                                 char *p;
13390                                 int len;
13391
13392                                 p = strchr(vp->text, '=') + 1;
13393                                 len = p - vp->text;
13394                                 p = single_quote(p);
13395
13396                                 out1fmt(
13397                                         "%s%s%.*s%s\n", myprefix, sep, len,
13398                                         vp->text, p
13399                                 );
13400                                 stunalloc(p);
13401                         }
13402                 }
13403         }
13404 }
13405
13406 static struct var **
13407 findvar(struct var **vpp, const char *name)
13408 {
13409         for (; *vpp; vpp = &(*vpp)->next) {
13410                 if (varequal((*vpp)->text, name)) {
13411                         break;
13412                 }
13413         }
13414         return vpp;
13415 }
13416
13417 /*
13418  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13419  * This file contains code for the times builtin.
13420  * $Id: ash.c,v 1.2 2001/06/28 07:46:40 andersen Exp $
13421  */
13422 static int timescmd (int argc, char **argv)
13423 {
13424         struct tms buf;
13425         long int clk_tck = sysconf(_SC_CLK_TCK);
13426
13427         times(&buf);
13428         printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13429                (int) (buf.tms_utime / clk_tck / 60),
13430                ((double) buf.tms_utime) / clk_tck,
13431                (int) (buf.tms_stime / clk_tck / 60),
13432                ((double) buf.tms_stime) / clk_tck,
13433                (int) (buf.tms_cutime / clk_tck / 60),
13434                ((double) buf.tms_cutime) / clk_tck,
13435                (int) (buf.tms_cstime / clk_tck / 60),
13436                ((double) buf.tms_cstime) / clk_tck);
13437         return 0;
13438 }
13439
13440
13441 /*-
13442  * Copyright (c) 1989, 1991, 1993, 1994
13443  *      The Regents of the University of California.  All rights reserved.
13444  *
13445  * This code is derived from software contributed to Berkeley by
13446  * Kenneth Almquist.
13447  *
13448  * Redistribution and use in source and binary forms, with or without
13449  * modification, are permitted provided that the following conditions
13450  * are met:
13451  * 1. Redistributions of source code must retain the above copyright
13452  *    notice, this list of conditions and the following disclaimer.
13453  * 2. Redistributions in binary form must reproduce the above copyright
13454  *    notice, this list of conditions and the following disclaimer in the
13455  *    documentation and/or other materials provided with the distribution.
13456  *
13457  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change 
13458  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> 
13459  *
13460  * 4. Neither the name of the University nor the names of its contributors
13461  *    may be used to endorse or promote products derived from this software
13462  *    without specific prior written permission.
13463  *
13464  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13465  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13466  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13467  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13468  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13469  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13470  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13471  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13472  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13473  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13474  * SUCH DAMAGE.
13475  */