Remove the now unused ARITH_* defines
[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 BB_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 BB_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 BB_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 BB_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 BB_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 BB_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 BB_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 BB_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                 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3228                 printf( "Enter 'help' for a list of built-in commands.\n\n");
3229                 do_banner=1;
3230         }
3231 }
3232
3233 static void
3234 optschanged(void)
3235 {
3236         setinteractive(iflag);
3237         setjobctl(mflag);
3238 }
3239
3240
3241 static int
3242 execcmd(argc, argv)
3243         int argc;
3244         char **argv;
3245 {
3246         if (argc > 1) {
3247                 struct strlist *sp;
3248
3249                 iflag = 0;              /* exit on error */
3250                 mflag = 0;
3251                 optschanged();
3252                 for (sp = cmdenviron; sp ; sp = sp->next)
3253                         setvareq(sp->text, VEXPORT|VSTACK);
3254                 shellexec(argv + 1, environment(), pathval(), 0);
3255         }
3256         return 0;
3257 }
3258
3259 static void
3260 eprintlist(struct strlist *sp)
3261 {
3262         for (; sp; sp = sp->next) {
3263                 out2fmt(" %s",sp->text);
3264         }
3265 }
3266
3267 /*
3268  * Exec a program.  Never returns.  If you change this routine, you may
3269  * have to change the find_command routine as well.
3270  */
3271
3272 static const char *pathopt;     /* set by padvance */
3273
3274 static void
3275 shellexec(argv, envp, path, idx)
3276         char **argv, **envp;
3277         const char *path;
3278         int idx;
3279 {
3280         char *cmdname;
3281         int e;
3282
3283         if (strchr(argv[0], '/') != NULL) {
3284                 tryexec(argv[0], argv, envp);
3285                 e = errno;
3286         } else {
3287                 e = ENOENT;
3288                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3289                         if (--idx < 0 && pathopt == NULL) {
3290                                 tryexec(cmdname, argv, envp);
3291                                 if (errno != ENOENT && errno != ENOTDIR)
3292                                         e = errno;
3293                         }
3294                         stunalloc(cmdname);
3295                 }
3296         }
3297
3298         /* Map to POSIX errors */
3299         switch (e) {
3300         case EACCES:
3301                 exerrno = 126;
3302                 break;
3303         case ENOENT:
3304                 exerrno = 127;
3305                 break;
3306         default:
3307                 exerrno = 2;
3308                 break;
3309         }
3310         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3311         /* NOTREACHED */
3312 }
3313
3314 /*
3315  * Clear traps on a fork.
3316  */
3317 static void
3318 clear_traps(void) {
3319         char **tp;
3320
3321         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3322                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
3323                         INTOFF;
3324                         ckfree(*tp);
3325                         *tp = NULL;
3326                         if (tp != &trap[0])
3327                                 setsignal(tp - trap);
3328                         INTON;
3329                 }
3330         }
3331 }
3332
3333
3334 static void
3335 initshellproc(void) {
3336
3337 #ifdef ASH_ALIAS
3338       /* from alias.c: */
3339       {
3340               rmaliases();
3341       }
3342 #endif
3343       /* from eval.c: */
3344       {
3345               exitstatus = 0;
3346       }
3347
3348       /* from exec.c: */
3349       {
3350               deletefuncs();
3351       }
3352
3353       /* from jobs.c: */
3354       {
3355               backgndpid = -1;
3356 #ifdef JOBS
3357               jobctl = 0;
3358 #endif
3359       }
3360
3361       /* from options.c: */
3362       {
3363               int i;
3364
3365               for (i = 0; i < NOPTS; i++)
3366                       optent_val(i) = 0;
3367               optschanged();
3368
3369       }
3370
3371       /* from redir.c: */
3372       {
3373               clearredir();
3374       }
3375
3376       /* from trap.c: */
3377       {
3378               char *sm;
3379
3380               clear_traps();
3381               for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3382                       if (*sm == S_IGN)
3383                               *sm = S_HARD_IGN;
3384               }
3385       }
3386
3387       /* from var.c: */
3388       {
3389               shprocvar();
3390       }
3391 }
3392
3393 static int preadbuffer(void);
3394 static void pushfile (void);
3395
3396 /*
3397  * Read a character from the script, returning PEOF on end of file.
3398  * Nul characters in the input are silently discarded.
3399  */
3400
3401 #ifndef ASH_OPTIMIZE_FOR_SIZE
3402 #define pgetc_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3403 static int
3404 pgetc(void)
3405 {
3406         return pgetc_macro();
3407 }
3408 #else
3409 static int
3410 pgetc_macro(void)
3411 {
3412         return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3413 }
3414
3415 static inline int
3416 pgetc(void)
3417 {
3418         return pgetc_macro();
3419 }
3420 #endif
3421
3422
3423 /*
3424  * Undo the last call to pgetc.  Only one character may be pushed back.
3425  * PEOF may be pushed back.
3426  */
3427
3428 static void pungetc(void) 
3429 {
3430         parsenleft++;
3431         parsenextc--;
3432 }
3433
3434
3435 static void
3436 popfile(void) {
3437         struct parsefile *pf = parsefile;
3438
3439         INTOFF;
3440         if (pf->fd >= 0)
3441                 close(pf->fd);
3442         if (pf->buf)
3443                 ckfree(pf->buf);
3444         while (pf->strpush)
3445                 popstring();
3446         parsefile = pf->prev;
3447         ckfree(pf);
3448         parsenleft = parsefile->nleft;
3449         parselleft = parsefile->lleft;
3450         parsenextc = parsefile->nextc;
3451         plinno = parsefile->linno;
3452         INTON;
3453 }
3454
3455
3456 /*
3457  * Return to top level.
3458  */
3459
3460 static void
3461 popallfiles(void) {
3462         while (parsefile != &basepf)
3463                 popfile();
3464 }
3465
3466 /*
3467  * Close the file(s) that the shell is reading commands from.  Called
3468  * after a fork is done.
3469  */
3470
3471 static void closescript(void) 
3472 {
3473         popallfiles();
3474         if (parsefile->fd > 0) {
3475                 close(parsefile->fd);
3476                 parsefile->fd = 0;
3477         }
3478 }
3479
3480
3481 /*
3482  * Like setinputfile, but takes an open file descriptor.  Call this with
3483  * interrupts off.
3484  */
3485
3486 static void setinputfd(int fd, int push)
3487 {
3488         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3489         if (push) {
3490                 pushfile();
3491                 parsefile->buf = 0;
3492         } else {
3493                 closescript();
3494                 while (parsefile->strpush)
3495                         popstring();
3496         }
3497         parsefile->fd = fd;
3498         if (parsefile->buf == NULL)
3499                 parsefile->buf = ckmalloc(BUFSIZ);
3500         parselleft = parsenleft = 0;
3501         plinno = 1;
3502 }
3503
3504
3505 /*
3506  * Set the input to take input from a file.  If push is set, push the
3507  * old input onto the stack first.
3508  */
3509
3510 static void
3511 setinputfile(const char *fname, int push)
3512 {
3513         int fd;
3514         int myfileno2;
3515
3516         INTOFF;
3517         if ((fd = open(fname, O_RDONLY)) < 0)
3518                 error("Can't open %s", fname);
3519         if (fd < 10) {
3520                 myfileno2 = dup_as_newfd(fd, 10);
3521                 close(fd);
3522                 if (myfileno2 < 0)
3523                         error("Out of file descriptors");
3524                 fd = myfileno2;
3525         }
3526         setinputfd(fd, push);
3527         INTON;
3528 }
3529
3530
3531 static void
3532 tryexec(char *cmd, char **argv, char **envp)
3533 {
3534         int e;
3535
3536 #ifdef BB_FEATURE_SH_STANDALONE_SHELL
3537         char *name = cmd;
3538         char** argv_l=argv;
3539         int argc_l;
3540 #ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3541         name = get_last_path_component(name);
3542 #endif
3543         argv_l=envp;
3544         for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3545                 putenv(*argv_l);
3546         argv_l=argv;
3547         for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3548         optind = 1;
3549         run_applet_by_name(name, argc_l, argv);
3550 #endif
3551         execve(cmd, argv, envp);
3552         e = errno;
3553         if (e == ENOEXEC) {
3554                 INTOFF;
3555                 initshellproc();
3556                 setinputfile(cmd, 0);
3557                 commandname = arg0 = savestr(argv[0]);
3558                 setparam(argv + 1);
3559                 exraise(EXSHELLPROC);
3560         }
3561         errno = e;
3562 }
3563
3564 static char *commandtext (const union node *);
3565
3566 /*
3567  * Do a path search.  The variable path (passed by reference) should be
3568  * set to the start of the path before the first call; padvance will update
3569  * this value as it proceeds.  Successive calls to padvance will return
3570  * the possible path expansions in sequence.  If an option (indicated by
3571  * a percent sign) appears in the path entry then the global variable
3572  * pathopt will be set to point to it; otherwise pathopt will be set to
3573  * NULL.
3574  */
3575
3576 static const char *pathopt;
3577
3578 static void growstackblock(void);
3579
3580
3581 static char *
3582 padvance(const char **path, const char *name)
3583 {
3584         const char *p;
3585         char *q;
3586         const char *start;
3587         int len;
3588
3589         if (*path == NULL)
3590                 return NULL;
3591         start = *path;
3592         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3593         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
3594         while (stackblocksize() < len)
3595                 growstackblock();
3596         q = stackblock();
3597         if (p != start) {
3598                 memcpy(q, start, p - start);
3599                 q += p - start;
3600                 *q++ = '/';
3601         }
3602         strcpy(q, name);
3603         pathopt = NULL;
3604         if (*p == '%') {
3605                 pathopt = ++p;
3606                 while (*p && *p != ':')  p++;
3607         }
3608         if (*p == ':')
3609                 *path = p + 1;
3610         else
3611                 *path = NULL;
3612         return stalloc(len);
3613 }
3614
3615 /*
3616  * Wrapper around strcmp for qsort/bsearch/...
3617  */
3618 static int
3619 pstrcmp(const void *a, const void *b)
3620 {
3621         return strcmp((const char *) a, (*(const char *const *) b) + 1);
3622 }
3623
3624 /*
3625  * Find a keyword is in a sorted array.
3626  */
3627
3628 static const char *const *
3629 findkwd(const char *s)
3630 {
3631         return  bsearch(s, tokname_array + KWDOFFSET,
3632                                         (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3633                                         sizeof(const char *), pstrcmp);
3634 }
3635
3636
3637 /*** Command hashing code ***/
3638
3639
3640 static int
3641 hashcmd(argc, argv)
3642         int argc;
3643         char **argv;
3644 {
3645         struct tblentry **pp;
3646         struct tblentry *cmdp;
3647         int c;
3648         int verbose;
3649         struct cmdentry entry;
3650         char *name;
3651 #ifdef ASH_ALIAS
3652         const struct alias *ap;
3653 #endif
3654
3655         verbose = 0;
3656         while ((c = nextopt("rvV")) != '\0') {
3657                 if (c == 'r') {
3658                         clearcmdentry(0);
3659                         return 0;
3660                 } else if (c == 'v' || c == 'V') {
3661                         verbose = c;
3662                 }
3663         }
3664         if (*argptr == NULL) {
3665                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3666                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3667                                 if (cmdp->cmdtype != CMDBUILTIN) {
3668                                         printentry(cmdp, verbose);
3669                                 }
3670                         }
3671                 }
3672                 return 0;
3673         }
3674         c = 0;
3675         while ((name = *argptr++) != NULL) {
3676                 if ((cmdp = cmdlookup(name, 0)) != NULL
3677                  && (cmdp->cmdtype == CMDNORMAL
3678                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3679                         delete_cmd_entry();
3680 #ifdef ASH_ALIAS
3681         /* Then look at the aliases */
3682                 if ((ap = lookupalias(name, 0)) != NULL) {
3683                         if (verbose=='v')
3684                                 printf("%s is an alias for %s\n", name, ap->val);
3685                         else
3686                                 printalias(ap);
3687                         continue;
3688                 }
3689 #endif
3690                         /* First look at the keywords */
3691                 if (findkwd(name)!=0) {
3692                         if (verbose=='v')
3693                                 printf("%s is a shell keyword\n", name);
3694                         else
3695                                 printf(snlfmt, name);
3696                         continue;
3697                 }
3698
3699                 find_command(name, &entry, DO_ERR, pathval());
3700                 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3701                 else if (verbose) {
3702                         cmdp = cmdlookup(name, 0);
3703                         if (cmdp) printentry(cmdp, verbose=='v');
3704                         flushall();
3705                 }
3706         }
3707         return c;
3708 }
3709
3710 static void
3711 printentry(cmdp, verbose)
3712         struct tblentry *cmdp;
3713         int verbose;
3714         {
3715         int idx;
3716         const char *path;
3717         char *name;
3718
3719         printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
3720         if (cmdp->cmdtype == CMDNORMAL) {
3721                 idx = cmdp->param.index;
3722                 path = pathval();
3723                 do {
3724                         name = padvance(&path, cmdp->cmdname);
3725                         stunalloc(name);
3726                 } while (--idx >= 0);
3727                 if(verbose)
3728                         out1str(name);
3729         } else if (cmdp->cmdtype == CMDBUILTIN) {
3730                 if(verbose)
3731                         out1str("a shell builtin");
3732         } else if (cmdp->cmdtype == CMDFUNCTION) {
3733                 if (verbose) {
3734                         INTOFF;
3735                         out1str("a function\n");
3736                         name = commandtext(cmdp->param.func);
3737                         printf("%s() {\n %s\n}", cmdp->cmdname, name);
3738                         ckfree(name);
3739                         INTON;
3740                 }
3741 #ifdef DEBUG
3742         } else {
3743                 error("internal error: cmdtype %d", cmdp->cmdtype);
3744 #endif
3745         }
3746         printf(snlfmt, cmdp->rehash ? "*" : nullstr);
3747 }
3748
3749
3750
3751 /*** List the available builtins ***/
3752
3753
3754 static int helpcmd(int argc, char** argv)
3755 {
3756         int col, i;
3757
3758         printf("\nBuilt-in commands:\n-------------------\n");
3759         for (col=0, i=0; i < NUMBUILTINS; i++) {
3760                 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3761                                 builtincmds[i].name+1);
3762                 if (col > 60) {
3763                         printf("\n");
3764                         col = 0;
3765                 }
3766         }
3767 #ifdef BB_FEATURE_SH_STANDALONE_SHELL
3768         {
3769                 extern const struct BB_applet applets[];
3770                 extern const size_t NUM_APPLETS;
3771
3772                 for (i=0; i < NUM_APPLETS; i++) {
3773
3774                         col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3775                                         applets[i].name);
3776                         if (col > 60) {
3777                                 printf("\n");
3778                                 col = 0;
3779                         }
3780                 }
3781         }
3782 #endif
3783         printf("\n\n");
3784         return EXIT_SUCCESS;
3785 }
3786
3787 /*
3788  * Resolve a command name.  If you change this routine, you may have to
3789  * change the shellexec routine as well.
3790  */
3791
3792 static int prefix (const char *, const char *);
3793
3794 static void
3795 find_command(const char *name, struct cmdentry *entry, int act, const char *path)
3796 {
3797         struct tblentry *cmdp;
3798         int idx;
3799         int prev;
3800         char *fullname;
3801         struct stat statb;
3802         int e;
3803         int bltin;
3804         int firstchange;
3805         int updatetbl;
3806         int regular;
3807         struct builtincmd *bcmd;
3808
3809         /* If name contains a slash, don't use the hash table */
3810         if (strchr(name, '/') != NULL) {
3811                 if (act & DO_ABS) {
3812                         while (stat(name, &statb) < 0) {
3813                                 if (errno != ENOENT && errno != ENOTDIR)
3814                                         e = errno;
3815                                 entry->cmdtype = CMDUNKNOWN;
3816                                 entry->u.index = -1;
3817                                 return;
3818                         }
3819                         entry->cmdtype = CMDNORMAL;
3820                         entry->u.index = -1;
3821                         return;
3822                 }
3823                 entry->cmdtype = CMDNORMAL;
3824                 entry->u.index = 0;
3825                 return;
3826         }
3827
3828         updatetbl = 1;
3829         if (act & DO_BRUTE) {
3830                 firstchange = path_change(path, &bltin);
3831         } else {
3832                 bltin = builtinloc;
3833                 firstchange = 9999;
3834         }
3835
3836         /* If name is in the table, and not invalidated by cd, we're done */
3837         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3838                 if (cmdp->cmdtype == CMDFUNCTION) {
3839                         if (act & DO_NOFUN) {
3840                                 updatetbl = 0;
3841                         } else {
3842                                 goto success;
3843                         }
3844                 } else if (act & DO_BRUTE) {
3845                         if ((cmdp->cmdtype == CMDNORMAL &&
3846                              cmdp->param.index >= firstchange) ||
3847                             (cmdp->cmdtype == CMDBUILTIN &&
3848                              ((builtinloc < 0 && bltin >= 0) ?
3849                               bltin : builtinloc) >= firstchange)) {
3850                                 /* need to recompute the entry */
3851                         } else {
3852                                 goto success;
3853                         }
3854                 } else {
3855                         goto success;
3856                 }
3857         }
3858
3859         bcmd = find_builtin(name);
3860         regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
3861
3862         if (regular) {
3863                 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
3864                         goto success;
3865                 }
3866         } else if (act & DO_BRUTE) {
3867                 if (firstchange == 0) {
3868                         updatetbl = 0;
3869                 }
3870         }
3871
3872         /* If %builtin not in path, check for builtin next */
3873         if (regular || (bltin < 0 && bcmd)) {
3874 builtin:
3875                 if (!updatetbl) {
3876                         entry->cmdtype = CMDBUILTIN;
3877                         entry->u.cmd = bcmd;
3878                         return;
3879                 }
3880                 INTOFF;
3881                 cmdp = cmdlookup(name, 1);
3882                 cmdp->cmdtype = CMDBUILTIN;
3883                 cmdp->param.cmd = bcmd;
3884                 INTON;
3885                 goto success;
3886         }
3887
3888         /* We have to search path. */
3889         prev = -1;              /* where to start */
3890         if (cmdp && cmdp->rehash) {     /* doing a rehash */
3891                 if (cmdp->cmdtype == CMDBUILTIN)
3892                         prev = builtinloc;
3893                 else
3894                         prev = cmdp->param.index;
3895         }
3896
3897         e = ENOENT;
3898         idx = -1;
3899 loop:
3900         while ((fullname = padvance(&path, name)) != NULL) {
3901                 stunalloc(fullname);
3902                 idx++;
3903                 if (idx >= firstchange) {
3904                         updatetbl = 0;
3905                 }
3906                 if (pathopt) {
3907                         if (prefix("builtin", pathopt)) {
3908                                 if ((bcmd = find_builtin(name))) {
3909                                         goto builtin;
3910                                 }
3911                                 continue;
3912                         } else if (!(act & DO_NOFUN) &&
3913                                    prefix("func", pathopt)) {
3914                                 /* handled below */
3915                         } else {
3916                                 continue;       /* ignore unimplemented options */
3917                         }
3918                 }
3919                 /* if rehash, don't redo absolute path names */
3920                 if (fullname[0] == '/' && idx <= prev &&
3921                     idx < firstchange) {
3922                         if (idx < prev)
3923                                 continue;
3924                         TRACE(("searchexec \"%s\": no change\n", name));
3925                         goto success;
3926                 }
3927                 while (stat(fullname, &statb) < 0) {
3928                         if (errno != ENOENT && errno != ENOTDIR)
3929                                 e = errno;
3930                         goto loop;
3931                 }
3932                 e = EACCES;     /* if we fail, this will be the error */
3933                 if (!S_ISREG(statb.st_mode))
3934                         continue;
3935                 if (pathopt) {          /* this is a %func directory */
3936                         stalloc(strlen(fullname) + 1);
3937                         readcmdfile(fullname);
3938                         if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3939                                 error("%s not defined in %s", name, fullname);
3940                         stunalloc(fullname);
3941                         goto success;
3942                 }
3943                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3944                 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3945                    be a function and we're being called with DO_NOFUN */
3946                 if (!updatetbl) {
3947                         entry->cmdtype = CMDNORMAL;
3948                         entry->u.index = idx;
3949                         return;
3950                 }
3951                 INTOFF;
3952                 cmdp = cmdlookup(name, 1);
3953                 cmdp->cmdtype = CMDNORMAL;
3954                 cmdp->param.index = idx;
3955                 INTON;
3956                 goto success;
3957         }
3958
3959         /* We failed.  If there was an entry for this command, delete it */
3960         if (cmdp && updatetbl)
3961                 delete_cmd_entry();
3962         if (act & DO_ERR)
3963                 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
3964         entry->cmdtype = CMDUNKNOWN;
3965         return;
3966
3967 success:
3968         cmdp->rehash = 0;
3969         entry->cmdtype = cmdp->cmdtype;
3970         entry->u = cmdp->param;
3971 }
3972
3973
3974
3975 /*
3976  * Search the table of builtin commands.
3977  */
3978
3979 static int
3980 bstrcmp(const void *name, const void *b)
3981 {
3982         return strcmp((const char *)name, (*(const char *const *) b)+1);
3983 }
3984
3985 static struct builtincmd *
3986 find_builtin(const char *name)
3987 {
3988         struct builtincmd *bp;
3989
3990         bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3991                 bstrcmp
3992         );
3993         return bp;
3994 }
3995
3996
3997 /*
3998  * Called when a cd is done.  Marks all commands so the next time they
3999  * are executed they will be rehashed.
4000  */
4001
4002 static void
4003 hashcd(void) {
4004         struct tblentry **pp;
4005         struct tblentry *cmdp;
4006
4007         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4008                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4009                         if (cmdp->cmdtype == CMDNORMAL
4010                          || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4011                                 cmdp->rehash = 1;
4012                 }
4013         }
4014 }
4015
4016
4017
4018 /*
4019  * Called before PATH is changed.  The argument is the new value of PATH;
4020  * pathval() still returns the old value at this point.  Called with
4021  * interrupts off.
4022  */
4023
4024 static void
4025 changepath(const char *newval)
4026 {
4027         int firstchange;
4028         int bltin;
4029
4030         firstchange = path_change(newval, &bltin);
4031         if (builtinloc < 0 && bltin >= 0)
4032                 builtinloc = bltin;             /* zap builtins */
4033         clearcmdentry(firstchange);
4034         builtinloc = bltin;
4035 }
4036
4037
4038 /*
4039  * Clear out command entries.  The argument specifies the first entry in
4040  * PATH which has changed.
4041  */
4042
4043 static void
4044 clearcmdentry(firstchange)
4045         int firstchange;
4046 {
4047         struct tblentry **tblp;
4048         struct tblentry **pp;
4049         struct tblentry *cmdp;
4050
4051         INTOFF;
4052         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4053                 pp = tblp;
4054                 while ((cmdp = *pp) != NULL) {
4055                         if ((cmdp->cmdtype == CMDNORMAL &&
4056                              cmdp->param.index >= firstchange)
4057                          || (cmdp->cmdtype == CMDBUILTIN &&
4058                              builtinloc >= firstchange)) {
4059                                 *pp = cmdp->next;
4060                                 ckfree(cmdp);
4061                         } else {
4062                                 pp = &cmdp->next;
4063                         }
4064                 }
4065         }
4066         INTON;
4067 }
4068
4069
4070 /*
4071  * Delete all functions.
4072  */
4073
4074 static void
4075 deletefuncs(void) {
4076         struct tblentry **tblp;
4077         struct tblentry **pp;
4078         struct tblentry *cmdp;
4079
4080         INTOFF;
4081         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4082                 pp = tblp;
4083                 while ((cmdp = *pp) != NULL) {
4084                         if (cmdp->cmdtype == CMDFUNCTION) {
4085                                 *pp = cmdp->next;
4086                                 freefunc(cmdp->param.func);
4087                                 ckfree(cmdp);
4088                         } else {
4089                                 pp = &cmdp->next;
4090                         }
4091                 }
4092         }
4093         INTON;
4094 }
4095
4096
4097
4098 /*
4099  * Locate a command in the command hash table.  If "add" is nonzero,
4100  * add the command to the table if it is not already present.  The
4101  * variable "lastcmdentry" is set to point to the address of the link
4102  * pointing to the entry, so that delete_cmd_entry can delete the
4103  * entry.
4104  */
4105
4106 static struct tblentry **lastcmdentry;
4107
4108 static struct tblentry *
4109 cmdlookup(const char *name, int add)
4110 {
4111         int hashval;
4112         const char *p;
4113         struct tblentry *cmdp;
4114         struct tblentry **pp;
4115
4116         p = name;
4117         hashval = *p << 4;
4118         while (*p)
4119                 hashval += *p++;
4120         hashval &= 0x7FFF;
4121         pp = &cmdtable[hashval % CMDTABLESIZE];
4122         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4123                 if (equal(cmdp->cmdname, name))
4124                         break;
4125                 pp = &cmdp->next;
4126         }
4127         if (add && cmdp == NULL) {
4128                 INTOFF;
4129                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4130                                         + strlen(name) + 1);
4131                 cmdp->next = NULL;
4132                 cmdp->cmdtype = CMDUNKNOWN;
4133                 cmdp->rehash = 0;
4134                 strcpy(cmdp->cmdname, name);
4135                 INTON;
4136         }
4137         lastcmdentry = pp;
4138         return cmdp;
4139 }
4140
4141 /*
4142  * Delete the command entry returned on the last lookup.
4143  */
4144
4145 static void
4146 delete_cmd_entry() {
4147         struct tblentry *cmdp;
4148
4149         INTOFF;
4150         cmdp = *lastcmdentry;
4151         *lastcmdentry = cmdp->next;
4152         ckfree(cmdp);
4153         INTON;
4154 }
4155
4156
4157
4158
4159
4160 static const unsigned char nodesize[26] = {
4161       ALIGN(sizeof (struct nbinary)),
4162       ALIGN(sizeof (struct ncmd)),
4163       ALIGN(sizeof (struct npipe)),
4164       ALIGN(sizeof (struct nredir)),
4165       ALIGN(sizeof (struct nredir)),
4166       ALIGN(sizeof (struct nredir)),
4167       ALIGN(sizeof (struct nbinary)),
4168       ALIGN(sizeof (struct nbinary)),
4169       ALIGN(sizeof (struct nif)),
4170       ALIGN(sizeof (struct nbinary)),
4171       ALIGN(sizeof (struct nbinary)),
4172       ALIGN(sizeof (struct nfor)),
4173       ALIGN(sizeof (struct ncase)),
4174       ALIGN(sizeof (struct nclist)),
4175       ALIGN(sizeof (struct narg)),
4176       ALIGN(sizeof (struct narg)),
4177       ALIGN(sizeof (struct nfile)),
4178       ALIGN(sizeof (struct nfile)),
4179       ALIGN(sizeof (struct nfile)),
4180       ALIGN(sizeof (struct nfile)),
4181       ALIGN(sizeof (struct nfile)),
4182       ALIGN(sizeof (struct ndup)),
4183       ALIGN(sizeof (struct ndup)),
4184       ALIGN(sizeof (struct nhere)),
4185       ALIGN(sizeof (struct nhere)),
4186       ALIGN(sizeof (struct nnot)),
4187 };
4188
4189
4190
4191 /*
4192  * Delete a function if it exists.
4193  */
4194
4195 static void
4196 unsetfunc(char *name)
4197 {
4198         struct tblentry *cmdp;
4199
4200         if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4201                 freefunc(cmdp->param.func);
4202                 delete_cmd_entry();
4203         }
4204 }
4205
4206
4207 /*
4208  * Locate and print what a word is...
4209  */
4210
4211 static int
4212 typecmd(int argc, char **argv)
4213 {
4214         int i;
4215         int err = 0;
4216         char *argv_a[2];
4217
4218         argv_a[1] = 0;
4219
4220         for (i = 1; i < argc; i++) {
4221                 argv_a[0] = argv[i];
4222                 argptr = argv_a;
4223                 optptr = "v";
4224                 err |= hashcmd(argc, argv);
4225         }
4226         return err;
4227 }
4228
4229 #ifdef ASH_CMDCMD
4230 static int
4231 commandcmd(argc, argv)
4232         int argc;
4233         char **argv;
4234 {
4235         int c;
4236         int default_path = 0;
4237         int verify_only = 0;
4238         int verbose_verify_only = 0;
4239
4240         while ((c = nextopt("pvV")) != '\0')
4241                 switch (c) {
4242                 case 'p':
4243                         default_path = 1;
4244                         break;
4245                 case 'v':
4246                         verify_only = 1;
4247                         break;
4248                 case 'V':
4249                         verbose_verify_only = 1;
4250                         break;
4251                 }
4252
4253         if (default_path + verify_only + verbose_verify_only > 1 ||
4254             !*argptr) {
4255                         out2str(
4256                                 "command [-p] command [arg ...]\n"
4257                                 "command {-v|-V} command\n");
4258                         return EX_USAGE;
4259         }
4260
4261         if (verify_only || verbose_verify_only) {
4262                 char *argv_a[2];
4263
4264                 argv_a[1] = 0;
4265                 argv_a[0] = *argptr;
4266                 argptr = argv_a;
4267                 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4268                 return hashcmd(argc, argv);
4269         }
4270
4271         return 0;
4272 }
4273 #endif
4274
4275 static int
4276 path_change(newval, bltin)
4277         const char *newval;
4278         int *bltin;
4279 {
4280         const char *old, *new;
4281         int idx;
4282         int firstchange;
4283
4284         old = pathval();
4285         new = newval;
4286         firstchange = 9999;     /* assume no change */
4287         idx = 0;
4288         *bltin = -1;
4289         for (;;) {
4290                 if (*old != *new) {
4291                         firstchange = idx;
4292                         if ((*old == '\0' && *new == ':')
4293                          || (*old == ':' && *new == '\0'))
4294                                 firstchange++;
4295                         old = new;      /* ignore subsequent differences */
4296                 }
4297                 if (*new == '\0')
4298                         break;
4299                 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4300                         *bltin = idx;
4301                 if (*new == ':') {
4302                         idx++;
4303                 }
4304                 new++, old++;
4305         }
4306         if (builtinloc >= 0 && *bltin < 0)
4307                 firstchange = 0;
4308         return firstchange;
4309 }
4310 /*
4311  * Routines to expand arguments to commands.  We have to deal with
4312  * backquotes, shell variables, and file metacharacters.
4313  */
4314 /*
4315  * _rmescape() flags
4316  */
4317 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
4318 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
4319
4320 /*
4321  * Structure specifying which parts of the string should be searched
4322  * for IFS characters.
4323  */
4324
4325 struct ifsregion {
4326         struct ifsregion *next; /* next region in list */
4327         int begoff;             /* offset of start of region */
4328         int endoff;             /* offset of end of region */
4329         int nulonly;            /* search for nul bytes only */
4330 };
4331
4332
4333 static char *expdest;                   /* output of current string */
4334 static struct nodelist *argbackq;      /* list of back quote expressions */
4335 static struct ifsregion ifsfirst;      /* first struct in list of ifs regions */
4336 static struct ifsregion *ifslastp;     /* last struct in list */
4337 static struct arglist exparg;          /* holds expanded arg list */
4338
4339 static void argstr (char *, int);
4340 static char *exptilde (char *, int);
4341 static void expbackq (union node *, int, int);
4342 static int subevalvar (char *, char *, int, int, int, int, int);
4343 static int varisset (char *, int);
4344 static void strtodest (const char *, int, int);
4345 static void varvalue (char *, int, int);
4346 static void recordregion (int, int, int);
4347 static void removerecordregions (int);
4348 static void ifsbreakup (char *, struct arglist *);
4349 static void ifsfree (void);
4350 static void expandmeta (struct strlist *, int);
4351 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4352 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4353 #if !defined(GLOB_BROKEN)
4354 static void addglob (const glob_t *);
4355 #endif
4356 #endif
4357 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4358 static void expmeta (char *, char *);
4359 #endif
4360 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4361 static struct strlist *expsort (struct strlist *);
4362 static struct strlist *msort (struct strlist *, int);
4363 #endif
4364 static int patmatch (char *, char *, int);
4365 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4366 static int patmatch2 (char *, char *, int);
4367 #else
4368 static int pmatch (char *, char *, int);
4369 #define patmatch2 patmatch
4370 #endif
4371 static char *cvtnum (int, char *);
4372
4373 /*
4374  * Expand shell variables and backquotes inside a here document.
4375  */
4376
4377 /* arg: the document, fd: where to write the expanded version */
4378 static inline void
4379 expandhere(union node *arg, int fd)
4380 {
4381         herefd = fd;
4382         expandarg(arg, (struct arglist *)NULL, 0);
4383         xwrite(fd, stackblock(), expdest - stackblock());
4384 }
4385
4386
4387 /*
4388  * Perform variable substitution and command substitution on an argument,
4389  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
4390  * perform splitting and file name expansion.  When arglist is NULL, perform
4391  * here document expansion.
4392  */
4393
4394 static void
4395 expandarg(arg, arglist, flag)
4396         union node *arg;
4397         struct arglist *arglist;
4398         int flag;
4399 {
4400         struct strlist *sp;
4401         char *p;
4402
4403         argbackq = arg->narg.backquote;
4404         STARTSTACKSTR(expdest);
4405         ifsfirst.next = NULL;
4406         ifslastp = NULL;
4407         argstr(arg->narg.text, flag);
4408         if (arglist == NULL) {
4409                 return;                 /* here document expanded */
4410         }
4411         STPUTC('\0', expdest);
4412         p = grabstackstr(expdest);
4413         exparg.lastp = &exparg.list;
4414         /*
4415          * TODO - EXP_REDIR
4416          */
4417         if (flag & EXP_FULL) {
4418                 ifsbreakup(p, &exparg);
4419                 *exparg.lastp = NULL;
4420                 exparg.lastp = &exparg.list;
4421                 expandmeta(exparg.list, flag);
4422         } else {
4423                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4424                         rmescapes(p);
4425                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4426                 sp->text = p;
4427                 *exparg.lastp = sp;
4428                 exparg.lastp = &sp->next;
4429         }
4430         ifsfree();
4431         *exparg.lastp = NULL;
4432         if (exparg.list) {
4433                 *arglist->lastp = exparg.list;
4434                 arglist->lastp = exparg.lastp;
4435         }
4436 }
4437
4438
4439 /*
4440  * Expand a variable, and return a pointer to the next character in the
4441  * input string.
4442  */
4443
4444 static inline char * evalvar(char *p, int flag)
4445 {
4446         int subtype;
4447         int varflags;
4448         char *var;
4449         const char *val;
4450         int patloc;
4451         int c;
4452         int set;
4453         int special;
4454         int startloc;
4455         int varlen;
4456         int easy;
4457         int quotes = flag & (EXP_FULL | EXP_CASE);
4458
4459         varflags = *p++;
4460         subtype = varflags & VSTYPE;
4461         var = p;
4462         special = 0;
4463         if (! is_name(*p))
4464                 special = 1;
4465         p = strchr(p, '=') + 1;
4466 again: /* jump here after setting a variable with ${var=text} */
4467         if (special) {
4468                 set = varisset(var, varflags & VSNUL);
4469                 val = NULL;
4470         } else {
4471                 val = lookupvar(var);
4472                 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4473                         val = NULL;
4474                         set = 0;
4475                 } else
4476                         set = 1;
4477         }
4478         varlen = 0;
4479         startloc = expdest - stackblock();
4480         if (set && subtype != VSPLUS) {
4481                 /* insert the value of the variable */
4482                 if (special) {
4483                         varvalue(var, varflags & VSQUOTE, flag);
4484                         if (subtype == VSLENGTH) {
4485                                 varlen = expdest - stackblock() - startloc;
4486                                 STADJUST(-varlen, expdest);
4487                         }
4488                 } else {
4489                         if (subtype == VSLENGTH) {
4490                                 varlen = strlen(val);
4491                         } else {
4492                                 strtodest(
4493                                         val,
4494                                         varflags & VSQUOTE ?
4495                                                 DQSYNTAX : BASESYNTAX,
4496                                         quotes
4497                                 );
4498                         }
4499                 }
4500         }
4501
4502         if (subtype == VSPLUS)
4503                 set = ! set;
4504
4505         easy = ((varflags & VSQUOTE) == 0 ||
4506                 (*var == '@' && shellparam.nparam != 1));
4507
4508
4509         switch (subtype) {
4510         case VSLENGTH:
4511                 expdest = cvtnum(varlen, expdest);
4512                 goto record;
4513
4514         case VSNORMAL:
4515                 if (!easy)
4516                         break;
4517 record:
4518                 recordregion(startloc, expdest - stackblock(),
4519                              varflags & VSQUOTE);
4520                 break;
4521
4522         case VSPLUS:
4523         case VSMINUS:
4524                 if (!set) {
4525                         argstr(p, flag);
4526                         break;
4527                 }
4528                 if (easy)
4529                         goto record;
4530                 break;
4531
4532         case VSTRIMLEFT:
4533         case VSTRIMLEFTMAX:
4534         case VSTRIMRIGHT:
4535         case VSTRIMRIGHTMAX:
4536                 if (!set)
4537                         break;
4538                 /*
4539                  * Terminate the string and start recording the pattern
4540                  * right after it
4541                  */
4542                 STPUTC('\0', expdest);
4543                 patloc = expdest - stackblock();
4544                 if (subevalvar(p, NULL, patloc, subtype,
4545                                startloc, varflags, quotes) == 0) {
4546                         int amount = (expdest - stackblock() - patloc) + 1;
4547                         STADJUST(-amount, expdest);
4548                 }
4549                 /* Remove any recorded regions beyond start of variable */
4550                 removerecordregions(startloc);
4551                 goto record;
4552
4553         case VSASSIGN:
4554         case VSQUESTION:
4555                 if (!set) {
4556                         if (subevalvar(p, var, 0, subtype, startloc,
4557                                        varflags, quotes)) {
4558                                 varflags &= ~VSNUL;
4559                                 /*
4560                                  * Remove any recorded regions beyond
4561                                  * start of variable
4562                                  */
4563                                 removerecordregions(startloc);
4564                                 goto again;
4565                         }
4566                         break;
4567                 }
4568                 if (easy)
4569                         goto record;
4570                 break;
4571
4572 #ifdef DEBUG
4573         default:
4574                 abort();
4575 #endif
4576         }
4577
4578         if (subtype != VSNORMAL) {      /* skip to end of alternative */
4579                 int nesting = 1;
4580                 for (;;) {
4581                         if ((c = *p++) == CTLESC)
4582                                 p++;
4583                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4584                                 if (set)
4585                                         argbackq = argbackq->next;
4586                         } else if (c == CTLVAR) {
4587                                 if ((*p++ & VSTYPE) != VSNORMAL)
4588                                         nesting++;
4589                         } else if (c == CTLENDVAR) {
4590                                 if (--nesting == 0)
4591                                         break;
4592                         }
4593                 }
4594         }
4595         return p;
4596 }
4597
4598
4599 /*
4600  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
4601  * characters to allow for further processing.  Otherwise treat
4602  * $@ like $* since no splitting will be performed.
4603  */
4604
4605 static void
4606 argstr(p, flag)
4607         char *p;
4608         int flag;
4609 {
4610         char c;
4611         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
4612         int firsteq = 1;
4613
4614         if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4615                 p = exptilde(p, flag);
4616         for (;;) {
4617                 switch (c = *p++) {
4618                 case '\0':
4619                 case CTLENDVAR: /* ??? */
4620                         goto breakloop;
4621                 case CTLQUOTEMARK:
4622                         /* "$@" syntax adherence hack */
4623                         if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4624                                 break;
4625                         if ((flag & EXP_FULL) != 0)
4626                                 STPUTC(c, expdest);
4627                         break;
4628                 case CTLESC:
4629                         if (quotes)
4630                                 STPUTC(c, expdest);
4631                         c = *p++;
4632                         STPUTC(c, expdest);
4633                         break;
4634                 case CTLVAR:
4635                         p = evalvar(p, flag);
4636                         break;
4637                 case CTLBACKQ:
4638                 case CTLBACKQ|CTLQUOTE:
4639                         expbackq(argbackq->n, c & CTLQUOTE, flag);
4640                         argbackq = argbackq->next;
4641                         break;
4642 #ifdef ASH_MATH_SUPPORT
4643                 case CTLENDARI:
4644                         expari(flag);
4645                         break;
4646 #endif
4647                 case ':':
4648                 case '=':
4649                         /*
4650                          * sort of a hack - expand tildes in variable
4651                          * assignments (after the first '=' and after ':'s).
4652                          */
4653                         STPUTC(c, expdest);
4654                         if (flag & EXP_VARTILDE && *p == '~') {
4655                                 if (c == '=') {
4656                                         if (firsteq)
4657                                                 firsteq = 0;
4658                                         else
4659                                                 break;
4660                                 }
4661                                 p = exptilde(p, flag);
4662                         }
4663                         break;
4664                 default:
4665                         STPUTC(c, expdest);
4666                 }
4667         }
4668 breakloop:;
4669         return;
4670 }
4671
4672 static char *
4673 exptilde(p, flag)
4674         char *p;
4675         int flag;
4676 {
4677         char c, *startp = p;
4678         struct passwd *pw;
4679         const char *home;
4680         int quotes = flag & (EXP_FULL | EXP_CASE);
4681
4682         while ((c = *p) != '\0') {
4683                 switch(c) {
4684                 case CTLESC:
4685                         return (startp);
4686                 case CTLQUOTEMARK:
4687                         return (startp);
4688                 case ':':
4689                         if (flag & EXP_VARTILDE)
4690                                 goto done;
4691                         break;
4692                 case '/':
4693                         goto done;
4694                 }
4695                 p++;
4696         }
4697 done:
4698         *p = '\0';
4699         if (*(startp+1) == '\0') {
4700                 if ((home = lookupvar("HOME")) == NULL)
4701                         goto lose;
4702         } else {
4703                 if ((pw = getpwnam(startp+1)) == NULL)
4704                         goto lose;
4705                 home = pw->pw_dir;
4706         }
4707         if (*home == '\0')
4708                 goto lose;
4709         *p = c;
4710         strtodest(home, SQSYNTAX, quotes);
4711         return (p);
4712 lose:
4713         *p = c;
4714         return (startp);
4715 }
4716
4717
4718 static void
4719 removerecordregions(int endoff)
4720 {
4721         if (ifslastp == NULL)
4722                 return;
4723
4724         if (ifsfirst.endoff > endoff) {
4725                 while (ifsfirst.next != NULL) {
4726                         struct ifsregion *ifsp;
4727                         INTOFF;
4728                         ifsp = ifsfirst.next->next;
4729                         ckfree(ifsfirst.next);
4730                         ifsfirst.next = ifsp;
4731                         INTON;
4732                 }
4733                 if (ifsfirst.begoff > endoff)
4734                         ifslastp = NULL;
4735                 else {
4736                         ifslastp = &ifsfirst;
4737                         ifsfirst.endoff = endoff;
4738                 }
4739                 return;
4740         }
4741
4742         ifslastp = &ifsfirst;
4743         while (ifslastp->next && ifslastp->next->begoff < endoff)
4744                 ifslastp=ifslastp->next;
4745         while (ifslastp->next != NULL) {
4746                 struct ifsregion *ifsp;
4747                 INTOFF;
4748                 ifsp = ifslastp->next->next;
4749                 ckfree(ifslastp->next);
4750                 ifslastp->next = ifsp;
4751                 INTON;
4752         }
4753         if (ifslastp->endoff > endoff)
4754                 ifslastp->endoff = endoff;
4755 }
4756
4757
4758 #ifdef ASH_MATH_SUPPORT
4759 /*
4760  * Expand arithmetic expression.  Backup to start of expression,
4761  * evaluate, place result in (backed up) result, adjust string position.
4762  */
4763 static void
4764 expari(int flag)
4765 {
4766         char *p, *start;
4767         int errcode;
4768         int result;
4769         int begoff;
4770         int quotes = flag & (EXP_FULL | EXP_CASE);
4771         int quoted;
4772
4773         /*      ifsfree(); */
4774
4775         /*
4776          * This routine is slightly over-complicated for
4777          * efficiency.  First we make sure there is
4778          * enough space for the result, which may be bigger
4779          * than the expression if we add exponentation.  Next we
4780          * scan backwards looking for the start of arithmetic.  If the
4781          * next previous character is a CTLESC character, then we
4782          * have to rescan starting from the beginning since CTLESC
4783          * characters have to be processed left to right.
4784          */
4785         CHECKSTRSPACE(10, expdest);
4786         USTPUTC('\0', expdest);
4787         start = stackblock();
4788         p = expdest - 1;
4789         while (*p != CTLARI && p >= start)
4790                 --p;
4791         if (*p != CTLARI)
4792                 error("missing CTLARI (shouldn't happen)");
4793         if (p > start && *(p-1) == CTLESC)
4794                 for (p = start; *p != CTLARI; p++)
4795                         if (*p == CTLESC)
4796                                 p++;
4797
4798         if (p[1] == '"')
4799                 quoted=1;
4800         else
4801                 quoted=0;
4802         begoff = p - start;
4803         removerecordregions(begoff);
4804         if (quotes)
4805                 rmescapes(p+2);
4806         result = arith(p+2, &errcode);
4807         if (errcode < 0) {
4808                 if(errcode == -2)
4809                         error("divide by zero");
4810                 else
4811                         error("syntax error: \"%s\"\n", p+2);
4812         }
4813         snprintf(p, 12, "%d", result);
4814
4815         while (*p++)
4816                 ;
4817
4818         if (quoted == 0)
4819                 recordregion(begoff, p - 1 - start, 0);
4820         result = expdest - p + 1;
4821         STADJUST(-result, expdest);
4822 }
4823 #endif
4824
4825 /*
4826  * Expand stuff in backwards quotes.
4827  */
4828
4829 static void
4830 expbackq(cmd, quoted, flag)
4831         union node *cmd;
4832         int quoted;
4833         int flag;
4834 {
4835         volatile struct backcmd in;
4836         int i;
4837         char buf[128];
4838         char *p;
4839         char *dest = expdest;
4840         volatile struct ifsregion saveifs;
4841         struct ifsregion *volatile savelastp;
4842         struct nodelist *volatile saveargbackq;
4843         char lastc;
4844         int startloc = dest - stackblock();
4845         int syntax = quoted ? DQSYNTAX : BASESYNTAX;
4846         volatile int saveherefd;
4847         int quotes = flag & (EXP_FULL | EXP_CASE);
4848         struct jmploc jmploc;
4849         struct jmploc *volatile savehandler;
4850         int ex;
4851
4852 #if __GNUC__
4853         /* Avoid longjmp clobbering */
4854         (void) &dest;
4855         (void) &syntax;
4856 #endif
4857
4858         in.fd = -1;
4859         in.buf = 0;
4860         in.jp = 0;
4861
4862         INTOFF;
4863         saveifs = ifsfirst;
4864         savelastp = ifslastp;
4865         saveargbackq = argbackq;
4866         saveherefd = herefd;
4867         herefd = -1;
4868         if ((ex = setjmp(jmploc.loc))) {
4869                 goto err1;
4870         }
4871         savehandler = handler;
4872         handler = &jmploc;
4873         INTON;
4874         p = grabstackstr(dest);
4875         evalbackcmd(cmd, (struct backcmd *) &in);
4876         ungrabstackstr(p, dest);
4877 err1:
4878         INTOFF;
4879         ifsfirst = saveifs;
4880         ifslastp = savelastp;
4881         argbackq = saveargbackq;
4882         herefd = saveherefd;
4883         if (ex) {
4884                 goto err2;
4885         }
4886
4887         p = in.buf;
4888         lastc = '\0';
4889         for (;;) {
4890                 if (--in.nleft < 0) {
4891                         if (in.fd < 0)
4892                                 break;
4893                         i = safe_read(in.fd, buf, sizeof buf);
4894                         TRACE(("expbackq: read returns %d\n", i));
4895                         if (i <= 0)
4896                                 break;
4897                         p = buf;
4898                         in.nleft = i - 1;
4899                 }
4900                 lastc = *p++;
4901                 if (lastc != '\0') {
4902                         if (quotes && SIT(lastc, syntax) == CCTL)
4903                                 STPUTC(CTLESC, dest);
4904                         STPUTC(lastc, dest);
4905                 }
4906         }
4907
4908         /* Eat all trailing newlines */
4909         for (; dest > stackblock() && dest[-1] == '\n';)
4910                 STUNPUTC(dest);
4911
4912 err2:
4913         if (in.fd >= 0)
4914                 close(in.fd);
4915         if (in.buf)
4916                 ckfree(in.buf);
4917         if (in.jp)
4918                 exitstatus = waitforjob(in.jp);
4919         handler = savehandler;
4920         if (ex) {
4921                 longjmp(handler->loc, 1);
4922         }
4923         if (quoted == 0)
4924                 recordregion(startloc, dest - stackblock(), 0);
4925         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4926                 (dest - stackblock()) - startloc,
4927                 (dest - stackblock()) - startloc,
4928                 stackblock() + startloc));
4929         expdest = dest;
4930         INTON;
4931 }
4932
4933 static int
4934 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4935         char *p;
4936         char *str;
4937         int strloc;
4938         int subtype;
4939         int startloc;
4940         int varflags;
4941         int quotes;
4942 {
4943         char *startp;
4944         char *loc = NULL;
4945         char *q;
4946         int c = 0;
4947         int saveherefd = herefd;
4948         struct nodelist *saveargbackq = argbackq;
4949         int amount;
4950
4951         herefd = -1;
4952         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4953         STACKSTRNUL(expdest);
4954         herefd = saveherefd;
4955         argbackq = saveargbackq;
4956         startp = stackblock() + startloc;
4957         if (str == NULL)
4958             str = stackblock() + strloc;
4959
4960         switch (subtype) {
4961         case VSASSIGN:
4962                 setvar(str, startp, 0);
4963                 amount = startp - expdest;
4964                 STADJUST(amount, expdest);
4965                 varflags &= ~VSNUL;
4966                 if (c != 0)
4967                         *loc = c;
4968                 return 1;
4969
4970         case VSQUESTION:
4971                 if (*p != CTLENDVAR) {
4972                         out2fmt(snlfmt, startp);
4973                         error((char *)NULL);
4974                 }
4975                 error("%.*s: parameter %snot set", p - str - 1,
4976                       str, (varflags & VSNUL) ? "null or "
4977                                               : nullstr);
4978                 /* NOTREACHED */
4979
4980         case VSTRIMLEFT:
4981                 for (loc = startp; loc < str; loc++) {
4982                         c = *loc;
4983                         *loc = '\0';
4984                         if (patmatch2(str, startp, quotes))
4985                                 goto recordleft;
4986                         *loc = c;
4987                         if (quotes && *loc == CTLESC)
4988                                 loc++;
4989                 }
4990                 return 0;
4991
4992         case VSTRIMLEFTMAX:
4993                 for (loc = str - 1; loc >= startp;) {
4994                         c = *loc;
4995                         *loc = '\0';
4996                         if (patmatch2(str, startp, quotes))
4997                                 goto recordleft;
4998                         *loc = c;
4999                         loc--;
5000                         if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5001                                 for (q = startp; q < loc; q++)
5002                                         if (*q == CTLESC)
5003                                                 q++;
5004                                 if (q > loc)
5005                                         loc--;
5006                         }
5007                 }
5008                 return 0;
5009
5010         case VSTRIMRIGHT:
5011                 for (loc = str - 1; loc >= startp;) {
5012                         if (patmatch2(str, loc, quotes))
5013                                 goto recordright;
5014                         loc--;
5015                         if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5016                                 for (q = startp; q < loc; q++)
5017                                         if (*q == CTLESC)
5018                                                 q++;
5019                                 if (q > loc)
5020                                         loc--;
5021                         }
5022                 }
5023                 return 0;
5024
5025         case VSTRIMRIGHTMAX:
5026                 for (loc = startp; loc < str - 1; loc++) {
5027                         if (patmatch2(str, loc, quotes))
5028                                 goto recordright;
5029                         if (quotes && *loc == CTLESC)
5030                                 loc++;
5031                 }
5032                 return 0;
5033
5034 #ifdef DEBUG
5035         default:
5036                 abort();
5037 #endif
5038         }
5039
5040 recordleft:
5041         *loc = c;
5042         amount = ((str - 1) - (loc - startp)) - expdest;
5043         STADJUST(amount, expdest);
5044         while (loc != str - 1)
5045                 *startp++ = *loc++;
5046         return 1;
5047
5048 recordright:
5049         amount = loc - expdest;
5050         STADJUST(amount, expdest);
5051         STPUTC('\0', expdest);
5052         STADJUST(-1, expdest);
5053         return 1;
5054 }
5055
5056
5057 /*
5058  * Test whether a specialized variable is set.
5059  */
5060
5061 static int
5062 varisset(name, nulok)
5063         char *name;
5064         int nulok;
5065 {
5066         if (*name == '!')
5067                 return backgndpid != -1;
5068         else if (*name == '@' || *name == '*') {
5069                 if (*shellparam.p == NULL)
5070                         return 0;
5071
5072                 if (nulok) {
5073                         char **av;
5074
5075                         for (av = shellparam.p; *av; av++)
5076                                 if (**av != '\0')
5077                                         return 1;
5078                         return 0;
5079                 }
5080         } else if (is_digit(*name)) {
5081                 char *ap;
5082                 int num = atoi(name);
5083
5084                 if (num > shellparam.nparam)
5085                         return 0;
5086
5087                 if (num == 0)
5088                         ap = arg0;
5089                 else
5090                         ap = shellparam.p[num - 1];
5091
5092                 if (nulok && (ap == NULL || *ap == '\0'))
5093                         return 0;
5094         }
5095         return 1;
5096 }
5097
5098 /*
5099  * Put a string on the stack.
5100  */
5101
5102 static void
5103 strtodest(const char *p, int syntax, int quotes)
5104 {
5105         while (*p) {
5106                 if (quotes && SIT(*p,syntax) == CCTL)
5107                         STPUTC(CTLESC, expdest);
5108                 STPUTC(*p++, expdest);
5109         }
5110 }
5111
5112 /*
5113  * Add the value of a specialized variable to the stack string.
5114  */
5115
5116 static void
5117 varvalue(char *name, int quoted, int flags)
5118 {
5119         int num;
5120         char *p;
5121         int i;
5122         int sep;
5123         int sepq = 0;
5124         char **ap;
5125         int syntax;
5126         int allow_split = flags & EXP_FULL;
5127         int quotes = flags & (EXP_FULL | EXP_CASE);
5128
5129         syntax = quoted ? DQSYNTAX : BASESYNTAX;
5130         switch (*name) {
5131         case '$':
5132                 num = rootpid;
5133                 goto numvar;
5134         case '?':
5135                 num = oexitstatus;
5136                 goto numvar;
5137         case '#':
5138                 num = shellparam.nparam;
5139                 goto numvar;
5140         case '!':
5141                 num = backgndpid;
5142 numvar:
5143                 expdest = cvtnum(num, expdest);
5144                 break;
5145         case '-':
5146                 for (i = 0 ; i < NOPTS ; i++) {
5147                         if (optent_val(i))
5148                                 STPUTC(optent_letter(optlist[i]), expdest);
5149                 }
5150                 break;
5151         case '@':
5152                 if (allow_split && quoted) {
5153                         sep = 1 << CHAR_BIT;
5154                         goto param;
5155                 }
5156                 /* fall through */
5157         case '*':
5158                 sep = ifsset() ? ifsval()[0] : ' ';
5159                 if (quotes) {
5160                         sepq = SIT(sep,syntax) == CCTL;
5161                 }
5162 param:
5163                 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5164                         strtodest(p, syntax, quotes);
5165                         if (*ap && sep) {
5166                                 if (sepq)
5167                                         STPUTC(CTLESC, expdest);
5168                                 STPUTC(sep, expdest);
5169                         }
5170                 }
5171                 break;
5172         case '0':
5173                 strtodest(arg0, syntax, quotes);
5174                 break;
5175         default:
5176                 num = atoi(name);
5177                 if (num > 0 && num <= shellparam.nparam) {
5178                         strtodest(shellparam.p[num - 1], syntax, quotes);
5179                 }
5180                 break;
5181         }
5182 }
5183
5184
5185 /*
5186  * Record the fact that we have to scan this region of the
5187  * string for IFS characters.
5188  */
5189
5190 static void
5191 recordregion(start, end, nulonly)
5192         int start;
5193         int end;
5194         int nulonly;
5195 {
5196         struct ifsregion *ifsp;
5197
5198         if (ifslastp == NULL) {
5199                 ifsp = &ifsfirst;
5200         } else {
5201                 INTOFF;
5202                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5203                 ifsp->next = NULL;
5204                 ifslastp->next = ifsp;
5205                 INTON;
5206         }
5207         ifslastp = ifsp;
5208         ifslastp->begoff = start;
5209         ifslastp->endoff = end;
5210         ifslastp->nulonly = nulonly;
5211 }
5212
5213
5214
5215 /*
5216  * Break the argument string into pieces based upon IFS and add the
5217  * strings to the argument list.  The regions of the string to be
5218  * searched for IFS characters have been stored by recordregion.
5219  */
5220 static void
5221 ifsbreakup(string, arglist)
5222         char *string;
5223         struct arglist *arglist;
5224         {
5225         struct ifsregion *ifsp;
5226         struct strlist *sp;
5227         char *start;
5228         char *p;
5229         char *q;
5230         const char *ifs, *realifs;
5231         int ifsspc;
5232         int nulonly;
5233
5234
5235         start = string;
5236         ifsspc = 0;
5237         nulonly = 0;
5238         realifs = ifsset() ? ifsval() : defifs;
5239         if (ifslastp != NULL) {
5240                 ifsp = &ifsfirst;
5241                 do {
5242                         p = string + ifsp->begoff;
5243                         nulonly = ifsp->nulonly;
5244                         ifs = nulonly ? nullstr : realifs;
5245                         ifsspc = 0;
5246                         while (p < string + ifsp->endoff) {
5247                                 q = p;
5248                                 if (*p == CTLESC)
5249                                         p++;
5250                                 if (strchr(ifs, *p)) {
5251                                         if (!nulonly)
5252                                                 ifsspc = (strchr(defifs, *p) != NULL);
5253                                         /* Ignore IFS whitespace at start */
5254                                         if (q == start && ifsspc) {
5255                                                 p++;
5256                                                 start = p;
5257                                                 continue;
5258                                         }
5259                                         *q = '\0';
5260                                         sp = (struct strlist *)stalloc(sizeof *sp);
5261                                         sp->text = start;
5262                                         *arglist->lastp = sp;
5263                                         arglist->lastp = &sp->next;
5264                                         p++;
5265                                         if (!nulonly) {
5266                                                 for (;;) {
5267                                                         if (p >= string + ifsp->endoff) {
5268                                                                 break;
5269                                                         }
5270                                                         q = p;
5271                                                         if (*p == CTLESC)
5272                                                                 p++;
5273                                                         if (strchr(ifs, *p) == NULL ) {
5274                                                                 p = q;
5275                                                                 break;
5276                                                         } else if (strchr(defifs, *p) == NULL) {
5277                                                                 if (ifsspc) {
5278                                                                         p++;
5279                                                                         ifsspc = 0;
5280                                                                 } else {
5281                                                                         p = q;
5282                                                                         break;
5283                                                                 }
5284                                                         } else
5285                                                                 p++;
5286                                                 }
5287                                         }
5288                                         start = p;
5289                                 } else
5290                                         p++;
5291                         }
5292                 } while ((ifsp = ifsp->next) != NULL);
5293                 if (!(*start || (!ifsspc && start > string && nulonly))) {
5294                         return;
5295                 }
5296         }
5297
5298         sp = (struct strlist *)stalloc(sizeof *sp);
5299         sp->text = start;
5300         *arglist->lastp = sp;
5301         arglist->lastp = &sp->next;
5302 }
5303
5304 static void
5305 ifsfree()
5306 {
5307         while (ifsfirst.next != NULL) {
5308                 struct ifsregion *ifsp;
5309                 INTOFF;
5310                 ifsp = ifsfirst.next->next;
5311                 ckfree(ifsfirst.next);
5312                 ifsfirst.next = ifsp;
5313                 INTON;
5314         }
5315         ifslastp = NULL;
5316         ifsfirst.next = NULL;
5317 }
5318
5319 /*
5320  * Add a file name to the list.
5321  */
5322
5323 static void
5324 addfname(const char *name)
5325 {
5326         char *p;
5327         struct strlist *sp;
5328
5329         p = sstrdup(name);
5330         sp = (struct strlist *)stalloc(sizeof *sp);
5331         sp->text = p;
5332         *exparg.lastp = sp;
5333         exparg.lastp = &sp->next;
5334 }
5335
5336 /*
5337  * Expand shell metacharacters.  At this point, the only control characters
5338  * should be escapes.  The results are stored in the list exparg.
5339  */
5340
5341 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5342 static void
5343 expandmeta(str, flag)
5344         struct strlist *str;
5345         int flag;
5346 {
5347         const char *p;
5348         glob_t pglob;
5349         /* TODO - EXP_REDIR */
5350
5351         while (str) {
5352                 if (fflag)
5353                         goto nometa;
5354                 p = preglob(str->text);
5355                 INTOFF;
5356                 switch (glob(p, 0, 0, &pglob)) {
5357                 case 0:
5358                         if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
5359                                 goto nometa2;
5360                         addglob(&pglob);
5361                         globfree(&pglob);
5362                         INTON;
5363                         break;
5364                 case GLOB_NOMATCH:
5365 nometa2:
5366                         globfree(&pglob);
5367                         INTON;
5368 nometa:
5369                         *exparg.lastp = str;
5370                         rmescapes(str->text);
5371                         exparg.lastp = &str->next;
5372                         break;
5373                 default:        /* GLOB_NOSPACE */
5374                         error("Out of space");
5375                 }
5376                 str = str->next;
5377         }
5378 }
5379
5380
5381 /*
5382  * Add the result of glob(3) to the list.
5383  */
5384
5385 static void
5386 addglob(pglob)
5387         const glob_t *pglob;
5388 {
5389         char **p = pglob->gl_pathv;
5390
5391         do {
5392                 addfname(*p);
5393         } while (*++p);
5394 }
5395
5396
5397 #else   /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5398 static char *expdir;
5399
5400
5401 static void
5402 expandmeta(str, flag)
5403         struct strlist *str;
5404         int flag;
5405 {
5406         char *p;
5407         struct strlist **savelastp;
5408         struct strlist *sp;
5409         char c;
5410         /* TODO - EXP_REDIR */
5411
5412         while (str) {
5413                 if (fflag)
5414                         goto nometa;
5415                 p = str->text;
5416                 for (;;) {                      /* fast check for meta chars */
5417                         if ((c = *p++) == '\0')
5418                                 goto nometa;
5419                         if (c == '*' || c == '?' || c == '[' || c == '!')
5420                                 break;
5421                 }
5422                 savelastp = exparg.lastp;
5423                 INTOFF;
5424                 if (expdir == NULL) {
5425                         int i = strlen(str->text);
5426                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5427                 }
5428
5429                 expmeta(expdir, str->text);
5430                 ckfree(expdir);
5431                 expdir = NULL;
5432                 INTON;
5433                 if (exparg.lastp == savelastp) {
5434                         /*
5435                          * no matches
5436                          */
5437 nometa:
5438                         *exparg.lastp = str;
5439                         rmescapes(str->text);
5440                         exparg.lastp = &str->next;
5441                 } else {
5442                         *exparg.lastp = NULL;
5443                         *savelastp = sp = expsort(*savelastp);
5444                         while (sp->next != NULL)
5445                                 sp = sp->next;
5446                         exparg.lastp = &sp->next;
5447                 }
5448                 str = str->next;
5449         }
5450 }
5451
5452
5453 /*
5454  * Do metacharacter (i.e. *, ?, [...]) expansion.
5455  */
5456
5457 static void
5458 expmeta(enddir, name)
5459         char *enddir;
5460         char *name;
5461         {
5462         char *p;
5463         const char *cp;
5464         char *q;
5465         char *start;
5466         char *endname;
5467         int metaflag;
5468         struct stat statb;
5469         DIR *dirp;
5470         struct dirent *dp;
5471         int atend;
5472         int matchdot;
5473
5474         metaflag = 0;
5475         start = name;
5476         for (p = name ; ; p++) {
5477                 if (*p == '*' || *p == '?')
5478                         metaflag = 1;
5479                 else if (*p == '[') {
5480                         q = p + 1;
5481                         if (*q == '!')
5482                                 q++;
5483                         for (;;) {
5484                                 while (*q == CTLQUOTEMARK)
5485                                         q++;
5486                                 if (*q == CTLESC)
5487                                         q++;
5488                                 if (*q == '/' || *q == '\0')
5489                                         break;
5490                                 if (*++q == ']') {
5491                                         metaflag = 1;
5492                                         break;
5493                                 }
5494                         }
5495                 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
5496                         metaflag = 1;
5497                 } else if (*p == '\0')
5498                         break;
5499                 else if (*p == CTLQUOTEMARK)
5500                         continue;
5501                 else if (*p == CTLESC)
5502                         p++;
5503                 if (*p == '/') {
5504                         if (metaflag)
5505                                 break;
5506                         start = p + 1;
5507                 }
5508         }
5509         if (metaflag == 0) {    /* we've reached the end of the file name */
5510                 if (enddir != expdir)
5511                         metaflag++;
5512                 for (p = name ; ; p++) {
5513                         if (*p == CTLQUOTEMARK)
5514                                 continue;
5515                         if (*p == CTLESC)
5516                                 p++;
5517                         *enddir++ = *p;
5518                         if (*p == '\0')
5519                                 break;
5520                 }
5521                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5522                         addfname(expdir);
5523                 return;
5524         }
5525         endname = p;
5526         if (start != name) {
5527                 p = name;
5528                 while (p < start) {
5529                         while (*p == CTLQUOTEMARK)
5530                                 p++;
5531                         if (*p == CTLESC)
5532                                 p++;
5533                         *enddir++ = *p++;
5534                 }
5535         }
5536         if (enddir == expdir) {
5537                 cp = ".";
5538         } else if (enddir == expdir + 1 && *expdir == '/') {
5539                 cp = "/";
5540         } else {
5541                 cp = expdir;
5542                 enddir[-1] = '\0';
5543         }
5544         if ((dirp = opendir(cp)) == NULL)
5545                 return;
5546         if (enddir != expdir)
5547                 enddir[-1] = '/';
5548         if (*endname == 0) {
5549                 atend = 1;
5550         } else {
5551                 atend = 0;
5552                 *endname++ = '\0';
5553         }
5554         matchdot = 0;
5555         p = start;
5556         while (*p == CTLQUOTEMARK)
5557                 p++;
5558         if (*p == CTLESC)
5559                 p++;
5560         if (*p == '.')
5561                 matchdot++;
5562         while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5563                 if (dp->d_name[0] == '.' && ! matchdot)
5564                         continue;
5565                 if (patmatch(start, dp->d_name, 0)) {
5566                         if (atend) {
5567                                 strcpy(enddir, dp->d_name);
5568                                 addfname(expdir);
5569                         } else {
5570                                 for (p = enddir, cp = dp->d_name;
5571                                      (*p++ = *cp++) != '\0';)
5572                                         continue;
5573                                 p[-1] = '/';
5574                                 expmeta(p, endname);
5575                         }
5576                 }
5577         }
5578         closedir(dirp);
5579         if (! atend)
5580                 endname[-1] = '/';
5581 }
5582 #endif  /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5583
5584
5585
5586 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5587 /*
5588  * Sort the results of file name expansion.  It calculates the number of
5589  * strings to sort and then calls msort (short for merge sort) to do the
5590  * work.
5591  */
5592
5593 static struct strlist *
5594 expsort(str)
5595         struct strlist *str;
5596         {
5597         int len;
5598         struct strlist *sp;
5599
5600         len = 0;
5601         for (sp = str ; sp ; sp = sp->next)
5602                 len++;
5603         return msort(str, len);
5604 }
5605
5606
5607 static struct strlist *
5608 msort(list, len)
5609         struct strlist *list;
5610         int len;
5611 {
5612         struct strlist *p, *q = NULL;
5613         struct strlist **lpp;
5614         int half;
5615         int n;
5616
5617         if (len <= 1)
5618                 return list;
5619         half = len >> 1;
5620         p = list;
5621         for (n = half ; --n >= 0 ; ) {
5622                 q = p;
5623                 p = p->next;
5624         }
5625         q->next = NULL;                 /* terminate first half of list */
5626         q = msort(list, half);          /* sort first half of list */
5627         p = msort(p, len - half);               /* sort second half */
5628         lpp = &list;
5629         for (;;) {
5630                 if (strcmp(p->text, q->text) < 0) {
5631                         *lpp = p;
5632                         lpp = &p->next;
5633                         if ((p = *lpp) == NULL) {
5634                                 *lpp = q;
5635                                 break;
5636                         }
5637                 } else {
5638                         *lpp = q;
5639                         lpp = &q->next;
5640                         if ((q = *lpp) == NULL) {
5641                                 *lpp = p;
5642                                 break;
5643                         }
5644                 }
5645         }
5646         return list;
5647 }
5648 #endif
5649
5650
5651
5652 /*
5653  * Returns true if the pattern matches the string.
5654  */
5655
5656 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5657 /* squoted: string might have quote chars */
5658 static int
5659 patmatch(char *pattern, char *string, int squoted)
5660 {
5661         const char *p;
5662         char *q;
5663
5664         p = preglob(pattern);
5665         q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5666
5667         return !fnmatch(p, q, 0);
5668 }
5669
5670
5671 static int
5672 patmatch2(char *pattern, char *string, int squoted)
5673 {
5674         char *p;
5675         int res;
5676
5677         sstrnleft--;
5678         p = grabstackstr(expdest);
5679         res = patmatch(pattern, string, squoted);
5680         ungrabstackstr(p, expdest);
5681         return res;
5682 }
5683 #else
5684 static int
5685 patmatch(char *pattern, char *string, int squoted) {
5686         return pmatch(pattern, string, squoted);
5687 }
5688
5689
5690 static int
5691 pmatch(char *pattern, char *string, int squoted)
5692 {
5693         char *p, *q;
5694         char c;
5695
5696         p = pattern;
5697         q = string;
5698         for (;;) {
5699                 switch (c = *p++) {
5700                 case '\0':
5701                         goto breakloop;
5702                 case CTLESC:
5703                         if (squoted && *q == CTLESC)
5704                                 q++;
5705                         if (*q++ != *p++)
5706                                 return 0;
5707                         break;
5708                 case CTLQUOTEMARK:
5709                         continue;
5710                 case '?':
5711                         if (squoted && *q == CTLESC)
5712                                 q++;
5713                         if (*q++ == '\0')
5714                                 return 0;
5715                         break;
5716                 case '*':
5717                         c = *p;
5718                         while (c == CTLQUOTEMARK || c == '*')
5719                                 c = *++p;
5720                         if (c != CTLESC &&  c != CTLQUOTEMARK &&
5721                             c != '?' && c != '*' && c != '[') {
5722                                 while (*q != c) {
5723                                         if (squoted && *q == CTLESC &&
5724                                             q[1] == c)
5725                                                 break;
5726                                         if (*q == '\0')
5727                                                 return 0;
5728                                         if (squoted && *q == CTLESC)
5729                                                 q++;
5730                                         q++;
5731                                 }
5732                         }
5733                         do {
5734                                 if (pmatch(p, q, squoted))
5735                                         return 1;
5736                                 if (squoted && *q == CTLESC)
5737                                         q++;
5738                         } while (*q++ != '\0');
5739                         return 0;
5740                 case '[': {
5741                         char *endp;
5742                         int invert, found;
5743                         char chr;
5744
5745                         endp = p;
5746                         if (*endp == '!')
5747                                 endp++;
5748                         for (;;) {
5749                                 while (*endp == CTLQUOTEMARK)
5750                                         endp++;
5751                                 if (*endp == '\0')
5752                                         goto dft;               /* no matching ] */
5753                                 if (*endp == CTLESC)
5754                                         endp++;
5755                                 if (*++endp == ']')
5756                                         break;
5757                         }
5758                         invert = 0;
5759                         if (*p == '!') {
5760                                 invert++;
5761                                 p++;
5762                         }
5763                         found = 0;
5764                         chr = *q++;
5765                         if (squoted && chr == CTLESC)
5766                                 chr = *q++;
5767                         if (chr == '\0')
5768                                 return 0;
5769                         c = *p++;
5770                         do {
5771                                 if (c == CTLQUOTEMARK)
5772                                         continue;
5773                                 if (c == CTLESC)
5774                                         c = *p++;
5775                                 if (*p == '-' && p[1] != ']') {
5776                                         p++;
5777                                         while (*p == CTLQUOTEMARK)
5778                                                 p++;
5779                                         if (*p == CTLESC)
5780                                                 p++;
5781                                         if (chr >= c && chr <= *p)
5782                                                 found = 1;
5783                                         p++;
5784                                 } else {
5785                                         if (chr == c)
5786                                                 found = 1;
5787                                 }
5788                         } while ((c = *p++) != ']');
5789                         if (found == invert)
5790                                 return 0;
5791                         break;
5792                 }
5793 dft:            default:
5794                         if (squoted && *q == CTLESC)
5795                                 q++;
5796                         if (*q++ != c)
5797                                 return 0;
5798                         break;
5799                 }
5800         }
5801 breakloop:
5802         if (*q != '\0')
5803                 return 0;
5804         return 1;
5805 }
5806 #endif
5807
5808
5809
5810 /*
5811  * Remove any CTLESC characters from a string.
5812  */
5813
5814 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5815 static char *
5816 _rmescapes(char *str, int flag)
5817 {
5818         char *p, *q, *r;
5819         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5820
5821         p = strpbrk(str, qchars);
5822         if (!p) {
5823                 return str;
5824         }
5825         q = p;
5826         r = str;
5827         if (flag & RMESCAPE_ALLOC) {
5828                 size_t len = p - str;
5829                 q = r = stalloc(strlen(p) + len + 1);
5830                 if (len > 0) {
5831                         memcpy(q, str, len);
5832                         q += len;
5833                 }
5834         }
5835         while (*p) {
5836                 if (*p == CTLQUOTEMARK) {
5837                         p++;
5838                         continue;
5839                 }
5840                 if (*p == CTLESC) {
5841                         p++;
5842                         if (flag & RMESCAPE_GLOB && *p != '/') {
5843                                 *q++ = '\\';
5844                         }
5845                 }
5846                 *q++ = *p++;
5847         }
5848         *q = '\0';
5849         return r;
5850 }
5851 #else
5852 static void
5853 rmescapes(str)
5854         char *str;
5855 {
5856         char *p, *q;
5857
5858         p = str;
5859         while (*p != CTLESC && *p != CTLQUOTEMARK) {
5860                 if (*p++ == '\0')
5861                         return;
5862         }
5863         q = p;
5864         while (*p) {
5865                 if (*p == CTLQUOTEMARK) {
5866                         p++;
5867                         continue;
5868                 }
5869                 if (*p == CTLESC)
5870                         p++;
5871                 *q++ = *p++;
5872         }
5873         *q = '\0';
5874 }
5875 #endif
5876
5877
5878
5879 /*
5880  * See if a pattern matches in a case statement.
5881  */
5882
5883 static int
5884 casematch(union node *pattern, const char *val)
5885 {
5886         struct stackmark smark;
5887         int result;
5888         char *p;
5889
5890         setstackmark(&smark);
5891         argbackq = pattern->narg.backquote;
5892         STARTSTACKSTR(expdest);
5893         ifslastp = NULL;
5894         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5895         STPUTC('\0', expdest);
5896         p = grabstackstr(expdest);
5897         result = patmatch(p, (char *)val, 0);
5898         popstackmark(&smark);
5899         return result;
5900 }
5901
5902 /*
5903  * Our own itoa().
5904  */
5905
5906 static char *
5907 cvtnum(num, buf)
5908         int num;
5909         char *buf;
5910         {
5911         int len;
5912
5913         CHECKSTRSPACE(32, buf);
5914         len = sprintf(buf, "%d", num);
5915         STADJUST(len, buf);
5916         return buf;
5917 }
5918 /*
5919  * Editline and history functions (and glue).
5920  */
5921 static int histcmd(argc, argv)
5922         int argc;
5923         char **argv;
5924 {
5925         error("not compiled with history support");
5926         /* NOTREACHED */
5927 }
5928
5929
5930 struct redirtab {
5931         struct redirtab *next;
5932         short renamed[10]; /* Current ash support only 0-9 descriptors */
5933         /* char on arm (and others) can't be negative */
5934 };
5935
5936 static struct redirtab *redirlist;
5937
5938 extern char **environ;
5939
5940
5941
5942 /*
5943  * Initialization code.
5944  */
5945
5946 static void
5947 init(void) {
5948
5949       /* from cd.c: */
5950       {
5951               setpwd(0, 0);
5952       }
5953
5954       /* from input.c: */
5955       {
5956               basepf.nextc = basepf.buf = basebuf;
5957       }
5958
5959       /* from var.c: */
5960       {
5961               char **envp;
5962               char ppid[32];
5963
5964               initvar();
5965               for (envp = environ ; *envp ; envp++) {
5966                       if (strchr(*envp, '=')) {
5967                               setvareq(*envp, VEXPORT|VTEXTFIXED);
5968                       }
5969               }
5970
5971               snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5972               setvar("PPID", ppid, 0);
5973       }
5974 }
5975
5976
5977
5978 /*
5979  * This routine is called when an error or an interrupt occurs in an
5980  * interactive shell and control is returned to the main command loop.
5981  */
5982
5983 /* 1 == check for aliases, 2 == also check for assignments */
5984 static int checkalias;  /* also used in no alias mode for check assignments */
5985
5986 static void
5987 reset(void) {
5988
5989       /* from eval.c: */
5990       {
5991               evalskip = 0;
5992               loopnest = 0;
5993               funcnest = 0;
5994       }
5995
5996       /* from input.c: */
5997       {
5998               if (exception != EXSHELLPROC)
5999                       parselleft = parsenleft = 0;      /* clear input buffer */
6000               popallfiles();
6001       }
6002
6003       /* from parser.c: */
6004       {
6005               tokpushback = 0;
6006               checkkwd = 0;
6007               checkalias = 0;
6008       }
6009
6010       /* from redir.c: */
6011       {
6012               while (redirlist)
6013                       popredir();
6014       }
6015
6016 }
6017
6018
6019
6020 /*
6021  * This file implements the input routines used by the parser.
6022  */
6023
6024 #ifdef BB_FEATURE_COMMAND_EDITING
6025 static const char * cmdedit_prompt;
6026 static inline void putprompt(const char *s) {
6027     cmdedit_prompt = s;
6028 }
6029 #else
6030 static inline void putprompt(const char *s) {
6031     out2str(s);
6032 }
6033 #endif
6034
6035 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
6036
6037
6038
6039 /*
6040  * Same as pgetc(), but ignores PEOA.
6041  */
6042
6043 #ifdef ASH_ALIAS
6044 static int
6045 pgetc2(void)
6046 {
6047         int c;
6048         do {
6049                 c = pgetc_macro();
6050         } while (c == PEOA);
6051         return c;
6052 }
6053 #else
6054 static inline int pgetc2() { return pgetc_macro(); }
6055 #endif
6056
6057 /*
6058  * Read a line from the script.
6059  */
6060
6061 static inline char *
6062 pfgets(char *line, int len)
6063 {
6064         char *p = line;
6065         int nleft = len;
6066         int c;
6067
6068         while (--nleft > 0) {
6069                 c = pgetc2();
6070                 if (c == PEOF) {
6071                         if (p == line)
6072                                 return NULL;
6073                         break;
6074                 }
6075                 *p++ = c;
6076                 if (c == '\n')
6077                         break;
6078         }
6079         *p = '\0';
6080         return line;
6081 }
6082
6083 static inline int
6084 preadfd(void)
6085 {
6086     int nr;
6087     char *buf =  parsefile->buf;
6088     parsenextc = buf;
6089
6090 retry:
6091 #ifdef BB_FEATURE_COMMAND_EDITING
6092         {
6093             if (!iflag || parsefile->fd)
6094                     nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6095             else {
6096                     nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
6097             }
6098         }
6099 #else
6100         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6101 #endif
6102
6103         if (nr < 0) {
6104                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6105                         int flags = fcntl(0, F_GETFL, 0);
6106                         if (flags >= 0 && flags & O_NONBLOCK) {
6107                                 flags &=~ O_NONBLOCK;
6108                                 if (fcntl(0, F_SETFL, flags) >= 0) {
6109                                         out2str("sh: turning off NDELAY mode\n");
6110                                         goto retry;
6111                                 }
6112                         }
6113                 }
6114         }
6115         return nr;
6116 }
6117
6118 static void
6119 popstring(void)
6120 {
6121         struct strpush *sp = parsefile->strpush;
6122
6123         INTOFF;
6124 #ifdef ASH_ALIAS
6125         if (sp->ap) {
6126                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6127                         if (!checkalias) {
6128                                 checkalias = 1;
6129                         }
6130                 }
6131                 if (sp->string != sp->ap->val) {
6132                         ckfree(sp->string);
6133                 }
6134
6135                 sp->ap->flag &= ~ALIASINUSE;
6136                 if (sp->ap->flag & ALIASDEAD) {
6137                         unalias(sp->ap->name);
6138                 }
6139         }
6140 #endif
6141         parsenextc = sp->prevstring;
6142         parsenleft = sp->prevnleft;
6143 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6144         parsefile->strpush = sp->prev;
6145         if (sp != &(parsefile->basestrpush))
6146                 ckfree(sp);
6147         INTON;
6148 }
6149
6150
6151 /*
6152  * Refill the input buffer and return the next input character:
6153  *
6154  * 1) If a string was pushed back on the input, pop it;
6155  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6156  *    from a string so we can't refill the buffer, return EOF.
6157  * 3) If the is more stuff in this buffer, use it else call read to fill it.
6158  * 4) Process input up to the next newline, deleting nul characters.
6159  */
6160
6161 static int
6162 preadbuffer(void)
6163 {
6164         char *p, *q;
6165         int more;
6166         char savec;
6167
6168         while (parsefile->strpush) {
6169 #ifdef ASH_ALIAS
6170                 if (parsenleft == -1 && parsefile->strpush->ap &&
6171                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6172                         return PEOA;
6173                 }
6174 #endif
6175                 popstring();
6176                 if (--parsenleft >= 0)
6177                         return (*parsenextc++);
6178         }
6179         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6180                 return PEOF;
6181         flushall();
6182
6183 again:
6184         if (parselleft <= 0) {
6185                 if ((parselleft = preadfd()) <= 0) {
6186                         parselleft = parsenleft = EOF_NLEFT;
6187                         return PEOF;
6188                 }
6189         }
6190
6191         q = p = parsenextc;
6192
6193         /* delete nul characters */
6194         for (more = 1; more;) {
6195                 switch (*p) {
6196                 case '\0':
6197                         p++;    /* Skip nul */
6198                         goto check;
6199
6200
6201                 case '\n':
6202                         parsenleft = q - parsenextc;
6203                         more = 0; /* Stop processing here */
6204                         break;
6205                 }
6206
6207                 *q++ = *p++;
6208 check:
6209                 if (--parselleft <= 0 && more) {
6210                         parsenleft = q - parsenextc - 1;
6211                         if (parsenleft < 0)
6212                                 goto again;
6213                         more = 0;
6214                 }
6215         }
6216
6217         savec = *q;
6218         *q = '\0';
6219
6220         if (vflag) {
6221                 out2str(parsenextc);
6222         }
6223
6224         *q = savec;
6225
6226         return *parsenextc++;
6227 }
6228
6229
6230 /*
6231  * Push a string back onto the input at this current parsefile level.
6232  * We handle aliases this way.
6233  */
6234 static void
6235 pushstring(char *s, int len, void *ap)
6236 {
6237         struct strpush *sp;
6238
6239         INTOFF;
6240 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6241         if (parsefile->strpush) {
6242                 sp = ckmalloc(sizeof (struct strpush));
6243                 sp->prev = parsefile->strpush;
6244                 parsefile->strpush = sp;
6245         } else
6246                 sp = parsefile->strpush = &(parsefile->basestrpush);
6247         sp->prevstring = parsenextc;
6248         sp->prevnleft = parsenleft;
6249 #ifdef ASH_ALIAS
6250         sp->ap = (struct alias *)ap;
6251         if (ap) {
6252                 ((struct alias *)ap)->flag |= ALIASINUSE;
6253                 sp->string = s;
6254         }
6255 #endif
6256         parsenextc = s;
6257         parsenleft = len;
6258         INTON;
6259 }
6260
6261
6262 /*
6263  * Like setinputfile, but takes input from a string.
6264  */
6265
6266 static void
6267 setinputstring(char *string)
6268 {
6269         INTOFF;
6270         pushfile();
6271         parsenextc = string;
6272         parsenleft = strlen(string);
6273         parsefile->buf = NULL;
6274         plinno = 1;
6275         INTON;
6276 }
6277
6278
6279
6280 /*
6281  * To handle the "." command, a stack of input files is used.  Pushfile
6282  * adds a new entry to the stack and popfile restores the previous level.
6283  */
6284
6285 static void
6286 pushfile(void) {
6287         struct parsefile *pf;
6288
6289         parsefile->nleft = parsenleft;
6290         parsefile->lleft = parselleft;
6291         parsefile->nextc = parsenextc;
6292         parsefile->linno = plinno;
6293         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6294         pf->prev = parsefile;
6295         pf->fd = -1;
6296         pf->strpush = NULL;
6297         pf->basestrpush.prev = NULL;
6298         parsefile = pf;
6299 }
6300
6301 #ifdef JOBS
6302 static void restartjob (struct job *);
6303 #endif
6304 static void freejob (struct job *);
6305 static struct job *getjob (const char *);
6306 static int dowait (int, struct job *);
6307 static void waitonint(int);
6308
6309
6310 /*
6311  * We keep track of whether or not fd0 has been redirected.  This is for
6312  * background commands, where we want to redirect fd0 to /dev/null only
6313  * if it hasn't already been redirected.
6314 */
6315 static int fd0_redirected = 0;
6316
6317 /* Return true if fd 0 has already been redirected at least once.  */
6318 static inline int
6319 fd0_redirected_p (void) 
6320 {
6321         return fd0_redirected != 0;
6322 }
6323
6324 static void dupredirect (const union node *, int, int fd1dup);
6325
6326 #ifdef JOBS
6327 /*
6328  * Turn job control on and off.
6329  *
6330  * Note:  This code assumes that the third arg to ioctl is a character
6331  * pointer, which is true on Berkeley systems but not System V.  Since
6332  * System V doesn't have job control yet, this isn't a problem now.
6333  */
6334
6335
6336
6337 static void setjobctl(int enable)
6338 {
6339 #ifdef OLD_TTY_DRIVER
6340         int ldisc;
6341 #endif
6342
6343         if (enable == jobctl || rootshell == 0)
6344                 return;
6345         if (enable) {
6346                 do { /* while we are in the background */
6347 #ifdef OLD_TTY_DRIVER
6348                         if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
6349 #else
6350                         initialpgrp = tcgetpgrp(2);
6351                         if (initialpgrp < 0) {
6352 #endif
6353                                 out2str("sh: can't access tty; job control turned off\n");
6354                                 mflag = 0;
6355                                 return;
6356                         }
6357                         if (initialpgrp == -1)
6358                                 initialpgrp = getpgrp();
6359                         else if (initialpgrp != getpgrp()) {
6360                                 killpg(initialpgrp, SIGTTIN);
6361                                 continue;
6362                         }
6363                 } while (0);
6364 #ifdef OLD_TTY_DRIVER
6365                 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
6366                         out2str("sh: need new tty driver to run job control; job control turned off\n");
6367                         mflag = 0;
6368                         return;
6369                 }
6370 #endif
6371                 setsignal(SIGTSTP);
6372                 setsignal(SIGTTOU);
6373                 setsignal(SIGTTIN);
6374                 setpgid(0, rootpid);
6375 #ifdef OLD_TTY_DRIVER
6376                 ioctl(2, TIOCSPGRP, (char *)&rootpid);
6377 #else
6378                 tcsetpgrp(2, rootpid);
6379 #endif
6380         } else { /* turning job control off */
6381                 setpgid(0, initialpgrp);
6382 #ifdef OLD_TTY_DRIVER
6383                 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
6384 #else
6385                 tcsetpgrp(2, initialpgrp);
6386 #endif
6387                 setsignal(SIGTSTP);
6388                 setsignal(SIGTTOU);
6389                 setsignal(SIGTTIN);
6390         }
6391         jobctl = enable;
6392 }
6393 #endif
6394
6395
6396 #ifdef JOBS
6397 static int
6398 killcmd(argc, argv)
6399         int argc;
6400         char **argv;
6401 {
6402         int signo = -1;
6403         int list = 0;
6404         int i;
6405         pid_t pid;
6406         struct job *jp;
6407
6408         if (argc <= 1) {
6409 usage:
6410                 error(
6411 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6412 "kill -l [exitstatus]"
6413                 );
6414         }
6415
6416         if (*argv[1] == '-') {
6417                 signo = decode_signal(argv[1] + 1, 1);
6418                 if (signo < 0) {
6419                         int c;
6420
6421                         while ((c = nextopt("ls:")) != '\0')
6422                                 switch (c) {
6423                                 case 'l':
6424                                         list = 1;
6425                                         break;
6426                                 case 's':
6427                                         signo = decode_signal(optionarg, 1);
6428                                         if (signo < 0) {
6429                                                 error(
6430                                                         "invalid signal number or name: %s",
6431                                                         optionarg
6432                                                 );
6433                                         }
6434                                         break;
6435 #ifdef DEBUG
6436                                 default:
6437                                         error(
6438         "nextopt returned character code 0%o", c);
6439 #endif
6440                         }
6441                 } else
6442                         argptr++;
6443         }
6444
6445         if (!list && signo < 0)
6446                 signo = SIGTERM;
6447
6448         if ((signo < 0 || !*argptr) ^ list) {
6449                 goto usage;
6450         }
6451
6452         if (list) {
6453                 const char *name;
6454
6455                 if (!*argptr) {
6456                         out1str("0\n");
6457                         for (i = 1; i < NSIG; i++) {
6458                                 name = u_signal_names(0, &i, 1);
6459                                 if(name)
6460                                         printf(snlfmt, name);
6461                         }
6462                         return 0;
6463                 }
6464                 name = u_signal_names(*argptr, &signo, -1);
6465                 if (name)
6466                         printf(snlfmt, name);
6467                 else
6468                         error("invalid signal number or exit status: %s",
6469                               *argptr);
6470                 return 0;
6471         }
6472
6473         do {
6474                 if (**argptr == '%') {
6475                         jp = getjob(*argptr);
6476                         if (jp->jobctl == 0)
6477                                 error("job %s not created under job control",
6478                                       *argptr);
6479                         pid = -jp->ps[0].pid;
6480                 } else
6481                         pid = atoi(*argptr);
6482                 if (kill(pid, signo) != 0)
6483                         error("%s: %m", *argptr);
6484         } while (*++argptr);
6485
6486         return 0;
6487 }
6488
6489 static int
6490 fgcmd(argc, argv)
6491         int argc;
6492         char **argv;
6493 {
6494         struct job *jp;
6495         int pgrp;
6496         int status;
6497
6498         jp = getjob(argv[1]);
6499         if (jp->jobctl == 0)
6500                 error("job not created under job control");
6501         pgrp = jp->ps[0].pid;
6502 #ifdef OLD_TTY_DRIVER
6503         ioctl(2, TIOCSPGRP, (char *)&pgrp);
6504 #else
6505         tcsetpgrp(2, pgrp);
6506 #endif
6507         restartjob(jp);
6508         INTOFF;
6509         status = waitforjob(jp);
6510         INTON;
6511         return status;
6512 }
6513
6514
6515 static int
6516 bgcmd(argc, argv)
6517         int argc;
6518         char **argv;
6519 {
6520         struct job *jp;
6521
6522         do {
6523                 jp = getjob(*++argv);
6524                 if (jp->jobctl == 0)
6525                         error("job not created under job control");
6526                 restartjob(jp);
6527         } while (--argc > 1);
6528         return 0;
6529 }
6530
6531
6532 static void
6533 restartjob(jp)
6534         struct job *jp;
6535 {
6536         struct procstat *ps;
6537         int i;
6538
6539         if (jp->state == JOBDONE)
6540                 return;
6541         INTOFF;
6542         killpg(jp->ps[0].pid, SIGCONT);
6543         for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6544                 if (WIFSTOPPED(ps->status)) {
6545                         ps->status = -1;
6546                         jp->state = 0;
6547                 }
6548         }
6549         INTON;
6550 }
6551 #endif
6552
6553 static void showjobs(int change);
6554
6555
6556 static int
6557 jobscmd(argc, argv)
6558         int argc;
6559         char **argv;
6560 {
6561         showjobs(0);
6562         return 0;
6563 }
6564
6565
6566 /*
6567  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
6568  * statuses have changed since the last call to showjobs.
6569  *
6570  * If the shell is interrupted in the process of creating a job, the
6571  * result may be a job structure containing zero processes.  Such structures
6572  * will be freed here.
6573  */
6574
6575 static void
6576 showjobs(change)
6577         int change;
6578 {
6579         int jobno;
6580         int procno;
6581         int i;
6582         struct job *jp;
6583         struct procstat *ps;
6584         int col;
6585         char s[64];
6586
6587         TRACE(("showjobs(%d) called\n", change));
6588         while (dowait(0, (struct job *)NULL) > 0);
6589         for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6590                 if (! jp->used)
6591                         continue;
6592                 if (jp->nprocs == 0) {
6593                         freejob(jp);
6594                         continue;
6595                 }
6596                 if (change && ! jp->changed)
6597                         continue;
6598                 procno = jp->nprocs;
6599                 for (ps = jp->ps ; ; ps++) {    /* for each process */
6600                         if (ps == jp->ps)
6601                                 snprintf(s, 64, "[%d] %ld ", jobno,
6602                                     (long)ps->pid);
6603                         else
6604                                 snprintf(s, 64, "    %ld ",
6605                                     (long)ps->pid);
6606                         out1str(s);
6607                         col = strlen(s);
6608                         s[0] = '\0';
6609                         if (ps->status == -1) {
6610                                 /* don't print anything */
6611                         } else if (WIFEXITED(ps->status)) {
6612                                 snprintf(s, 64, "Exit %d",
6613                                        WEXITSTATUS(ps->status));
6614                         } else {
6615 #ifdef JOBS
6616                                 if (WIFSTOPPED(ps->status))
6617                                         i = WSTOPSIG(ps->status);
6618                                 else /* WIFSIGNALED(ps->status) */
6619 #endif
6620                                         i = WTERMSIG(ps->status);
6621                                 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
6622                                         strcpy(s, sys_siglist[i & 0x7F]);
6623                                 else
6624                                         snprintf(s, 64, "Signal %d", i & 0x7F);
6625                                 if (WCOREDUMP(ps->status))
6626                                         strcat(s, " (core dumped)");
6627                         }
6628                         out1str(s);
6629                         col += strlen(s);
6630                         printf(
6631                                 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6632                                 ps->cmd
6633                         );
6634                         if (--procno <= 0)
6635                                 break;
6636                 }
6637                 jp->changed = 0;
6638                 if (jp->state == JOBDONE) {
6639                         freejob(jp);
6640                 }
6641         }
6642 }
6643
6644
6645 /*
6646  * Mark a job structure as unused.
6647  */
6648
6649 static void
6650 freejob(struct job *jp)
6651 {
6652         const struct procstat *ps;
6653         int i;
6654
6655         INTOFF;
6656         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6657                 if (ps->cmd != nullstr)
6658                         ckfree(ps->cmd);
6659         }
6660         if (jp->ps != &jp->ps0)
6661                 ckfree(jp->ps);
6662         jp->used = 0;
6663 #ifdef JOBS
6664         if (curjob == jp - jobtab + 1)
6665                 curjob = 0;
6666 #endif
6667         INTON;
6668 }
6669
6670
6671
6672 static int
6673 waitcmd(argc, argv)
6674         int argc;
6675         char **argv;
6676 {
6677         struct job *job;
6678         int status, retval;
6679         struct job *jp;
6680
6681         if (--argc > 0) {
6682 start:
6683                 job = getjob(*++argv);
6684         } else {
6685                 job = NULL;
6686         }
6687         for (;;) {      /* loop until process terminated or stopped */
6688                 if (job != NULL) {
6689                         if (job->state) {
6690                                 status = job->ps[job->nprocs - 1].status;
6691                                 if (! iflag)
6692                                         freejob(job);
6693                                 if (--argc) {
6694                                         goto start;
6695                                 }
6696                                 if (WIFEXITED(status))
6697                                         retval = WEXITSTATUS(status);
6698 #ifdef JOBS
6699                                 else if (WIFSTOPPED(status))
6700                                         retval = WSTOPSIG(status) + 128;
6701 #endif
6702                                 else {
6703                                         /* XXX: limits number of signals */
6704                                         retval = WTERMSIG(status) + 128;
6705                                 }
6706                                 return retval;
6707                         }
6708                 } else {
6709                         for (jp = jobtab ; ; jp++) {
6710                                 if (jp >= jobtab + njobs) {     /* no running procs */
6711                                         return 0;
6712                                 }
6713                                 if (jp->used && jp->state == 0)
6714                                         break;
6715                         }
6716                 }
6717                 if (dowait(2, 0) < 0 && errno == EINTR) {
6718                         return 129;
6719                 }
6720         }
6721 }
6722
6723
6724
6725 /*
6726  * Convert a job name to a job structure.
6727  */
6728
6729 static struct job *
6730 getjob(const char *name)
6731 {
6732         int jobno;
6733         struct job *jp;
6734         int pid;
6735         int i;
6736
6737         if (name == NULL) {
6738 #ifdef JOBS
6739 currentjob:
6740                 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6741                         error("No current job");
6742                 return &jobtab[jobno - 1];
6743 #else
6744                 error("No current job");
6745 #endif
6746         } else if (name[0] == '%') {
6747                 if (is_digit(name[1])) {
6748                         jobno = number(name + 1);
6749                         if (jobno > 0 && jobno <= njobs
6750                          && jobtab[jobno - 1].used != 0)
6751                                 return &jobtab[jobno - 1];
6752 #ifdef JOBS
6753                 } else if (name[1] == '%' && name[2] == '\0') {
6754                         goto currentjob;
6755 #endif
6756                 } else {
6757                         struct job *found = NULL;
6758                         for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6759                                 if (jp->used && jp->nprocs > 0
6760                                  && prefix(name + 1, jp->ps[0].cmd)) {
6761                                         if (found)
6762                                                 error("%s: ambiguous", name);
6763                                         found = jp;
6764                                 }
6765                         }
6766                         if (found)
6767                                 return found;
6768                 }
6769         } else if (is_number(name, &pid)) {
6770                 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6771                         if (jp->used && jp->nprocs > 0
6772                          && jp->ps[jp->nprocs - 1].pid == pid)
6773                                 return jp;
6774                 }
6775         }
6776         error("No such job: %s", name);
6777         /* NOTREACHED */
6778 }
6779
6780
6781
6782 /*
6783  * Return a new job structure,
6784  */
6785
6786 static struct job *
6787 makejob(const union node *node, int nprocs)
6788 {
6789         int i;
6790         struct job *jp;
6791
6792         for (i = njobs, jp = jobtab ; ; jp++) {
6793                 if (--i < 0) {
6794                         INTOFF;
6795                         if (njobs == 0) {
6796                                 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6797                         } else {
6798                                 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6799                                 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6800                                 /* Relocate `ps' pointers */
6801                                 for (i = 0; i < njobs; i++)
6802                                         if (jp[i].ps == &jobtab[i].ps0)
6803                                                 jp[i].ps = &jp[i].ps0;
6804                                 ckfree(jobtab);
6805                                 jobtab = jp;
6806                         }
6807                         jp = jobtab + njobs;
6808                         for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6809                         INTON;
6810                         break;
6811                 }
6812                 if (jp->used == 0)
6813                         break;
6814         }
6815         INTOFF;
6816         jp->state = 0;
6817         jp->used = 1;
6818         jp->changed = 0;
6819         jp->nprocs = 0;
6820 #ifdef JOBS
6821         jp->jobctl = jobctl;
6822 #endif
6823         if (nprocs > 1) {
6824                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6825         } else {
6826                 jp->ps = &jp->ps0;
6827         }
6828         INTON;
6829         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6830             jp - jobtab + 1));
6831         return jp;
6832 }
6833
6834
6835 /*
6836  * Fork of a subshell.  If we are doing job control, give the subshell its
6837  * own process group.  Jp is a job structure that the job is to be added to.
6838  * N is the command that will be evaluated by the child.  Both jp and n may
6839  * be NULL.  The mode parameter can be one of the following:
6840  *      FORK_FG - Fork off a foreground process.
6841  *      FORK_BG - Fork off a background process.
6842  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
6843  *                   process group even if job control is on.
6844  *
6845  * When job control is turned off, background processes have their standard
6846  * input redirected to /dev/null (except for the second and later processes
6847  * in a pipeline).
6848  */
6849
6850
6851
6852 static int
6853 forkshell(struct job *jp, const union node *n, int mode)
6854 {
6855         int pid;
6856 #ifdef JOBS
6857         int pgrp;
6858 #endif
6859         const char *devnull = _PATH_DEVNULL;
6860         const char *nullerr = "Can't open %s";
6861
6862         TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6863             mode));
6864         INTOFF;
6865         pid = fork();
6866         if (pid == -1) {
6867                 TRACE(("Fork failed, errno=%d\n", errno));
6868                 INTON;
6869                 error("Cannot fork");
6870         }
6871         if (pid == 0) {
6872                 struct job *p;
6873                 int wasroot;
6874                 int i;
6875
6876                 TRACE(("Child shell %d\n", getpid()));
6877                 wasroot = rootshell;
6878                 rootshell = 0;
6879                 closescript();
6880                 INTON;
6881                 clear_traps();
6882 #ifdef JOBS
6883                 jobctl = 0;             /* do job control only in root shell */
6884                 if (wasroot && mode != FORK_NOJOB && mflag) {
6885                         if (jp == NULL || jp->nprocs == 0)
6886                                 pgrp = getpid();
6887                         else
6888                                 pgrp = jp->ps[0].pid;
6889                         setpgid(0, pgrp);
6890                         if (mode == FORK_FG) {
6891                                 /*** this causes superfluous TIOCSPGRPS ***/
6892 #ifdef OLD_TTY_DRIVER
6893                                 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
6894                                         error("TIOCSPGRP failed, errno=%d", errno);
6895 #else
6896                                 if (tcsetpgrp(2, pgrp) < 0)
6897                                         error("tcsetpgrp failed, errno=%d", errno);
6898 #endif
6899                         }
6900                         setsignal(SIGTSTP);
6901                         setsignal(SIGTTOU);
6902                 } else if (mode == FORK_BG) {
6903                         ignoresig(SIGINT);
6904                         ignoresig(SIGQUIT);
6905                         if ((jp == NULL || jp->nprocs == 0) &&
6906                             ! fd0_redirected_p ()) {
6907                                 close(0);
6908                                 if (open(devnull, O_RDONLY) != 0)
6909                                         error(nullerr, devnull);
6910                         }
6911                 }
6912 #else
6913                 if (mode == FORK_BG) {
6914                         ignoresig(SIGINT);
6915                         ignoresig(SIGQUIT);
6916                         if ((jp == NULL || jp->nprocs == 0) &&
6917                             ! fd0_redirected_p ()) {
6918                                 close(0);
6919                                 if (open(devnull, O_RDONLY) != 0)
6920                                         error(nullerr, devnull);
6921                         }
6922                 }
6923 #endif
6924                 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6925                         if (p->used)
6926                                 freejob(p);
6927                 if (wasroot && iflag) {
6928                         setsignal(SIGINT);
6929                         setsignal(SIGQUIT);
6930                         setsignal(SIGTERM);
6931                 }
6932                 return pid;
6933         }
6934 #ifdef JOBS
6935         if (rootshell && mode != FORK_NOJOB && mflag) {
6936                 if (jp == NULL || jp->nprocs == 0)
6937                         pgrp = pid;
6938                 else
6939                         pgrp = jp->ps[0].pid;
6940                 setpgid(pid, pgrp);
6941         }
6942 #endif
6943         if (mode == FORK_BG)
6944                 backgndpid = pid;               /* set $! */
6945         if (jp) {
6946                 struct procstat *ps = &jp->ps[jp->nprocs++];
6947                 ps->pid = pid;
6948                 ps->status = -1;
6949                 ps->cmd = nullstr;
6950                 if (iflag && rootshell && n)
6951                         ps->cmd = commandtext(n);
6952         }
6953         INTON;
6954         TRACE(("In parent shell:  child = %d\n", pid));
6955         return pid;
6956 }
6957
6958
6959
6960 /*
6961  * Wait for job to finish.
6962  *
6963  * Under job control we have the problem that while a child process is
6964  * running interrupts generated by the user are sent to the child but not
6965  * to the shell.  This means that an infinite loop started by an inter-
6966  * active user may be hard to kill.  With job control turned off, an
6967  * interactive user may place an interactive program inside a loop.  If
6968  * the interactive program catches interrupts, the user doesn't want
6969  * these interrupts to also abort the loop.  The approach we take here
6970  * is to have the shell ignore interrupt signals while waiting for a
6971  * forground process to terminate, and then send itself an interrupt
6972  * signal if the child process was terminated by an interrupt signal.
6973  * Unfortunately, some programs want to do a bit of cleanup and then
6974  * exit on interrupt; unless these processes terminate themselves by
6975  * sending a signal to themselves (instead of calling exit) they will
6976  * confuse this approach.
6977  */
6978
6979 static int
6980 waitforjob(struct job *jp)
6981 {
6982 #ifdef JOBS
6983         int mypgrp = getpgrp();
6984 #endif
6985         int status;
6986         int st;
6987         struct sigaction act, oact;
6988
6989         INTOFF;
6990         intreceived = 0;
6991 #ifdef JOBS
6992         if (!jobctl) {
6993 #else
6994         if (!iflag) {
6995 #endif
6996                 sigaction(SIGINT, 0, &act);
6997                 act.sa_handler = waitonint;
6998                 sigaction(SIGINT, &act, &oact);
6999         }
7000         TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7001         while (jp->state == 0) {
7002                 dowait(1, jp);
7003         }
7004 #ifdef JOBS
7005         if (!jobctl) {
7006 #else
7007         if (!iflag) {
7008 #endif
7009                 sigaction(SIGINT, &oact, 0);
7010                 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7011         }
7012 #ifdef JOBS
7013         if (jp->jobctl) {
7014 #ifdef OLD_TTY_DRIVER
7015                 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
7016                         error("TIOCSPGRP failed, errno=%d\n", errno);
7017 #else
7018                 if (tcsetpgrp(2, mypgrp) < 0)
7019                         error("tcsetpgrp failed, errno=%d\n", errno);
7020 #endif
7021         }
7022         if (jp->state == JOBSTOPPED)
7023                 curjob = jp - jobtab + 1;
7024 #endif
7025         status = jp->ps[jp->nprocs - 1].status;
7026         /* convert to 8 bits */
7027         if (WIFEXITED(status))
7028                 st = WEXITSTATUS(status);
7029 #ifdef JOBS
7030         else if (WIFSTOPPED(status))
7031                 st = WSTOPSIG(status) + 128;
7032 #endif
7033         else
7034                 st = WTERMSIG(status) + 128;
7035 #ifdef JOBS
7036         if (jp->jobctl) {
7037                 /*
7038                  * This is truly gross.
7039                  * If we're doing job control, then we did a TIOCSPGRP which
7040                  * caused us (the shell) to no longer be in the controlling
7041                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
7042                  * intuit from the subprocess exit status whether a SIGINT
7043                  * occured, and if so interrupt ourselves.  Yuck.  - mycroft
7044                  */
7045                 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7046                         raise(SIGINT);
7047         }
7048         if (jp->state == JOBDONE)
7049
7050 #endif
7051                 freejob(jp);
7052         INTON;
7053         return st;
7054 }
7055
7056
7057
7058 /*
7059  * Wait for a process to terminate.
7060  */
7061
7062 /*
7063  * Do a wait system call.  If job control is compiled in, we accept
7064  * stopped processes.  If block is zero, we return a value of zero
7065  * rather than blocking.
7066  *
7067  * System V doesn't have a non-blocking wait system call.  It does
7068  * have a SIGCLD signal that is sent to a process when one of it's
7069  * children dies.  The obvious way to use SIGCLD would be to install
7070  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7071  * was received, and have waitproc bump another counter when it got
7072  * the status of a process.  Waitproc would then know that a wait
7073  * system call would not block if the two counters were different.
7074  * This approach doesn't work because if a process has children that
7075  * have not been waited for, System V will send it a SIGCLD when it
7076  * installs a signal handler for SIGCLD.  What this means is that when
7077  * a child exits, the shell will be sent SIGCLD signals continuously
7078  * until is runs out of stack space, unless it does a wait call before
7079  * restoring the signal handler.  The code below takes advantage of
7080  * this (mis)feature by installing a signal handler for SIGCLD and
7081  * then checking to see whether it was called.  If there are any
7082  * children to be waited for, it will be.
7083  *
7084  */
7085
7086 static inline int
7087 waitproc(int block, int *status)
7088 {
7089         int flags;
7090
7091         flags = 0;
7092 #ifdef JOBS
7093         if (jobctl)
7094                 flags |= WUNTRACED;
7095 #endif
7096         if (block == 0)
7097                 flags |= WNOHANG;
7098         return wait3(status, flags, (struct rusage *)NULL);
7099 }
7100
7101 static int
7102 dowait(int block, struct job *job)
7103 {
7104         int pid;
7105         int status;
7106         struct procstat *sp;
7107         struct job *jp;
7108         struct job *thisjob;
7109         int done;
7110         int stopped;
7111         int core;
7112         int sig;
7113
7114         TRACE(("dowait(%d) called\n", block));
7115         do {
7116                 pid = waitproc(block, &status);
7117                 TRACE(("wait returns %d, status=%d\n", pid, status));
7118         } while (!(block & 2) && pid == -1 && errno == EINTR);
7119         if (pid <= 0)
7120                 return pid;
7121         INTOFF;
7122         thisjob = NULL;
7123         for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7124                 if (jp->used) {
7125                         done = 1;
7126                         stopped = 1;
7127                         for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7128                                 if (sp->pid == -1)
7129                                         continue;
7130                                 if (sp->pid == pid) {
7131                                         TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7132                                         sp->status = status;
7133                                         thisjob = jp;
7134                                 }
7135                                 if (sp->status == -1)
7136                                         stopped = 0;
7137                                 else if (WIFSTOPPED(sp->status))
7138                                         done = 0;
7139                         }
7140                         if (stopped) {          /* stopped or done */
7141                                 int state = done? JOBDONE : JOBSTOPPED;
7142                                 if (jp->state != state) {
7143                                         TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7144                                         jp->state = state;
7145 #ifdef JOBS
7146                                         if (done && curjob == jp - jobtab + 1)
7147                                                 curjob = 0;             /* no current job */
7148 #endif
7149                                 }
7150                         }
7151                 }
7152         }
7153         INTON;
7154         if (! rootshell || ! iflag || (job && thisjob == job)) {
7155                 core = WCOREDUMP(status);
7156 #ifdef JOBS
7157                 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7158                 else
7159 #endif
7160                 if (WIFEXITED(status)) sig = 0;
7161                 else sig = WTERMSIG(status);
7162
7163                 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7164                         if (thisjob != job)
7165                                 out2fmt("%d: ", pid);
7166 #ifdef JOBS
7167                         if (sig == SIGTSTP && rootshell && iflag)
7168                                 out2fmt("%%%ld ",
7169                                     (long)(job - jobtab + 1));
7170 #endif
7171                         if (sig < NSIG && sys_siglist[sig])
7172                                 out2str(sys_siglist[sig]);
7173                         else
7174                                 out2fmt("Signal %d", sig);
7175                         if (core)
7176                                 out2str(" - core dumped");
7177                         out2c('\n');
7178                 } else {
7179                         TRACE(("Not printing status: status=%d, sig=%d\n",
7180                                status, sig));
7181                 }
7182         } else {
7183                 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7184                 if (thisjob)
7185                         thisjob->changed = 1;
7186         }
7187         return pid;
7188 }
7189
7190
7191
7192
7193 /*
7194  * return 1 if there are stopped jobs, otherwise 0
7195  */
7196 static int
7197 stoppedjobs(void)
7198 {
7199         int jobno;
7200         struct job *jp;
7201
7202         if (job_warning)
7203                 return (0);
7204         for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7205                 if (jp->used == 0)
7206                         continue;
7207                 if (jp->state == JOBSTOPPED) {
7208                         out2str("You have stopped jobs.\n");
7209                         job_warning = 2;
7210                         return (1);
7211                 }
7212         }
7213
7214         return (0);
7215 }
7216
7217 /*
7218  * Return a string identifying a command (to be printed by the
7219  * jobs command.
7220  */
7221
7222 static char *cmdnextc;
7223 static int cmdnleft;
7224 #define MAXCMDTEXT      200
7225
7226 static void
7227 cmdputs(const char *s)
7228 {
7229         const char *p;
7230         char *q;
7231         char c;
7232         int subtype = 0;
7233
7234         if (cmdnleft <= 0)
7235                 return;
7236         p = s;
7237         q = cmdnextc;
7238         while ((c = *p++) != '\0') {
7239                 if (c == CTLESC)
7240                         *q++ = *p++;
7241                 else if (c == CTLVAR) {
7242                         *q++ = '$';
7243                         if (--cmdnleft > 0)
7244                                 *q++ = '{';
7245                         subtype = *p++;
7246                 } else if (c == '=' && subtype != 0) {
7247                         *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7248                         subtype = 0;
7249                 } else if (c == CTLENDVAR) {
7250                         *q++ = '}';
7251                 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7252                         cmdnleft++;             /* ignore it */
7253                 else
7254                         *q++ = c;
7255                 if (--cmdnleft <= 0) {
7256                         *q++ = '.';
7257                         *q++ = '.';
7258                         *q++ = '.';
7259                         break;
7260                 }
7261         }
7262         cmdnextc = q;
7263 }
7264
7265 #define CMDTXT_TABLE
7266 #ifdef CMDTXT_TABLE
7267 /*
7268  * To collect a lot of redundant code in cmdtxt() case statements, we
7269  * implement a mini language here.  Each type of node struct has an
7270  * associated instruction sequence that operates on its members via
7271  * their offsets.  The instruction are pack in unsigned chars with
7272  * format   IIDDDDDE   where the bits are
7273  *   I : part of the instruction opcode, which are
7274  *       00 : member is a pointer to another node -- process it recursively
7275  *       40 : member is a pointer to a char string -- output it
7276  *       80 : output the string whose index is stored in the data field
7277  *       CC : flag signaling that this case needs external processing
7278  *   D : data - either the (shifted) index of a fixed string to output or
7279  *              the actual offset of the member to operate on in the struct
7280  *              (since we assume bit 0 is set, the offset is not shifted)
7281  *   E : flag signaling end of instruction sequence
7282  *
7283  * WARNING: In order to handle larger offsets for 64bit archs, this code
7284  *          assumes that no offset can be an odd number and stores the
7285  *          end-of-instructions flag in bit 0.
7286  */
7287
7288 #define CMDTXT_NOMORE      0x01 /* NOTE: no offset should be odd */
7289 #define CMDTXT_CHARPTR     0x40
7290 #define CMDTXT_STRING      0x80
7291 #define CMDTXT_SPECIAL     0xC0
7292 #define CMDTXT_OFFSETMASK  0x3E
7293
7294 static const char * const cmdtxt_strings[] = {
7295  /* 0     1    2    3       4       5      6          7     */
7296         "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7297  /* 8         9        10       11        12      13       */
7298     "while ", "; do ", "; done", "until ", "for ", " in ...",
7299  /* 14       15     16        17     */
7300         "case ", "???", "() ...", "<<..."
7301 };
7302
7303 static const char * const redir_strings[] = {
7304         ">", "<", "<>", ">>", ">|", ">&", "<&"
7305 };
7306
7307 static const unsigned char cmdtxt_ops[] = {
7308 #define CMDTXT_NSEMI    0
7309         offsetof(union node, nbinary.ch1),
7310         0|CMDTXT_STRING,
7311         offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7312 #define CMDTXT_NCMD     (CMDTXT_NSEMI + 3)
7313 #define CMDTXT_NPIPE    (CMDTXT_NCMD)
7314 #define  CMDTXT_NCASE    (CMDTXT_NCMD)
7315 #define  CMDTXT_NTO      (CMDTXT_NCMD)
7316 #define  CMDTXT_NFROM    (CMDTXT_NCMD)
7317 #define  CMDTXT_NFROMTO  (CMDTXT_NCMD)
7318 #define  CMDTXT_NAPPEND  (CMDTXT_NCMD)
7319 #define  CMDTXT_NTOOV    (CMDTXT_NCMD)
7320 #define  CMDTXT_NTOFD    (CMDTXT_NCMD)
7321 #define  CMDTXT_NFROMFD  (CMDTXT_NCMD)
7322         CMDTXT_SPECIAL,
7323 #define CMDTXT_NREDIR   (CMDTXT_NPIPE + 1)
7324 #define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7325         offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7326 #define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7327         (1*2)|CMDTXT_STRING,
7328         offsetof(union node, nredir.n),
7329         (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7330 #define CMDTXT_NAND     (CMDTXT_NSUBSHELL + 3)
7331         offsetof(union node, nbinary.ch1),
7332         (3*2)|CMDTXT_STRING,
7333         offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7334 #define CMDTXT_NOR      (CMDTXT_NAND + 3)
7335         offsetof(union node, nbinary.ch1),
7336         (4*2)|CMDTXT_STRING,
7337         offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7338 #define CMDTXT_NIF      (CMDTXT_NOR + 3)
7339         (5*2)|CMDTXT_STRING,
7340         offsetof(union node, nif.test),
7341         (6*2)|CMDTXT_STRING,
7342         offsetof(union node, nif.ifpart),
7343         (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7344 #define CMDTXT_NWHILE   (CMDTXT_NIF + 5)
7345         (8*2)|CMDTXT_STRING,
7346         offsetof(union node, nbinary.ch1),
7347         (9*2)|CMDTXT_STRING,
7348         offsetof(union node, nbinary.ch2),
7349         (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7350 #define CMDTXT_NUNTIL   (CMDTXT_NWHILE + 5)
7351         (11*2)|CMDTXT_STRING,
7352         offsetof(union node, nbinary.ch1),
7353         (9*2)|CMDTXT_STRING,
7354         offsetof(union node, nbinary.ch2),
7355         (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7356 #define CMDTXT_NFOR     (CMDTXT_NUNTIL + 5)
7357         (12*2)|CMDTXT_STRING,
7358         offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7359         (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7360 #define CMDTXT_NCLIST   (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7361 #define  CMDTXT_NNOT     (CMDTXT_NCLIST)        /* TODO: IS THIS CORRECT??? */
7362         (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7363 #define CMDTXT_NDEFUN   (CMDTXT_NCLIST + 1)
7364         offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7365         (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7366 #define CMDTXT_NARG     (CMDTXT_NDEFUN + 2)
7367         offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7368 #define CMDTXT_NHERE    (CMDTXT_NARG + 1)
7369 #define CMDTXT_NXHERE   (CMDTXT_NHERE)
7370         (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7371 };
7372
7373 #if CMDTXT_NXHERE != 36
7374 #error CMDTXT_NXHERE
7375 #endif
7376
7377 static const unsigned char cmdtxt_ops_index[26] = {
7378         CMDTXT_NSEMI,
7379         CMDTXT_NCMD,
7380         CMDTXT_NPIPE,
7381         CMDTXT_NREDIR,
7382         CMDTXT_NBACKGND,
7383         CMDTXT_NSUBSHELL,
7384         CMDTXT_NAND,
7385         CMDTXT_NOR,
7386         CMDTXT_NIF,
7387         CMDTXT_NWHILE,
7388         CMDTXT_NUNTIL,
7389         CMDTXT_NFOR,
7390         CMDTXT_NCASE,
7391         CMDTXT_NCLIST,
7392         CMDTXT_NDEFUN,
7393         CMDTXT_NARG,
7394         CMDTXT_NTO,
7395         CMDTXT_NFROM,
7396         CMDTXT_NFROMTO,
7397         CMDTXT_NAPPEND,
7398         CMDTXT_NTOOV,
7399         CMDTXT_NTOFD,
7400         CMDTXT_NFROMFD,
7401         CMDTXT_NHERE,
7402         CMDTXT_NXHERE,
7403         CMDTXT_NNOT,
7404 };
7405
7406 static void
7407 cmdtxt(const union node *n)
7408 {
7409         const char *p;
7410
7411         if (n == NULL)
7412                 return;
7413
7414         p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7415         if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7416                 do {
7417                         if (*p & CMDTXT_STRING) { /* output fixed string */
7418                                 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
7419                         } else {
7420                                 const char *pf = ((const char *) n)
7421                                                                   + ((int)(*p & CMDTXT_OFFSETMASK));
7422                                 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7423                                         cmdputs(*((const char **) pf));
7424                                 } else {                /* output field */
7425                                         cmdtxt(*((const union node **) pf));
7426                                 }
7427                         }
7428                 } while (!(*p++ & CMDTXT_NOMORE));
7429         } else if (n->type == NCMD) {
7430                 union node *np;
7431                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7432                         cmdtxt(np);
7433                         if (np->narg.next)
7434                                 cmdputs(spcstr);
7435                 }
7436                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7437                         cmdputs(spcstr);
7438                         cmdtxt(np);
7439                 }
7440         } else if (n->type == NPIPE) {
7441                 struct nodelist *lp;
7442                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7443                         cmdtxt(lp->n);
7444                         if (lp->next)
7445                                 cmdputs(" | ");
7446                 }
7447         } else if (n->type == NCASE) {
7448                 cmdputs(cmdtxt_strings[14]);
7449                 cmdputs(n->ncase.expr->narg.text);
7450                 cmdputs(cmdtxt_strings[13]);
7451         } else {
7452 #if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7453 #error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7454 #endif
7455                 char s[2];
7456
7457 #ifdef DEBUG
7458                 assert((n->type >= NTO) && (n->type <= NFROMFD));
7459 #endif
7460
7461                 p = redir_strings[n->type - NTO];
7462                 if (n->nfile.fd != ('>' == *p)) {
7463                         s[0] = n->nfile.fd + '0';
7464                         s[1] = '\0';
7465                         cmdputs(s);
7466                 }
7467                 cmdputs(p);
7468                 if (n->type >= NTOFD) {
7469                         s[0] = n->ndup.dupfd + '0';
7470                         s[1] = '\0';
7471                         cmdputs(s);
7472                 } else {
7473                         cmdtxt(n->nfile.fname);
7474                 }
7475         }
7476 }
7477 #else  /* CMDTXT_TABLE */
7478 static void
7479 cmdtxt(const union node *n)
7480 {
7481         union node *np;
7482         struct nodelist *lp;
7483         const char *p;
7484         int i;
7485         char s[2];
7486
7487         if (n == NULL)
7488                 return;
7489         switch (n->type) {
7490         case NSEMI:
7491                 cmdtxt(n->nbinary.ch1);
7492                 cmdputs("; ");
7493                 cmdtxt(n->nbinary.ch2);
7494                 break;
7495         case NAND:
7496                 cmdtxt(n->nbinary.ch1);
7497                 cmdputs(" && ");
7498                 cmdtxt(n->nbinary.ch2);
7499                 break;
7500         case NOR:
7501                 cmdtxt(n->nbinary.ch1);
7502                 cmdputs(" || ");
7503                 cmdtxt(n->nbinary.ch2);
7504                 break;
7505         case NPIPE:
7506                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7507                         cmdtxt(lp->n);
7508                         if (lp->next)
7509                                 cmdputs(" | ");
7510                 }
7511                 break;
7512         case NSUBSHELL:
7513                 cmdputs("(");
7514                 cmdtxt(n->nredir.n);
7515                 cmdputs(")");
7516                 break;
7517         case NREDIR:
7518         case NBACKGND:
7519                 cmdtxt(n->nredir.n);
7520                 break;
7521         case NIF:
7522                 cmdputs("if ");
7523                 cmdtxt(n->nif.test);
7524                 cmdputs("; then ");
7525                 cmdtxt(n->nif.ifpart);
7526                 cmdputs("...");
7527                 break;
7528         case NWHILE:
7529                 cmdputs("while ");
7530                 goto until;
7531         case NUNTIL:
7532                 cmdputs("until ");
7533 until:
7534                 cmdtxt(n->nbinary.ch1);
7535                 cmdputs("; do ");
7536                 cmdtxt(n->nbinary.ch2);
7537                 cmdputs("; done");
7538                 break;
7539         case NFOR:
7540                 cmdputs("for ");
7541                 cmdputs(n->nfor.var);
7542                 cmdputs(" in ...");
7543                 break;
7544         case NCASE:
7545                 cmdputs("case ");
7546                 cmdputs(n->ncase.expr->narg.text);
7547                 cmdputs(" in ...");
7548                 break;
7549         case NDEFUN:
7550                 cmdputs(n->narg.text);
7551                 cmdputs("() ...");
7552                 break;
7553         case NCMD:
7554                 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7555                         cmdtxt(np);
7556                         if (np->narg.next)
7557                                 cmdputs(spcstr);
7558                 }
7559                 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7560                         cmdputs(spcstr);
7561                         cmdtxt(np);
7562                 }
7563                 break;
7564         case NARG:
7565                 cmdputs(n->narg.text);
7566                 break;
7567         case NTO:
7568                 p = ">";  i = 1;  goto redir;
7569         case NAPPEND:
7570                 p = ">>";  i = 1;  goto redir;
7571         case NTOFD:
7572                 p = ">&";  i = 1;  goto redir;
7573         case NTOOV:
7574                 p = ">|";  i = 1;  goto redir;
7575         case NFROM:
7576                 p = "<";  i = 0;  goto redir;
7577         case NFROMFD:
7578                 p = "<&";  i = 0;  goto redir;
7579         case NFROMTO:
7580                 p = "<>";  i = 0;  goto redir;
7581 redir:
7582                 if (n->nfile.fd != i) {
7583                         s[0] = n->nfile.fd + '0';
7584                         s[1] = '\0';
7585                         cmdputs(s);
7586                 }
7587                 cmdputs(p);
7588                 if (n->type == NTOFD || n->type == NFROMFD) {
7589                         s[0] = n->ndup.dupfd + '0';
7590                         s[1] = '\0';
7591                         cmdputs(s);
7592                 } else {
7593                         cmdtxt(n->nfile.fname);
7594                 }
7595                 break;
7596         case NHERE:
7597         case NXHERE:
7598                 cmdputs("<<...");
7599                 break;
7600         default:
7601                 cmdputs("???");
7602                 break;
7603         }
7604 }
7605 #endif /* CMDTXT_TABLE */
7606
7607 static char *
7608 commandtext(const union node *n)
7609 {
7610         char *name;
7611
7612         cmdnextc = name = ckmalloc(MAXCMDTEXT);
7613         cmdnleft = MAXCMDTEXT - 4;
7614         cmdtxt(n);
7615         *cmdnextc = '\0';
7616         return name;
7617 }
7618
7619
7620 static void waitonint(int sig) {
7621         intreceived = 1;
7622         return;
7623 }
7624 /*
7625  * Routines to check for mail.  (Perhaps make part of main.c?)
7626  */
7627
7628
7629 #define MAXMBOXES 10
7630
7631
7632 static int nmboxes;                     /* number of mailboxes */
7633 static time_t mailtime[MAXMBOXES];      /* times of mailboxes */
7634
7635
7636
7637 /*
7638  * Print appropriate message(s) if mail has arrived.  If the argument is
7639  * nozero, then the value of MAIL has changed, so we just update the
7640  * values.
7641  */
7642
7643 static void
7644 chkmail(int silent)
7645 {
7646         int i;
7647         const char *mpath;
7648         char *p;
7649         char *q;
7650         struct stackmark smark;
7651         struct stat statb;
7652
7653         if (silent)
7654                 nmboxes = 10;
7655         if (nmboxes == 0)
7656                 return;
7657         setstackmark(&smark);
7658         mpath = mpathset()? mpathval() : mailval();
7659         for (i = 0 ; i < nmboxes ; i++) {
7660                 p = padvance(&mpath, nullstr);
7661                 if (p == NULL)
7662                         break;
7663                 if (*p == '\0')
7664                         continue;
7665                 for (q = p ; *q ; q++);
7666 #ifdef DEBUG
7667                 if (q[-1] != '/')
7668                         abort();
7669 #endif
7670                 q[-1] = '\0';                   /* delete trailing '/' */
7671                 if (stat(p, &statb) < 0)
7672                         statb.st_size = 0;
7673                 if (statb.st_size > mailtime[i] && ! silent) {
7674                         out2fmt(snlfmt,
7675                                 pathopt? pathopt : "you have mail");
7676                 }
7677                 mailtime[i] = statb.st_size;
7678         }
7679         nmboxes = i;
7680         popstackmark(&smark);
7681 }
7682
7683 #define PROFILE 0
7684
7685 #if PROFILE
7686 static short profile_buf[16384];
7687 extern int etext();
7688 #endif
7689
7690 static void read_profile (const char *);
7691 static void cmdloop (int);
7692 static void options (int);
7693 static void setoption (int, int);
7694 static void procargs (int, char **);
7695
7696
7697 /*
7698  * Main routine.  We initialize things, parse the arguments, execute
7699  * profiles if we're a login shell, and then call cmdloop to execute
7700  * commands.  The setjmp call sets up the location to jump to when an
7701  * exception occurs.  When an exception occurs the variable "state"
7702  * is used to figure out how far we had gotten.
7703  */
7704
7705 int
7706 ash_main(argc, argv)
7707         int argc;
7708         char **argv;
7709 {
7710         struct jmploc jmploc;
7711         struct stackmark smark;
7712         volatile int state;
7713         const char *shinit;
7714
7715         BLTINCMD = find_builtin("builtin");
7716         EXECCMD = find_builtin("exec");
7717         EVALCMD = find_builtin("eval");
7718
7719 #ifndef BB_FEATURE_SH_FANCY_PROMPT
7720         unsetenv("PS1");
7721         unsetenv("PS2");
7722 #endif
7723
7724 #if PROFILE
7725         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7726 #endif
7727 #if defined(linux) || defined(__GNU__)
7728         signal(SIGCHLD, SIG_DFL);
7729 #endif
7730         state = 0;
7731         if (setjmp(jmploc.loc)) {
7732                 INTOFF;
7733                 /*
7734                  * When a shell procedure is executed, we raise the
7735                  * exception EXSHELLPROC to clean up before executing
7736                  * the shell procedure.
7737                  */
7738                 if (exception == EXSHELLPROC) {
7739                         rootpid = getpid();
7740                         rootshell = 1;
7741                         minusc = NULL;
7742                         state = 3;
7743                 } else {
7744                         if (exception == EXEXEC) {
7745                                 exitstatus = exerrno;
7746                         } else if (exception == EXERROR) {
7747                                 exitstatus = 2;
7748                         }
7749                     if (state == 0 || iflag == 0 || ! rootshell)
7750                             exitshell(exitstatus);
7751                 }
7752                 reset();
7753                 if (exception == EXINT) {
7754                         out2c('\n');
7755                 }
7756                 popstackmark(&smark);
7757                 FORCEINTON;                             /* enable interrupts */
7758                 if (state == 1)
7759                         goto state1;
7760                 else if (state == 2)
7761                         goto state2;
7762                 else if (state == 3)
7763                         goto state3;
7764                 else
7765                         goto state4;
7766         }
7767         handler = &jmploc;
7768 #ifdef DEBUG
7769         opentrace();
7770         trputs("Shell args:  ");  trargs(argv);
7771 #endif
7772         rootpid = getpid();
7773         rootshell = 1;
7774         init();
7775         setstackmark(&smark);
7776         procargs(argc, argv);
7777         if (argv[0] && argv[0][0] == '-') {
7778                 state = 1;
7779                 read_profile("/etc/profile");
7780 state1:
7781                 state = 2;
7782                 read_profile(".profile");
7783         }
7784 state2:
7785         state = 3;
7786 #ifndef linux
7787         if (getuid() == geteuid() && getgid() == getegid()) {
7788 #endif
7789                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7790                         state = 3;
7791                         read_profile(shinit);
7792                 }
7793 #ifndef linux
7794         }
7795 #endif
7796 state3:
7797         state = 4;
7798         if (sflag == 0 || minusc) {
7799                 static const char sigs[] =  {
7800                     SIGINT, SIGQUIT, SIGHUP,
7801 #ifdef SIGTSTP
7802                     SIGTSTP,
7803 #endif
7804                     SIGPIPE
7805                 };
7806 #define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
7807                 int i;
7808
7809                 for (i = 0; i < SIGSSIZE; i++)
7810                     setsignal(sigs[i]);
7811         }
7812
7813         if (minusc)
7814                 evalstring(minusc, 0);
7815
7816         if (sflag || minusc == NULL) {
7817 state4: /* XXX ??? - why isn't this before the "if" statement */
7818                 cmdloop(1);
7819         }
7820 #if PROFILE
7821         monitor(0);
7822 #endif
7823         exitshell(exitstatus);
7824         /* NOTREACHED */
7825 }
7826
7827
7828 /*
7829  * Read and execute commands.  "Top" is nonzero for the top level command
7830  * loop; it turns on prompting if the shell is interactive.
7831  */
7832
7833 static void
7834 cmdloop(int top)
7835 {
7836         union node *n;
7837         struct stackmark smark;
7838         int inter;
7839         int numeof = 0;
7840
7841         TRACE(("cmdloop(%d) called\n", top));
7842         setstackmark(&smark);
7843         for (;;) {
7844                 if (pendingsigs)
7845                         dotrap();
7846                 inter = 0;
7847                 if (iflag && top) {
7848                         inter++;
7849                         showjobs(1);
7850                         chkmail(0);
7851                         flushall();
7852                 }
7853                 n = parsecmd(inter);
7854                 /* showtree(n); DEBUG */
7855                 if (n == NEOF) {
7856                         if (!top || numeof >= 50)
7857                                 break;
7858                         if (!stoppedjobs()) {
7859                                 if (!Iflag)
7860                                         break;
7861                                 out2str("\nUse \"exit\" to leave shell.\n");
7862                         }
7863                         numeof++;
7864                 } else if (n != NULL && nflag == 0) {
7865                         job_warning = (job_warning == 2) ? 1 : 0;
7866                         numeof = 0;
7867                         evaltree(n, 0);
7868                 }
7869                 popstackmark(&smark);
7870                 setstackmark(&smark);
7871                 if (evalskip == SKIPFILE) {
7872                         evalskip = 0;
7873                         break;
7874                 }
7875         }
7876         popstackmark(&smark);
7877 }
7878
7879
7880
7881 /*
7882  * Read /etc/profile or .profile.  Return on error.
7883  */
7884
7885 static void
7886 read_profile(name)
7887         const char *name;
7888 {
7889         int fd;
7890         int xflag_save;
7891         int vflag_save;
7892
7893         INTOFF;
7894         if ((fd = open(name, O_RDONLY)) >= 0)
7895                 setinputfd(fd, 1);
7896         INTON;
7897         if (fd < 0)
7898                 return;
7899         /* -q turns off -x and -v just when executing init files */
7900         /* Note: Might do a little redundant work, but reduces code size. */
7901         xflag_save = xflag;
7902         vflag_save = vflag;
7903         if (qflag)  {
7904                 vflag = xflag = 0;
7905         }
7906         cmdloop(0);
7907         xflag = xflag_save;
7908         vflag = vflag_save;
7909         popfile();
7910 }
7911
7912
7913
7914 /*
7915  * Read a file containing shell functions.
7916  */
7917
7918 static void
7919 readcmdfile(const char *name)
7920 {
7921         int fd;
7922
7923         INTOFF;
7924         if ((fd = open(name, O_RDONLY)) >= 0)
7925                 setinputfd(fd, 1);
7926         else
7927                 error("Can't open %s", name);
7928         INTON;
7929         cmdloop(0);
7930         popfile();
7931 }
7932
7933
7934
7935 /*
7936  * Take commands from a file.  To be compatable we should do a path
7937  * search for the file, which is necessary to find sub-commands.
7938  */
7939
7940
7941 static inline char *
7942 find_dot_file(char *mybasename)
7943 {
7944         char *fullname;
7945         const char *path = pathval();
7946         struct stat statb;
7947
7948         /* don't try this for absolute or relative paths */
7949         if (strchr(mybasename, '/'))
7950                 return mybasename;
7951
7952         while ((fullname = padvance(&path, mybasename)) != NULL) {
7953                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7954                         /*
7955                          * Don't bother freeing here, since it will
7956                          * be freed by the caller.
7957                          */
7958                         return fullname;
7959                 }
7960                 stunalloc(fullname);
7961         }
7962
7963         /* not found in the PATH */
7964         error("%s: not found", mybasename);
7965         /* NOTREACHED */
7966 }
7967
7968 static int
7969 dotcmd(argc, argv)
7970         int argc;
7971         char **argv;
7972 {
7973         struct strlist *sp;
7974         exitstatus = 0;
7975
7976         for (sp = cmdenviron; sp ; sp = sp->next)
7977                 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7978
7979         if (argc >= 2) {                /* That's what SVR2 does */
7980                 char *fullname;
7981                 struct stackmark smark;
7982
7983                 setstackmark(&smark);
7984                 fullname = find_dot_file(argv[1]);
7985                 setinputfile(fullname, 1);
7986                 commandname = fullname;
7987                 cmdloop(0);
7988                 popfile();
7989                 popstackmark(&smark);
7990         }
7991         return exitstatus;
7992 }
7993
7994
7995 static int
7996 exitcmd(argc, argv)
7997         int argc;
7998         char **argv;
7999 {
8000         if (stoppedjobs())
8001                 return 0;
8002         if (argc > 1)
8003                 exitstatus = number(argv[1]);
8004         else
8005                 exitstatus = oexitstatus;
8006         exitshell(exitstatus);
8007         /* NOTREACHED */
8008 }
8009
8010 static pointer
8011 stalloc(int nbytes)
8012 {
8013         char *p;
8014
8015         nbytes = ALIGN(nbytes);
8016         if (nbytes > stacknleft) {
8017                 int blocksize;
8018                 struct stack_block *sp;
8019
8020                 blocksize = nbytes;
8021                 if (blocksize < MINSIZE)
8022                         blocksize = MINSIZE;
8023                 INTOFF;
8024                 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8025                 sp->prev = stackp;
8026                 stacknxt = sp->space;
8027                 stacknleft = blocksize;
8028                 stackp = sp;
8029                 INTON;
8030         }
8031         p = stacknxt;
8032         stacknxt += nbytes;
8033         stacknleft -= nbytes;
8034         return p;
8035 }
8036
8037
8038 static void
8039 stunalloc(pointer p)
8040 {
8041 #ifdef DEBUG
8042         if (p == NULL) {                /*DEBUG */
8043                 write(2, "stunalloc\n", 10);
8044                 abort();
8045         }
8046 #endif
8047         if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8048                 p = stackp->space;
8049         }
8050         stacknleft += stacknxt - (char *)p;
8051         stacknxt = p;
8052 }
8053
8054
8055 static void
8056 setstackmark(struct stackmark *mark)
8057 {
8058         mark->stackp = stackp;
8059         mark->stacknxt = stacknxt;
8060         mark->stacknleft = stacknleft;
8061         mark->marknext = markp;
8062         markp = mark;
8063 }
8064
8065
8066 static void
8067 popstackmark(struct stackmark *mark)
8068 {
8069         struct stack_block *sp;
8070
8071         INTOFF;
8072         markp = mark->marknext;
8073         while (stackp != mark->stackp) {
8074                 sp = stackp;
8075                 stackp = sp->prev;
8076                 ckfree(sp);
8077         }
8078         stacknxt = mark->stacknxt;
8079         stacknleft = mark->stacknleft;
8080         INTON;
8081 }
8082
8083
8084 /*
8085  * When the parser reads in a string, it wants to stick the string on the
8086  * stack and only adjust the stack pointer when it knows how big the
8087  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
8088  * of space on top of the stack and stackblocklen returns the length of
8089  * this block.  Growstackblock will grow this space by at least one byte,
8090  * possibly moving it (like realloc).  Grabstackblock actually allocates the
8091  * part of the block that has been used.
8092  */
8093
8094 static void
8095 growstackblock(void) {
8096         char *p;
8097         int newlen = ALIGN(stacknleft * 2 + 100);
8098         char *oldspace = stacknxt;
8099         int oldlen = stacknleft;
8100         struct stack_block *sp;
8101         struct stack_block *oldstackp;
8102
8103         if (stacknxt == stackp->space && stackp != &stackbase) {
8104                 INTOFF;
8105                 oldstackp = stackp;
8106                 sp = stackp;
8107                 stackp = sp->prev;
8108                 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8109                 sp->prev = stackp;
8110                 stackp = sp;
8111                 stacknxt = sp->space;
8112                 stacknleft = newlen;
8113                 {
8114                   /* Stack marks pointing to the start of the old block
8115                    * must be relocated to point to the new block
8116                    */
8117                   struct stackmark *xmark;
8118                   xmark = markp;
8119                   while (xmark != NULL && xmark->stackp == oldstackp) {
8120                     xmark->stackp = stackp;
8121                     xmark->stacknxt = stacknxt;
8122                     xmark->stacknleft = stacknleft;
8123                     xmark = xmark->marknext;
8124                   }
8125                 }
8126                 INTON;
8127         } else {
8128                 p = stalloc(newlen);
8129                 memcpy(p, oldspace, oldlen);
8130                 stacknxt = p;                   /* free the space */
8131                 stacknleft += newlen;           /* we just allocated */
8132         }
8133 }
8134
8135
8136
8137 static inline void
8138 grabstackblock(int len)
8139 {
8140         len = ALIGN(len);
8141         stacknxt += len;
8142         stacknleft -= len;
8143 }
8144
8145
8146
8147 /*
8148  * The following routines are somewhat easier to use that the above.
8149  * The user declares a variable of type STACKSTR, which may be declared
8150  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
8151  * the user uses the macro STPUTC to add characters to the string.  In
8152  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8153  * grown as necessary.  When the user is done, she can just leave the
8154  * string there and refer to it using stackblock().  Or she can allocate
8155  * the space for it using grabstackstr().  If it is necessary to allow
8156  * someone else to use the stack temporarily and then continue to grow
8157  * the string, the user should use grabstack to allocate the space, and
8158  * then call ungrabstr(p) to return to the previous mode of operation.
8159  *
8160  * USTPUTC is like STPUTC except that it doesn't check for overflow.
8161  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8162  * is space for at least one character.
8163  */
8164
8165
8166 static char *
8167 growstackstr(void) {
8168         int len = stackblocksize();
8169         if (herefd >= 0 && len >= 1024) {
8170                 xwrite(herefd, stackblock(), len);
8171                 sstrnleft = len - 1;
8172                 return stackblock();
8173         }
8174         growstackblock();
8175         sstrnleft = stackblocksize() - len - 1;
8176         return stackblock() + len;
8177 }
8178
8179
8180 /*
8181  * Called from CHECKSTRSPACE.
8182  */
8183
8184 static char *
8185 makestrspace(size_t newlen) {
8186         int len = stackblocksize() - sstrnleft;
8187         do {
8188                 growstackblock();
8189                 sstrnleft = stackblocksize() - len;
8190         } while (sstrnleft < newlen);
8191         return stackblock() + len;
8192 }
8193
8194
8195
8196 static void
8197 ungrabstackstr(char *s, char *p)
8198 {
8199         stacknleft += stacknxt - s;
8200         stacknxt = s;
8201         sstrnleft = stacknleft - (p - s);
8202 }
8203 /*
8204  * Miscelaneous builtins.
8205  */
8206
8207
8208 #undef rflag
8209
8210 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8211 typedef long rlim_t;
8212 #endif
8213
8214
8215
8216 /*
8217  * The read builtin.  The -e option causes backslashes to escape the
8218  * following character.
8219  *
8220  * This uses unbuffered input, which may be avoidable in some cases.
8221  */
8222
8223 static int
8224 readcmd(int argc, char **argv)
8225 {
8226         char **ap;
8227         int backslash;
8228         char c;
8229         int rflag;
8230         char *prompt;
8231         const char *ifs;
8232         char *p;
8233         int startword;
8234         int status;
8235         int i;
8236
8237         rflag = 0;
8238         prompt = NULL;
8239         while ((i = nextopt("p:r")) != '\0') {
8240                 if (i == 'p')
8241                         prompt = optionarg;
8242                 else
8243                         rflag = 1;
8244         }
8245         if (prompt && isatty(0)) {
8246                 out2str(prompt);     /* read without cmdedit */
8247                 flushall();
8248         }
8249         if (*(ap = argptr) == NULL)
8250                 error("arg count");
8251         if ((ifs = bltinlookup("IFS")) == NULL)
8252                 ifs = defifs;
8253         status = 0;
8254         startword = 1;
8255         backslash = 0;
8256         STARTSTACKSTR(p);
8257         for (;;) {
8258                 if (read(0, &c, 1) != 1) {
8259                         status = 1;
8260                         break;
8261                 }
8262                 if (c == '\0')
8263                         continue;
8264                 if (backslash) {
8265                         backslash = 0;
8266                         if (c != '\n')
8267                                 STPUTC(c, p);
8268                         continue;
8269                 }
8270                 if (!rflag && c == '\\') {
8271                         backslash++;
8272                         continue;
8273                 }
8274                 if (c == '\n')
8275                         break;
8276                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8277                         continue;
8278                 }
8279                 startword = 0;
8280                 if (backslash && c == '\\') {
8281                         if (read(0, &c, 1) != 1) {
8282                                 status = 1;
8283                                 break;
8284                         }
8285                         STPUTC(c, p);
8286                 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8287                         STACKSTRNUL(p);
8288                         setvar(*ap, stackblock(), 0);
8289                         ap++;
8290                         startword = 1;
8291                         STARTSTACKSTR(p);
8292                 } else {
8293                         STPUTC(c, p);
8294                 }
8295         }
8296         STACKSTRNUL(p);
8297         /* Remove trailing blanks */
8298         while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8299                 *p = '\0';
8300         setvar(*ap, stackblock(), 0);
8301         while (*++ap != NULL)
8302                 setvar(*ap, nullstr, 0);
8303         return status;
8304 }
8305
8306
8307
8308 static int
8309 umaskcmd(argc, argv)
8310         int argc;
8311         char **argv;
8312 {
8313         static const char permuser[3] = "ugo";
8314         static const char permmode[3] = "rwx";
8315         static const short int permmask[] = {
8316                 S_IRUSR, S_IWUSR, S_IXUSR,
8317                 S_IRGRP, S_IWGRP, S_IXGRP,
8318                 S_IROTH, S_IWOTH, S_IXOTH
8319         };
8320
8321         char *ap;
8322         mode_t mask;
8323         int i;
8324         int symbolic_mode = 0;
8325
8326         while (nextopt("S") != '\0') {
8327                 symbolic_mode = 1;
8328         }
8329
8330         INTOFF;
8331         mask = umask(0);
8332         umask(mask);
8333         INTON;
8334
8335         if ((ap = *argptr) == NULL) {
8336                 if (symbolic_mode) {
8337                         char buf[18];
8338                         char *p = buf;
8339                         for (i=0 ; i<3 ; i++) {
8340                                 int j;
8341                                 *p++ = permuser[i];
8342                                 *p++ = '=';
8343                                 for (j=0 ; j<3 ; j++) {
8344                                         if ((mask & permmask[3*i+j]) == 0) {
8345                                                 *p++ = permmode[j];
8346                                         }
8347                                 }
8348                                 *p++ = ',';
8349                         }
8350                         *--p = 0;
8351                         puts(buf);
8352                 } else {
8353                         printf("%.4o\n", mask);
8354                 }
8355         } else {
8356                 if (is_digit((unsigned char)*ap)) {
8357                         mask = 0;
8358                         do {
8359                                 if (*ap >= '8' || *ap < '0')
8360                                         error("Illegal number: %s", argv[1]);
8361                                 mask = (mask << 3) + (*ap - '0');
8362                         } while (*++ap != '\0');
8363                         umask(mask);
8364                 } else {
8365                         mask = ~mask & 0777;
8366                         if (parse_mode(ap, &mask) == FALSE) {
8367                                 error("Illegal mode: %s", ap);
8368                         }
8369                         umask(~mask & 0777);
8370                 }
8371         }
8372         return 0;
8373 }
8374
8375 /*
8376  * ulimit builtin
8377  *
8378  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8379  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8380  * ash by J.T. Conklin.
8381  *
8382  * Public domain.
8383  */
8384
8385 struct limits {
8386         const char *name;
8387         short   cmd;
8388         short   factor; /* multiply by to get rlim_{cur,max} values */
8389 };
8390
8391 static const struct limits limits[] = {
8392 #ifdef RLIMIT_CPU
8393         { "time(seconds)",             RLIMIT_CPU,        1 },
8394 #endif
8395 #ifdef RLIMIT_FSIZE
8396         { "file(blocks)",              RLIMIT_FSIZE,    512 },
8397 #endif
8398 #ifdef RLIMIT_DATA
8399         { "data(kbytes)",              RLIMIT_DATA,    1024 },
8400 #endif
8401 #ifdef RLIMIT_STACK
8402         { "stack(kbytes)",             RLIMIT_STACK,   1024 },
8403 #endif
8404 #ifdef  RLIMIT_CORE
8405         { "coredump(blocks)",          RLIMIT_CORE,     512 },
8406 #endif
8407 #ifdef RLIMIT_RSS
8408         { "memory(kbytes)",            RLIMIT_RSS,     1024 },
8409 #endif
8410 #ifdef RLIMIT_MEMLOCK
8411         { "locked memory(kbytes)",     RLIMIT_MEMLOCK, 1024 },
8412 #endif
8413 #ifdef RLIMIT_NPROC
8414         { "process(processes)",        RLIMIT_NPROC,      1 },
8415 #endif
8416 #ifdef RLIMIT_NOFILE
8417         { "nofiles(descriptors)",      RLIMIT_NOFILE,     1 },
8418 #endif
8419 #ifdef RLIMIT_VMEM
8420         { "vmemory(kbytes)",           RLIMIT_VMEM,    1024 },
8421 #endif
8422 #ifdef RLIMIT_SWAP
8423         { "swap(kbytes)",              RLIMIT_SWAP,    1024 },
8424 #endif
8425         { NULL,                         0,                 0 }
8426 };
8427
8428 static int
8429 ulimitcmd(argc, argv)
8430         int argc;
8431         char **argv;
8432 {
8433         static const char unlimited_string[] = "unlimited";
8434         int     c;
8435         rlim_t val = 0;
8436         enum { SOFT = 0x1, HARD = 0x2 }
8437                         how = SOFT | HARD;
8438         const struct limits     *l;
8439         int             set, all = 0;
8440         int             optc, what;
8441         struct rlimit   limit;
8442
8443         what = 'f';
8444
8445         while ((optc = nextopt("HSa"
8446 #ifdef RLIMIT_CPU
8447         "t"
8448 #endif
8449 #ifdef RLIMIT_FSIZE
8450         "f"
8451 #endif
8452 #ifdef RLIMIT_DATA
8453         "d"
8454 #endif
8455 #ifdef RLIMIT_STACK
8456         "s"
8457 #endif
8458 #ifdef  RLIMIT_CORE
8459         "c"
8460 #endif
8461 #ifdef RLIMIT_RSS
8462         "m"
8463 #endif
8464 #ifdef RLIMIT_MEMLOCK
8465         "l"
8466 #endif
8467 #ifdef RLIMIT_NPROC
8468         "p"
8469 #endif
8470 #ifdef RLIMIT_NOFILE
8471         "n"
8472 #endif
8473 #ifdef RLIMIT_VMEM
8474         "v"
8475 #endif
8476 #ifdef RLIMIT_SWAP
8477         "w"
8478 #endif
8479                                         )) != '\0') {
8480                 if (optc == 'H') {
8481                         how = HARD;
8482                 } else if (optc == 'S') {
8483                         how = SOFT;
8484                 } else if (optc == 'a') {
8485                         all = 1;
8486                 } else {
8487                         what = optc;
8488                 }
8489         }
8490
8491         for (l = limits; l->name; l++) {
8492                 if(l->name[0] == what)
8493                         break;
8494                 if(l->name[1]=='w' && what=='w')
8495                         break;
8496         }
8497
8498         set = *argptr ? 1 : 0;
8499         if (set) {
8500                 char *p = *argptr;
8501
8502                 if (all || argptr[1])
8503                         error("too many arguments");
8504                 if (strcmp(p, unlimited_string) == 0)
8505                         val = RLIM_INFINITY;
8506                 else {
8507                         val = (rlim_t) 0;
8508
8509                         while ((c = *p++) >= '0' && c <= '9')
8510                         {
8511                                 val = (val * 10) + (long)(c - '0');
8512                                 if (val < (rlim_t) 0)
8513                                         break;
8514                         }
8515                         if (c)
8516                                 error("bad number");
8517                         val *= l->factor;
8518                 }
8519         }
8520
8521         if (all) {
8522                 for (l = limits; l->name; l++) {
8523                         printf("%-20s ", l->name);
8524                         getrlimit(l->cmd, &limit);
8525                 OUTPUT_LIMIT:
8526                         if (how & SOFT)
8527                                 val = limit.rlim_cur;
8528                         else if (how & HARD)
8529                                 val = limit.rlim_max;
8530
8531                         if (val == RLIM_INFINITY)
8532                                 puts(unlimited_string);
8533                         else
8534                         {
8535                                 val /= l->factor;
8536                                 printf("%lld\n", (long long) val);
8537                         }
8538                         if (!all) {
8539                                 break;
8540                         }
8541                 }
8542                 return 0;
8543         }
8544
8545         if (!set) {
8546                 goto OUTPUT_LIMIT;
8547         }
8548
8549         getrlimit(l->cmd, &limit);
8550         if (how & HARD)
8551                 limit.rlim_max = val;
8552         if (how & SOFT)
8553                 limit.rlim_cur = val;
8554         if (setrlimit(l->cmd, &limit) < 0)
8555                 error("error setting limit (%m)");
8556         return 0;
8557 }
8558 /*
8559  * prefix -- see if pfx is a prefix of string.
8560  */
8561
8562 static int
8563 prefix(char const *pfx, char const *string)
8564 {
8565         while (*pfx) {
8566                 if (*pfx++ != *string++)
8567                         return 0;
8568         }
8569         return 1;
8570 }
8571
8572 /*
8573  * Return true if s is a string of digits, and save munber in intptr
8574  * nagative is bad
8575  */
8576
8577 static int
8578 is_number(const char *p, int *intptr)
8579 {
8580         int ret = 0;
8581
8582         do {
8583                 if (! is_digit(*p))
8584                         return 0;
8585                 ret *= 10;
8586                 ret += digit_val(*p);
8587                 p++;
8588         } while (*p != '\0');
8589
8590         *intptr = ret;
8591         return 1;
8592 }
8593
8594 /*
8595  * Convert a string of digits to an integer, printing an error message on
8596  * failure.
8597  */
8598
8599 static int
8600 number(const char *s)
8601 {
8602         int i;
8603         if (! is_number(s, &i))
8604                 error("Illegal number: %s", s);
8605         return i;
8606 }
8607
8608 /*
8609  * Produce a possibly single quoted string suitable as input to the shell.
8610  * The return string is allocated on the stack.
8611  */
8612
8613 static char *
8614 single_quote(const char *s) {
8615         char *p;
8616
8617         STARTSTACKSTR(p);
8618
8619         do {
8620                 char *q = p;
8621                 size_t len1, len1p, len2, len2p;
8622
8623                 len1 = strcspn(s, "'");
8624                 len2 = strspn(s + len1, "'");
8625
8626                 len1p = len1 ? len1 + 2 : len1;
8627                 len2p = len2 + ((len2 < 2) ? len2 : 2);
8628
8629                 CHECKSTRSPACE(len1p + len2p + 1, p);
8630
8631                 if (len1) {
8632                         *p = '\'';
8633                         q = p + 1 + len1;
8634                         memcpy(p + 1, s, len1);
8635                         *q++ = '\'';
8636                         s += len1;
8637                 }
8638
8639                 if (len2 > 1) {
8640                         *q = '"';
8641                         q += 1 + len2;
8642                         memcpy(q + 1, s, len2);
8643                         *q = '"';
8644                         s += len2;
8645                 } else if (len2 == 1) {
8646                         *q++ = '\\';
8647                         *q = '\'';
8648                         s++;
8649                 }
8650
8651                 STADJUST(len1p + len2p, p);
8652         } while (*s);
8653
8654         USTPUTC(0, p);
8655
8656         return grabstackstr(p);
8657 }
8658
8659 /*
8660  * Like strdup but works with the ash stack.
8661  */
8662
8663 static char *
8664 sstrdup(const char *p)
8665 {
8666         size_t len = strlen(p) + 1;
8667         return memcpy(stalloc(len), p, len);
8668 }
8669
8670
8671 /*
8672  * Routine for dealing with parsed shell commands.
8673  */
8674
8675
8676 static void sizenodelist (const struct nodelist *);
8677 static struct nodelist *copynodelist (const struct nodelist *);
8678 static char *nodesavestr (const char *);
8679
8680 #define CALCSIZE_TABLE
8681 #define COPYNODE_TABLE
8682 #if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8683 /*
8684  * To collect a lot of redundant code in case statements for copynode()
8685  * and calcsize(), we implement a mini language here.  Each type of node
8686  * struct has an associated instruction sequence that operates on its
8687  * members via their offsets.  The instruction are pack in unsigned chars
8688  * with format   IIDDDDDE   where the bits are
8689  *   I : part of the instruction opcode, which are
8690  *       00 : member is a pointer to another node
8691  *       40 : member is an integer
8692  *       80 : member is a pointer to a nodelist
8693  *       CC : member is a pointer to a char string
8694  *   D : data - the actual offset of the member to operate on in the struct
8695  *              (since we assume bit 0 is set, it is not shifted)
8696  *   E : flag signaling end of instruction sequence
8697  *
8698  * WARNING: In order to handle larger offsets for 64bit archs, this code
8699  *          assumes that no offset can be an odd number and stores the
8700  *          end-of-instructions flag in bit 0.
8701  */
8702
8703 #define NODE_INTEGER    0x40
8704 #define NODE_NODELIST   0x80
8705 #define NODE_CHARPTR    0xC0
8706 #define NODE_NOMORE             0x01    /* Note: no offset should be odd (aligned)*/
8707 #define NODE_MBRMASK    0xC0
8708 #define NODE_OFFSETMASK 0x3E
8709
8710 static const unsigned char copynode_ops[35] = {
8711 #define COPYNODE_OPS0   0
8712         offsetof(union node, nbinary.ch2),
8713         offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8714 #define COPYNODE_OPS1   (COPYNODE_OPS0 + 2)
8715         offsetof(union node, ncmd.redirect),
8716         offsetof(union node, ncmd.args),
8717         offsetof(union node, ncmd.assign),
8718         offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8719 #define COPYNODE_OPS2   (COPYNODE_OPS1 + 4)
8720         offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8721         offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8722 #define COPYNODE_OPS3   (COPYNODE_OPS2 + 2)
8723         offsetof(union node, nredir.redirect),
8724         offsetof(union node, nredir.n)|NODE_NOMORE,
8725 #define COPYNODE_OPS4   (COPYNODE_OPS3 + 2)
8726         offsetof(union node, nif.elsepart),
8727         offsetof(union node, nif.ifpart),
8728         offsetof(union node, nif.test)|NODE_NOMORE,
8729 #define COPYNODE_OPS5   (COPYNODE_OPS4 + 3)
8730         offsetof(union node, nfor.var)|NODE_CHARPTR,
8731         offsetof(union node, nfor.body),
8732         offsetof(union node, nfor.args)|NODE_NOMORE,
8733 #define COPYNODE_OPS6   (COPYNODE_OPS5 + 3)
8734         offsetof(union node, ncase.cases),
8735         offsetof(union node, ncase.expr)|NODE_NOMORE,
8736 #define COPYNODE_OPS7   (COPYNODE_OPS6 + 2)
8737         offsetof(union node, nclist.body),
8738         offsetof(union node, nclist.pattern),
8739         offsetof(union node, nclist.next)|NODE_NOMORE,
8740 #define COPYNODE_OPS8   (COPYNODE_OPS7 + 3)
8741         offsetof(union node, narg.backquote)|NODE_NODELIST,
8742         offsetof(union node, narg.text)|NODE_CHARPTR,
8743         offsetof(union node, narg.next)|NODE_NOMORE,
8744 #define COPYNODE_OPS9   (COPYNODE_OPS8 + 3)
8745         offsetof(union node, nfile.fname),
8746         offsetof(union node, nfile.fd)|NODE_INTEGER,
8747         offsetof(union node, nfile.next)|NODE_NOMORE,
8748 #define COPYNODE_OPS10   (COPYNODE_OPS9 + 3)
8749         offsetof(union node, ndup.vname),
8750         offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8751         offsetof(union node, ndup.fd)|NODE_INTEGER,
8752         offsetof(union node, ndup.next)|NODE_NOMORE,
8753 #define COPYNODE_OPS11   (COPYNODE_OPS10 + 4)
8754         offsetof(union node, nhere.doc),
8755         offsetof(union node, nhere.fd)|NODE_INTEGER,
8756         offsetof(union node, nhere.next)|NODE_NOMORE,
8757 #define COPYNODE_OPS12   (COPYNODE_OPS11 + 3)
8758         offsetof(union node, nnot.com)|NODE_NOMORE,
8759 };
8760
8761 #if COPYNODE_OPS12 != 34
8762 #error COPYNODE_OPS12 is incorrect
8763 #endif
8764
8765 static const unsigned char copynode_ops_index[26] = {
8766         COPYNODE_OPS0, /* NSEMI */
8767         COPYNODE_OPS1, /* NCMD */
8768         COPYNODE_OPS2, /* NPIPE */
8769         COPYNODE_OPS3, /* NREDIR */
8770         COPYNODE_OPS3, /* NBACKGND */
8771         COPYNODE_OPS3, /* NSUBSHELL */
8772         COPYNODE_OPS0, /* NAND */
8773         COPYNODE_OPS0, /* NOR */
8774         COPYNODE_OPS4, /* NIF */
8775         COPYNODE_OPS0, /* NWHILE */
8776         COPYNODE_OPS0, /* NUNTIL */
8777         COPYNODE_OPS5, /* NFOR */
8778         COPYNODE_OPS6, /* NCASE */
8779         COPYNODE_OPS7, /* NCLIST */
8780         COPYNODE_OPS8, /* NDEFUN */
8781         COPYNODE_OPS8, /* NARG */
8782         COPYNODE_OPS9, /* NTO */
8783         COPYNODE_OPS9, /* NFROM */
8784         COPYNODE_OPS9, /* NFROMTO */
8785         COPYNODE_OPS9, /* NAPPEND */
8786         COPYNODE_OPS9, /* NTOOV */
8787         COPYNODE_OPS10, /* NTOFD */
8788         COPYNODE_OPS10, /* NFROMFD */
8789         COPYNODE_OPS11, /* NHERE */
8790         COPYNODE_OPS11, /* NXHERE */
8791         COPYNODE_OPS12, /* NNOT */
8792 };
8793
8794 #if NODE_CHARPTR != NODE_MBRMASK
8795 #error NODE_CHARPTR != NODE_MBRMASK!!!
8796 #endif
8797 #endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8798
8799 #ifdef COPYNODE_TABLE
8800 static union node *
8801 copynode(const union node *n)
8802 {
8803       union node *new;
8804           const unsigned char *p;
8805
8806       if (n == NULL) {
8807           return NULL;
8808           }
8809       new = funcblock;
8810       new->type = n->type;
8811       funcblock = (char *) funcblock + (int) nodesize[n->type];
8812           p = copynode_ops + (int) copynode_ops_index[n->type];
8813           do {
8814                   char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8815                   const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8816
8817                   if (!(*p & NODE_MBRMASK)) { /* standard node */
8818                           *((union node **)nn) = copynode(*((const union node **) no));
8819                   } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8820                           *((const char **)nn) = nodesavestr(*((const char **)no));
8821                   } else if (*p & NODE_NODELIST) { /* nodelist */
8822                           *((struct nodelist **)nn)
8823                                   = copynodelist(*((const struct nodelist **) no));
8824                   } else {                              /* integer */
8825                           *((int *) nn) = *((int *) no);
8826                   }
8827           } while (!(*p++ & NODE_NOMORE));
8828       return new;
8829 }
8830 #else  /* COPYNODE_TABLE */
8831 static union node *
8832 copynode(const union node *n)
8833 {
8834       union node *new;
8835
8836       if (n == NULL)
8837         return NULL;
8838       new = funcblock;
8839       funcblock = (char *) funcblock + nodesize[n->type];
8840       switch (n->type) {
8841       case NSEMI:
8842       case NAND:
8843       case NOR:
8844       case NWHILE:
8845       case NUNTIL:
8846             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8847             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8848             break;
8849       case NCMD:
8850             new->ncmd.redirect = copynode(n->ncmd.redirect);
8851             new->ncmd.args = copynode(n->ncmd.args);
8852             new->ncmd.assign = copynode(n->ncmd.assign);
8853             new->ncmd.backgnd = n->ncmd.backgnd;
8854             break;
8855       case NPIPE:
8856             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8857             new->npipe.backgnd = n->npipe.backgnd;
8858             break;
8859       case NREDIR:
8860       case NBACKGND:
8861       case NSUBSHELL:
8862             new->nredir.redirect = copynode(n->nredir.redirect);
8863             new->nredir.n = copynode(n->nredir.n);
8864             break;
8865       case NIF:
8866             new->nif.elsepart = copynode(n->nif.elsepart);
8867             new->nif.ifpart = copynode(n->nif.ifpart);
8868             new->nif.test = copynode(n->nif.test);
8869             break;
8870       case NFOR:
8871             new->nfor.var = nodesavestr(n->nfor.var);
8872             new->nfor.body = copynode(n->nfor.body);
8873             new->nfor.args = copynode(n->nfor.args);
8874             break;
8875       case NCASE:
8876             new->ncase.cases = copynode(n->ncase.cases);
8877             new->ncase.expr = copynode(n->ncase.expr);
8878             break;
8879       case NCLIST:
8880             new->nclist.body = copynode(n->nclist.body);
8881             new->nclist.pattern = copynode(n->nclist.pattern);
8882             new->nclist.next = copynode(n->nclist.next);
8883             break;
8884       case NDEFUN:
8885       case NARG:
8886             new->narg.backquote = copynodelist(n->narg.backquote);
8887             new->narg.text = nodesavestr(n->narg.text);
8888             new->narg.next = copynode(n->narg.next);
8889             break;
8890       case NTO:
8891       case NFROM:
8892       case NFROMTO:
8893       case NAPPEND:
8894       case NTOOV:
8895             new->nfile.fname = copynode(n->nfile.fname);
8896             new->nfile.fd = n->nfile.fd;
8897             new->nfile.next = copynode(n->nfile.next);
8898             break;
8899       case NTOFD:
8900       case NFROMFD:
8901             new->ndup.vname = copynode(n->ndup.vname);
8902             new->ndup.dupfd = n->ndup.dupfd;
8903             new->ndup.fd = n->ndup.fd;
8904             new->ndup.next = copynode(n->ndup.next);
8905             break;
8906       case NHERE:
8907       case NXHERE:
8908             new->nhere.doc = copynode(n->nhere.doc);
8909             new->nhere.fd = n->nhere.fd;
8910             new->nhere.next = copynode(n->nhere.next);
8911             break;
8912       case NNOT:
8913             new->nnot.com = copynode(n->nnot.com);
8914             break;
8915       };
8916       new->type = n->type;
8917       return new;
8918 }
8919 #endif /* COPYNODE_TABLE */
8920
8921 #ifdef CALCSIZE_TABLE
8922 static void
8923 calcsize(const union node *n)
8924 {
8925           const unsigned char *p;
8926
8927       if (n == NULL)
8928             return;
8929       funcblocksize += (int) nodesize[n->type];
8930
8931           p = copynode_ops + (int) copynode_ops_index[n->type];
8932           do {
8933                   const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8934
8935                   if (!(*p & NODE_MBRMASK)) { /* standard node */
8936                           calcsize(*((const union node **) no));
8937                   } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8938                           funcstringsize += strlen(*((const char **)no)) + 1;
8939                   } else if (*p & NODE_NODELIST) { /* nodelist */
8940                           sizenodelist(*((const struct nodelist **) no));
8941                   }     /* else integer -- ignore */
8942           } while (!(*p++ & NODE_NOMORE));
8943 }
8944 #else  /* CALCSIZE_TABLE */
8945 static void
8946 calcsize(const union node *n)
8947 {
8948       if (n == NULL)
8949             return;
8950       funcblocksize += nodesize[n->type];
8951       switch (n->type) {
8952       case NSEMI:
8953       case NAND:
8954       case NOR:
8955       case NWHILE:
8956       case NUNTIL:
8957             calcsize(n->nbinary.ch2);
8958             calcsize(n->nbinary.ch1);
8959             break;
8960       case NCMD:
8961             calcsize(n->ncmd.redirect);
8962             calcsize(n->ncmd.args);
8963             calcsize(n->ncmd.assign);
8964             break;
8965       case NPIPE:
8966             sizenodelist(n->npipe.cmdlist);
8967             break;
8968       case NREDIR:
8969       case NBACKGND:
8970       case NSUBSHELL:
8971             calcsize(n->nredir.redirect);
8972             calcsize(n->nredir.n);
8973             break;
8974       case NIF:
8975             calcsize(n->nif.elsepart);
8976             calcsize(n->nif.ifpart);
8977             calcsize(n->nif.test);
8978             break;
8979       case NFOR:
8980             funcstringsize += strlen(n->nfor.var) + 1;
8981             calcsize(n->nfor.body);
8982             calcsize(n->nfor.args);
8983             break;
8984       case NCASE:
8985             calcsize(n->ncase.cases);
8986             calcsize(n->ncase.expr);
8987             break;
8988       case NCLIST:
8989             calcsize(n->nclist.body);
8990             calcsize(n->nclist.pattern);
8991             calcsize(n->nclist.next);
8992             break;
8993       case NDEFUN:
8994       case NARG:
8995             sizenodelist(n->narg.backquote);
8996             funcstringsize += strlen(n->narg.text) + 1;
8997             calcsize(n->narg.next);
8998             break;
8999       case NTO:
9000       case NFROM:
9001       case NFROMTO:
9002       case NAPPEND:
9003       case NTOOV:
9004             calcsize(n->nfile.fname);
9005             calcsize(n->nfile.next);
9006             break;
9007       case NTOFD:
9008       case NFROMFD:
9009             calcsize(n->ndup.vname);
9010             calcsize(n->ndup.next);
9011             break;
9012       case NHERE:
9013       case NXHERE:
9014             calcsize(n->nhere.doc);
9015             calcsize(n->nhere.next);
9016             break;
9017       case NNOT:
9018             calcsize(n->nnot.com);
9019             break;
9020       };
9021 }
9022 #endif /* CALCSIZE_TABLE */
9023
9024 static void
9025 sizenodelist(const struct nodelist *lp)
9026 {
9027         while (lp) {
9028                 funcblocksize += ALIGN(sizeof(struct nodelist));
9029                 calcsize(lp->n);
9030                 lp = lp->next;
9031         }
9032 }
9033
9034
9035 static struct nodelist *
9036 copynodelist(const struct nodelist *lp)
9037 {
9038         struct nodelist *start;
9039         struct nodelist **lpp;
9040
9041         lpp = &start;
9042         while (lp) {
9043                 *lpp = funcblock;
9044                 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9045                 (*lpp)->n = copynode(lp->n);
9046                 lp = lp->next;
9047                 lpp = &(*lpp)->next;
9048         }
9049         *lpp = NULL;
9050         return start;
9051 }
9052
9053
9054 static char *
9055 nodesavestr(const char *s)
9056 {
9057         const char *p = s;
9058         char *q = funcstring;
9059         char   *rtn = funcstring;
9060
9061         while ((*q++ = *p++) != '\0')
9062                 continue;
9063         funcstring = q;
9064         return rtn;
9065 }
9066
9067 #ifdef ASH_GETOPTS
9068 static int getopts (char *, char *, char **, int *, int *);
9069 #endif
9070
9071
9072 /*
9073  * Process the shell command line arguments.
9074  */
9075
9076 static void
9077 procargs(argc, argv)
9078         int argc;
9079         char **argv;
9080 {
9081         int i;
9082
9083         argptr = argv;
9084         if (argc > 0)
9085                 argptr++;
9086         for (i = 0; i < NOPTS; i++)
9087                 optent_val(i) = 2;
9088         options(1);
9089         if (*argptr == NULL && minusc == NULL)
9090                 sflag = 1;
9091         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9092                 iflag = 1;
9093         if (mflag == 2)
9094                 mflag = iflag;
9095         for (i = 0; i < NOPTS; i++)
9096                 if (optent_val(i) == 2)
9097                         optent_val(i) = 0;
9098         arg0 = argv[0];
9099         if (sflag == 0 && minusc == NULL) {
9100                 commandname = argv[0];
9101                 arg0 = *argptr++;
9102                 setinputfile(arg0, 0);
9103                 commandname = arg0;
9104         }
9105         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9106         if (argptr && minusc && *argptr)
9107                 arg0 = *argptr++;
9108
9109         shellparam.p = argptr;
9110         shellparam.optind = 1;
9111         shellparam.optoff = -1;
9112         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9113         while (*argptr) {
9114                 shellparam.nparam++;
9115                 argptr++;
9116         }
9117         optschanged();
9118 }
9119
9120
9121
9122 /*
9123  * Process shell options.  The global variable argptr contains a pointer
9124  * to the argument list; we advance it past the options.
9125  */
9126
9127 static inline void
9128 minus_o(const char *name, int val)
9129 {
9130         int i;
9131
9132         if (name == NULL) {
9133                 out1str("Current option settings\n");
9134                 for (i = 0; i < NOPTS; i++)
9135                         printf("%-16s%s\n", optent_name(optlist[i]),
9136                                 optent_val(i) ? "on" : "off");
9137         } else {
9138                 for (i = 0; i < NOPTS; i++)
9139                         if (equal(name, optent_name(optlist[i]))) {
9140                                 setoption(optent_letter(optlist[i]), val);
9141                                 return;
9142                         }
9143                 error("Illegal option -o %s", name);
9144         }
9145 }
9146
9147
9148 static void
9149 options(int cmdline)
9150 {
9151         char *p;
9152         int val;
9153         int c;
9154
9155         if (cmdline)
9156                 minusc = NULL;
9157         while ((p = *argptr) != NULL) {
9158                 argptr++;
9159                 if ((c = *p++) == '-') {
9160                         val = 1;
9161                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9162                                 if (!cmdline) {
9163                                         /* "-" means turn off -x and -v */
9164                                         if (p[0] == '\0')
9165                                                 xflag = vflag = 0;
9166                                         /* "--" means reset params */
9167                                         else if (*argptr == NULL)
9168                                                 setparam(argptr);
9169                                 }
9170                                 break;    /* "-" or  "--" terminates options */
9171                         }
9172                 } else if (c == '+') {
9173                         val = 0;
9174                 } else {
9175                         argptr--;
9176                         break;
9177                 }
9178                 while ((c = *p++) != '\0') {
9179                         if (c == 'c' && cmdline) {
9180                                 char *q;
9181 #ifdef NOHACK   /* removing this code allows sh -ce 'foo' for compat */
9182                                 if (*p == '\0')
9183 #endif
9184                                         q = *argptr++;
9185                                 if (q == NULL || minusc != NULL)
9186                                         error("Bad -c option");
9187                                 minusc = q;
9188 #ifdef NOHACK
9189                                 break;
9190 #endif
9191                         } else if (c == 'o') {
9192                                 minus_o(*argptr, val);
9193                                 if (*argptr)
9194                                         argptr++;
9195                         } else {
9196                                 setoption(c, val);
9197                         }
9198                 }
9199         }
9200 }
9201
9202
9203 static void
9204 setoption(int flag, int val)
9205 {
9206         int i;
9207
9208         for (i = 0; i < NOPTS; i++)
9209                 if (optent_letter(optlist[i]) == flag) {
9210                         optent_val(i) = val;
9211                         if (val) {
9212                                 /* #%$ hack for ksh semantics */
9213                                 if (flag == 'V')
9214                                         Eflag = 0;
9215                                 else if (flag == 'E')
9216                                         Vflag = 0;
9217                         }
9218                         return;
9219                 }
9220         error("Illegal option -%c", flag);
9221         /* NOTREACHED */
9222 }
9223
9224
9225
9226 /*
9227  * Set the shell parameters.
9228  */
9229
9230 static void
9231 setparam(char **argv)
9232 {
9233         char **newparam;
9234         char **ap;
9235         int nparam;
9236
9237         for (nparam = 0 ; argv[nparam] ; nparam++);
9238         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9239         while (*argv) {
9240                 *ap++ = savestr(*argv++);
9241         }
9242         *ap = NULL;
9243         freeparam(&shellparam);
9244         shellparam.malloc = 1;
9245         shellparam.nparam = nparam;
9246         shellparam.p = newparam;
9247         shellparam.optind = 1;
9248         shellparam.optoff = -1;
9249 }
9250
9251
9252 /*
9253  * Free the list of positional parameters.
9254  */
9255
9256 static void
9257 freeparam(volatile struct shparam *param)
9258 {
9259         char **ap;
9260
9261         if (param->malloc) {
9262                 for (ap = param->p ; *ap ; ap++)
9263                         ckfree(*ap);
9264                 ckfree(param->p);
9265         }
9266 }
9267
9268
9269
9270 /*
9271  * The shift builtin command.
9272  */
9273
9274 static int
9275 shiftcmd(argc, argv)
9276         int argc;
9277         char **argv;
9278 {
9279         int n;
9280         char **ap1, **ap2;
9281
9282         n = 1;
9283         if (argc > 1)
9284                 n = number(argv[1]);
9285         if (n > shellparam.nparam)
9286                 error("can't shift that many");
9287         INTOFF;
9288         shellparam.nparam -= n;
9289         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9290                 if (shellparam.malloc)
9291                         ckfree(*ap1);
9292         }
9293         ap2 = shellparam.p;
9294         while ((*ap2++ = *ap1++) != NULL);
9295         shellparam.optind = 1;
9296         shellparam.optoff = -1;
9297         INTON;
9298         return 0;
9299 }
9300
9301
9302
9303 /*
9304  * The set command builtin.
9305  */
9306
9307 static int
9308 setcmd(argc, argv)
9309         int argc;
9310         char **argv;
9311 {
9312         if (argc == 1)
9313                 return showvarscmd(argc, argv);
9314         INTOFF;
9315         options(0);
9316         optschanged();
9317         if (*argptr != NULL) {
9318                 setparam(argptr);
9319         }
9320         INTON;
9321         return 0;
9322 }
9323
9324
9325 static void
9326 getoptsreset(const char *value)
9327 {
9328         shellparam.optind = number(value);
9329         shellparam.optoff = -1;
9330 }
9331
9332 #ifdef BB_LOCALE_SUPPORT
9333 static void change_lc_all(const char *value)
9334 {
9335         if(value != 0 && *value != 0)
9336                 setlocale(LC_ALL, value);
9337 }
9338
9339 static void change_lc_ctype(const char *value)
9340 {
9341         if(value != 0 && *value != 0)
9342                 setlocale(LC_CTYPE, value);
9343 }
9344
9345 #endif
9346
9347 #ifdef ASH_GETOPTS
9348 /*
9349  * The getopts builtin.  Shellparam.optnext points to the next argument
9350  * to be processed.  Shellparam.optptr points to the next character to
9351  * be processed in the current argument.  If shellparam.optnext is NULL,
9352  * then it's the first time getopts has been called.
9353  */
9354
9355 static int
9356 getoptscmd(argc, argv)
9357         int argc;
9358         char **argv;
9359 {
9360         char **optbase;
9361
9362         if (argc < 3)
9363                 error("Usage: getopts optstring var [arg]");
9364         else if (argc == 3) {
9365                 optbase = shellparam.p;
9366                 if (shellparam.optind > shellparam.nparam + 1) {
9367                         shellparam.optind = 1;
9368                         shellparam.optoff = -1;
9369                 }
9370         }
9371         else {
9372                 optbase = &argv[3];
9373                 if (shellparam.optind > argc - 2) {
9374                         shellparam.optind = 1;
9375                         shellparam.optoff = -1;
9376                 }
9377         }
9378
9379         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9380                        &shellparam.optoff);
9381 }
9382
9383 /*
9384  * Safe version of setvar, returns 1 on success 0 on failure.
9385  */
9386
9387 static int
9388 setvarsafe(name, val, flags)
9389         const char *name, *val;
9390         int flags;
9391 {
9392         struct jmploc jmploc;
9393         struct jmploc *volatile savehandler = handler;
9394         int err = 0;
9395 #ifdef __GNUC__
9396         (void) &err;
9397 #endif
9398
9399         if (setjmp(jmploc.loc))
9400                 err = 1;
9401         else {
9402                 handler = &jmploc;
9403                 setvar(name, val, flags);
9404         }
9405         handler = savehandler;
9406         return err;
9407 }
9408
9409 static int
9410 getopts(optstr, optvar, optfirst, myoptind, optoff)
9411         char *optstr;
9412         char *optvar;
9413         char **optfirst;
9414         int *myoptind;
9415         int *optoff;
9416 {
9417         char *p, *q;
9418         char c = '?';
9419         int done = 0;
9420         int err = 0;
9421         char s[10];
9422         char **optnext = optfirst + *myoptind - 1;
9423
9424         if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9425             strlen(*(optnext - 1)) < *optoff)
9426                 p = NULL;
9427         else
9428                 p = *(optnext - 1) + *optoff;
9429         if (p == NULL || *p == '\0') {
9430                 /* Current word is done, advance */
9431                 if (optnext == NULL)
9432                         return 1;
9433                 p = *optnext;
9434                 if (p == NULL || *p != '-' || *++p == '\0') {
9435 atend:
9436                         *myoptind = optnext - optfirst + 1;
9437                         p = NULL;
9438                         done = 1;
9439                         goto out;
9440                 }
9441                 optnext++;
9442                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9443                         goto atend;
9444         }
9445
9446         c = *p++;
9447         for (q = optstr; *q != c; ) {
9448                 if (*q == '\0') {
9449                         if (optstr[0] == ':') {
9450                                 s[0] = c;
9451                                 s[1] = '\0';
9452                                 err |= setvarsafe("OPTARG", s, 0);
9453                         }
9454                         else {
9455                                 out2fmt("Illegal option -%c\n", c);
9456                                 (void) unsetvar("OPTARG");
9457                         }
9458                         c = '?';
9459                         goto bad;
9460                 }
9461                 if (*++q == ':')
9462                         q++;
9463         }
9464
9465         if (*++q == ':') {
9466                 if (*p == '\0' && (p = *optnext) == NULL) {
9467                         if (optstr[0] == ':') {
9468                                 s[0] = c;
9469                                 s[1] = '\0';
9470                                 err |= setvarsafe("OPTARG", s, 0);
9471                                 c = ':';
9472                         }
9473                         else {
9474                                 out2fmt("No arg for -%c option\n", c);
9475                                 (void) unsetvar("OPTARG");
9476                                 c = '?';
9477                         }
9478                         goto bad;
9479                 }
9480
9481                 if (p == *optnext)
9482                         optnext++;
9483                 setvarsafe("OPTARG", p, 0);
9484                 p = NULL;
9485         }
9486         else
9487                 setvarsafe("OPTARG", "", 0);
9488         *myoptind = optnext - optfirst + 1;
9489         goto out;
9490
9491 bad:
9492         *myoptind = 1;
9493         p = NULL;
9494 out:
9495         *optoff = p ? p - *(optnext - 1) : -1;
9496         snprintf(s, sizeof(s), "%d", *myoptind);
9497         err |= setvarsafe("OPTIND", s, VNOFUNC);
9498         s[0] = c;
9499         s[1] = '\0';
9500         err |= setvarsafe(optvar, s, 0);
9501         if (err) {
9502                 *myoptind = 1;
9503                 *optoff = -1;
9504                 exraise(EXERROR);
9505         }
9506         return done;
9507 }
9508 #endif
9509
9510 /*
9511  * XXX - should get rid of.  have all builtins use getopt(3).  the
9512  * library getopt must have the BSD extension static variable "optreset"
9513  * otherwise it can't be used within the shell safely.
9514  *
9515  * Standard option processing (a la getopt) for builtin routines.  The
9516  * only argument that is passed to nextopt is the option string; the
9517  * other arguments are unnecessary.  It return the character, or '\0' on
9518  * end of input.
9519  */
9520
9521 static int
9522 nextopt(const char *optstring)
9523 {
9524         char *p;
9525         const char *q;
9526         char c;
9527
9528         if ((p = optptr) == NULL || *p == '\0') {
9529                 p = *argptr;
9530                 if (p == NULL || *p != '-' || *++p == '\0')
9531                         return '\0';
9532                 argptr++;
9533                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9534                         return '\0';
9535         }
9536         c = *p++;
9537         for (q = optstring ; *q != c ; ) {
9538                 if (*q == '\0')
9539                         error("Illegal option -%c", c);
9540                 if (*++q == ':')
9541                         q++;
9542         }
9543         if (*++q == ':') {
9544                 if (*p == '\0' && (p = *argptr++) == NULL)
9545                         error("No arg for -%c option", c);
9546                 optionarg = p;
9547                 p = NULL;
9548         }
9549         optptr = p;
9550         return c;
9551 }
9552
9553 static void
9554 flushall() {
9555         INTOFF;
9556         fflush(stdout);
9557         INTON;
9558 }
9559
9560
9561 static void
9562 out2fmt(const char *fmt, ...)
9563 {
9564         va_list ap;
9565         va_start(ap, fmt);
9566         vfprintf(stderr, fmt, ap);
9567         va_end(ap);
9568 }
9569
9570 /*
9571  * Version of write which resumes after a signal is caught.
9572  */
9573
9574 static int
9575 xwrite(int fd, const char *buf, int nbytes)
9576 {
9577         int ntry;
9578         int i;
9579         int n;
9580
9581         n = nbytes;
9582         ntry = 0;
9583         for (;;) {
9584                 i = write(fd, buf, n);
9585                 if (i > 0) {
9586                         if ((n -= i) <= 0)
9587                                 return nbytes;
9588                         buf += i;
9589                         ntry = 0;
9590                 } else if (i == 0) {
9591                         if (++ntry > 10)
9592                                 return nbytes - n;
9593                 } else if (errno != EINTR) {
9594                         return -1;
9595                 }
9596         }
9597 }
9598
9599
9600 /*
9601  * Shell command parser.
9602  */
9603
9604 #define EOFMARKLEN 79
9605
9606
9607
9608 struct heredoc {
9609         struct heredoc *next;   /* next here document in list */
9610         union node *here;               /* redirection node */
9611         char *eofmark;          /* string indicating end of input */
9612         int striptabs;          /* if set, strip leading tabs */
9613 };
9614
9615 static struct heredoc *heredoclist;     /* list of here documents to read */
9616 static int parsebackquote;              /* nonzero if we are inside backquotes */
9617 static int doprompt;                    /* if set, prompt the user */
9618 static int needprompt;                  /* true if interactive and at start of line */
9619 static int lasttoken;                   /* last token read */
9620
9621 static char *wordtext;                  /* text of last word returned by readtoken */
9622
9623 static struct nodelist *backquotelist;
9624 static union node *redirnode;
9625 static struct heredoc *heredoc;
9626 static int quoteflag;                   /* set if (part of) last token was quoted */
9627 static int startlinno;                  /* line # where last token started */
9628
9629
9630 static union node *list (int);
9631 static union node *andor (void);
9632 static union node *pipeline (void);
9633 static union node *command (void);
9634 static union node *simplecmd (void);
9635 static void parsefname (void);
9636 static void parseheredoc (void);
9637 static char peektoken (void);
9638 static int readtoken (void);
9639 static int xxreadtoken (void);
9640 static int readtoken1 (int, int, const char *, int);
9641 static int noexpand (char *);
9642 static void synexpect (int) __attribute__((noreturn));
9643 static void synerror (const char *) __attribute__((noreturn));
9644 static void setprompt (int);
9645
9646
9647 /*
9648  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9649  * valid parse tree indicating a blank line.)
9650  */
9651
9652 static union node *
9653 parsecmd(int interact)
9654 {
9655         int t;
9656
9657         tokpushback = 0;
9658         doprompt = interact;
9659         if (doprompt)
9660                 setprompt(1);
9661         else
9662                 setprompt(0);
9663         needprompt = 0;
9664         t = readtoken();
9665         if (t == TEOF)
9666                 return NEOF;
9667         if (t == TNL)
9668                 return NULL;
9669         tokpushback++;
9670         return list(1);
9671 }
9672
9673
9674 static union node *
9675 list(nlflag)
9676         int nlflag;
9677 {
9678         union node *n1, *n2, *n3;
9679         int tok;
9680
9681         checkkwd = 2;
9682         if (nlflag == 0 && peektoken())
9683                 return NULL;
9684         n1 = NULL;
9685         for (;;) {
9686                 n2 = andor();
9687                 tok = readtoken();
9688                 if (tok == TBACKGND) {
9689                         if (n2->type == NCMD || n2->type == NPIPE) {
9690                                 n2->ncmd.backgnd = 1;
9691                         } else if (n2->type == NREDIR) {
9692                                 n2->type = NBACKGND;
9693                         } else {
9694                                 n3 = (union node *)stalloc(sizeof (struct nredir));
9695                                 n3->type = NBACKGND;
9696                                 n3->nredir.n = n2;
9697                                 n3->nredir.redirect = NULL;
9698                                 n2 = n3;
9699                         }
9700                 }
9701                 if (n1 == NULL) {
9702                         n1 = n2;
9703                 }
9704                 else {
9705                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9706                         n3->type = NSEMI;
9707                         n3->nbinary.ch1 = n1;
9708                         n3->nbinary.ch2 = n2;
9709                         n1 = n3;
9710                 }
9711                 switch (tok) {
9712                 case TBACKGND:
9713                 case TSEMI:
9714                         tok = readtoken();
9715                         /* fall through */
9716                 case TNL:
9717                         if (tok == TNL) {
9718                                 parseheredoc();
9719                                 if (nlflag)
9720                                         return n1;
9721                         } else {
9722                                 tokpushback++;
9723                         }
9724                         checkkwd = 2;
9725                         if (peektoken())
9726                                 return n1;
9727                         break;
9728                 case TEOF:
9729                         if (heredoclist)
9730                                 parseheredoc();
9731                         else
9732                                 pungetc();              /* push back EOF on input */
9733                         return n1;
9734                 default:
9735                         if (nlflag)
9736                                 synexpect(-1);
9737                         tokpushback++;
9738                         return n1;
9739                 }
9740         }
9741 }
9742
9743
9744
9745 static union node *
9746 andor() {
9747         union node *n1, *n2, *n3;
9748         int t;
9749
9750         checkkwd = 1;
9751         n1 = pipeline();
9752         for (;;) {
9753                 if ((t = readtoken()) == TAND) {
9754                         t = NAND;
9755                 } else if (t == TOR) {
9756                         t = NOR;
9757                 } else {
9758                         tokpushback++;
9759                         return n1;
9760                 }
9761                 checkkwd = 2;
9762                 n2 = pipeline();
9763                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9764                 n3->type = t;
9765                 n3->nbinary.ch1 = n1;
9766                 n3->nbinary.ch2 = n2;
9767                 n1 = n3;
9768         }
9769 }
9770
9771
9772
9773 static union node *
9774 pipeline() {
9775         union node *n1, *n2, *pipenode;
9776         struct nodelist *lp, *prev;
9777         int negate;
9778
9779         negate = 0;
9780         TRACE(("pipeline: entered\n"));
9781         if (readtoken() == TNOT) {
9782                 negate = !negate;
9783                 checkkwd = 1;
9784         } else
9785                 tokpushback++;
9786         n1 = command();
9787         if (readtoken() == TPIPE) {
9788                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9789                 pipenode->type = NPIPE;
9790                 pipenode->npipe.backgnd = 0;
9791                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9792                 pipenode->npipe.cmdlist = lp;
9793                 lp->n = n1;
9794                 do {
9795                         prev = lp;
9796                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9797                         checkkwd = 2;
9798                         lp->n = command();
9799                         prev->next = lp;
9800                 } while (readtoken() == TPIPE);
9801                 lp->next = NULL;
9802                 n1 = pipenode;
9803         }
9804         tokpushback++;
9805         if (negate) {
9806                 n2 = (union node *)stalloc(sizeof (struct nnot));
9807                 n2->type = NNOT;
9808                 n2->nnot.com = n1;
9809                 return n2;
9810         } else
9811                 return n1;
9812 }
9813
9814
9815
9816 static union node *
9817 command() {
9818         union node *n1, *n2;
9819         union node *ap, **app;
9820         union node *cp, **cpp;
9821         union node *redir, **rpp;
9822         int t;
9823
9824         redir = NULL;
9825         n1 = NULL;
9826         rpp = &redir;
9827
9828         /* Check for redirection which may precede command */
9829         while (readtoken() == TREDIR) {
9830                 *rpp = n2 = redirnode;
9831                 rpp = &n2->nfile.next;
9832                 parsefname();
9833         }
9834         tokpushback++;
9835
9836         switch (readtoken()) {
9837         case TIF:
9838                 n1 = (union node *)stalloc(sizeof (struct nif));
9839                 n1->type = NIF;
9840                 n1->nif.test = list(0);
9841                 if (readtoken() != TTHEN)
9842                         synexpect(TTHEN);
9843                 n1->nif.ifpart = list(0);
9844                 n2 = n1;
9845                 while (readtoken() == TELIF) {
9846                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9847                         n2 = n2->nif.elsepart;
9848                         n2->type = NIF;
9849                         n2->nif.test = list(0);
9850                         if (readtoken() != TTHEN)
9851                                 synexpect(TTHEN);
9852                         n2->nif.ifpart = list(0);
9853                 }
9854                 if (lasttoken == TELSE)
9855                         n2->nif.elsepart = list(0);
9856                 else {
9857                         n2->nif.elsepart = NULL;
9858                         tokpushback++;
9859                 }
9860                 if (readtoken() != TFI)
9861                         synexpect(TFI);
9862                 checkkwd = 1;
9863                 break;
9864         case TWHILE:
9865         case TUNTIL: {
9866                 int got;
9867                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9868                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9869                 n1->nbinary.ch1 = list(0);
9870                 if ((got=readtoken()) != TDO) {
9871 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9872                         synexpect(TDO);
9873                 }
9874                 n1->nbinary.ch2 = list(0);
9875                 if (readtoken() != TDONE)
9876                         synexpect(TDONE);
9877                 checkkwd = 1;
9878                 break;
9879         }
9880         case TFOR:
9881                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9882                         synerror("Bad for loop variable");
9883                 n1 = (union node *)stalloc(sizeof (struct nfor));
9884                 n1->type = NFOR;
9885                 n1->nfor.var = wordtext;
9886                 checkkwd = 1;
9887                 if (readtoken() == TIN) {
9888                         app = &ap;
9889                         while (readtoken() == TWORD) {
9890                                 n2 = (union node *)stalloc(sizeof (struct narg));
9891                                 n2->type = NARG;
9892                                 n2->narg.text = wordtext;
9893                                 n2->narg.backquote = backquotelist;
9894                                 *app = n2;
9895                                 app = &n2->narg.next;
9896                         }
9897                         *app = NULL;
9898                         n1->nfor.args = ap;
9899                         if (lasttoken != TNL && lasttoken != TSEMI)
9900                                 synexpect(-1);
9901                 } else {
9902                         static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9903                                                                    '@', '=', '\0'};
9904                         n2 = (union node *)stalloc(sizeof (struct narg));
9905                         n2->type = NARG;
9906                         n2->narg.text = argvars;
9907                         n2->narg.backquote = NULL;
9908                         n2->narg.next = NULL;
9909                         n1->nfor.args = n2;
9910                         /*
9911                          * Newline or semicolon here is optional (but note
9912                          * that the original Bourne shell only allowed NL).
9913                          */
9914                         if (lasttoken != TNL && lasttoken != TSEMI)
9915                                 tokpushback++;
9916                 }
9917                 checkkwd = 2;
9918                 if (readtoken() != TDO)
9919                         synexpect(TDO);
9920                 n1->nfor.body = list(0);
9921                 if (readtoken() != TDONE)
9922                         synexpect(TDONE);
9923                 checkkwd = 1;
9924                 break;
9925         case TCASE:
9926                 n1 = (union node *)stalloc(sizeof (struct ncase));
9927                 n1->type = NCASE;
9928                 if (readtoken() != TWORD)
9929                         synexpect(TWORD);
9930                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9931                 n2->type = NARG;
9932                 n2->narg.text = wordtext;
9933                 n2->narg.backquote = backquotelist;
9934                 n2->narg.next = NULL;
9935                 do {
9936                         checkkwd = 1;
9937                 } while (readtoken() == TNL);
9938                 if (lasttoken != TIN)
9939                         synerror("expecting \"in\"");
9940                 cpp = &n1->ncase.cases;
9941                 checkkwd = 2, readtoken();
9942                 do {
9943                         if (lasttoken == TLP)
9944                                 readtoken();
9945                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9946                         cp->type = NCLIST;
9947                         app = &cp->nclist.pattern;
9948                         for (;;) {
9949                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9950                                 ap->type = NARG;
9951                                 ap->narg.text = wordtext;
9952                                 ap->narg.backquote = backquotelist;
9953                                 if (checkkwd = 2, readtoken() != TPIPE)
9954                                         break;
9955                                 app = &ap->narg.next;
9956                                 readtoken();
9957                         }
9958                         ap->narg.next = NULL;
9959                         if (lasttoken != TRP)
9960                                 synexpect(TRP);
9961                         cp->nclist.body = list(0);
9962
9963                         checkkwd = 2;
9964                         if ((t = readtoken()) != TESAC) {
9965                                 if (t != TENDCASE)
9966                                         synexpect(TENDCASE);
9967                                 else
9968                                         checkkwd = 2, readtoken();
9969                         }
9970                         cpp = &cp->nclist.next;
9971                 } while(lasttoken != TESAC);
9972                 *cpp = NULL;
9973                 checkkwd = 1;
9974                 break;
9975         case TLP:
9976                 n1 = (union node *)stalloc(sizeof (struct nredir));
9977                 n1->type = NSUBSHELL;
9978                 n1->nredir.n = list(0);
9979                 n1->nredir.redirect = NULL;
9980                 if (readtoken() != TRP)
9981                         synexpect(TRP);
9982                 checkkwd = 1;
9983                 break;
9984         case TBEGIN:
9985                 n1 = list(0);
9986                 if (readtoken() != TEND)
9987                         synexpect(TEND);
9988                 checkkwd = 1;
9989                 break;
9990         /* Handle an empty command like other simple commands.  */
9991         case TSEMI:
9992         case TAND:
9993         case TOR:
9994         case TNL:
9995         case TEOF:
9996         case TRP:
9997         case TBACKGND:
9998                 /*
9999                  * An empty command before a ; doesn't make much sense, and
10000                  * should certainly be disallowed in the case of `if ;'.
10001                  */
10002                 if (!redir)
10003                         synexpect(-1);
10004         case TWORD:
10005                 tokpushback++;
10006                 n1 = simplecmd();
10007                 return n1;
10008         default:
10009                 synexpect(-1);
10010                 /* NOTREACHED */
10011         }
10012
10013         /* Now check for redirection which may follow command */
10014         while (readtoken() == TREDIR) {
10015                 *rpp = n2 = redirnode;
10016                 rpp = &n2->nfile.next;
10017                 parsefname();
10018         }
10019         tokpushback++;
10020         *rpp = NULL;
10021         if (redir) {
10022                 if (n1->type != NSUBSHELL) {
10023                         n2 = (union node *)stalloc(sizeof (struct nredir));
10024                         n2->type = NREDIR;
10025                         n2->nredir.n = n1;
10026                         n1 = n2;
10027                 }
10028                 n1->nredir.redirect = redir;
10029         }
10030
10031         return n1;
10032 }
10033
10034
10035 static union node *
10036 simplecmd() {
10037         union node *args, **app;
10038         union node *n = NULL;
10039         union node *vars, **vpp;
10040         union node **rpp, *redir;
10041
10042         args = NULL;
10043         app = &args;
10044         vars = NULL;
10045         vpp = &vars;
10046         redir = NULL;
10047         rpp = &redir;
10048
10049         checkalias = 2;
10050         for (;;) {
10051                 switch (readtoken()) {
10052                 case TWORD:
10053                 case TASSIGN:
10054                         n = (union node *)stalloc(sizeof (struct narg));
10055                         n->type = NARG;
10056                         n->narg.text = wordtext;
10057                         n->narg.backquote = backquotelist;
10058                         if (lasttoken == TWORD) {
10059                                 *app = n;
10060                                 app = &n->narg.next;
10061                         } else {
10062                                 *vpp = n;
10063                                 vpp = &n->narg.next;
10064                         }
10065                         break;
10066                 case TREDIR:
10067                         *rpp = n = redirnode;
10068                         rpp = &n->nfile.next;
10069                         parsefname();   /* read name of redirection file */
10070                         break;
10071                 case TLP:
10072                         if (
10073                                 args && app == &args->narg.next &&
10074                                 !vars && !redir
10075                         ) {
10076                                 /* We have a function */
10077                                 if (readtoken() != TRP)
10078                                         synexpect(TRP);
10079                                 n->type = NDEFUN;
10080                                 checkkwd = 2;
10081                                 n->narg.next = command();
10082                                 return n;
10083                         }
10084                         /* fall through */
10085                 default:
10086                         tokpushback++;
10087                         goto out;
10088                 }
10089         }
10090 out:
10091         *app = NULL;
10092         *vpp = NULL;
10093         *rpp = NULL;
10094         n = (union node *)stalloc(sizeof (struct ncmd));
10095         n->type = NCMD;
10096         n->ncmd.backgnd = 0;
10097         n->ncmd.args = args;
10098         n->ncmd.assign = vars;
10099         n->ncmd.redirect = redir;
10100         return n;
10101 }
10102
10103 static union node *
10104 makename(void) {
10105         union node *n;
10106
10107         n = (union node *)stalloc(sizeof (struct narg));
10108         n->type = NARG;
10109         n->narg.next = NULL;
10110         n->narg.text = wordtext;
10111         n->narg.backquote = backquotelist;
10112         return n;
10113 }
10114
10115 static void fixredir(union node *n, const char *text, int err)
10116 {
10117         TRACE(("Fix redir %s %d\n", text, err));
10118         if (!err)
10119                 n->ndup.vname = NULL;
10120
10121         if (is_digit(text[0]) && text[1] == '\0')
10122                 n->ndup.dupfd = digit_val(text[0]);
10123         else if (text[0] == '-' && text[1] == '\0')
10124                 n->ndup.dupfd = -1;
10125         else {
10126
10127                 if (err)
10128                         synerror("Bad fd number");
10129                 else
10130                         n->ndup.vname = makename();
10131         }
10132 }
10133
10134
10135 static void
10136 parsefname(void) {
10137         union node *n = redirnode;
10138
10139         if (readtoken() != TWORD)
10140                 synexpect(-1);
10141         if (n->type == NHERE) {
10142                 struct heredoc *here = heredoc;
10143                 struct heredoc *p;
10144                 int i;
10145
10146                 if (quoteflag == 0)
10147                         n->type = NXHERE;
10148                 TRACE(("Here document %d\n", n->type));
10149                 if (here->striptabs) {
10150                         while (*wordtext == '\t')
10151                                 wordtext++;
10152                 }
10153                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10154                         synerror("Illegal eof marker for << redirection");
10155                 rmescapes(wordtext);
10156                 here->eofmark = wordtext;
10157                 here->next = NULL;
10158                 if (heredoclist == NULL)
10159                         heredoclist = here;
10160                 else {
10161                         for (p = heredoclist ; p->next ; p = p->next);
10162                         p->next = here;
10163                 }
10164         } else if (n->type == NTOFD || n->type == NFROMFD) {
10165                 fixredir(n, wordtext, 0);
10166         } else {
10167                 n->nfile.fname = makename();
10168         }
10169 }
10170
10171
10172 /*
10173  * Input any here documents.
10174  */
10175
10176 static void
10177 parseheredoc() {
10178         struct heredoc *here;
10179         union node *n;
10180
10181         while (heredoclist) {
10182                 here = heredoclist;
10183                 heredoclist = here->next;
10184                 if (needprompt) {
10185                         setprompt(2);
10186                         needprompt = 0;
10187                 }
10188                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10189                                 here->eofmark, here->striptabs);
10190                 n = (union node *)stalloc(sizeof (struct narg));
10191                 n->narg.type = NARG;
10192                 n->narg.next = NULL;
10193                 n->narg.text = wordtext;
10194                 n->narg.backquote = backquotelist;
10195                 here->here->nhere.doc = n;
10196         }
10197 }
10198
10199 static char
10200 peektoken() {
10201         int t;
10202
10203         t = readtoken();
10204         tokpushback++;
10205         return tokname_array[t][0];
10206 }
10207
10208 static int
10209 readtoken() {
10210         int t;
10211
10212 #ifdef ASH_ALIAS
10213         int savecheckalias = checkalias;
10214         int savecheckkwd = checkkwd;
10215         struct alias *ap;
10216 #endif
10217
10218 #ifdef DEBUG
10219         int alreadyseen = tokpushback;
10220 #endif
10221
10222 #ifdef ASH_ALIAS
10223 top:
10224 #endif
10225
10226         t = xxreadtoken();
10227
10228 #ifdef ASH_ALIAS
10229         checkalias = savecheckalias;
10230 #endif
10231
10232         if (checkkwd) {
10233                 /*
10234                  * eat newlines
10235                  */
10236                 if (checkkwd == 2) {
10237                         checkkwd = 0;
10238                         while (t == TNL) {
10239                                 parseheredoc();
10240                                 t = xxreadtoken();
10241                         }
10242                 }
10243                 checkkwd = 0;
10244                 /*
10245                  * check for keywords
10246                  */
10247                 if (t == TWORD && !quoteflag)
10248                 {
10249                         const char *const *pp;
10250
10251                         if ((pp = findkwd(wordtext))) {
10252                                 lasttoken = t = pp - tokname_array;
10253                                 TRACE(("keyword %s recognized\n", tokname(t)));
10254                                 goto out;
10255                         }
10256                 }
10257         }
10258
10259
10260         if (t != TWORD) {
10261                 if (t != TREDIR) {
10262                         checkalias = 0;
10263                 }
10264         } else if (checkalias == 2 && isassignment(wordtext)) {
10265                 lasttoken = t = TASSIGN;
10266 #ifdef ASH_ALIAS
10267         } else if (checkalias) {
10268                 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10269                         if (*ap->val) {
10270                                 pushstring(ap->val, strlen(ap->val), ap);
10271                         }
10272                         checkkwd = savecheckkwd;
10273                         goto top;
10274                 }
10275                 checkalias = 0;
10276 #endif
10277         }
10278 out:
10279 #ifdef DEBUG
10280         if (!alreadyseen)
10281             TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10282         else
10283             TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10284 #endif
10285         return (t);
10286 }
10287
10288
10289 /*
10290  * Read the next input token.
10291  * If the token is a word, we set backquotelist to the list of cmds in
10292  *      backquotes.  We set quoteflag to true if any part of the word was
10293  *      quoted.
10294  * If the token is TREDIR, then we set redirnode to a structure containing
10295  *      the redirection.
10296  * In all cases, the variable startlinno is set to the number of the line
10297  *      on which the token starts.
10298  *
10299  * [Change comment:  here documents and internal procedures]
10300  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
10301  *  word parsing code into a separate routine.  In this case, readtoken
10302  *  doesn't need to have any internal procedures, but parseword does.
10303  *  We could also make parseoperator in essence the main routine, and
10304  *  have parseword (readtoken1?) handle both words and redirection.]
10305  */
10306
10307 #define NEW_xxreadtoken
10308 #ifdef NEW_xxreadtoken
10309
10310 static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10311 static const char xxreadtoken_tokens[] = {
10312         TNL, TLP, TRP,                          /* only single occurrence allowed */
10313         TBACKGND, TPIPE, TSEMI,         /* if single occurrence */
10314         TEOF,                                           /* corresponds to trailing nul */
10315         TAND, TOR, TENDCASE,            /* if double occurrence */
10316 };
10317
10318 #define xxreadtoken_doubles \
10319         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10320 #define xxreadtoken_singles \
10321         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10322
10323 static int
10324 xxreadtoken() {
10325         int c;
10326
10327         if (tokpushback) {
10328                 tokpushback = 0;
10329                 return lasttoken;
10330         }
10331         if (needprompt) {
10332                 setprompt(2);
10333                 needprompt = 0;
10334         }
10335         startlinno = plinno;
10336         for (;;) {      /* until token or start of word found */
10337                 c = pgetc_macro();
10338
10339                 if ((c!=' ') && (c!='\t')
10340 #ifdef ASH_ALIAS
10341                         && (c!=PEOA)
10342 #endif
10343                         ) {
10344                         if (c=='#') {
10345                                 while ((c = pgetc()) != '\n' && c != PEOF);
10346                                 pungetc();
10347                         } else if (c=='\\') {
10348                                 if (pgetc() != '\n') {
10349                                         pungetc();
10350                                         goto READTOKEN1;
10351                                 }
10352                                 startlinno = ++plinno;
10353                                 setprompt(doprompt ? 2 : 0);
10354                         } else {
10355                                 const char *p
10356                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10357
10358                                 if (c!=PEOF) {
10359                                         if (c=='\n') {
10360                                                 plinno++;
10361                                                 needprompt = doprompt;
10362                                         }
10363
10364                                         p = strchr(xxreadtoken_chars, c);
10365                                         if (p == NULL) {
10366                                         READTOKEN1:
10367                                                 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10368                                         }
10369                         
10370                                         if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10371                                                 if (pgetc() == *p) { /* double occurrence? */
10372                                                         p += xxreadtoken_doubles + 1;
10373                                                 } else {
10374                                                         pungetc();
10375                                                 }
10376                                         }
10377                                 }
10378
10379                                 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10380                         }
10381                 }
10382         }
10383 }
10384
10385
10386 #else
10387 #define RETURN(token)   return lasttoken = token
10388
10389 static int
10390 xxreadtoken() {
10391         int c;
10392
10393         if (tokpushback) {
10394                 tokpushback = 0;
10395                 return lasttoken;
10396         }
10397         if (needprompt) {
10398                 setprompt(2);
10399                 needprompt = 0;
10400         }
10401         startlinno = plinno;
10402         for (;;) {      /* until token or start of word found */
10403                 c = pgetc_macro();
10404                 switch (c) {
10405                 case ' ': case '\t':
10406 #ifdef ASH_ALIAS
10407                 case PEOA:
10408 #endif
10409                         continue;
10410                 case '#':
10411                         while ((c = pgetc()) != '\n' && c != PEOF);
10412                         pungetc();
10413                         continue;
10414                 case '\\':
10415                         if (pgetc() == '\n') {
10416                                 startlinno = ++plinno;
10417                                 if (doprompt)
10418                                         setprompt(2);
10419                                 else
10420                                         setprompt(0);
10421                                 continue;
10422                         }
10423                         pungetc();
10424                         goto breakloop;
10425                 case '\n':
10426                         plinno++;
10427                         needprompt = doprompt;
10428                         RETURN(TNL);
10429                 case PEOF:
10430                         RETURN(TEOF);
10431                 case '&':
10432                         if (pgetc() == '&')
10433                                 RETURN(TAND);
10434                         pungetc();
10435                         RETURN(TBACKGND);
10436                 case '|':
10437                         if (pgetc() == '|')
10438                                 RETURN(TOR);
10439                         pungetc();
10440                         RETURN(TPIPE);
10441                 case ';':
10442                         if (pgetc() == ';')
10443                                 RETURN(TENDCASE);
10444                         pungetc();
10445                         RETURN(TSEMI);
10446                 case '(':
10447                         RETURN(TLP);
10448                 case ')':
10449                         RETURN(TRP);
10450                 default:
10451                         goto breakloop;
10452                 }
10453         }
10454 breakloop:
10455         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10456 #undef RETURN
10457 }
10458 #endif
10459
10460
10461 /*
10462  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10463  * is not NULL, read a here document.  In the latter case, eofmark is the
10464  * word which marks the end of the document and striptabs is true if
10465  * leading tabs should be stripped from the document.  The argument firstc
10466  * is the first character of the input token or document.
10467  *
10468  * Because C does not have internal subroutines, I have simulated them
10469  * using goto's to implement the subroutine linkage.  The following macros
10470  * will run code that appears at the end of readtoken1.
10471  */
10472
10473 #define CHECKEND()      {goto checkend; checkend_return:;}
10474 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10475 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10476 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10477 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10478 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10479
10480 static int
10481 readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10482 {
10483         int c = firstc;
10484         char *out;
10485         int len;
10486         char line[EOFMARKLEN + 1];
10487         struct nodelist *bqlist;
10488         int quotef;
10489         int dblquote;
10490         int varnest;    /* levels of variables expansion */
10491         int arinest;    /* levels of arithmetic expansion */
10492         int parenlevel; /* levels of parens in arithmetic */
10493         int dqvarnest;  /* levels of variables expansion within double quotes */
10494         int oldstyle;
10495         int prevsyntax; /* syntax before arithmetic */
10496 #if __GNUC__
10497         /* Avoid longjmp clobbering */
10498         (void) &out;
10499         (void) &quotef;
10500         (void) &dblquote;
10501         (void) &varnest;
10502         (void) &arinest;
10503         (void) &parenlevel;
10504         (void) &dqvarnest;
10505         (void) &oldstyle;
10506         (void) &prevsyntax;
10507         (void) &syntax;
10508 #endif
10509
10510         startlinno = plinno;
10511         dblquote = 0;
10512         if (syntax == DQSYNTAX)
10513                 dblquote = 1;
10514         quotef = 0;
10515         bqlist = NULL;
10516         varnest = 0;
10517         arinest = 0;
10518         parenlevel = 0;
10519         dqvarnest = 0;
10520
10521         STARTSTACKSTR(out);
10522         loop: { /* for each line, until end of word */
10523                 CHECKEND();     /* set c to PEOF if at end of here document */
10524                 for (;;) {      /* until end of line or end of word */
10525                         CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
10526                         switch(SIT(c,syntax)) {
10527                         case CNL:       /* '\n' */
10528                                 if (syntax == BASESYNTAX)
10529                                         goto endword;   /* exit outer loop */
10530                                 USTPUTC(c, out);
10531                                 plinno++;
10532                                 if (doprompt)
10533                                         setprompt(2);
10534                                 else
10535                                         setprompt(0);
10536                                 c = pgetc();
10537                                 goto loop;              /* continue outer loop */
10538                         case CWORD:
10539                                 USTPUTC(c, out);
10540                                 break;
10541                         case CCTL:
10542                                 if ((eofmark == NULL || dblquote) &&
10543                                     dqvarnest == 0)
10544                                         USTPUTC(CTLESC, out);
10545                                 USTPUTC(c, out);
10546                                 break;
10547                         case CBACK:     /* backslash */
10548                                 c = pgetc2();
10549                                 if (c == PEOF) {
10550                                         USTPUTC('\\', out);
10551                                         pungetc();
10552                                 } else if (c == '\n') {
10553                                         if (doprompt)
10554                                                 setprompt(2);
10555                                         else
10556                                                 setprompt(0);
10557                                 } else {
10558                                         if (dblquote && c != '\\' && c != '`' && c != '$'
10559                                                          && (c != '"' || eofmark != NULL))
10560                                                 USTPUTC('\\', out);
10561                                         if (SIT(c,SQSYNTAX) == CCTL)
10562                                                 USTPUTC(CTLESC, out);
10563                                         else if (eofmark == NULL)
10564                                                 USTPUTC(CTLQUOTEMARK, out);
10565                                         USTPUTC(c, out);
10566                                         quotef++;
10567                                 }
10568                                 break;
10569                         case CSQUOTE:
10570                                 if (eofmark == NULL)
10571                                         USTPUTC(CTLQUOTEMARK, out);
10572                                 syntax = SQSYNTAX;
10573                                 break;
10574                         case CDQUOTE:
10575                                 if (eofmark == NULL)
10576                                         USTPUTC(CTLQUOTEMARK, out);
10577                                 syntax = DQSYNTAX;
10578                                 dblquote = 1;
10579                                 break;
10580                         case CENDQUOTE:
10581                                 if (eofmark != NULL && arinest == 0 &&
10582                                     varnest == 0) {
10583                                         USTPUTC(c, out);
10584                                 } else {
10585                                         if (arinest) {
10586                                                 syntax = ARISYNTAX;
10587                                                 dblquote = 0;
10588                                         } else if (eofmark == NULL &&
10589                                                    dqvarnest == 0) {
10590                                                 syntax = BASESYNTAX;
10591                                                 dblquote = 0;
10592                                         }
10593                                         quotef++;
10594                                 }
10595                                 break;
10596                         case CVAR:      /* '$' */
10597                                 PARSESUB();             /* parse substitution */
10598                                 break;
10599                         case CENDVAR:   /* '}' */
10600                                 if (varnest > 0) {
10601                                         varnest--;
10602                                         if (dqvarnest > 0) {
10603                                                 dqvarnest--;
10604                                         }
10605                                         USTPUTC(CTLENDVAR, out);
10606                                 } else {
10607                                         USTPUTC(c, out);
10608                                 }
10609                                 break;
10610 #ifdef ASH_MATH_SUPPORT
10611                         case CLP:       /* '(' in arithmetic */
10612                                 parenlevel++;
10613                                 USTPUTC(c, out);
10614                                 break;
10615                         case CRP:       /* ')' in arithmetic */
10616                                 if (parenlevel > 0) {
10617                                         USTPUTC(c, out);
10618                                         --parenlevel;
10619                                 } else {
10620                                         if (pgetc() == ')') {
10621                                                 if (--arinest == 0) {
10622                                                         USTPUTC(CTLENDARI, out);
10623                                                         syntax = prevsyntax;
10624                                                         if (syntax == DQSYNTAX)
10625                                                                 dblquote = 1;
10626                                                         else
10627                                                                 dblquote = 0;
10628                                                 } else
10629                                                         USTPUTC(')', out);
10630                                         } else {
10631                                                 /*
10632                                                  * unbalanced parens
10633                                                  *  (don't 2nd guess - no error)
10634                                                  */
10635                                                 pungetc();
10636                                                 USTPUTC(')', out);
10637                                         }
10638                                 }
10639                                 break;
10640 #endif
10641                         case CBQUOTE:   /* '`' */
10642                                 PARSEBACKQOLD();
10643                                 break;
10644                         case CENDFILE:
10645                                 goto endword;           /* exit outer loop */
10646                         case CIGN:
10647                                 break;
10648                         default:
10649                                 if (varnest == 0)
10650                                         goto endword;   /* exit outer loop */
10651 #ifdef ASH_ALIAS
10652                                 if (c != PEOA)
10653 #endif
10654                                         USTPUTC(c, out);
10655
10656                         }
10657                         c = pgetc_macro();
10658                 }
10659         }
10660 endword:
10661         if (syntax == ARISYNTAX)
10662                 synerror("Missing '))'");
10663         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10664                 synerror("Unterminated quoted string");
10665         if (varnest != 0) {
10666                 startlinno = plinno;
10667                 synerror("Missing '}'");
10668         }
10669         USTPUTC('\0', out);
10670         len = out - stackblock();
10671         out = stackblock();
10672         if (eofmark == NULL) {
10673                 if ((c == '>' || c == '<')
10674                  && quotef == 0
10675                  && len <= 2
10676                  && (*out == '\0' || is_digit(*out))) {
10677                         PARSEREDIR();
10678                         return lasttoken = TREDIR;
10679                 } else {
10680                         pungetc();
10681                 }
10682         }
10683         quoteflag = quotef;
10684         backquotelist = bqlist;
10685         grabstackblock(len);
10686         wordtext = out;
10687         return lasttoken = TWORD;
10688 /* end of readtoken routine */
10689
10690
10691
10692 /*
10693  * Check to see whether we are at the end of the here document.  When this
10694  * is called, c is set to the first character of the next input line.  If
10695  * we are at the end of the here document, this routine sets the c to PEOF.
10696  */
10697
10698 checkend: {
10699         if (eofmark) {
10700 #ifdef ASH_ALIAS
10701                 if (c == PEOA) {
10702                         c = pgetc2();
10703                 }
10704 #endif
10705                 if (striptabs) {
10706                         while (c == '\t') {
10707                                 c = pgetc2();
10708                         }
10709                 }
10710                 if (c == *eofmark) {
10711                         if (pfgets(line, sizeof line) != NULL) {
10712                                 const char *p, *q;
10713
10714                                 p = line;
10715                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10716                                 if (*p == '\n' && *q == '\0') {
10717                                         c = PEOF;
10718                                         plinno++;
10719                                         needprompt = doprompt;
10720                                 } else {
10721                                         pushstring(line, strlen(line), NULL);
10722                                 }
10723                         }
10724                 }
10725         }
10726         goto checkend_return;
10727 }
10728
10729
10730 /*
10731  * Parse a redirection operator.  The variable "out" points to a string
10732  * specifying the fd to be redirected.  The variable "c" contains the
10733  * first character of the redirection operator.
10734  */
10735
10736 parseredir: {
10737         char fd = *out;
10738         union node *np;
10739
10740         np = (union node *)stalloc(sizeof (struct nfile));
10741         if (c == '>') {
10742                 np->nfile.fd = 1;
10743                 c = pgetc();
10744                 if (c == '>')
10745                         np->type = NAPPEND;
10746                 else if (c == '&')
10747                         np->type = NTOFD;
10748                 else if (c == '|')
10749                         np->type = NTOOV;
10750                 else {
10751                         np->type = NTO;
10752                         pungetc();
10753                 }
10754         } else {        /* c == '<' */
10755                 np->nfile.fd = 0;
10756                 switch (c = pgetc()) {
10757                 case '<':
10758                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10759                                 np = (union node *)stalloc(sizeof (struct nhere));
10760                                 np->nfile.fd = 0;
10761                         }
10762                         np->type = NHERE;
10763                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10764                         heredoc->here = np;
10765                         if ((c = pgetc()) == '-') {
10766                                 heredoc->striptabs = 1;
10767                         } else {
10768                                 heredoc->striptabs = 0;
10769                                 pungetc();
10770                         }
10771                         break;
10772
10773                 case '&':
10774                         np->type = NFROMFD;
10775                         break;
10776
10777                 case '>':
10778                         np->type = NFROMTO;
10779                         break;
10780
10781                 default:
10782                         np->type = NFROM;
10783                         pungetc();
10784                         break;
10785                 }
10786         }
10787         if (fd != '\0')
10788                 np->nfile.fd = digit_val(fd);
10789         redirnode = np;
10790         goto parseredir_return;
10791 }
10792
10793
10794 /*
10795  * Parse a substitution.  At this point, we have read the dollar sign
10796  * and nothing else.
10797  */
10798
10799 parsesub: {
10800         int subtype;
10801         int typeloc;
10802         int flags;
10803         char *p;
10804         static const char types[] = "}-+?=";
10805
10806         c = pgetc();
10807         if (
10808                 c <= PEOA  ||
10809                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10810         ) {
10811                 USTPUTC('$', out);
10812                 pungetc();
10813         } else if (c == '(') {  /* $(command) or $((arith)) */
10814                 if (pgetc() == '(') {
10815                         PARSEARITH();
10816                 } else {
10817                         pungetc();
10818                         PARSEBACKQNEW();
10819                 }
10820         } else {
10821                 USTPUTC(CTLVAR, out);
10822                 typeloc = out - stackblock();
10823                 USTPUTC(VSNORMAL, out);
10824                 subtype = VSNORMAL;
10825                 if (c == '{') {
10826                         c = pgetc();
10827                         if (c == '#') {
10828                                 if ((c = pgetc()) == '}')
10829                                         c = '#';
10830                                 else
10831                                         subtype = VSLENGTH;
10832                         }
10833                         else
10834                                 subtype = 0;
10835                 }
10836                 if (c > PEOA && is_name(c)) {
10837                         do {
10838                                 STPUTC(c, out);
10839                                 c = pgetc();
10840                         } while (c > PEOA && is_in_name(c));
10841                 } else if (is_digit(c)) {
10842                         do {
10843                                 USTPUTC(c, out);
10844                                 c = pgetc();
10845                         } while (is_digit(c));
10846                 }
10847                 else if (is_special(c)) {
10848                         USTPUTC(c, out);
10849                         c = pgetc();
10850                 }
10851                 else
10852 badsub:                 synerror("Bad substitution");
10853
10854                 STPUTC('=', out);
10855                 flags = 0;
10856                 if (subtype == 0) {
10857                         switch (c) {
10858                         case ':':
10859                                 flags = VSNUL;
10860                                 c = pgetc();
10861                                 /*FALLTHROUGH*/
10862                         default:
10863                                 p = strchr(types, c);
10864                                 if (p == NULL)
10865                                         goto badsub;
10866                                 subtype = p - types + VSNORMAL;
10867                                 break;
10868                         case '%':
10869                         case '#':
10870                                 {
10871                                         int cc = c;
10872                                         subtype = c == '#' ? VSTRIMLEFT :
10873                                                              VSTRIMRIGHT;
10874                                         c = pgetc();
10875                                         if (c == cc)
10876                                                 subtype++;
10877                                         else
10878                                                 pungetc();
10879                                         break;
10880                                 }
10881                         }
10882                 } else {
10883                         pungetc();
10884                 }
10885                 if (dblquote || arinest)
10886                         flags |= VSQUOTE;
10887                 *(stackblock() + typeloc) = subtype | flags;
10888                 if (subtype != VSNORMAL) {
10889                         varnest++;
10890                         if (dblquote) {
10891                                 dqvarnest++;
10892                         }
10893                 }
10894         }
10895         goto parsesub_return;
10896 }
10897
10898
10899 /*
10900  * Called to parse command substitutions.  Newstyle is set if the command
10901  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10902  * list of commands (passed by reference), and savelen is the number of
10903  * characters on the top of the stack which must be preserved.
10904  */
10905
10906 parsebackq: {
10907         struct nodelist **nlpp;
10908         int savepbq;
10909         union node *n;
10910         char *volatile str;
10911         struct jmploc jmploc;
10912         struct jmploc *volatile savehandler;
10913         int savelen;
10914         int saveprompt;
10915 #ifdef __GNUC__
10916         (void) &saveprompt;
10917 #endif
10918
10919         savepbq = parsebackquote;
10920         if (setjmp(jmploc.loc)) {
10921                 if (str)
10922                         ckfree(str);
10923                 parsebackquote = 0;
10924                 handler = savehandler;
10925                 longjmp(handler->loc, 1);
10926         }
10927         INTOFF;
10928         str = NULL;
10929         savelen = out - stackblock();
10930         if (savelen > 0) {
10931                 str = ckmalloc(savelen);
10932                 memcpy(str, stackblock(), savelen);
10933         }
10934         savehandler = handler;
10935         handler = &jmploc;
10936         INTON;
10937         if (oldstyle) {
10938                 /* We must read until the closing backquote, giving special
10939                    treatment to some slashes, and then push the string and
10940                    reread it as input, interpreting it normally.  */
10941                 char *pout;
10942                 int pc;
10943                 int psavelen;
10944                 char *pstr;
10945
10946
10947                 STARTSTACKSTR(pout);
10948                 for (;;) {
10949                         if (needprompt) {
10950                                 setprompt(2);
10951                                 needprompt = 0;
10952                         }
10953                         switch (pc = pgetc()) {
10954                         case '`':
10955                                 goto done;
10956
10957                         case '\\':
10958                                 if ((pc = pgetc()) == '\n') {
10959                                         plinno++;
10960                                         if (doprompt)
10961                                                 setprompt(2);
10962                                         else
10963                                                 setprompt(0);
10964                                         /*
10965                                          * If eating a newline, avoid putting
10966                                          * the newline into the new character
10967                                          * stream (via the STPUTC after the
10968                                          * switch).
10969                                          */
10970                                         continue;
10971                                 }
10972                                 if (pc != '\\' && pc != '`' && pc != '$'
10973                                     && (!dblquote || pc != '"'))
10974                                         STPUTC('\\', pout);
10975                                 if (pc > PEOA) {
10976                                         break;
10977                                 }
10978                                 /* fall through */
10979
10980                         case PEOF:
10981 #ifdef ASH_ALIAS
10982                         case PEOA:
10983 #endif
10984                                 startlinno = plinno;
10985                                 synerror("EOF in backquote substitution");
10986
10987                         case '\n':
10988                                 plinno++;
10989                                 needprompt = doprompt;
10990                                 break;
10991
10992                         default:
10993                                 break;
10994                         }
10995                         STPUTC(pc, pout);
10996                 }
10997 done:
10998                 STPUTC('\0', pout);
10999                 psavelen = pout - stackblock();
11000                 if (psavelen > 0) {
11001                         pstr = grabstackstr(pout);
11002                         setinputstring(pstr);
11003                 }
11004         }
11005         nlpp = &bqlist;
11006         while (*nlpp)
11007                 nlpp = &(*nlpp)->next;
11008         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11009         (*nlpp)->next = NULL;
11010         parsebackquote = oldstyle;
11011
11012         if (oldstyle) {
11013                 saveprompt = doprompt;
11014                 doprompt = 0;
11015         }
11016
11017         n = list(0);
11018
11019         if (oldstyle)
11020                 doprompt = saveprompt;
11021         else {
11022                 if (readtoken() != TRP)
11023                         synexpect(TRP);
11024         }
11025
11026         (*nlpp)->n = n;
11027         if (oldstyle) {
11028                 /*
11029                  * Start reading from old file again, ignoring any pushed back
11030                  * tokens left from the backquote parsing
11031                  */
11032                 popfile();
11033                 tokpushback = 0;
11034         }
11035         while (stackblocksize() <= savelen)
11036                 growstackblock();
11037         STARTSTACKSTR(out);
11038         if (str) {
11039                 memcpy(out, str, savelen);
11040                 STADJUST(savelen, out);
11041                 INTOFF;
11042                 ckfree(str);
11043                 str = NULL;
11044                 INTON;
11045         }
11046         parsebackquote = savepbq;
11047         handler = savehandler;
11048         if (arinest || dblquote)
11049                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11050         else
11051                 USTPUTC(CTLBACKQ, out);
11052         if (oldstyle)
11053                 goto parsebackq_oldreturn;
11054         else
11055                 goto parsebackq_newreturn;
11056 }
11057
11058 /*
11059  * Parse an arithmetic expansion (indicate start of one and set state)
11060  */
11061 parsearith: {
11062
11063         if (++arinest == 1) {
11064                 prevsyntax = syntax;
11065                 syntax = ARISYNTAX;
11066                 USTPUTC(CTLARI, out);
11067                 if (dblquote)
11068                         USTPUTC('"',out);
11069                 else
11070                         USTPUTC(' ',out);
11071         } else {
11072                 /*
11073                  * we collapse embedded arithmetic expansion to
11074                  * parenthesis, which should be equivalent
11075                  */
11076                 USTPUTC('(', out);
11077         }
11078         goto parsearith_return;
11079 }
11080
11081 } /* end of readtoken */
11082
11083
11084 /*
11085  * Returns true if the text contains nothing to expand (no dollar signs
11086  * or backquotes).
11087  */
11088
11089 static int
11090 noexpand(text)
11091         char *text;
11092         {
11093         char *p;
11094         char c;
11095
11096         p = text;
11097         while ((c = *p++) != '\0') {
11098                 if (c == CTLQUOTEMARK)
11099                         continue;
11100                 if (c == CTLESC)
11101                         p++;
11102                 else if (SIT(c,BASESYNTAX) == CCTL)
11103                         return 0;
11104         }
11105         return 1;
11106 }
11107
11108
11109 /*
11110  * Return true if the argument is a legal variable name (a letter or
11111  * underscore followed by zero or more letters, underscores, and digits).
11112  */
11113
11114 static int
11115 goodname(const char *name)
11116 {
11117         const char *p;
11118
11119         p = name;
11120         if (! is_name(*p))
11121                 return 0;
11122         while (*++p) {
11123                 if (! is_in_name(*p))
11124                         return 0;
11125         }
11126         return 1;
11127 }
11128
11129
11130 /*
11131  * Called when an unexpected token is read during the parse.  The argument
11132  * is the token that is expected, or -1 if more than one type of token can
11133  * occur at this point.
11134  */
11135
11136 static void
11137 synexpect(token)
11138         int token;
11139 {
11140         char msg[64];
11141         int l;
11142
11143         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11144         if (token >= 0)
11145                 sprintf(msg+l, " (expecting %s)", tokname(token));
11146         synerror(msg);
11147         /* NOTREACHED */
11148 }
11149
11150
11151 static void
11152 synerror(const char *msg)
11153 {
11154         if (commandname)
11155                 out2fmt("%s: %d: ", commandname, startlinno);
11156         out2fmt("Syntax error: %s\n", msg);
11157         error((char *)NULL);
11158         /* NOTREACHED */
11159 }
11160
11161
11162 /*
11163  * called by editline -- any expansions to the prompt
11164  *    should be added here.
11165  */
11166 static void
11167 setprompt(int whichprompt)
11168 {
11169     char *prompt;
11170     switch (whichprompt) {
11171         case 1:
11172                 prompt = ps1val();
11173                 break;
11174         case 2:
11175                 prompt = ps2val();
11176                 break;
11177         default:                /* 0 */
11178                 prompt = "";
11179     }
11180     putprompt(prompt);
11181 }
11182
11183
11184 /*
11185  * Code for dealing with input/output redirection.
11186  */
11187
11188 #define EMPTY -2                /* marks an unused slot in redirtab */
11189 #ifndef PIPE_BUF
11190 # define PIPESIZE 4096          /* amount of buffering in a pipe */
11191 #else
11192 # define PIPESIZE PIPE_BUF
11193 #endif
11194
11195
11196 /*
11197  * Open a file in noclobber mode.
11198  * The code was copied from bash.
11199  */
11200 static inline int
11201 noclobberopen(const char *fname)
11202 {
11203         int r, fd;
11204         struct stat finfo, finfo2;
11205
11206         /*
11207          * If the file exists and is a regular file, return an error
11208          * immediately.
11209          */
11210         r = stat(fname, &finfo);
11211         if (r == 0 && S_ISREG(finfo.st_mode)) {
11212                 errno = EEXIST;
11213                 return -1;
11214         }
11215
11216         /*
11217          * If the file was not present (r != 0), make sure we open it
11218          * exclusively so that if it is created before we open it, our open
11219          * will fail.  Make sure that we do not truncate an existing file.
11220          * Note that we don't turn on O_EXCL unless the stat failed -- if the
11221          * file was not a regular file, we leave O_EXCL off.
11222          */
11223         if (r != 0)
11224                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11225         fd = open(fname, O_WRONLY|O_CREAT, 0666);
11226
11227         /* If the open failed, return the file descriptor right away. */
11228         if (fd < 0)
11229                 return fd;
11230
11231         /*
11232          * OK, the open succeeded, but the file may have been changed from a
11233          * non-regular file to a regular file between the stat and the open.
11234          * We are assuming that the O_EXCL open handles the case where FILENAME
11235          * did not exist and is symlinked to an existing file between the stat
11236          * and open.
11237          */
11238
11239         /*
11240          * If we can open it and fstat the file descriptor, and neither check
11241          * revealed that it was a regular file, and the file has not been
11242          * replaced, return the file descriptor.
11243          */
11244          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11245              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11246                 return fd;
11247
11248         /* The file has been replaced.  badness. */
11249         close(fd);
11250         errno = EEXIST;
11251         return -1;
11252 }
11253
11254 /*
11255  * Handle here documents.  Normally we fork off a process to write the
11256  * data to a pipe.  If the document is short, we can stuff the data in
11257  * the pipe without forking.
11258  */
11259
11260 static inline int
11261 openhere(const union node *redir)
11262 {
11263         int pip[2];
11264         int len = 0;
11265
11266         if (pipe(pip) < 0)
11267                 error("Pipe call failed");
11268         if (redir->type == NHERE) {
11269                 len = strlen(redir->nhere.doc->narg.text);
11270                 if (len <= PIPESIZE) {
11271                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11272                         goto out;
11273                 }
11274         }
11275         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11276                 close(pip[0]);
11277                 signal(SIGINT, SIG_IGN);
11278                 signal(SIGQUIT, SIG_IGN);
11279                 signal(SIGHUP, SIG_IGN);
11280 #ifdef SIGTSTP
11281                 signal(SIGTSTP, SIG_IGN);
11282 #endif
11283                 signal(SIGPIPE, SIG_DFL);
11284                 if (redir->type == NHERE)
11285                         xwrite(pip[1], redir->nhere.doc->narg.text, len);
11286                 else
11287                         expandhere(redir->nhere.doc, pip[1]);
11288                 _exit(0);
11289         }
11290 out:
11291         close(pip[1]);
11292         return pip[0];
11293 }
11294
11295
11296 static inline int
11297 openredirect(const union node *redir)
11298 {
11299         char *fname;
11300         int f;
11301
11302         switch (redir->nfile.type) {
11303         case NFROM:
11304                 fname = redir->nfile.expfname;
11305                 if ((f = open(fname, O_RDONLY)) < 0)
11306                         goto eopen;
11307                 break;
11308         case NFROMTO:
11309                 fname = redir->nfile.expfname;
11310                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11311                         goto ecreate;
11312                 break;
11313         case NTO:
11314                 /* Take care of noclobber mode. */
11315                 if (Cflag) {
11316                         fname = redir->nfile.expfname;
11317                         if ((f = noclobberopen(fname)) < 0)
11318                                 goto ecreate;
11319                         break;
11320                 }
11321         case NTOOV:
11322                 fname = redir->nfile.expfname;
11323 #ifdef O_CREAT
11324                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11325                         goto ecreate;
11326 #else
11327                 if ((f = creat(fname, 0666)) < 0)
11328                         goto ecreate;
11329 #endif
11330                 break;
11331         case NAPPEND:
11332                 fname = redir->nfile.expfname;
11333 #ifdef O_APPEND
11334                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11335                         goto ecreate;
11336 #else
11337                 if ((f = open(fname, O_WRONLY)) < 0
11338                  && (f = creat(fname, 0666)) < 0)
11339                         goto ecreate;
11340                 lseek(f, (off_t)0, 2);
11341 #endif
11342                 break;
11343         default:
11344 #ifdef DEBUG
11345                 abort();
11346 #endif
11347                 /* Fall through to eliminate warning. */
11348         case NTOFD:
11349         case NFROMFD:
11350                 f = -1;
11351                 break;
11352         case NHERE:
11353         case NXHERE:
11354                 f = openhere(redir);
11355                 break;
11356         }
11357
11358         return f;
11359 ecreate:
11360         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11361 eopen:
11362         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11363 }
11364
11365
11366 /*
11367  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
11368  * old file descriptors are stashed away so that the redirection can be
11369  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
11370  * standard output, and the standard error if it becomes a duplicate of
11371  * stdout.
11372  */
11373
11374 static void
11375 redirect(union node *redir, int flags)
11376 {
11377         union node *n;
11378         struct redirtab *sv = NULL;
11379         int i;
11380         int fd;
11381         int newfd;
11382         int try;
11383         int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11384
11385         if (flags & REDIR_PUSH) {
11386                 sv = ckmalloc(sizeof (struct redirtab));
11387                 for (i = 0 ; i < 10 ; i++)
11388                         sv->renamed[i] = EMPTY;
11389                 sv->next = redirlist;
11390                 redirlist = sv;
11391         }
11392         for (n = redir ; n ; n = n->nfile.next) {
11393                 fd = n->nfile.fd;
11394                 try = 0;
11395                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11396                     n->ndup.dupfd == fd)
11397                         continue; /* redirect from/to same file descriptor */
11398
11399                 INTOFF;
11400                 newfd = openredirect(n);
11401                 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11402                         if (newfd == fd) {
11403                                 try++;
11404                         } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11405                                 switch (errno) {
11406                                 case EBADF:
11407                                         if (!try) {
11408                                                 dupredirect(n, newfd, fd1dup);
11409                                                 try++;
11410                                                 break;
11411                                         }
11412                                         /* FALLTHROUGH*/
11413                                 default:
11414                                         if (newfd >= 0) {
11415                                                 close(newfd);
11416                                         }
11417                                         INTON;
11418                                         error("%d: %m", fd);
11419                                         /* NOTREACHED */
11420                                 }
11421                         }
11422                         if (!try) {
11423                                 close(fd);
11424                                 if (flags & REDIR_PUSH) {
11425                                         sv->renamed[fd] = i;
11426                                 }
11427                         }
11428                 } else if (fd != newfd) {
11429                         close(fd);
11430                 }
11431                 if (fd == 0)
11432                         fd0_redirected++;
11433                 if (!try)
11434                         dupredirect(n, newfd, fd1dup);
11435                 INTON;
11436         }
11437 }
11438
11439
11440 static void
11441 dupredirect(const union node *redir, int f, int fd1dup)
11442 {
11443         int fd = redir->nfile.fd;
11444
11445         if(fd==1)
11446                 fd1dup = 0;
11447         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11448                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11449                         if (redir->ndup.dupfd!=1 || fd1dup!=1)
11450                                 dup_as_newfd(redir->ndup.dupfd, fd);
11451                 }
11452                 return;
11453         }
11454
11455         if (f != fd) {
11456                 dup_as_newfd(f, fd);
11457                 close(f);
11458         }
11459         return;
11460 }
11461
11462
11463
11464 /*
11465  * Undo the effects of the last redirection.
11466  */
11467
11468 static void
11469 popredir(void)
11470 {
11471         struct redirtab *rp = redirlist;
11472         int i;
11473
11474         INTOFF;
11475         for (i = 0 ; i < 10 ; i++) {
11476                 if (rp->renamed[i] != EMPTY) {
11477                         if (i == 0)
11478                                 fd0_redirected--;
11479                         close(i);
11480                         if (rp->renamed[i] >= 0) {
11481                                 dup_as_newfd(rp->renamed[i], i);
11482                                 close(rp->renamed[i]);
11483                         }
11484                 }
11485         }
11486         redirlist = rp->next;
11487         ckfree(rp);
11488         INTON;
11489 }
11490
11491 /*
11492  * Discard all saved file descriptors.
11493  */
11494
11495 static void
11496 clearredir(void) {
11497         struct redirtab *rp;
11498         int i;
11499
11500         for (rp = redirlist ; rp ; rp = rp->next) {
11501                 for (i = 0 ; i < 10 ; i++) {
11502                         if (rp->renamed[i] >= 0) {
11503                                 close(rp->renamed[i]);
11504                         }
11505                         rp->renamed[i] = EMPTY;
11506                 }
11507         }
11508 }
11509
11510
11511 /*
11512  * Copy a file descriptor to be >= to.  Returns -1
11513  * if the source file descriptor is closed, EMPTY if there are no unused
11514  * file descriptors left.
11515  */
11516
11517 static int
11518 dup_as_newfd(from, to)
11519         int from;
11520         int to;
11521 {
11522         int newfd;
11523
11524         newfd = fcntl(from, F_DUPFD, to);
11525         if (newfd < 0) {
11526                 if (errno == EMFILE)
11527                         return EMPTY;
11528                 else
11529                         error("%d: %m", from);
11530         }
11531         return newfd;
11532 }
11533
11534 #ifdef DEBUG
11535 static void shtree (union node *, int, char *, FILE*);
11536 static void shcmd (union node *, FILE *);
11537 static void sharg (union node *, FILE *);
11538 static void indent (int, char *, FILE *);
11539 static void trstring (char *);
11540
11541
11542 static void
11543 showtree(n)
11544         union node *n;
11545 {
11546         trputs("showtree called\n");
11547         shtree(n, 1, NULL, stdout);
11548 }
11549
11550
11551 static void
11552 shtree(n, ind, pfx, fp)
11553         union node *n;
11554         int ind;
11555         char *pfx;
11556         FILE *fp;
11557 {
11558         struct nodelist *lp;
11559         const char *s;
11560
11561         if (n == NULL)
11562                 return;
11563
11564         indent(ind, pfx, fp);
11565         switch(n->type) {
11566         case NSEMI:
11567                 s = "; ";
11568                 goto binop;
11569         case NAND:
11570                 s = " && ";
11571                 goto binop;
11572         case NOR:
11573                 s = " || ";
11574 binop:
11575                 shtree(n->nbinary.ch1, ind, NULL, fp);
11576            /*    if (ind < 0) */
11577                         fputs(s, fp);
11578                 shtree(n->nbinary.ch2, ind, NULL, fp);
11579                 break;
11580         case NCMD:
11581                 shcmd(n, fp);
11582                 if (ind >= 0)
11583                         putc('\n', fp);
11584                 break;
11585         case NPIPE:
11586                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11587                         shcmd(lp->n, fp);
11588                         if (lp->next)
11589                                 fputs(" | ", fp);
11590                 }
11591                 if (n->npipe.backgnd)
11592                         fputs(" &", fp);
11593                 if (ind >= 0)
11594                         putc('\n', fp);
11595                 break;
11596         default:
11597                 fprintf(fp, "<node type %d>", n->type);
11598                 if (ind >= 0)
11599                         putc('\n', fp);
11600                 break;
11601         }
11602 }
11603
11604
11605
11606 static void
11607 shcmd(cmd, fp)
11608         union node *cmd;
11609         FILE *fp;
11610 {
11611         union node *np;
11612         int first;
11613         const char *s;
11614         int dftfd;
11615
11616         first = 1;
11617         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11618                 if (! first)
11619                         putchar(' ');
11620                 sharg(np, fp);
11621                 first = 0;
11622         }
11623         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11624                 if (! first)
11625                         putchar(' ');
11626 #if 1
11627                 s = "*error*";
11628                 dftfd = 0;
11629                 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11630                         s = redir_strings[np->nfile.type - NTO];
11631                         if (*s == '>') {
11632                                 dftfd = 1;
11633                         }
11634                 }
11635 #else
11636                 switch (np->nfile.type) {
11637                         case NTO:       s = ">";  dftfd = 1; break;
11638                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11639                         case NTOFD:     s = ">&"; dftfd = 1; break;
11640                         case NTOOV:     s = ">|"; dftfd = 1; break;
11641                         case NFROM:     s = "<";  dftfd = 0; break;
11642                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11643                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11644                         default:        s = "*error*"; dftfd = 0; break;
11645                 }
11646 #endif
11647                 if (np->nfile.fd != dftfd)
11648                         fprintf(fp, "%d", np->nfile.fd);
11649                 fputs(s, fp);
11650                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11651                         fprintf(fp, "%d", np->ndup.dupfd);
11652                 } else {
11653                         sharg(np->nfile.fname, fp);
11654                 }
11655                 first = 0;
11656         }
11657 }
11658
11659
11660
11661 static void
11662 sharg(arg, fp)
11663         union node *arg;
11664         FILE *fp;
11665         {
11666         char *p;
11667         struct nodelist *bqlist;
11668         int subtype;
11669
11670         if (arg->type != NARG) {
11671                 printf("<node type %d>\n", arg->type);
11672                 fflush(stdout);
11673                 abort();
11674         }
11675         bqlist = arg->narg.backquote;
11676         for (p = arg->narg.text ; *p ; p++) {
11677                 switch (*p) {
11678                 case CTLESC:
11679                         putc(*++p, fp);
11680                         break;
11681                 case CTLVAR:
11682                         putc('$', fp);
11683                         putc('{', fp);
11684                         subtype = *++p;
11685                         if (subtype == VSLENGTH)
11686                                 putc('#', fp);
11687
11688                         while (*p != '=')
11689                                 putc(*p++, fp);
11690
11691                         if (subtype & VSNUL)
11692                                 putc(':', fp);
11693
11694                         switch (subtype & VSTYPE) {
11695                         case VSNORMAL:
11696                                 putc('}', fp);
11697                                 break;
11698                         case VSMINUS:
11699                                 putc('-', fp);
11700                                 break;
11701                         case VSPLUS:
11702                                 putc('+', fp);
11703                                 break;
11704                         case VSQUESTION:
11705                                 putc('?', fp);
11706                                 break;
11707                         case VSASSIGN:
11708                                 putc('=', fp);
11709                                 break;
11710                         case VSTRIMLEFT:
11711                                 putc('#', fp);
11712                                 break;
11713                         case VSTRIMLEFTMAX:
11714                                 putc('#', fp);
11715                                 putc('#', fp);
11716                                 break;
11717                         case VSTRIMRIGHT:
11718                                 putc('%', fp);
11719                                 break;
11720                         case VSTRIMRIGHTMAX:
11721                                 putc('%', fp);
11722                                 putc('%', fp);
11723                                 break;
11724                         case VSLENGTH:
11725                                 break;
11726                         default:
11727                                 printf("<subtype %d>", subtype);
11728                         }
11729                         break;
11730                 case CTLENDVAR:
11731                      putc('}', fp);
11732                      break;
11733                 case CTLBACKQ:
11734                 case CTLBACKQ|CTLQUOTE:
11735                         putc('$', fp);
11736                         putc('(', fp);
11737                         shtree(bqlist->n, -1, NULL, fp);
11738                         putc(')', fp);
11739                         break;
11740                 default:
11741                         putc(*p, fp);
11742                         break;
11743                 }
11744         }
11745 }
11746
11747
11748 static void
11749 indent(amount, pfx, fp)
11750         int amount;
11751         char *pfx;
11752         FILE *fp;
11753 {
11754         int i;
11755
11756         for (i = 0 ; i < amount ; i++) {
11757                 if (pfx && i == amount - 1)
11758                         fputs(pfx, fp);
11759                 putc('\t', fp);
11760         }
11761 }
11762 #endif
11763
11764
11765
11766 /*
11767  * Debugging stuff.
11768  */
11769
11770
11771 #ifdef DEBUG
11772 FILE *tracefile;
11773
11774 #if DEBUG == 2
11775 static int debug = 1;
11776 #else
11777 static int debug = 0;
11778 #endif
11779
11780
11781 static void
11782 trputc(c)
11783         int c;
11784 {
11785         if (tracefile == NULL)
11786                 return;
11787         putc(c, tracefile);
11788         if (c == '\n')
11789                 fflush(tracefile);
11790 }
11791
11792 static void
11793 trace(const char *fmt, ...)
11794 {
11795         va_list va;
11796         va_start(va, fmt);
11797         if (tracefile != NULL) {
11798                 (void) vfprintf(tracefile, fmt, va);
11799                 if (strchr(fmt, '\n'))
11800                         (void) fflush(tracefile);
11801         }
11802         va_end(va);
11803 }
11804
11805
11806 static void
11807 trputs(s)
11808         const char *s;
11809 {
11810         if (tracefile == NULL)
11811                 return;
11812         fputs(s, tracefile);
11813         if (strchr(s, '\n'))
11814                 fflush(tracefile);
11815 }
11816
11817
11818 static void
11819 trstring(s)
11820         char *s;
11821 {
11822         char *p;
11823         char c;
11824
11825         if (tracefile == NULL)
11826                 return;
11827         putc('"', tracefile);
11828         for (p = s ; *p ; p++) {
11829                 switch (*p) {
11830                 case '\n':  c = 'n';  goto backslash;
11831                 case '\t':  c = 't';  goto backslash;
11832                 case '\r':  c = 'r';  goto backslash;
11833                 case '"':  c = '"';  goto backslash;
11834                 case '\\':  c = '\\';  goto backslash;
11835                 case CTLESC:  c = 'e';  goto backslash;
11836                 case CTLVAR:  c = 'v';  goto backslash;
11837                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11838                 case CTLBACKQ:  c = 'q';  goto backslash;
11839                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11840 backslash:        putc('\\', tracefile);
11841                         putc(c, tracefile);
11842                         break;
11843                 default:
11844                         if (*p >= ' ' && *p <= '~')
11845                                 putc(*p, tracefile);
11846                         else {
11847                                 putc('\\', tracefile);
11848                                 putc(*p >> 6 & 03, tracefile);
11849                                 putc(*p >> 3 & 07, tracefile);
11850                                 putc(*p & 07, tracefile);
11851                         }
11852                         break;
11853                 }
11854         }
11855         putc('"', tracefile);
11856 }
11857
11858
11859 static void
11860 trargs(ap)
11861         char **ap;
11862 {
11863         if (tracefile == NULL)
11864                 return;
11865         while (*ap) {
11866                 trstring(*ap++);
11867                 if (*ap)
11868                         putc(' ', tracefile);
11869                 else
11870                         putc('\n', tracefile);
11871         }
11872         fflush(tracefile);
11873 }
11874
11875
11876 static void
11877 opentrace() {
11878         char s[100];
11879 #ifdef O_APPEND
11880         int flags;
11881 #endif
11882
11883         if (!debug)
11884                 return;
11885 #ifdef not_this_way
11886         {
11887                 char *p;
11888                 if ((p = getenv("HOME")) == NULL) {
11889                         if (geteuid() == 0)
11890                                 p = "/";
11891                         else
11892                                 p = "/tmp";
11893                 }
11894                 strcpy(s, p);
11895                 strcat(s, "/trace");
11896         }
11897 #else
11898         strcpy(s, "./trace");
11899 #endif /* not_this_way */
11900         if ((tracefile = fopen(s, "a")) == NULL) {
11901                 fprintf(stderr, "Can't open %s\n", s);
11902                 return;
11903         }
11904 #ifdef O_APPEND
11905         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11906                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11907 #endif
11908         fputs("\nTracing started.\n", tracefile);
11909         fflush(tracefile);
11910 }
11911 #endif /* DEBUG */
11912
11913
11914 /*
11915  * The trap builtin.
11916  */
11917
11918 static int
11919 trapcmd(argc, argv)
11920         int argc;
11921         char **argv;
11922 {
11923         char *action;
11924         char **ap;
11925         int signo;
11926
11927         if (argc <= 1) {
11928                 for (signo = 0 ; signo < NSIG ; signo++) {
11929                         if (trap[signo] != NULL) {
11930                                 char *p;
11931                                 const char *sn;
11932
11933                                 p = single_quote(trap[signo]);
11934                                 sn = sys_siglist[signo];
11935                                 if(sn==NULL)
11936                                         sn = u_signal_names(0, &signo, 0);
11937                                 if(sn==NULL)
11938                                         sn = "???";
11939                                 printf("trap -- %s %s\n", p, sn);
11940                                 stunalloc(p);
11941                         }
11942                 }
11943                 return 0;
11944         }
11945         ap = argv + 1;
11946         if (argc == 2)
11947                 action = NULL;
11948         else
11949                 action = *ap++;
11950         while (*ap) {
11951                 if ((signo = decode_signal(*ap, 0)) < 0)
11952                         error("%s: bad trap", *ap);
11953                 INTOFF;
11954                 if (action) {
11955                         if (action[0] == '-' && action[1] == '\0')
11956                                 action = NULL;
11957                         else
11958                                 action = savestr(action);
11959                 }
11960                 if (trap[signo])
11961                         ckfree(trap[signo]);
11962                 trap[signo] = action;
11963                 if (signo != 0)
11964                         setsignal(signo);
11965                 INTON;
11966                 ap++;
11967         }
11968         return 0;
11969 }
11970
11971
11972
11973
11974
11975
11976 /*
11977  * Set the signal handler for the specified signal.  The routine figures
11978  * out what it should be set to.
11979  */
11980
11981 static void
11982 setsignal(int signo)
11983 {
11984         int action;
11985         char *t;
11986         struct sigaction act;
11987
11988         if ((t = trap[signo]) == NULL)
11989                 action = S_DFL;
11990         else if (*t != '\0')
11991                 action = S_CATCH;
11992         else
11993                 action = S_IGN;
11994         if (rootshell && action == S_DFL) {
11995                 switch (signo) {
11996                 case SIGINT:
11997                         if (iflag || minusc || sflag == 0)
11998                                 action = S_CATCH;
11999                         break;
12000                 case SIGQUIT:
12001 #ifdef DEBUG
12002                         {
12003
12004                         if (debug)
12005                                 break;
12006                         }
12007 #endif
12008                         /* FALLTHROUGH */
12009                 case SIGTERM:
12010                         if (iflag)
12011                                 action = S_IGN;
12012                         break;
12013 #ifdef JOBS
12014                 case SIGTSTP:
12015                 case SIGTTOU:
12016                         if (mflag)
12017                                 action = S_IGN;
12018                         break;
12019 #endif
12020                 }
12021         }
12022
12023         t = &sigmode[signo - 1];
12024         if (*t == 0) {
12025                 /*
12026                  * current setting unknown
12027                  */
12028                 if (sigaction(signo, 0, &act) == -1) {
12029                         /*
12030                          * Pretend it worked; maybe we should give a warning
12031                          * here, but other shells don't. We don't alter
12032                          * sigmode, so that we retry every time.
12033                          */
12034                         return;
12035                 }
12036                 if (act.sa_handler == SIG_IGN) {
12037                         if (mflag && (signo == SIGTSTP ||
12038                              signo == SIGTTIN || signo == SIGTTOU)) {
12039                                 *t = S_IGN;     /* don't hard ignore these */
12040                         } else
12041                                 *t = S_HARD_IGN;
12042                 } else {
12043                         *t = S_RESET;   /* force to be set */
12044                 }
12045         }
12046         if (*t == S_HARD_IGN || *t == action)
12047                 return;
12048         act.sa_handler = ((action == S_CATCH) ? onsig
12049                                           : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
12050         *t = action;
12051         act.sa_flags = 0;
12052         sigemptyset(&act.sa_mask);
12053         sigaction(signo, &act, 0);
12054 }
12055
12056 /*
12057  * Ignore a signal.
12058  */
12059
12060 static void
12061 ignoresig(signo)
12062         int signo;
12063 {
12064         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12065                 signal(signo, SIG_IGN);
12066         }
12067         sigmode[signo - 1] = S_HARD_IGN;
12068 }
12069
12070
12071 /*
12072  * Signal handler.
12073  */
12074
12075 static void
12076 onsig(int signo)
12077 {
12078         if (signo == SIGINT && trap[SIGINT] == NULL) {
12079                 onint();
12080                 return;
12081         }
12082         gotsig[signo - 1] = 1;
12083         pendingsigs++;
12084 }
12085
12086
12087 /*
12088  * Called to execute a trap.  Perhaps we should avoid entering new trap
12089  * handlers while we are executing a trap handler.
12090  */
12091
12092 static void
12093 dotrap(void)
12094 {
12095         int i;
12096         int savestatus;
12097
12098         for (;;) {
12099                 for (i = 1 ; ; i++) {
12100                         if (gotsig[i - 1])
12101                                 break;
12102                         if (i >= NSIG - 1)
12103                                 goto done;
12104                 }
12105                 gotsig[i - 1] = 0;
12106                 savestatus=exitstatus;
12107                 evalstring(trap[i], 0);
12108                 exitstatus=savestatus;
12109         }
12110 done:
12111         pendingsigs = 0;
12112 }
12113
12114 /*
12115  * Called to exit the shell.
12116  */
12117
12118 static void
12119 exitshell(int status)
12120 {
12121         struct jmploc loc1, loc2;
12122         char *p;
12123
12124         TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12125         if (setjmp(loc1.loc)) {
12126                 goto l1;
12127         }
12128         if (setjmp(loc2.loc)) {
12129                 goto l2;
12130         }
12131         handler = &loc1;
12132         if ((p = trap[0]) != NULL && *p != '\0') {
12133                 trap[0] = NULL;
12134                 evalstring(p, 0);
12135         }
12136 l1:   handler = &loc2;                  /* probably unnecessary */
12137         flushall();
12138 #ifdef JOBS
12139         setjobctl(0);
12140 #endif
12141 l2:   _exit(status);
12142         /* NOTREACHED */
12143 }
12144
12145 static int decode_signal(const char *string, int minsig)
12146 {
12147         int signo;
12148         const char *name = u_signal_names(string, &signo, minsig);
12149
12150         return name ? signo : -1;
12151 }
12152
12153 static struct var **hashvar (const char *);
12154 static void showvars (const char *, int, int);
12155 static struct var **findvar (struct var **, const char *);
12156
12157 /*
12158  * Initialize the varable symbol tables and import the environment
12159  */
12160
12161 /*
12162  * This routine initializes the builtin variables.  It is called when the
12163  * shell is initialized and again when a shell procedure is spawned.
12164  */
12165
12166 static void
12167 initvar() {
12168         const struct varinit *ip;
12169         struct var *vp;
12170         struct var **vpp;
12171
12172         for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12173                 if ((vp->flags & VEXPORT) == 0) {
12174                         vpp = hashvar(ip->text);
12175                         vp->next = *vpp;
12176                         *vpp = vp;
12177                         vp->text = strdup(ip->text);
12178                         vp->flags = ip->flags;
12179                         vp->func = ip->func;
12180                 }
12181         }
12182         /*
12183          * PS1 depends on uid
12184          */
12185         if ((vps1.flags & VEXPORT) == 0) {
12186                 vpp = hashvar("PS1=");
12187                 vps1.next = *vpp;
12188                 *vpp = &vps1;
12189                 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12190                 vps1.flags = VSTRFIXED|VTEXTFIXED;
12191         }
12192 }
12193
12194 /*
12195  * Set the value of a variable.  The flags argument is ored with the
12196  * flags of the variable.  If val is NULL, the variable is unset.
12197  */
12198
12199 static void
12200 setvar(name, val, flags)
12201         const char *name, *val;
12202         int flags;
12203 {
12204         const char *p;
12205         int len;
12206         int namelen;
12207         char *nameeq;
12208         int isbad;
12209         int vallen = 0;
12210
12211         isbad = 0;
12212         p = name;
12213         if (! is_name(*p))
12214                 isbad = 1;
12215         p++;
12216         for (;;) {
12217                 if (! is_in_name(*p)) {
12218                         if (*p == '\0' || *p == '=')
12219                                 break;
12220                         isbad = 1;
12221                 }
12222                 p++;
12223         }
12224         namelen = p - name;
12225         if (isbad)
12226                 error("%.*s: bad variable name", namelen, name);
12227         len = namelen + 2;              /* 2 is space for '=' and '\0' */
12228         if (val == NULL) {
12229                 flags |= VUNSET;
12230         } else {
12231                 len += vallen = strlen(val);
12232         }
12233         INTOFF;
12234         nameeq = ckmalloc(len);
12235         memcpy(nameeq, name, namelen);
12236         nameeq[namelen] = '=';
12237         if (val) {
12238                 memcpy(nameeq + namelen + 1, val, vallen + 1);
12239         } else {
12240                 nameeq[namelen + 1] = '\0';
12241         }
12242         setvareq(nameeq, flags);
12243         INTON;
12244 }
12245
12246
12247
12248 /*
12249  * Same as setvar except that the variable and value are passed in
12250  * the first argument as name=value.  Since the first argument will
12251  * be actually stored in the table, it should not be a string that
12252  * will go away.
12253  */
12254
12255 static void
12256 setvareq(s, flags)
12257         char *s;
12258         int flags;
12259 {
12260         struct var *vp, **vpp;
12261
12262         vpp = hashvar(s);
12263         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12264         if ((vp = *findvar(vpp, s))) {
12265                 if (vp->flags & VREADONLY) {
12266                         size_t len = strchr(s, '=') - s;
12267                         error("%.*s: is read only", len, s);
12268                 }
12269                 INTOFF;
12270
12271                 if (vp->func && (flags & VNOFUNC) == 0)
12272                         (*vp->func)(strchr(s, '=') + 1);
12273
12274                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12275                         ckfree(vp->text);
12276
12277                 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12278                 vp->flags |= flags;
12279                 vp->text = s;
12280
12281                 /*
12282                  * We could roll this to a function, to handle it as
12283                  * a regular variable function callback, but why bother?
12284                  */
12285                 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12286                         chkmail(1);
12287                 INTON;
12288                 return;
12289         }
12290         /* not found */
12291         vp = ckmalloc(sizeof (*vp));
12292         vp->flags = flags;
12293         vp->text = s;
12294         vp->next = *vpp;
12295         vp->func = NULL;
12296         *vpp = vp;
12297 }
12298
12299
12300
12301 /*
12302  * Process a linked list of variable assignments.
12303  */
12304
12305 static void
12306 listsetvar(mylist)
12307         struct strlist *mylist;
12308         {
12309         struct strlist *lp;
12310
12311         INTOFF;
12312         for (lp = mylist ; lp ; lp = lp->next) {
12313                 setvareq(savestr(lp->text), 0);
12314         }
12315         INTON;
12316 }
12317
12318
12319
12320 /*
12321  * Find the value of a variable.  Returns NULL if not set.
12322  */
12323
12324 static const char *
12325 lookupvar(name)
12326         const char *name;
12327         {
12328         struct var *v;
12329
12330         if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12331                 return strchr(v->text, '=') + 1;
12332         }
12333         return NULL;
12334 }
12335
12336
12337
12338 /*
12339  * Search the environment of a builtin command.
12340  */
12341
12342 static const char *
12343 bltinlookup(const char *name)
12344 {
12345         const struct strlist *sp;
12346
12347         for (sp = cmdenviron ; sp ; sp = sp->next) {
12348                 if (varequal(sp->text, name))
12349                         return strchr(sp->text, '=') + 1;
12350         }
12351         return lookupvar(name);
12352 }
12353
12354
12355
12356 /*
12357  * Generate a list of exported variables.  This routine is used to construct
12358  * the third argument to execve when executing a program.
12359  */
12360
12361 static char **
12362 environment() {
12363         int nenv;
12364         struct var **vpp;
12365         struct var *vp;
12366         char **env;
12367         char **ep;
12368
12369         nenv = 0;
12370         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12371                 for (vp = *vpp ; vp ; vp = vp->next)
12372                         if (vp->flags & VEXPORT)
12373                                 nenv++;
12374         }
12375         ep = env = stalloc((nenv + 1) * sizeof *env);
12376         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12377                 for (vp = *vpp ; vp ; vp = vp->next)
12378                         if (vp->flags & VEXPORT)
12379                                 *ep++ = vp->text;
12380         }
12381         *ep = NULL;
12382         return env;
12383 }
12384
12385
12386 /*
12387  * Called when a shell procedure is invoked to clear out nonexported
12388  * variables.  It is also necessary to reallocate variables of with
12389  * VSTACK set since these are currently allocated on the stack.
12390  */
12391
12392 static void
12393 shprocvar(void) {
12394         struct var **vpp;
12395         struct var *vp, **prev;
12396
12397         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12398                 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12399                         if ((vp->flags & VEXPORT) == 0) {
12400                                 *prev = vp->next;
12401                                 if ((vp->flags & VTEXTFIXED) == 0)
12402                                         ckfree(vp->text);
12403                                 if ((vp->flags & VSTRFIXED) == 0)
12404                                         ckfree(vp);
12405                         } else {
12406                                 if (vp->flags & VSTACK) {
12407                                         vp->text = savestr(vp->text);
12408                                         vp->flags &=~ VSTACK;
12409                                 }
12410                                 prev = &vp->next;
12411                         }
12412                 }
12413         }
12414         initvar();
12415 }
12416
12417
12418
12419 /*
12420  * Command to list all variables which are set.  Currently this command
12421  * is invoked from the set command when the set command is called without
12422  * any variables.
12423  */
12424
12425 static int
12426 showvarscmd(argc, argv)
12427         int argc;
12428         char **argv;
12429 {
12430         showvars(nullstr, VUNSET, VUNSET);
12431         return 0;
12432 }
12433
12434
12435
12436 /*
12437  * The export and readonly commands.
12438  */
12439
12440 static int
12441 exportcmd(argc, argv)
12442         int argc;
12443         char **argv;
12444 {
12445         struct var *vp;
12446         char *name;
12447         const char *p;
12448         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12449         int pflag;
12450
12451         listsetvar(cmdenviron);
12452         pflag = (nextopt("p") == 'p');
12453         if (argc > 1 && !pflag) {
12454                 while ((name = *argptr++) != NULL) {
12455                         if ((p = strchr(name, '=')) != NULL) {
12456                                 p++;
12457                         } else {
12458                                 if ((vp = *findvar(hashvar(name), name))) {
12459                                         vp->flags |= flag;
12460                                         goto found;
12461                                 }
12462                         }
12463                         setvar(name, p, flag);
12464 found:;
12465                 }
12466         } else {
12467                 showvars(argv[0], flag, 0);
12468         }
12469         return 0;
12470 }
12471
12472
12473 /*
12474  * The "local" command.
12475  */
12476
12477 /* funcnest nonzero if we are currently evaluating a function */
12478
12479 static int
12480 localcmd(argc, argv)
12481         int argc;
12482         char **argv;
12483 {
12484         char *name;
12485
12486         if (! funcnest)
12487                 error("Not in a function");
12488         while ((name = *argptr++) != NULL) {
12489                 mklocal(name);
12490         }
12491         return 0;
12492 }
12493
12494
12495 /*
12496  * Make a variable a local variable.  When a variable is made local, it's
12497  * value and flags are saved in a localvar structure.  The saved values
12498  * will be restored when the shell function returns.  We handle the name
12499  * "-" as a special case.
12500  */
12501
12502 static void
12503 mklocal(name)
12504         char *name;
12505         {
12506         struct localvar *lvp;
12507         struct var **vpp;
12508         struct var *vp;
12509
12510         INTOFF;
12511         lvp = ckmalloc(sizeof (struct localvar));
12512         if (name[0] == '-' && name[1] == '\0') {
12513                 char *p;
12514                 p = ckmalloc(sizeof optet_vals);
12515                 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
12516                 vp = NULL;
12517         } else {
12518                 vpp = hashvar(name);
12519                 vp = *findvar(vpp, name);
12520                 if (vp == NULL) {
12521                         if (strchr(name, '='))
12522                                 setvareq(savestr(name), VSTRFIXED);
12523                         else
12524                                 setvar(name, NULL, VSTRFIXED);
12525                         vp = *vpp;      /* the new variable */
12526                         lvp->text = NULL;
12527                         lvp->flags = VUNSET;
12528                 } else {
12529                         lvp->text = vp->text;
12530                         lvp->flags = vp->flags;
12531                         vp->flags |= VSTRFIXED|VTEXTFIXED;
12532                         if (strchr(name, '='))
12533                                 setvareq(savestr(name), 0);
12534                 }
12535         }
12536         lvp->vp = vp;
12537         lvp->next = localvars;
12538         localvars = lvp;
12539         INTON;
12540 }
12541
12542
12543 /*
12544  * Called after a function returns.
12545  */
12546
12547 static void
12548 poplocalvars() {
12549         struct localvar *lvp;
12550         struct var *vp;
12551
12552         while ((lvp = localvars) != NULL) {
12553                 localvars = lvp->next;
12554                 vp = lvp->vp;
12555                 if (vp == NULL) {       /* $- saved */
12556                         memcpy(optet_vals, lvp->text, sizeof optet_vals);
12557                         ckfree(lvp->text);
12558                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12559                         (void)unsetvar(vp->text);
12560                 } else {
12561                         if ((vp->flags & VTEXTFIXED) == 0)
12562                                 ckfree(vp->text);
12563                         vp->flags = lvp->flags;
12564                         vp->text = lvp->text;
12565                 }
12566                 ckfree(lvp);
12567         }
12568 }
12569
12570
12571 static int
12572 setvarcmd(argc, argv)
12573         int argc;
12574         char **argv;
12575 {
12576         if (argc <= 2)
12577                 return unsetcmd(argc, argv);
12578         else if (argc == 3)
12579                 setvar(argv[1], argv[2], 0);
12580         else
12581                 error("List assignment not implemented");
12582         return 0;
12583 }
12584
12585
12586 /*
12587  * The unset builtin command.  We unset the function before we unset the
12588  * variable to allow a function to be unset when there is a readonly variable
12589  * with the same name.
12590  */
12591
12592 static int
12593 unsetcmd(argc, argv)
12594         int argc;
12595         char **argv;
12596 {
12597         char **ap;
12598         int i;
12599         int flg_func = 0;
12600         int flg_var = 0;
12601         int ret = 0;
12602
12603         while ((i = nextopt("vf")) != '\0') {
12604                 if (i == 'f')
12605                         flg_func = 1;
12606                 else
12607                         flg_var = 1;
12608         }
12609         if (flg_func == 0 && flg_var == 0)
12610                 flg_var = 1;
12611
12612         for (ap = argptr; *ap ; ap++) {
12613                 if (flg_func)
12614                         unsetfunc(*ap);
12615                 if (flg_var)
12616                         ret |= unsetvar(*ap);
12617         }
12618         return ret;
12619 }
12620
12621
12622 /*
12623  * Unset the specified variable.
12624  */
12625
12626 static int
12627 unsetvar(const char *s)
12628 {
12629         struct var **vpp;
12630         struct var *vp;
12631
12632         vpp = findvar(hashvar(s), s);
12633         vp = *vpp;
12634         if (vp) {
12635                 if (vp->flags & VREADONLY)
12636                         return (1);
12637                 INTOFF;
12638                 if (*(strchr(vp->text, '=') + 1) != '\0')
12639                         setvar(s, nullstr, 0);
12640                 vp->flags &= ~VEXPORT;
12641                 vp->flags |= VUNSET;
12642                 if ((vp->flags & VSTRFIXED) == 0) {
12643                         if ((vp->flags & VTEXTFIXED) == 0)
12644                                 ckfree(vp->text);
12645                         *vpp = vp->next;
12646                         ckfree(vp);
12647                 }
12648                 INTON;
12649                 return (0);
12650         }
12651
12652         return (0);
12653 }
12654
12655
12656
12657 /*
12658  * Find the appropriate entry in the hash table from the name.
12659  */
12660
12661 static struct var **
12662 hashvar(const char *p)
12663 {
12664         unsigned int hashval;
12665
12666         hashval = ((unsigned char) *p) << 4;
12667         while (*p && *p != '=')
12668                 hashval += (unsigned char) *p++;
12669         return &vartab[hashval % VTABSIZE];
12670 }
12671
12672
12673
12674 /*
12675  * Returns true if the two strings specify the same varable.  The first
12676  * variable name is terminated by '='; the second may be terminated by
12677  * either '=' or '\0'.
12678  */
12679
12680 static int
12681 varequal(const char *p, const char *q)
12682 {
12683         while (*p == *q++) {
12684                 if (*p++ == '=')
12685                         return 1;
12686         }
12687         if (*p == '=' && *(q - 1) == '\0')
12688                 return 1;
12689         return 0;
12690 }
12691
12692 static void
12693 showvars(const char *myprefix, int mask, int xor)
12694 {
12695         struct var **vpp;
12696         struct var *vp;
12697         const char *sep = myprefix == nullstr ? myprefix : spcstr;
12698
12699         for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12700                 for (vp = *vpp ; vp ; vp = vp->next) {
12701                         if ((vp->flags & mask) ^ xor) {
12702                                 char *p;
12703                                 int len;
12704
12705                                 p = strchr(vp->text, '=') + 1;
12706                                 len = p - vp->text;
12707                                 p = single_quote(p);
12708
12709                                 printf("%s%s%.*s%s\n", myprefix, sep, len,
12710                                         vp->text, p);
12711                                 stunalloc(p);
12712                         }
12713                 }
12714         }
12715 }
12716
12717 static struct var **
12718 findvar(struct var **vpp, const char *name)
12719 {
12720         for (; *vpp; vpp = &(*vpp)->next) {
12721                 if (varequal((*vpp)->text, name)) {
12722                         break;
12723                 }
12724         }
12725         return vpp;
12726 }
12727
12728 /*
12729  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12730  * This file contains code for the times builtin.
12731  * $Id: ash.c,v 1.27 2001/10/19 00:08:17 andersen Exp $
12732  */
12733 static int timescmd (int argc, char **argv)
12734 {
12735         struct tms buf;
12736         long int clk_tck = sysconf(_SC_CLK_TCK);
12737
12738         times(&buf);
12739         printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12740                (int) (buf.tms_utime / clk_tck / 60),
12741                ((double) buf.tms_utime) / clk_tck,
12742                (int) (buf.tms_stime / clk_tck / 60),
12743                ((double) buf.tms_stime) / clk_tck,
12744                (int) (buf.tms_cutime / clk_tck / 60),
12745                ((double) buf.tms_cutime) / clk_tck,
12746                (int) (buf.tms_cstime / clk_tck / 60),
12747                ((double) buf.tms_cstime) / clk_tck);
12748         return 0;
12749 }
12750
12751 #ifdef ASH_MATH_SUPPORT
12752 /* The let builtin.  */
12753 int letcmd(int argc, char **argv)
12754 {
12755         int errcode;
12756         long result=0;
12757         if (argc == 2) {
12758                 char *tmp, *expression, p[13];
12759                 expression = strchr(argv[1], '=');
12760                 if (!expression) {
12761                         /* Cannot use 'error()' here, or the return code
12762                          * will be incorrect */
12763                         out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12764                         return 0;
12765                 }
12766                 *expression = '\0';
12767                 tmp = ++expression;
12768                 result = arith(tmp, &errcode);
12769                 if (errcode < 0) {
12770                         /* Cannot use 'error()' here, or the return code
12771                          * will be incorrect */
12772                         out2fmt("sh: let: ");
12773                         if(errcode == -2)
12774                                 out2fmt("divide by zero");
12775                         else
12776                                 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
12777                         return 0;
12778                 }
12779                 snprintf(p, 12, "%ld", result);
12780                 setvar(argv[1], savestr(p), 0);
12781         } else if (argc >= 3)
12782                 synerror("invalid operand");
12783         return !result;
12784 }
12785 #endif
12786
12787
12788
12789 /*-
12790  * Copyright (c) 1989, 1991, 1993, 1994
12791  *      The Regents of the University of California.  All rights reserved.
12792  *
12793  * This code is derived from software contributed to Berkeley by
12794  * Kenneth Almquist.
12795  *
12796  * Redistribution and use in source and binary forms, with or without
12797  * modification, are permitted provided that the following conditions
12798  * are met:
12799  * 1. Redistributions of source code must retain the above copyright
12800  *    notice, this list of conditions and the following disclaimer.
12801  * 2. Redistributions in binary form must reproduce the above copyright
12802  *    notice, this list of conditions and the following disclaimer in the
12803  *    documentation and/or other materials provided with the distribution.
12804  *
12805  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12806  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
12807  *
12808  * 4. Neither the name of the University nor the names of its contributors
12809  *    may be used to endorse or promote products derived from this software
12810  *    without specific prior written permission.
12811  *
12812  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12813  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12814  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12815  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12816  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12817  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12818  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12819  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12820  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12821  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
12822  * SUCH DAMAGE.
12823  */