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