*: add optimization barrier to all "G trick" locations
[oweals/busybox.git] / shell / msh.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Minix shell port for busybox
4  *
5  * This version of the Minix shell was adapted for use in busybox
6  * by Erik Andersen <andersen@codepoet.org>
7  *
8  * - backtick expansion did not work properly
9  *   Jonas Holmberg <jonas.holmberg@axis.com>
10  *   Robert Schwebel <r.schwebel@pengutronix.de>
11  *   Erik Andersen <andersen@codepoet.org>
12  *
13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
14  */
15
16 #include <sys/times.h>
17 #include <setjmp.h>
18
19 #ifdef STANDALONE
20 # ifndef _GNU_SOURCE
21 #  define _GNU_SOURCE
22 # endif
23 # include <sys/types.h>
24 # include <sys/stat.h>
25 # include <sys/wait.h>
26 # include <signal.h>
27 # include <stdio.h>
28 # include <stdlib.h>
29 # include <unistd.h>
30 # include <string.h>
31 # include <errno.h>
32 # include <dirent.h>
33 # include <fcntl.h>
34 # include <ctype.h>
35 # include <assert.h>
36 # define bb_dev_null "/dev/null"
37 # define DEFAULT_SHELL "/proc/self/exe"
38 # define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39 # define bb_banner "busybox standalone"
40 # define ENABLE_FEATURE_SH_STANDALONE 0
41 # define bb_msg_memory_exhausted "memory exhausted"
42 # define xmalloc(size) malloc(size)
43 # define msh_main(argc,argv) main(argc,argv)
44 # define safe_read(fd,buf,count) read(fd,buf,count)
45 # define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
46 # define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
47 # define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
48 # define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
49 static int find_applet_by_name(const char *applet)
50 {
51         return -1;
52 }
53 static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
54 {
55         unsigned i, out, res;
56         assert(sizeof(unsigned) == 4);
57         if (buflen) {
58                 out = 0;
59                 for (i = 1000000000; i; i /= 10) {
60                         res = n / i;
61                         if (res || out || i == 1) {
62                                 if (!--buflen) break;
63                                 out++;
64                                 n -= res*i;
65                                 *buf++ = '0' + res;
66                         }
67                 }
68         }
69         return buf;
70 }
71 static char *itoa_to_buf(int n, char *buf, unsigned buflen)
72 {
73         if (buflen && n < 0) {
74                 n = -n;
75                 *buf++ = '-';
76                 buflen--;
77         }
78         return utoa_to_buf((unsigned)n, buf, buflen);
79 }
80 static char local_buf[12];
81 static char *itoa(int n)
82 {
83         *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
84         return local_buf;
85 }
86 #else
87 # include "busybox.h" /* for applet_names */
88 #endif
89
90 //#define MSHDEBUG 4
91
92 #ifdef MSHDEBUG
93 int mshdbg = MSHDEBUG;
94
95 #define DBGPRINTF(x)    if (mshdbg>0) printf x
96 #define DBGPRINTF0(x)   if (mshdbg>0) printf x
97 #define DBGPRINTF1(x)   if (mshdbg>1) printf x
98 #define DBGPRINTF2(x)   if (mshdbg>2) printf x
99 #define DBGPRINTF3(x)   if (mshdbg>3) printf x
100 #define DBGPRINTF4(x)   if (mshdbg>4) printf x
101 #define DBGPRINTF5(x)   if (mshdbg>5) printf x
102 #define DBGPRINTF6(x)   if (mshdbg>6) printf x
103 #define DBGPRINTF7(x)   if (mshdbg>7) printf x
104 #define DBGPRINTF8(x)   if (mshdbg>8) printf x
105 #define DBGPRINTF9(x)   if (mshdbg>9) printf x
106
107 int mshdbg_rc = 0;
108
109 #define RCPRINTF(x)     if (mshdbg_rc) printf x
110
111 #else
112
113 #define DBGPRINTF(x)
114 #define DBGPRINTF0(x) ((void)0)
115 #define DBGPRINTF1(x) ((void)0)
116 #define DBGPRINTF2(x) ((void)0)
117 #define DBGPRINTF3(x) ((void)0)
118 #define DBGPRINTF4(x) ((void)0)
119 #define DBGPRINTF5(x) ((void)0)
120 #define DBGPRINTF6(x) ((void)0)
121 #define DBGPRINTF7(x) ((void)0)
122 #define DBGPRINTF8(x) ((void)0)
123 #define DBGPRINTF9(x) ((void)0)
124
125 #define RCPRINTF(x) ((void)0)
126
127 #endif                                                  /* MSHDEBUG */
128
129
130 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
131 # define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132 # define DEFAULT_USER_PROMPT "\\u:\\w$ "
133 #else
134 # define DEFAULT_ROOT_PROMPT "# "
135 # define DEFAULT_USER_PROMPT "$ "
136 #endif
137
138
139 /* -------- sh.h -------- */
140 /*
141  * shell
142  */
143
144 #define LINELIM   2100
145 #define NPUSH     8                             /* limit to input nesting */
146
147 #undef NOFILE
148 #define NOFILE    20                    /* Number of open files */
149 #define NUFILE    10                    /* Number of user-accessible files */
150 #define FDBASE    10                    /* First file usable by Shell */
151
152 /*
153  * values returned by wait
154  */
155 #define WAITSIG(s)  ((s) & 0177)
156 #define WAITVAL(s)  (((s) >> 8) & 0377)
157 #define WAITCORE(s) (((s) & 0200) != 0)
158
159 /*
160  * library and system definitions
161  */
162 typedef void xint;                      /* base type of jmp_buf, for not broken compilers */
163
164 /*
165  * shell components
166  */
167 #define NOBLOCK ((struct op *)NULL)
168 #define NOWORD  ((char *)NULL)
169 #define NOWORDS ((char **)NULL)
170 #define NOPIPE  ((int *)NULL)
171
172 /*
173  * redirection
174  */
175 struct ioword {
176         short io_unit;                  /* unit affected */
177         short io_flag;                  /* action (below) */
178         char *io_name;                  /* file name */
179 };
180
181 #define IOREAD   1                      /* < */
182 #define IOHERE   2                      /* << (here file) */
183 #define IOWRITE  4                      /* > */
184 #define IOCAT    8                      /* >> */
185 #define IOXHERE  16                     /* ${}, ` in << */
186 #define IODUP    32                     /* >&digit */
187 #define IOCLOSE  64                     /* >&- */
188
189 #define IODEFAULT (-1)                  /* token for default IO unit */
190
191
192 /*
193  * Description of a command or an operation on commands.
194  * Might eventually use a union.
195  */
196 struct op {
197         smallint type;                  /* operation type, see Txxxx below */
198         char **words;                   /* arguments to a command */
199         struct ioword **ioact;          /* IO actions (eg, < > >>) */
200         struct op *left;
201         struct op *right;
202         char *str;                      /* identifier for case and for */
203 };
204
205 #define TCOM    1       /* command */
206 #define TPAREN  2       /* (c-list) */
207 #define TPIPE   3       /* a | b */
208 #define TLIST   4       /* a [&;] b */
209 #define TOR     5       /* || */
210 #define TAND    6       /* && */
211 #define TFOR    7
212 #define TDO     8
213 #define TCASE   9
214 #define TIF     10
215 #define TWHILE  11
216 #define TUNTIL  12
217 #define TELIF   13
218 #define TPAT    14      /* pattern in case */
219 #define TBRACE  15      /* {c-list} */
220 #define TASYNC  16      /* c & */
221 /* Added to support "." file expansion */
222 #define TDOT    17
223
224 /* Strings for names to make debug easier */
225 #ifdef MSHDEBUG
226 static const char *const T_CMD_NAMES[] = {
227         "PLACEHOLDER",
228         "TCOM",
229         "TPAREN",
230         "TPIPE",
231         "TLIST",
232         "TOR",
233         "TAND",
234         "TFOR",
235         "TDO",
236         "TCASE",
237         "TIF",
238         "TWHILE",
239         "TUNTIL",
240         "TELIF",
241         "TPAT",
242         "TBRACE",
243         "TASYNC",
244         "TDOT",
245 };
246 #endif
247
248 #define AREASIZE (90000)
249
250 /*
251  * flags to control evaluation of words
252  */
253 #define DOSUB    1      /* interpret $, `, and quotes */
254 #define DOBLANK  2      /* perform blank interpretation */
255 #define DOGLOB   4      /* interpret [?* */
256 #define DOKEY    8      /* move words with `=' to 2nd arg. list */
257 #define DOTRIM   16     /* trim resulting string */
258
259 #define DOALL    (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
260
261
262 struct brkcon {
263         jmp_buf brkpt;
264         struct brkcon *nextlev;
265 };
266
267
268 static smallint trapset;                        /* trap pending (signal number) */
269
270 static smallint yynerrs;                        /* yacc (flag) */
271
272 /* moved to G: static char line[LINELIM]; */
273
274 #if ENABLE_FEATURE_EDITING
275 static char *current_prompt;
276 static line_input_t *line_input_state;
277 #endif
278
279
280 /*
281  * other functions
282  */
283 static const char *rexecve(char *c, char **v, char **envp);
284 static char *evalstr(char *cp, int f);
285 static char *putn(int n);
286 static char *unquote(char *as);
287 static int rlookup(char *n);
288 static struct wdblock *glob(char *cp, struct wdblock *wb);
289 static int my_getc(int ec);
290 static int subgetc(char ec, int quoted);
291 static char **makenv(int all, struct wdblock *wb);
292 static char **eval(char **ap, int f);
293 static int setstatus(int s);
294 static int waitfor(int lastpid, int canintr);
295
296 static void onintr(int s);              /* SIGINT handler */
297
298 static int newenv(int f);
299 static void quitenv(void);
300 static void next(int f);
301 static void setdash(void);
302 static void onecommand(void);
303 static void runtrap(int i);
304
305
306 /* -------- area stuff -------- */
307
308 #define REGSIZE   sizeof(struct region)
309 #define GROWBY    (256)
310 /* #define SHRINKBY (64) */
311 #undef  SHRINKBY
312 #define FREE      (32767)
313 #define BUSY      (0)
314 #define ALIGN     (sizeof(int)-1)
315
316
317 struct region {
318         struct region *next;
319         int area;
320 };
321
322
323 /* -------- grammar stuff -------- */
324 typedef union {
325         char *cp;
326         char **wp;
327         int i;
328         struct op *o;
329 } YYSTYPE;
330
331 #define WORD    256
332 #define LOGAND  257
333 #define LOGOR   258
334 #define BREAK   259
335 #define IF      260
336 #define THEN    261
337 #define ELSE    262
338 #define ELIF    263
339 #define FI      264
340 #define CASE    265
341 #define ESAC    266
342 #define FOR     267
343 #define WHILE   268
344 #define UNTIL   269
345 #define DO      270
346 #define DONE    271
347 #define IN      272
348 /* Added for "." file expansion */
349 #define DOT     273
350
351 #define YYERRCODE 300
352
353 /* flags to yylex */
354 #define CONTIN 01     /* skip new lines to complete command */
355
356 static struct op *pipeline(int cf);
357 static struct op *andor(void);
358 static struct op *c_list(void);
359 static int synio(int cf);
360 static void musthave(int c, int cf);
361 static struct op *simple(void);
362 static struct op *nested(int type, int mark);
363 static struct op *command(int cf);
364 static struct op *dogroup(int onlydone);
365 static struct op *thenpart(void);
366 static struct op *elsepart(void);
367 static struct op *caselist(void);
368 static struct op *casepart(void);
369 static char **pattern(void);
370 static char **wordlist(void);
371 static struct op *list(struct op *t1, struct op *t2);
372 static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
373 static struct op *newtp(void);
374 static struct op *namelist(struct op *t);
375 static char **copyw(void);
376 static void word(char *cp);
377 static struct ioword **copyio(void);
378 static struct ioword *io(int u, int f, char *cp);
379 static int yylex(int cf);
380 static int collect(int c, int c1);
381 static int dual(int c);
382 static void diag(int ec);
383 static char *tree(unsigned size);
384
385 /* -------- var.h -------- */
386
387 struct var {
388         char *value;
389         char *name;
390         struct var *next;
391         char status;
392 };
393
394 #define COPYV   1                               /* flag to setval, suggesting copy */
395 #define RONLY   01                              /* variable is read-only */
396 #define EXPORT  02                              /* variable is to be exported */
397 #define GETCELL 04                              /* name & value space was got with getcell */
398
399 static int yyparse(void);
400
401
402 /* -------- io.h -------- */
403 /* io buffer */
404 struct iobuf {
405         unsigned id;            /* buffer id */
406         char buf[512];          /* buffer */
407         char *bufp;             /* pointer into buffer */
408         char *ebufp;            /* pointer to end of buffer */
409 };
410
411 /* possible arguments to an IO function */
412 struct ioarg {
413         const char *aword;
414         char **awordlist;
415         int afile;              /* file descriptor */
416         unsigned afid;          /* buffer id */
417         off_t afpos;            /* file position */
418         struct iobuf *afbuf;    /* buffer for this file */
419 };
420
421 /* an input generator's state */
422 struct io {
423         int (*iofn) (struct ioarg *, struct io *);
424         struct ioarg *argp;
425         int peekc;
426         char prev;              /* previous character read by readc() */
427         char nlcount;           /* for `'s */
428         char xchar;             /* for `'s */
429         char task;              /* reason for pushed IO */
430 };
431 /* ->task: */
432 #define XOTHER  0       /* none of the below */
433 #define XDOLL   1       /* expanding ${} */
434 #define XGRAVE  2       /* expanding `'s */
435 #define XIO     3       /* file IO */
436
437
438 /*
439  * input generators for IO structure
440  */
441 static int nlchar(struct ioarg *ap);
442 static int strchar(struct ioarg *ap);
443 static int qstrchar(struct ioarg *ap);
444 static int filechar(struct ioarg *ap);
445 static int herechar(struct ioarg *ap);
446 static int linechar(struct ioarg *ap);
447 static int gravechar(struct ioarg *ap, struct io *iop);
448 static int qgravechar(struct ioarg *ap, struct io *iop);
449 static int dolchar(struct ioarg *ap);
450 static int wdchar(struct ioarg *ap);
451 static void scraphere(void);
452 static void freehere(int area);
453 static void gethere(void);
454 static void markhere(char *s, struct ioword *iop);
455 static int herein(char *hname, int xdoll);
456 static int run(struct ioarg *argp, int (*f) (struct ioarg *));
457
458
459 static int eofc(void);
460 static int readc(void);
461 static void unget(int c);
462 static void ioecho(char c);
463
464
465 /*
466  * IO control
467  */
468 static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
469 #define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
470 static int remap(int fd);
471 static int openpipe(int *pv);
472 static void closepipe(int *pv);
473 static struct io *setbase(struct io *ip);
474
475 /* -------- word.h -------- */
476
477 #define NSTART  16                              /* default number of words to allow for initially */
478
479 struct wdblock {
480         short w_bsize;
481         short w_nword;
482         /* bounds are arbitrary */
483         char *w_words[1];
484 };
485
486 static struct wdblock *addword(char *wd, struct wdblock *wb);
487 static struct wdblock *newword(int nw);
488 static char **getwords(struct wdblock *wb);
489
490 /* -------- misc stuff -------- */
491
492 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
493 static int execute(struct op *t, int *pin, int *pout, int no_fork);
494 static int iosetup(struct ioword *iop, int pipein, int pipeout);
495 static void brkset(struct brkcon *bc);
496 static int dolabel(struct op *t);
497 static int dohelp(struct op *t);
498 static int dochdir(struct op *t);
499 static int doshift(struct op *t);
500 static int dologin(struct op *t);
501 static int doumask(struct op *t);
502 static int doexec(struct op *t);
503 static int dodot(struct op *t);
504 static int dowait(struct op *t);
505 static int doread(struct op *t);
506 static int doeval(struct op *t);
507 static int dotrap(struct op *t);
508 static int getsig(char *s);
509 static void setsig(int n, sighandler_t f);
510 static int getn(char *as);
511 static int dobreak(struct op *t);
512 static int docontinue(struct op *t);
513 static int brkcontin(char *cp, int val);
514 static int doexit(struct op *t);
515 static int doexport(struct op *t);
516 static int doreadonly(struct op *t);
517 static void rdexp(char **wp, void (*f) (struct var *), int key);
518 static void badid(char *s);
519 static int doset(struct op *t);
520 static void varput(char *s, int out);
521 static int dotimes(struct op *t);
522 static int expand(const char *cp, struct wdblock **wbp, int f);
523 static char *blank(int f);
524 static int dollar(int quoted);
525 static int grave(int quoted);
526 static void globname(char *we, char *pp);
527 static char *generate(char *start1, char *end1, char *middle, char *end);
528 static int anyspcl(struct wdblock *wb);
529 static int xstrcmp(char *p1, char *p2);
530 static void glob0(char *a0, unsigned a1, int a2,
531                                   int (*a3) (char *, char *));
532 static void readhere(char **name, char *s, int ec);
533 static int xxchar(struct ioarg *ap);
534
535 struct here {
536         char *h_tag;
537         char h_dosub;
538         struct ioword *h_iop;
539         struct here *h_next;
540 };
541
542 static const char *const signame[] = {
543         "Signal 0",
544         "Hangup",
545         NULL,  /* interrupt */
546         "Quit",
547         "Illegal instruction",
548         "Trace/BPT trap",
549         "Abort",
550         "Bus error",
551         "Floating Point Exception",
552         "Killed",
553         "SIGUSR1",
554         "SIGSEGV",
555         "SIGUSR2",
556         NULL,  /* broken pipe */
557         "Alarm clock",
558         "Terminated"
559 };
560
561
562 typedef int (*builtin_func_ptr)(struct op *);
563
564 struct builtincmd {
565         const char *name;
566         builtin_func_ptr builtinfunc;
567 };
568
569 static const struct builtincmd builtincmds[] = {
570         { "."       , dodot      },
571         { ":"       , dolabel    },
572         { "break"   , dobreak    },
573         { "cd"      , dochdir    },
574         { "continue", docontinue },
575         { "eval"    , doeval     },
576         { "exec"    , doexec     },
577         { "exit"    , doexit     },
578         { "export"  , doexport   },
579         { "help"    , dohelp     },
580         { "login"   , dologin    },
581         { "newgrp"  , dologin    },
582         { "read"    , doread     },
583         { "readonly", doreadonly },
584         { "set"     , doset      },
585         { "shift"   , doshift    },
586         { "times"   , dotimes    },
587         { "trap"    , dotrap     },
588         { "umask"   , doumask    },
589         { "wait"    , dowait     },
590         { NULL      , NULL       },
591 };
592
593 static struct op *scantree(struct op *);
594 static struct op *dowholefile(int, int);
595
596
597 /* Globals */
598 static char **dolv;
599 static int dolc;
600 static int exstat;
601 static smallint gflg;                   /* (seems to be a parse error indicator) */
602 static smallint interactive;            /* Is this an interactive shell */
603 static smallint execflg;
604 static smallint isbreak;                /* "break" statement was seen */
605 static int multiline;                   /* '\n' changed to ';' (counter) */
606 static struct op *outtree;              /* result from parser */
607 static xint *failpt;
608 static xint *errpt;
609 static struct brkcon *brklist;
610 static struct wdblock *wdlist;
611 static struct wdblock *iolist;
612
613 #ifdef MSHDEBUG
614 static struct var *mshdbg_var;
615 #endif
616 static struct var *vlist;               /* dictionary */
617 static struct var *homedir;             /* home directory */
618 static struct var *prompt;              /* main prompt */
619 static struct var *cprompt;             /* continuation prompt */
620 static struct var *path;                /* search path for commands */
621 static struct var *shell;               /* shell to interpret command files */
622 static struct var *ifs;                 /* field separators */
623
624 static int areanum;                     /* current allocation area */
625 static smallint intr;                   /* interrupt pending (bool) */
626 static smallint heedint = 1;            /* heed interrupt signals (bool) */
627 static int inparse;
628 static char *null = (char*)"";          /* null value for variable */
629 static void (*qflag)(int) = SIG_IGN;
630 static int startl;
631 static int peeksym;
632 static int nlseen;
633 static int iounit = IODEFAULT;
634 static YYSTYPE yylval;
635 static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
636
637 static struct here *inhere;     /* list of hear docs while parsing */
638 static struct here *acthere;    /* list of active here documents */
639 static struct region *areabot;  /* bottom of area */
640 static struct region *areatop;  /* top of area */
641 static struct region *areanxt;  /* starting point of scan */
642 static void *brktop;
643 static void *brkaddr;
644
645 #define AFID_NOBUF      (~0)
646 #define AFID_ID         0
647
648
649 /*
650  * parsing & execution environment
651  */
652 struct env {
653         char *linep;
654         struct io *iobase;
655         struct io *iop;
656         xint *errpt;            /* void * */
657         int iofd;
658         struct env *oenv;
659 };
660
661
662 struct globals {
663         struct env global_env;
664         struct ioarg temparg; // = { .afid = AFID_NOBUF };      /* temporary for PUSHIO */
665         unsigned bufid; // = AFID_ID;   /* buffer id counter */
666         char ourtrap[_NSIG + 1];
667         char *trap[_NSIG + 1];
668         struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
669         struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
670         struct ioarg ioargstack[NPUSH];
671         /*
672          * flags:
673          * -e: quit on error
674          * -k: look for name=value everywhere on command line
675          * -n: no execution
676          * -t: exit after reading and executing one command
677          * -v: echo as read
678          * -x: trace
679          * -u: unset variables net diagnostic
680          */
681         char flags['z' - 'a' + 1];
682         char filechar_cmdbuf[BUFSIZ];
683         char line[LINELIM];
684         char child_cmd[LINELIM];
685
686         struct io iostack[NPUSH];
687
688         char grave__var_name[LINELIM];
689         char grave__alt_value[LINELIM];
690 };
691
692 #define G (*ptr_to_globals)
693 #define global_env      (G.global_env     )
694 #define temparg         (G.temparg        )
695 #define bufid           (G.bufid          )
696 #define ourtrap         (G.ourtrap        )
697 #define trap            (G.trap           )
698 #define sharedbuf       (G.sharedbuf      )
699 #define mainbuf         (G.mainbuf        )
700 #define ioargstack      (G.ioargstack     )
701 /* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
702 #define FLAG            (G.flags - 'a'    )
703 #define filechar_cmdbuf (G.filechar_cmdbuf)
704 #define line            (G.line           )
705 #define child_cmd       (G.child_cmd      )
706 #define iostack         (G.iostack        )
707 #define INIT_G() do { \
708         SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
709         global_env.linep = line; \
710         global_env.iobase = iostack; \
711         global_env.iop = iostack - 1; \
712         global_env.iofd = FDBASE; \
713         temparg.afid = AFID_NOBUF; \
714         bufid = AFID_ID; \
715 } while (0)
716
717
718 /* in substitution */
719 #define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
720
721 #define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
722
723 #ifdef MSHDEBUG
724 void print_t(struct op *t)
725 {
726         DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
727                   T_CMD_NAMES[t->type], t->words, t->ioact));
728
729         if (t->words) {
730                 DBGPRINTF(("T: W1: %s", t->words[0]));
731         }
732 }
733
734 void print_tree(struct op *head)
735 {
736         if (head == NULL) {
737                 DBGPRINTF(("PRINT_TREE: no tree\n"));
738                 return;
739         }
740
741         DBGPRINTF(("NODE: %p,  left %p, right %p\n", head, head->left,
742                            head->right));
743
744         if (head->left)
745                 print_tree(head->left);
746
747         if (head->right)
748                 print_tree(head->right);
749 }
750 #endif /* MSHDEBUG */
751
752
753 /*
754  * IO functions
755  */
756 static void prs(const char *s)
757 {
758         if (*s)
759                 write(2, s, strlen(s));
760 }
761
762 static void prn(unsigned u)
763 {
764         prs(itoa(u));
765 }
766
767 static void echo(char **wp)
768 {
769         int i;
770
771         prs("+");
772         for (i = 0; wp[i]; i++) {
773                 if (i)
774                         prs(" ");
775                 prs(wp[i]);
776         }
777         prs("\n");
778 }
779
780 static void closef(int i)
781 {
782         if (i > 2)
783                 close(i);
784 }
785
786 static void closeall(void)
787 {
788         int u;
789
790         for (u = NUFILE; u < NOFILE;)
791                 close(u++);
792 }
793
794
795 /* fail but return to process next command */
796 static void fail(void) ATTRIBUTE_NORETURN;
797 static void fail(void)
798 {
799         longjmp(failpt, 1);
800         /* NOTREACHED */
801 }
802
803 /* abort shell (or fail in subshell) */
804 static void leave(void) ATTRIBUTE_NORETURN;
805 static void leave(void)
806 {
807         DBGPRINTF(("LEAVE: leave called!\n"));
808
809         if (execflg)
810                 fail();
811         scraphere();
812         freehere(1);
813         runtrap(0);
814         _exit(exstat);
815         /* NOTREACHED */
816 }
817
818 static void warn(const char *s)
819 {
820         if (*s) {
821                 prs(s);
822                 exstat = -1;
823         }
824         prs("\n");
825         if (FLAG['e'])
826                 leave();
827 }
828
829 static void err(const char *s)
830 {
831         warn(s);
832         if (FLAG['n'])
833                 return;
834         if (!interactive)
835                 leave();
836         if (global_env.errpt)
837                 longjmp(global_env.errpt, 1);
838         closeall();
839         global_env.iop = global_env.iobase = iostack;
840 }
841
842
843 /* -------- area.c -------- */
844
845 /*
846  * All memory between (char *)areabot and (char *)(areatop+1) is
847  * exclusively administered by the area management routines.
848  * It is assumed that sbrk() and brk() manipulate the high end.
849  */
850
851 #define sbrk(X) ({ \
852         void * __q = (void *)-1; \
853         if (brkaddr + (int)(X) < brktop) { \
854                 __q = brkaddr; \
855                 brkaddr += (int)(X); \
856         } \
857         __q; \
858 })
859
860 static void initarea(void)
861 {
862         brkaddr = xmalloc(AREASIZE);
863         brktop = brkaddr + AREASIZE;
864
865         while ((long) sbrk(0) & ALIGN)
866                 sbrk(1);
867         areabot = (struct region *) sbrk(REGSIZE);
868
869         areabot->next = areabot;
870         areabot->area = BUSY;
871         areatop = areabot;
872         areanxt = areabot;
873 }
874
875 static char *getcell(unsigned nbytes)
876 {
877         int nregio;
878         struct region *p, *q;
879         int i;
880
881         if (nbytes == 0) {
882                 puts("getcell(0)");
883                 abort();
884         }
885         /* silly and defeats the algorithm */
886         /*
887          * round upwards and add administration area
888          */
889         nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
890         p = areanxt;
891         for (;;) {
892                 if (p->area > areanum) {
893                         /*
894                          * merge free cells
895                          */
896                         while ((q = p->next)->area > areanum && q != areanxt)
897                                 p->next = q->next;
898                         /*
899                          * exit loop if cell big enough
900                          */
901                         if (q >= p + nregio)
902                                 goto found;
903                 }
904                 p = p->next;
905                 if (p == areanxt)
906                         break;
907         }
908         i = nregio >= GROWBY ? nregio : GROWBY;
909         p = (struct region *) sbrk(i * REGSIZE);
910         if (p == (struct region *) -1)
911                 return NULL;
912         p--;
913         if (p != areatop) {
914                 puts("not contig");
915                 abort();                                /* allocated areas are contiguous */
916         }
917         q = p + i;
918         p->next = q;
919         p->area = FREE;
920         q->next = areabot;
921         q->area = BUSY;
922         areatop = q;
923  found:
924         /*
925          * we found a FREE area big enough, pointed to by 'p', and up to 'q'
926          */
927         areanxt = p + nregio;
928         if (areanxt < q) {
929                 /*
930                  * split into requested area and rest
931                  */
932                 if (areanxt + 1 > q) {
933                         puts("OOM");
934                         abort();                        /* insufficient space left for admin */
935                 }
936                 areanxt->next = q;
937                 areanxt->area = FREE;
938                 p->next = areanxt;
939         }
940         p->area = areanum;
941         return (char *) (p + 1);
942 }
943
944 static void freecell(char *cp)
945 {
946         struct region *p;
947
948         p = (struct region *) cp;
949         if (p != NULL) {
950                 p--;
951                 if (p < areanxt)
952                         areanxt = p;
953                 p->area = FREE;
954         }
955 }
956 #define DELETE(obj) freecell((char *)obj)
957
958 static void freearea(int a)
959 {
960         struct region *p, *top;
961
962         top = areatop;
963         for (p = areabot; p != top; p = p->next)
964                 if (p->area >= a)
965                         p->area = FREE;
966 }
967
968 static void setarea(char *cp, int a)
969 {
970         struct region *p;
971
972         p = (struct region *) cp;
973         if (p != NULL)
974                 (p - 1)->area = a;
975 }
976
977 static int getarea(char *cp)
978 {
979         return ((struct region *) cp - 1)->area;
980 }
981
982 static void garbage(void)
983 {
984         struct region *p, *q, *top;
985
986         top = areatop;
987         for (p = areabot; p != top; p = p->next) {
988                 if (p->area > areanum) {
989                         while ((q = p->next)->area > areanum)
990                                 p->next = q->next;
991                         areanxt = p;
992                 }
993         }
994 #ifdef SHRINKBY
995         if (areatop >= q + SHRINKBY && q->area > areanum) {
996                 brk((char *) (q + 1));
997                 q->next = areabot;
998                 q->area = BUSY;
999                 areatop = q;
1000         }
1001 #endif
1002 }
1003
1004 static char *space(int n)
1005 {
1006         char *cp;
1007
1008         cp = getcell(n);
1009         if (cp == NULL)
1010                 err("out of string space");
1011         return cp;
1012 }
1013
1014 static char *strsave(const char *s, int a)
1015 {
1016         char *cp;
1017
1018         cp = space(strlen(s) + 1);
1019         if (cp == NULL) {
1020 // FIXME: I highly doubt this is good.
1021                 return (char*)"";
1022         }
1023         setarea(cp, a);
1024         strcpy(cp, s);
1025         return cp;
1026 }
1027
1028
1029 /* -------- var.c -------- */
1030
1031 static int eqname(const char *n1, const char *n2)
1032 {
1033         for (; *n1 != '=' && *n1 != '\0'; n1++)
1034                 if (*n2++ != *n1)
1035                         return 0;
1036         return *n2 == '\0' || *n2 == '=';
1037 }
1038
1039 static const char *findeq(const char *cp)
1040 {
1041         while (*cp != '\0' && *cp != '=')
1042                 cp++;
1043         return cp;
1044 }
1045
1046 /*
1047  * Find the given name in the dictionary
1048  * and return its value.  If the name was
1049  * not previously there, enter it now and
1050  * return a null value.
1051  */
1052 static struct var *lookup(const char *n)
1053 {
1054 // FIXME: dirty hack
1055         static struct var dummy;
1056
1057         struct var *vp;
1058         const char *cp;
1059         char *xp;
1060         int c;
1061
1062         if (isdigit(*n)) {
1063                 dummy.name = (char*)n;
1064                 for (c = 0; isdigit(*n) && c < 1000; n++)
1065                         c = c * 10 + *n - '0';
1066                 dummy.status = RONLY;
1067                 dummy.value = (c <= dolc ? dolv[c] : null);
1068                 return &dummy;
1069         }
1070
1071         for (vp = vlist; vp; vp = vp->next)
1072                 if (eqname(vp->name, n))
1073                         return vp;
1074
1075         cp = findeq(n);
1076         vp = (struct var *) space(sizeof(*vp));
1077         if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
1078                 dummy.name = dummy.value = (char*)"";
1079                 return &dummy;
1080         }
1081
1082         xp = vp->name;
1083         while ((*xp = *n++) != '\0' && *xp != '=')
1084                 xp++;
1085         *xp++ = '=';
1086         *xp = '\0';
1087         setarea((char *) vp, 0);
1088         setarea((char *) vp->name, 0);
1089         vp->value = null;
1090         vp->next = vlist;
1091         vp->status = GETCELL;
1092         vlist = vp;
1093         return vp;
1094 }
1095
1096 /*
1097  * if name is not NULL, it must be
1098  * a prefix of the space `val',
1099  * and end with `='.
1100  * this is all so that exporting
1101  * values is reasonably painless.
1102  */
1103 static void nameval(struct var *vp, const char *val, const char *name)
1104 {
1105         const char *cp;
1106         char *xp;
1107         int fl;
1108
1109         if (vp->status & RONLY) {
1110                 xp = vp->name;
1111                 while (*xp && *xp != '=')
1112                         fputc(*xp++, stderr);
1113                 err(" is read-only");
1114                 return;
1115         }
1116         fl = 0;
1117         if (name == NULL) {
1118                 xp = space(strlen(vp->name) + strlen(val) + 2);
1119                 if (xp == NULL)
1120                         return;
1121                 /* make string: name=value */
1122                 setarea(xp, 0);
1123                 name = xp;
1124                 cp = vp->name;
1125                 while ((*xp = *cp++) != '\0' && *xp != '=')
1126                         xp++;
1127                 *xp++ = '=';
1128                 strcpy(xp, val);
1129                 val = xp;
1130                 fl = GETCELL;
1131         }
1132         if (vp->status & GETCELL)
1133                 freecell(vp->name);             /* form new string `name=value' */
1134         vp->name = (char*)name;
1135         vp->value = (char*)val;
1136         vp->status |= fl;
1137 }
1138
1139 /*
1140  * give variable at `vp' the value `val'.
1141  */
1142 static void setval(struct var *vp, const char *val)
1143 {
1144         nameval(vp, val, NULL);
1145 }
1146
1147 static void export(struct var *vp)
1148 {
1149         vp->status |= EXPORT;
1150 }
1151
1152 static void ronly(struct var *vp)
1153 {
1154         if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1155                 vp->status |= RONLY;
1156 }
1157
1158 static int isassign(const char *s)
1159 {
1160         unsigned char c;
1161         DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1162
1163         c = *s;
1164         /* no isalpha() - we shouldn't use locale */
1165         /* c | 0x20 - lowercase (Latin) letters */
1166         if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1167                 /* not letter */
1168                 return 0;
1169
1170         while (1) {
1171                 c = *++s;
1172                 if (c == '=')
1173                         return 1;
1174                 if (c == '\0')
1175                         return 0;
1176                 if (c != '_'
1177                  && (unsigned)(c - '0') > 9  /* not number */
1178                  && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
1179                 ) {
1180                         return 0;
1181                 }
1182         }
1183 }
1184
1185 static int assign(const char *s, int cf)
1186 {
1187         const char *cp;
1188         struct var *vp;
1189
1190         DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1191
1192         if (!isalpha(*s) && *s != '_')
1193                 return 0;
1194         for (cp = s; *cp != '='; cp++)
1195                 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1196                         return 0;
1197         vp = lookup(s);
1198         nameval(vp, ++cp, cf == COPYV ? NULL : s);
1199         if (cf != COPYV)
1200                 vp->status &= ~GETCELL;
1201         return 1;
1202 }
1203
1204 static int checkname(char *cp)
1205 {
1206         DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1207
1208         if (!isalpha(*cp++) && *(cp - 1) != '_')
1209                 return 0;
1210         while (*cp)
1211                 if (!isalnum(*cp++) && *(cp - 1) != '_')
1212                         return 0;
1213         return 1;
1214 }
1215
1216 static void putvlist(int f, int out)
1217 {
1218         struct var *vp;
1219
1220         for (vp = vlist; vp; vp = vp->next) {
1221                 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1222                         if (vp->status & EXPORT)
1223                                 write(out, "export ", 7);
1224                         if (vp->status & RONLY)
1225                                 write(out, "readonly ", 9);
1226                         write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1227                         write(out, "\n", 1);
1228                 }
1229         }
1230 }
1231
1232
1233 /*
1234  * trap handling
1235  */
1236 static void sig(int i)
1237 {
1238         trapset = i;
1239         signal(i, sig);
1240 }
1241
1242 static void runtrap(int i)
1243 {
1244         char *trapstr;
1245
1246         trapstr = trap[i];
1247         if (trapstr == NULL)
1248                 return;
1249
1250         if (i == 0)
1251                 trap[i] = NULL;
1252
1253         RUN(aword, trapstr, nlchar);
1254 }
1255
1256
1257 static void setdash(void)
1258 {
1259         char *cp;
1260         int c;
1261         char m['z' - 'a' + 1];
1262
1263         cp = m;
1264         for (c = 'a'; c <= 'z'; c++)
1265                 if (FLAG[c])
1266                         *cp++ = c;
1267         *cp = '\0';
1268         setval(lookup("-"), m);
1269 }
1270
1271 static int newfile(char *s)
1272 {
1273         int f;
1274
1275         DBGPRINTF7(("NEWFILE: opening %s\n", s));
1276
1277         f = 0;
1278         if (NOT_LONE_DASH(s)) {
1279                 DBGPRINTF(("NEWFILE: s is %s\n", s));
1280                 f = open(s, O_RDONLY);
1281                 if (f < 0) {
1282                         prs(s);
1283                         err(": cannot open");
1284                         return 1;
1285                 }
1286         }
1287
1288         next(remap(f));
1289         return 0;
1290 }
1291
1292
1293 struct op *scantree(struct op *head)
1294 {
1295         struct op *dotnode;
1296
1297         if (head == NULL)
1298                 return NULL;
1299
1300         if (head->left != NULL) {
1301                 dotnode = scantree(head->left);
1302                 if (dotnode)
1303                         return dotnode;
1304         }
1305
1306         if (head->right != NULL) {
1307                 dotnode = scantree(head->right);
1308                 if (dotnode)
1309                         return dotnode;
1310         }
1311
1312         if (head->words == NULL)
1313                 return NULL;
1314
1315         DBGPRINTF5(("SCANTREE: checking node %p\n", head));
1316
1317         if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
1318                 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
1319                 return head;
1320         }
1321
1322         return NULL;
1323 }
1324
1325
1326 static void onecommand(void)
1327 {
1328         int i;
1329         jmp_buf m1;
1330
1331         DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
1332
1333         while (global_env.oenv)
1334                 quitenv();
1335
1336         areanum = 1;
1337         freehere(areanum);
1338         freearea(areanum);
1339         garbage();
1340         wdlist = 0;
1341         iolist = 0;
1342         global_env.errpt = 0;
1343         global_env.linep = line;
1344         yynerrs = 0;
1345         multiline = 0;
1346         inparse = 1;
1347         intr = 0;
1348         execflg = 0;
1349
1350         failpt = m1;
1351         setjmp(failpt);         /* Bruce Evans' fix */
1352         failpt = m1;
1353         if (setjmp(failpt) || yyparse() || intr) {
1354                 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1355
1356                 while (global_env.oenv)
1357                         quitenv();
1358                 scraphere();
1359                 if (!interactive && intr)
1360                         leave();
1361                 inparse = 0;
1362                 intr = 0;
1363                 return;
1364         }
1365
1366         inparse = 0;
1367         brklist = 0;
1368         intr = 0;
1369         execflg = 0;
1370
1371         if (!FLAG['n']) {
1372                 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
1373                                    outtree));
1374                 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
1375         }
1376
1377         if (!interactive && intr) {
1378                 execflg = 0;
1379                 leave();
1380         }
1381
1382         i = trapset;
1383         if (i != 0) {
1384                 trapset = 0;
1385                 runtrap(i);
1386         }
1387 }
1388
1389 static int newenv(int f)
1390 {
1391         struct env *ep;
1392
1393         DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1394
1395         if (f) {
1396                 quitenv();
1397                 return 1;
1398         }
1399
1400         ep = (struct env *) space(sizeof(*ep));
1401         if (ep == NULL) {
1402                 while (global_env.oenv)
1403                         quitenv();
1404                 fail();
1405         }
1406         *ep = global_env;
1407         global_env.oenv = ep;
1408         global_env.errpt = errpt;
1409
1410         return 0;
1411 }
1412
1413 static void quitenv(void)
1414 {
1415         struct env *ep;
1416         int fd;
1417
1418         DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
1419
1420         ep = global_env.oenv;
1421         if (ep != NULL) {
1422                 fd = global_env.iofd;
1423                 global_env = *ep;
1424                 /* should close `'d files */
1425                 DELETE(ep);
1426                 while (--fd >= global_env.iofd)
1427                         close(fd);
1428         }
1429 }
1430
1431 /*
1432  * Is character c in s?
1433  */
1434 static int any(int c, const char *s)
1435 {
1436         while (*s)
1437                 if (*s++ == c)
1438                         return 1;
1439         return 0;
1440 }
1441
1442 /*
1443  * Is any character from s1 in s2?
1444  */
1445 static int anys(const char *s1, const char *s2)
1446 {
1447         while (*s1)
1448                 if (any(*s1++, s2))
1449                         return 1;
1450         return 0;
1451 }
1452
1453 static char *putn(int n)
1454 {
1455         return itoa(n);
1456 }
1457
1458 static void next(int f)
1459 {
1460         PUSHIO(afile, f, filechar);
1461 }
1462
1463 static void onintr(int s)                                       /* ANSI C requires a parameter */
1464 {
1465         signal(SIGINT, onintr);
1466         intr = 1;
1467         if (interactive) {
1468                 if (inparse) {
1469                         prs("\n");
1470                         fail();
1471                 }
1472         } else if (heedint) {
1473                 execflg = 0;
1474                 leave();
1475         }
1476 }
1477
1478
1479 /* -------- gmatch.c -------- */
1480 /*
1481  * int gmatch(string, pattern)
1482  * char *string, *pattern;
1483  *
1484  * Match a pattern as in sh(1).
1485  */
1486
1487 #define CMASK   0377
1488 #define QUOTE   0200
1489 #define QMASK   (CMASK & ~QUOTE)
1490 #define NOT     '!'                                     /* might use ^ */
1491
1492 static const char *cclass(const char *p, int sub)
1493 {
1494         int c, d, not, found;
1495
1496         not = (*p == NOT);
1497         if (not != 0)
1498                 p++;
1499         found = not;
1500         do {
1501                 if (*p == '\0')
1502                         return NULL;
1503                 c = *p & CMASK;
1504                 if (p[1] == '-' && p[2] != ']') {
1505                         d = p[2] & CMASK;
1506                         p++;
1507                 } else
1508                         d = c;
1509                 if (c == sub || (c <= sub && sub <= d))
1510                         found = !not;
1511         } while (*++p != ']');
1512         return found ? p + 1 : NULL;
1513 }
1514
1515 static int gmatch(const char *s, const char *p)
1516 {
1517         int sc, pc;
1518
1519         if (s == NULL || p == NULL)
1520                 return 0;
1521
1522         while ((pc = *p++ & CMASK) != '\0') {
1523                 sc = *s++ & QMASK;
1524                 switch (pc) {
1525                 case '[':
1526                         p = cclass(p, sc);
1527                         if (p == NULL)
1528                                 return 0;
1529                         break;
1530
1531                 case '?':
1532                         if (sc == 0)
1533                                 return 0;
1534                         break;
1535
1536                 case '*':
1537                         s--;
1538                         do {
1539                                 if (*p == '\0' || gmatch(s, p))
1540                                         return 1;
1541                         } while (*s++ != '\0');
1542                         return 0;
1543
1544                 default:
1545                         if (sc != (pc & ~QUOTE))
1546                                 return 0;
1547                 }
1548         }
1549         return *s == '\0';
1550 }
1551
1552
1553 /* -------- csyn.c -------- */
1554 /*
1555  * shell: syntax (C version)
1556  */
1557
1558 static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1559 static void yyerror(const char *s)
1560 {
1561         yynerrs = 1;
1562         if (interactive && global_env.iop <= iostack) {
1563                 multiline = 0;
1564                 while (eofc() == 0 && yylex(0) != '\n')
1565                         continue;
1566         }
1567         err(s);
1568         fail();
1569 }
1570
1571 static void zzerr(void) ATTRIBUTE_NORETURN;
1572 static void zzerr(void)
1573 {
1574         yyerror("syntax error");
1575 }
1576
1577 int yyparse(void)
1578 {
1579         DBGPRINTF7(("YYPARSE: enter...\n"));
1580
1581         startl = 1;
1582         peeksym = 0;
1583         yynerrs = 0;
1584         outtree = c_list();
1585         musthave('\n', 0);
1586         return yynerrs; /* 0/1 */
1587 }
1588
1589 static struct op *pipeline(int cf)
1590 {
1591         struct op *t, *p;
1592         int c;
1593
1594         DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1595
1596         t = command(cf);
1597
1598         DBGPRINTF9(("PIPELINE: t=%p\n", t));
1599
1600         if (t != NULL) {
1601                 while ((c = yylex(0)) == '|') {
1602                         p = command(CONTIN);
1603                         if (p == NULL) {
1604                                 DBGPRINTF8(("PIPELINE: error!\n"));
1605                                 zzerr();
1606                         }
1607
1608                         if (t->type != TPAREN && t->type != TCOM) {
1609                                 /* shell statement */
1610                                 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1611                         }
1612
1613                         t = block(TPIPE, t, p, NOWORDS);
1614                 }
1615                 peeksym = c;
1616         }
1617
1618         DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
1619         return t;
1620 }
1621
1622 static struct op *andor(void)
1623 {
1624         struct op *t, *p;
1625         int c;
1626
1627         DBGPRINTF7(("ANDOR: enter...\n"));
1628
1629         t = pipeline(0);
1630
1631         DBGPRINTF9(("ANDOR: t=%p\n", t));
1632
1633         if (t != NULL) {
1634                 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1635                         p = pipeline(CONTIN);
1636                         if (p == NULL) {
1637                                 DBGPRINTF8(("ANDOR: error!\n"));
1638                                 zzerr();
1639                         }
1640
1641                         t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1642                 }                                               /* WHILE */
1643
1644                 peeksym = c;
1645         }
1646
1647         DBGPRINTF7(("ANDOR: returning t=%p\n", t));
1648         return t;
1649 }
1650
1651 static struct op *c_list(void)
1652 {
1653         struct op *t, *p;
1654         int c;
1655
1656         DBGPRINTF7(("C_LIST: enter...\n"));
1657
1658         t = andor();
1659
1660         if (t != NULL) {
1661                 peeksym = yylex(0);
1662                 if (peeksym == '&')
1663                         t = block(TASYNC, t, NOBLOCK, NOWORDS);
1664
1665                 while ((c = yylex(0)) == ';' || c == '&'
1666                            || (multiline && c == '\n')) {
1667
1668                         p = andor();
1669                         if (p== NULL)
1670                                 return t;
1671
1672                         peeksym = yylex(0);
1673                         if (peeksym == '&')
1674                                 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1675
1676                         t = list(t, p);
1677                 }                                               /* WHILE */
1678
1679                 peeksym = c;
1680         }
1681         /* IF */
1682         DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1683         return t;
1684 }
1685
1686 static int synio(int cf)
1687 {
1688         struct ioword *iop;
1689         int i;
1690         int c;
1691
1692         DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1693
1694         c = yylex(cf);
1695         if (c != '<' && c != '>') {
1696                 peeksym = c;
1697                 return 0;
1698         }
1699
1700         i = yylval.i;
1701         musthave(WORD, 0);
1702         iop = io(iounit, i, yylval.cp);
1703         iounit = IODEFAULT;
1704
1705         if (i & IOHERE)
1706                 markhere(yylval.cp, iop);
1707
1708         DBGPRINTF7(("SYNIO: returning 1\n"));
1709         return 1;
1710 }
1711
1712 static void musthave(int c, int cf)
1713 {
1714         peeksym = yylex(cf);
1715         if (peeksym != c) {
1716                 DBGPRINTF7(("MUSTHAVE: error!\n"));
1717                 zzerr();
1718         }
1719
1720         peeksym = 0;
1721 }
1722
1723 static struct op *simple(void)
1724 {
1725         struct op *t;
1726
1727         t = NULL;
1728         for (;;) {
1729                 switch (peeksym = yylex(0)) {
1730                 case '<':
1731                 case '>':
1732                         (void) synio(0);
1733                         break;
1734
1735                 case WORD:
1736                         if (t == NULL) {
1737                                 t = newtp();
1738                                 t->type = TCOM;
1739                         }
1740                         peeksym = 0;
1741                         word(yylval.cp);
1742                         break;
1743
1744                 default:
1745                         return t;
1746                 }
1747         }
1748 }
1749
1750 static struct op *nested(int type, int mark)
1751 {
1752         struct op *t;
1753
1754         DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1755
1756         multiline++;
1757         t = c_list();
1758         musthave(mark, 0);
1759         multiline--;
1760         return block(type, t, NOBLOCK, NOWORDS);
1761 }
1762
1763 static struct op *command(int cf)
1764 {
1765         struct op *t;
1766         struct wdblock *iosave;
1767         int c;
1768
1769         DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1770
1771         iosave = iolist;
1772         iolist = NULL;
1773
1774         if (multiline)
1775                 cf |= CONTIN;
1776
1777         while (synio(cf))
1778                 cf = 0;
1779
1780         c = yylex(cf);
1781
1782         switch (c) {
1783         default:
1784                 peeksym = c;
1785                 t = simple();
1786                 if (t == NULL) {
1787                         if (iolist == NULL)
1788                                 return NULL;
1789                         t = newtp();
1790                         t->type = TCOM;
1791                 }
1792                 break;
1793
1794         case '(':
1795                 t = nested(TPAREN, ')');
1796                 break;
1797
1798         case '{':
1799                 t = nested(TBRACE, '}');
1800                 break;
1801
1802         case FOR:
1803                 t = newtp();
1804                 t->type = TFOR;
1805                 musthave(WORD, 0);
1806                 startl = 1;
1807                 t->str = yylval.cp;
1808                 multiline++;
1809                 t->words = wordlist();
1810                 c = yylex(0);
1811                 if (c != '\n' && c != ';')
1812                         peeksym = c;
1813                 t->left = dogroup(0);
1814                 multiline--;
1815                 break;
1816
1817         case WHILE:
1818         case UNTIL:
1819                 multiline++;
1820                 t = newtp();
1821                 t->type = (c == WHILE ? TWHILE : TUNTIL);
1822                 t->left = c_list();
1823                 t->right = dogroup(1);
1824                 t->words = NULL;
1825                 multiline--;
1826                 break;
1827
1828         case CASE:
1829                 t = newtp();
1830                 t->type = TCASE;
1831                 musthave(WORD, 0);
1832                 t->str = yylval.cp;
1833                 startl++;
1834                 multiline++;
1835                 musthave(IN, CONTIN);
1836                 startl++;
1837
1838                 t->left = caselist();
1839
1840                 musthave(ESAC, 0);
1841                 multiline--;
1842                 break;
1843
1844         case IF:
1845                 multiline++;
1846                 t = newtp();
1847                 t->type = TIF;
1848                 t->left = c_list();
1849                 t->right = thenpart();
1850                 musthave(FI, 0);
1851                 multiline--;
1852                 break;
1853
1854         case DOT:
1855                 t = newtp();
1856                 t->type = TDOT;
1857
1858                 musthave(WORD, 0);              /* gets name of file */
1859                 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1860
1861                 word(yylval.cp);                /* add word to wdlist */
1862                 word(NOWORD);                   /* terminate  wdlist */
1863                 t->words = copyw();             /* dup wdlist */
1864                 break;
1865
1866         }
1867
1868         while (synio(0));
1869
1870         t = namelist(t);
1871         iolist = iosave;
1872
1873         DBGPRINTF(("COMMAND: returning %p\n", t));
1874
1875         return t;
1876 }
1877
1878 static struct op *dowholefile(int type, int mark)
1879 {
1880         struct op *t;
1881
1882         DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1883
1884         multiline++;
1885         t = c_list();
1886         multiline--;
1887         t = block(type, t, NOBLOCK, NOWORDS);
1888         DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
1889         return t;
1890 }
1891
1892 static struct op *dogroup(int onlydone)
1893 {
1894         int c;
1895         struct op *mylist;
1896
1897         c = yylex(CONTIN);
1898         if (c == DONE && onlydone)
1899                 return NULL;
1900         if (c != DO)
1901                 zzerr();
1902         mylist = c_list();
1903         musthave(DONE, 0);
1904         return mylist;
1905 }
1906
1907 static struct op *thenpart(void)
1908 {
1909         int c;
1910         struct op *t;
1911
1912         c = yylex(0);
1913         if (c != THEN) {
1914                 peeksym = c;
1915                 return NULL;
1916         }
1917         t = newtp();
1918         /*t->type = 0; - newtp() did this */
1919         t->left = c_list();
1920         if (t->left == NULL)
1921                 zzerr();
1922         t->right = elsepart();
1923         return t;
1924 }
1925
1926 static struct op *elsepart(void)
1927 {
1928         int c;
1929         struct op *t;
1930
1931         switch (c = yylex(0)) {
1932         case ELSE:
1933                 t = c_list();
1934                 if (t == NULL)
1935                         zzerr();
1936                 return t;
1937
1938         case ELIF:
1939                 t = newtp();
1940                 t->type = TELIF;
1941                 t->left = c_list();
1942                 t->right = thenpart();
1943                 return t;
1944
1945         default:
1946                 peeksym = c;
1947                 return NULL;
1948         }
1949 }
1950
1951 static struct op *caselist(void)
1952 {
1953         struct op *t;
1954
1955         t = NULL;
1956         while ((peeksym = yylex(CONTIN)) != ESAC) {
1957                 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
1958                 t = list(t, casepart());
1959         }
1960
1961         DBGPRINTF(("CASELIST, returning t=%p\n", t));
1962         return t;
1963 }
1964
1965 static struct op *casepart(void)
1966 {
1967         struct op *t;
1968
1969         DBGPRINTF7(("CASEPART: enter...\n"));
1970
1971         t = newtp();
1972         t->type = TPAT;
1973         t->words = pattern();
1974         musthave(')', 0);
1975         t->left = c_list();
1976         peeksym = yylex(CONTIN);
1977         if (peeksym != ESAC)
1978                 musthave(BREAK, CONTIN);
1979
1980         DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
1981
1982         return t;
1983 }
1984
1985 static char **pattern(void)
1986 {
1987         int c, cf;
1988
1989         cf = CONTIN;
1990         do {
1991                 musthave(WORD, cf);
1992                 word(yylval.cp);
1993                 cf = 0;
1994                 c = yylex(0);
1995         } while (c == '|');
1996         peeksym = c;
1997         word(NOWORD);
1998
1999         return copyw();
2000 }
2001
2002 static char **wordlist(void)
2003 {
2004         int c;
2005
2006         c = yylex(0);
2007         if (c != IN) {
2008                 peeksym = c;
2009                 return NULL;
2010         }
2011         startl = 0;
2012         while ((c = yylex(0)) == WORD)
2013                 word(yylval.cp);
2014         word(NOWORD);
2015         peeksym = c;
2016         return copyw();
2017 }
2018
2019 /*
2020  * supporting functions
2021  */
2022 static struct op *list(struct op *t1, struct op *t2)
2023 {
2024         DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
2025
2026         if (t1 == NULL)
2027                 return t2;
2028         if (t2 == NULL)
2029                 return t1;
2030
2031         return block(TLIST, t1, t2, NOWORDS);
2032 }
2033
2034 static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
2035 {
2036         struct op *t;
2037
2038         DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2039
2040         t = newtp();
2041         t->type = type;
2042         t->left = t1;
2043         t->right = t2;
2044         t->words = wp;
2045
2046         DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
2047
2048         return t;
2049 }
2050
2051 /* See if given string is a shell multiline (FOR, IF, etc) */
2052 static int rlookup(char *n)
2053 {
2054         struct res {
2055                 char r_name[6];
2056                 int16_t r_val;
2057         };
2058         static const struct res restab[] = {
2059                 { "for"  , FOR    },
2060                 { "case" , CASE   },
2061                 { "esac" , ESAC   },
2062                 { "while", WHILE  },
2063                 { "do"   , DO     },
2064                 { "done" , DONE   },
2065                 { "if"   , IF     },
2066                 { "in"   , IN     },
2067                 { "then" , THEN   },
2068                 { "else" , ELSE   },
2069                 { "elif" , ELIF   },
2070                 { "until", UNTIL  },
2071                 { "fi"   , FI     },
2072                 { ";;"   , BREAK  },
2073                 { "||"   , LOGOR  },
2074                 { "&&"   , LOGAND },
2075                 { "{"    , '{'    },
2076                 { "}"    , '}'    },
2077                 { "."    , DOT    },
2078                 { },
2079         };
2080
2081         const struct res *rp;
2082
2083         DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2084
2085         for (rp = restab; rp->r_name[0]; rp++)
2086                 if (strcmp(rp->r_name, n) == 0) {
2087                         DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2088                         return rp->r_val;       /* Return numeric code for shell multiline */
2089                 }
2090
2091         DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2092         return 0;                                       /* Not a shell multiline */
2093 }
2094
2095 static struct op *newtp(void)
2096 {
2097         struct op *t;
2098
2099         t = (struct op *) tree(sizeof(*t));
2100         memset(t, 0, sizeof(*t));
2101
2102         DBGPRINTF3(("NEWTP: allocated %p\n", t));
2103
2104         return t;
2105 }
2106
2107 static struct op *namelist(struct op *t)
2108 {
2109         DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
2110                                 T_CMD_NAMES[t->type], iolist));
2111
2112         if (iolist) {
2113                 iolist = addword((char *) NULL, iolist);
2114                 t->ioact = copyio();
2115         } else
2116                 t->ioact = NULL;
2117
2118         if (t->type != TCOM) {
2119                 if (t->type != TPAREN && t->ioact != NULL) {
2120                         t = block(TPAREN, t, NOBLOCK, NOWORDS);
2121                         t->ioact = t->left->ioact;
2122                         t->left->ioact = NULL;
2123                 }
2124                 return t;
2125         }
2126
2127         word(NOWORD);
2128         t->words = copyw();
2129
2130         return t;
2131 }
2132
2133 static char **copyw(void)
2134 {
2135         char **wd;
2136
2137         wd = getwords(wdlist);
2138         wdlist = 0;
2139         return wd;
2140 }
2141
2142 static void word(char *cp)
2143 {
2144         wdlist = addword(cp, wdlist);
2145 }
2146
2147 static struct ioword **copyio(void)
2148 {
2149         struct ioword **iop;
2150
2151         iop = (struct ioword **) getwords(iolist);
2152         iolist = 0;
2153         return iop;
2154 }
2155
2156 static struct ioword *io(int u, int f, char *cp)
2157 {
2158         struct ioword *iop;
2159
2160         iop = (struct ioword *) tree(sizeof(*iop));
2161         iop->io_unit = u;
2162         iop->io_flag = f;
2163         iop->io_name = cp;
2164         iolist = addword((char *) iop, iolist);
2165         return iop;
2166 }
2167
2168 static int yylex(int cf)
2169 {
2170         int c, c1;
2171         int atstart;
2172
2173         c = peeksym;
2174         if (c > 0) {
2175                 peeksym = 0;
2176                 if (c == '\n')
2177                         startl = 1;
2178                 return c;
2179         }
2180
2181         nlseen = 0;
2182         atstart = startl;
2183         startl = 0;
2184         yylval.i = 0;
2185         global_env.linep = line;
2186
2187 /* MALAMO */
2188         line[LINELIM - 1] = '\0';
2189
2190  loop:
2191         while ((c = my_getc(0)) == ' ' || c == '\t')    /* Skip whitespace */
2192                 ;
2193
2194         switch (c) {
2195         default:
2196                 if (any(c, "0123456789")) {
2197                         c1 = my_getc(0);
2198                         unget(c1);
2199                         if (c1 == '<' || c1 == '>') {
2200                                 iounit = c - '0';
2201                                 goto loop;
2202                         }
2203                         *global_env.linep++ = c;
2204                         c = c1;
2205                 }
2206                 break;
2207
2208         case '#':                                       /* Comment, skip to next newline or End-of-string */
2209                 while ((c = my_getc(0)) != '\0' && c != '\n');
2210                 unget(c);
2211                 goto loop;
2212
2213         case 0:
2214                 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2215                 return c;
2216
2217         case '$':
2218                 DBGPRINTF9(("YYLEX: found $\n"));
2219                 *global_env.linep++ = c;
2220                 c = my_getc(0);
2221                 if (c == '{') {
2222                         c = collect(c, '}');
2223                         if (c != '\0')
2224                                 return c;
2225                         goto pack;
2226                 }
2227                 break;
2228
2229         case '`':
2230         case '\'':
2231         case '"':
2232                 c = collect(c, c);
2233                 if (c != '\0')
2234                         return c;
2235                 goto pack;
2236
2237         case '|':
2238         case '&':
2239         case ';':
2240                 startl = 1;
2241                 /* If more chars process them, else return NULL char */
2242                 c1 = dual(c);
2243                 if (c1 != '\0')
2244                         return c1;
2245                 return c;
2246
2247         case '^':
2248                 startl = 1;
2249                 return '|';
2250         case '>':
2251         case '<':
2252                 diag(c);
2253                 return c;
2254
2255         case '\n':
2256                 nlseen++;
2257                 gethere();
2258                 startl = 1;
2259                 if (multiline || cf & CONTIN) {
2260                         if (interactive && global_env.iop <= iostack) {
2261 #if ENABLE_FEATURE_EDITING
2262                                 current_prompt = cprompt->value;
2263 #else
2264                                 prs(cprompt->value);
2265 #endif
2266                         }
2267                         if (cf & CONTIN)
2268                                 goto loop;
2269                 }
2270                 return c;
2271
2272         case '(':
2273         case ')':
2274                 startl = 1;
2275                 return c;
2276         }
2277
2278         unget(c);
2279
2280  pack:
2281         while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
2282                 if (global_env.linep >= elinep)
2283                         err("word too long");
2284                 else
2285                         *global_env.linep++ = c;
2286         };
2287
2288         unget(c);
2289
2290         if (any(c, "\"'`$"))
2291                 goto loop;
2292
2293         *global_env.linep++ = '\0';
2294
2295         if (atstart) {
2296                 c = rlookup(line);
2297                 if (c != 0) {
2298                         startl = 1;
2299                         return c;
2300                 }
2301         }
2302
2303         yylval.cp = strsave(line, areanum);
2304         return WORD;
2305 }
2306
2307
2308 static int collect(int c, int c1)
2309 {
2310         char s[2];
2311
2312         DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2313
2314         *global_env.linep++ = c;
2315         while ((c = my_getc(c1)) != c1) {
2316                 if (c == 0) {
2317                         unget(c);
2318                         s[0] = c1;
2319                         s[1] = 0;
2320                         prs("no closing ");
2321                         yyerror(s);
2322                         return YYERRCODE;
2323                 }
2324                 if (interactive && c == '\n' && global_env.iop <= iostack) {
2325 #if ENABLE_FEATURE_EDITING
2326                         current_prompt = cprompt->value;
2327 #else
2328                         prs(cprompt->value);
2329 #endif
2330                 }
2331                 *global_env.linep++ = c;
2332         }
2333
2334         *global_env.linep++ = c;
2335
2336         DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2337
2338         return 0;
2339 }
2340
2341 /* "multiline commands" helper func */
2342 /* see if next 2 chars form a shell multiline */
2343 static int dual(int c)
2344 {
2345         char s[3];
2346         char *cp = s;
2347
2348         DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2349
2350         *cp++ = c;              /* c is the given "peek" char */
2351         *cp++ = my_getc(0);     /* get next char of input */
2352         *cp = '\0';             /* add EOS marker */
2353
2354         c = rlookup(s);         /* see if 2 chars form a shell multiline */
2355         if (c == 0)
2356                 unget(*--cp);   /* String is not a shell multiline, put peek char back */
2357
2358         return c;               /* String is multiline, return numeric multiline (restab) code */
2359 }
2360
2361 static void diag(int ec)
2362 {
2363         int c;
2364
2365         DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2366
2367         c = my_getc(0);
2368         if (c == '>' || c == '<') {
2369                 if (c != ec)
2370                         zzerr();
2371                 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
2372                 c = my_getc(0);
2373         } else
2374                 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
2375         if (c != '&' || yylval.i == IOHERE)
2376                 unget(c);
2377         else
2378                 yylval.i |= IODUP;
2379 }
2380
2381 static char *tree(unsigned size)
2382 {
2383         char *t;
2384
2385         t = getcell(size);
2386         if (t == NULL) {
2387                 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2388                 prs("command line too complicated\n");
2389                 fail();
2390                 /* NOTREACHED */
2391         }
2392         return t;
2393 }
2394
2395
2396 /* VARARGS1 */
2397 /* ARGSUSED */
2398
2399 /* -------- exec.c -------- */
2400
2401 static struct op **find1case(struct op *t, const char *w)
2402 {
2403         struct op *t1;
2404         struct op **tp;
2405         char **wp;
2406         char *cp;
2407
2408         if (t == NULL) {
2409                 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2410                 return NULL;
2411         }
2412
2413         DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2414                                 T_CMD_NAMES[t->type]));
2415
2416         if (t->type == TLIST) {
2417                 tp = find1case(t->left, w);
2418                 if (tp != NULL) {
2419                         DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2420                         return tp;
2421                 }
2422                 t1 = t->right;                  /* TPAT */
2423         } else
2424                 t1 = t;
2425
2426         for (wp = t1->words; *wp;) {
2427                 cp = evalstr(*wp++, DOSUB);
2428                 if (cp && gmatch(w, cp)) {
2429                         DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2430                                                 &t1->left));
2431                         return &t1->left;
2432                 }
2433         }
2434
2435         DBGPRINTF(("FIND1CASE: returning NULL\n"));
2436         return NULL;
2437 }
2438
2439 static struct op *findcase(struct op *t, const char *w)
2440 {
2441         struct op **tp;
2442
2443         tp = find1case(t, w);
2444         return tp != NULL ? *tp : NULL;
2445 }
2446
2447 /*
2448  * execute tree
2449  */
2450
2451 static int execute(struct op *t, int *pin, int *pout, int no_fork)
2452 {
2453         struct op *t1;
2454         volatile int i, rv, a;
2455         const char *cp;
2456         char **wp, **wp2;
2457         struct var *vp;
2458         struct op *outtree_save;
2459         struct brkcon bc;
2460
2461 #if __GNUC__
2462         /* Avoid longjmp clobbering */
2463         (void) &wp;
2464 #endif
2465
2466         if (t == NULL) {
2467                 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2468                 return 0;
2469         }
2470
2471         DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
2472                            t->type, T_CMD_NAMES[t->type],
2473                            ((t->words == NULL) ? "NULL" : t->words[0])));
2474
2475         rv = 0;
2476         a = areanum++;
2477         wp2 = t->words;
2478         wp = (wp2 != NULL)
2479                 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2480                 : NULL;
2481
2482         switch (t->type) {
2483         case TDOT:
2484                 DBGPRINTF3(("EXECUTE: TDOT\n"));
2485
2486                 outtree_save = outtree;
2487
2488                 newfile(evalstr(t->words[0], DOALL));
2489
2490                 t->left = dowholefile(TLIST, 0);
2491                 t->right = NULL;
2492
2493                 outtree = outtree_save;
2494
2495                 if (t->left)
2496                         rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2497                 if (t->right)
2498                         rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2499                 break;
2500
2501         case TPAREN:
2502                 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2503                 break;
2504
2505         case TCOM:
2506                 rv = forkexec(t, pin, pout, no_fork, wp);
2507                 break;
2508
2509         case TPIPE:
2510                 {
2511                         int pv[2];
2512
2513                         rv = openpipe(pv);
2514                         if (rv < 0)
2515                                 break;
2516                         pv[0] = remap(pv[0]);
2517                         pv[1] = remap(pv[1]);
2518                         (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2519                         rv = execute(t->right, pv, pout, /* no_fork: */ 0);
2520                 }
2521                 break;
2522
2523         case TLIST:
2524                 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2525                 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2526                 break;
2527
2528         case TASYNC:
2529                 {
2530                         smallint hinteractive = interactive;
2531
2532                         DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2533
2534                         i = vfork();
2535                         if (i == 0) { /* child */
2536                                 signal(SIGINT, SIG_IGN);
2537                                 signal(SIGQUIT, SIG_IGN);
2538                                 if (interactive)
2539                                         signal(SIGTERM, SIG_DFL);
2540                                 interactive = 0;
2541                                 if (pin == NULL) {
2542                                         close(0);
2543                                         xopen(bb_dev_null, O_RDONLY);
2544                                 }
2545                                 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
2546                         }
2547                         interactive = hinteractive;
2548                         if (i != -1) {
2549                                 setval(lookup("!"), putn(i));
2550                                 closepipe(pin);
2551                                 if (interactive) {
2552                                         prs(putn(i));
2553                                         prs("\n");
2554                                 }
2555                         } else
2556                                 rv = -1;
2557                         setstatus(rv);
2558                 }
2559                 break;
2560
2561         case TOR:
2562         case TAND:
2563                 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
2564                 t1 = t->right;
2565                 if (t1 != NULL && (rv == 0) == (t->type == TAND))
2566                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2567                 break;
2568
2569         case TFOR:
2570                 if (wp == NULL) {
2571                         wp = dolv + 1;
2572                         i = dolc;
2573                         if (i < 0)
2574                                 i = 0;
2575                 } else {
2576                         i = -1;
2577                         while (*wp++ != NULL);
2578                 }
2579                 vp = lookup(t->str);
2580                 while (setjmp(bc.brkpt))
2581                         if (isbreak)
2582                                 goto broken;
2583                 brkset(&bc);
2584                 for (t1 = t->left; i-- && *wp != NULL;) {
2585                         setval(vp, *wp++);
2586                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2587                 }
2588                 brklist = brklist->nextlev;
2589                 break;
2590
2591         case TWHILE:
2592         case TUNTIL:
2593                 while (setjmp(bc.brkpt))
2594                         if (isbreak)
2595                                 goto broken;
2596                 brkset(&bc);
2597                 t1 = t->left;
2598                 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
2599                         rv = execute(t->right, pin, pout, /* no_fork: */ 0);
2600                 brklist = brklist->nextlev;
2601                 break;
2602
2603         case TIF:
2604         case TELIF:
2605                 if (t->right != NULL) {
2606                         rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2607                                 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2608                                 execute(t->right->right, pin, pout, /* no_fork: */ 0);
2609                 }
2610                 break;
2611
2612         case TCASE:
2613                 cp = evalstr(t->str, DOSUB | DOTRIM);
2614                 if (cp == NULL)
2615                         cp = "";
2616
2617                 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2618                                         ((t->str == NULL) ? "NULL" : t->str),
2619                                         ((cp == NULL) ? "NULL" : cp)));
2620
2621                 t1 = findcase(t->left, cp);
2622                 if (t1 != NULL) {
2623                         DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
2624                         rv = execute(t1, pin, pout, /* no_fork: */ 0);
2625                         DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2626                 }
2627                 break;
2628
2629         case TBRACE:
2630 /*
2631                 iopp = t->ioact;
2632                 if (i)
2633                         while (*iopp)
2634                                 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2635                                         rv = -1;
2636                                         break;
2637                                 }
2638 */
2639                 if (rv >= 0) {
2640                         t1 = t->left;
2641                         if (t1) {
2642                                 rv = execute(t1, pin, pout, /* no_fork: */ 0);
2643                         }
2644                 }
2645                 break;
2646
2647         };
2648
2649  broken:
2650         t->words = wp2;
2651         isbreak = 0;
2652         freehere(areanum);
2653         freearea(areanum);
2654         areanum = a;
2655         if (interactive && intr) {
2656                 closeall();
2657                 fail();
2658         }
2659
2660         i = trapset;
2661         if (i != 0) {
2662                 trapset = 0;
2663                 runtrap(i);
2664         }
2665
2666         DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
2667         return rv;
2668 }
2669
2670 static builtin_func_ptr inbuilt(const char *s)
2671 {
2672         const struct builtincmd *bp;
2673
2674         for (bp = builtincmds; bp->name; bp++)
2675                 if (strcmp(bp->name, s) == 0)
2676                         return bp->builtinfunc;
2677         return NULL;
2678 }
2679
2680 static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
2681 {
2682         pid_t newpid;
2683         int i;
2684         builtin_func_ptr bltin = NULL;
2685         const char *bltin_name = NULL;
2686         const char *cp;
2687         struct ioword **iopp;
2688         int resetsig;
2689         char **owp;
2690         int forked;
2691
2692         int *hpin = pin;
2693         int *hpout = pout;
2694         char *hwp;
2695         smallint hinteractive;
2696         smallint hintr;
2697         smallint hexecflg;
2698         struct brkcon *hbrklist;
2699
2700 #if __GNUC__
2701         /* Avoid longjmp clobbering */
2702         (void) &pin;
2703         (void) &pout;
2704         (void) &wp;
2705         (void) &bltin;
2706         (void) &cp;
2707         (void) &resetsig;
2708         (void) &owp;
2709 #endif
2710
2711         DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2712                         pout, no_fork));
2713         DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2714                         ((t->words == NULL) ? "NULL" : t->words[0])));
2715         owp = wp;
2716         resetsig = 0;
2717         if (t->type == TCOM) {
2718                 while (*wp++ != NULL)
2719                         continue;
2720                 cp = *wp;
2721
2722                 /* strip all initial assignments */
2723                 /* FIXME: not correct wrt PATH=yyy command etc */
2724                 if (FLAG['x']) {
2725                         DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
2726                                                 cp, wp, owp));
2727                         echo(cp ? wp : owp);
2728                 }
2729
2730                 if (cp == NULL) {
2731                         if (t->ioact == NULL) {
2732                                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2733                                         continue;
2734                                 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2735                                 return setstatus(0);
2736                         }
2737                 } else { /* cp != NULL */
2738                         bltin_name = cp;
2739                         bltin = inbuilt(cp);
2740                 }
2741         }
2742
2743         forked = 0;
2744         t->words = wp;
2745         DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2746                         no_fork, owp));
2747         /* Don't fork if it is a lone builtin (not in pipe)
2748          * OR we are told to _not_ fork */
2749         if ((!bltin || pin || pout)   /* not lone bltin AND */
2750          && !no_fork                  /* not told to avoid fork */
2751         ) {
2752                 /* Save values in case child alters them after vfork */
2753                 hpin = pin;
2754                 hpout = pout;
2755                 hwp = *wp;
2756                 hinteractive = interactive;
2757                 hintr = intr;
2758                 hbrklist = brklist;
2759                 hexecflg = execflg;
2760
2761                 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2762                 newpid = vfork();
2763                 if (newpid == -1) {
2764                         DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
2765                         return -1;
2766                 }
2767
2768                 if (newpid > 0) {  /* Parent */
2769                         /* Restore values */
2770                         pin = hpin;
2771                         pout = hpout;
2772                         *wp = hwp;
2773                         interactive = hinteractive;
2774                         intr = hintr;
2775                         brklist = hbrklist;
2776                         execflg = hexecflg;
2777
2778                         closepipe(pin);
2779                         return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2780                 }
2781
2782                 /* Child */
2783                 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
2784                 if (interactive) {
2785                         signal(SIGINT, SIG_IGN);
2786                         signal(SIGQUIT, SIG_IGN);
2787                         resetsig = 1;
2788                 }
2789                 interactive = 0;
2790                 intr = 0;
2791                 forked = 1;
2792                 brklist = 0;
2793                 execflg = 0;
2794         }
2795
2796         if (owp)
2797                 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2798                         if (!bltin)
2799                                 export(lookup(cp));
2800
2801         if (pin) { /* NB: close _first_, then move fds! */
2802                 close(pin[1]);
2803                 xmove_fd(pin[0], 0);
2804         }
2805         if (pout) {
2806                 close(pout[0]);
2807                 xmove_fd(pout[1], 1);
2808         }
2809
2810         iopp = t->ioact;
2811         if (iopp) {
2812                 if (bltin && bltin != doexec) {
2813                         prs(bltin_name);
2814                         err(": cannot redirect shell command");
2815                         if (forked)
2816                                 _exit(-1);
2817                         return -1;
2818                 }
2819                 while (*iopp) {
2820                         if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2821                                 /* system-detected error */
2822                                 if (forked)
2823                                         _exit(-1);
2824                                 return -1;
2825                         }
2826                 }
2827         }
2828
2829         if (bltin) {
2830                 if (forked || pin || pout) {
2831                         /* Builtin in pipe: disallowed */
2832                         /* TODO: allow "exec"? */
2833                         prs(bltin_name);
2834                         err(": cannot run builtin as part of pipe");
2835                         if (forked)
2836                                 _exit(-1);
2837                         return -1;
2838                 }
2839                 i = setstatus(bltin(t));
2840                 if (forked)
2841                         _exit(i);
2842                 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
2843                 return i;
2844         }
2845
2846         /* should use FIOCEXCL */
2847         for (i = FDBASE; i < NOFILE; i++)
2848                 close(i);
2849         if (resetsig) {
2850                 signal(SIGINT, SIG_DFL);
2851                 signal(SIGQUIT, SIG_DFL);
2852         }
2853
2854         if (t->type == TPAREN)
2855                 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
2856         if (wp[0] == NULL)
2857                 _exit(0);
2858
2859         cp = rexecve(wp[0], wp, makenv(0, NULL));
2860         prs(wp[0]);
2861         prs(": ");
2862         err(cp);
2863         if (!execflg)
2864                 trap[0] = NULL;
2865
2866         DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
2867
2868         leave();
2869         /* NOTREACHED */
2870         return 0;
2871 }
2872
2873 /*
2874  * 0< 1> are ignored as required
2875  * within pipelines.
2876  */
2877 static int iosetup(struct ioword *iop, int pipein, int pipeout)
2878 {
2879         int u = -1;
2880         char *cp = NULL;
2881         const char *msg;
2882
2883         DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
2884                            pipein, pipeout));
2885
2886         if (iop->io_unit == IODEFAULT)  /* take default */
2887                 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
2888
2889         if (pipein && iop->io_unit == 0)
2890                 return 0;
2891
2892         if (pipeout && iop->io_unit == 1)
2893                 return 0;
2894
2895         msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
2896         if ((iop->io_flag & IOHERE) == 0) {
2897                 cp = iop->io_name; /* huh?? */
2898                 cp = evalstr(cp, DOSUB | DOTRIM);
2899                 if (cp == NULL)
2900                         return 1;
2901         }
2902
2903         if (iop->io_flag & IODUP) {
2904                 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2905                         prs(cp);
2906                         err(": illegal >& argument");
2907                         return 1;
2908                 }
2909                 if (*cp == '-')
2910                         iop->io_flag = IOCLOSE;
2911                 iop->io_flag &= ~(IOREAD | IOWRITE);
2912         }
2913
2914         switch (iop->io_flag) {
2915         case IOREAD:
2916                 u = open(cp, O_RDONLY);
2917                 break;
2918
2919         case IOHERE:
2920         case IOHERE | IOXHERE:
2921                 u = herein(iop->io_name, iop->io_flag & IOXHERE);
2922                 cp = (char*)"here file";
2923                 break;
2924
2925         case IOWRITE | IOCAT:
2926                 u = open(cp, O_WRONLY);
2927                 if (u >= 0) {
2928                         lseek(u, (long) 0, SEEK_END);
2929                         break;
2930                 }
2931                 /* fall through to creation if >>file doesn't exist */
2932
2933         case IOWRITE:
2934                 u = creat(cp, 0666);
2935                 break;
2936
2937         case IODUP:
2938                 u = dup2(*cp - '0', iop->io_unit);
2939                 break;
2940
2941         case IOCLOSE:
2942                 close(iop->io_unit);
2943                 return 0;
2944         }
2945
2946         if (u < 0) {
2947                 prs(cp);
2948                 prs(": cannot ");
2949                 warn(msg);
2950                 return 1;
2951         }
2952         if (u != iop->io_unit) {
2953                 dup2(u, iop->io_unit);
2954                 close(u);
2955         }
2956         return 0;
2957 }
2958
2959 /*
2960  * Enter a new loop level (marked for break/continue).
2961  */
2962 static void brkset(struct brkcon *bc)
2963 {
2964         bc->nextlev = brklist;
2965         brklist = bc;
2966 }
2967
2968 /*
2969  * Wait for the last process created.
2970  * Print a message for each process found
2971  * that was killed by a signal.
2972  * Ignore interrupt signals while waiting
2973  * unless `canintr' is true.
2974  */
2975 static int waitfor(int lastpid, int canintr)
2976 {
2977         int pid, rv;
2978         int s;
2979         smallint oheedint = heedint;
2980
2981         heedint = 0;
2982         rv = 0;
2983         do {
2984                 pid = wait(&s);
2985                 if (pid == -1) {
2986                         if (errno != EINTR || canintr)
2987                                 break;
2988                 } else {
2989                         rv = WAITSIG(s);
2990                         if (rv != 0) {
2991                                 if (rv < ARRAY_SIZE(signame)) {
2992                                         if (signame[rv] != NULL) {
2993                                                 if (pid != lastpid) {
2994                                                         prn(pid);
2995                                                         prs(": ");
2996                                                 }
2997                                                 prs(signame[rv]);
2998                                         }
2999                                 } else {
3000                                         if (pid != lastpid) {
3001                                                 prn(pid);
3002                                                 prs(": ");
3003                                         }
3004                                         prs("Signal ");
3005                                         prn(rv);
3006                                         prs(" ");
3007                                 }
3008                                 if (WAITCORE(s))
3009                                         prs(" - core dumped");
3010                                 if (rv >= ARRAY_SIZE(signame) || signame[rv])
3011                                         prs("\n");
3012                                 rv = -1;
3013                         } else
3014                                 rv = WAITVAL(s);
3015                 }
3016         } while (pid != lastpid);
3017         heedint = oheedint;
3018         if (intr) {
3019                 if (interactive) {
3020                         if (canintr)
3021                                 intr = 0;
3022                 } else {
3023                         if (exstat == 0)
3024                                 exstat = rv;
3025                         onintr(0);
3026                 }
3027         }
3028         return rv;
3029 }
3030
3031 static int setstatus(int s)
3032 {
3033         exstat = s;
3034         setval(lookup("?"), putn(s));
3035         return s;
3036 }
3037
3038 /*
3039  * PATH-searching interface to execve.
3040  * If getenv("PATH") were kept up-to-date,
3041  * execvp might be used.
3042  */
3043 static const char *rexecve(char *c, char **v, char **envp)
3044 {
3045         int i;
3046         const char *sp;
3047         char *tp;
3048         int asis = 0;
3049         char *name = c;
3050
3051         if (ENABLE_FEATURE_SH_STANDALONE) {
3052                 if (find_applet_by_name(name) >= 0) {
3053                         /* We have to exec here since we vforked.  Running
3054                          * run_applet_and_exit() won't work and bad things
3055                          * will happen. */
3056                         execve(bb_busybox_exec_path, v, envp);
3057                 }
3058         }
3059
3060         DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3061
3062         sp = any('/', c) ? "" : path->value;
3063         asis = (*sp == '\0');
3064         while (asis || *sp != '\0') {
3065                 asis = 0;
3066                 tp = global_env.linep;
3067                 for (; *sp != '\0'; tp++) {
3068                         *tp = *sp++;
3069                         if (*tp == ':') {
3070                                 asis = (*sp == '\0');
3071                                 break;
3072                         }
3073                 }
3074                 if (tp != global_env.linep)
3075                         *tp++ = '/';
3076                 for (i = 0; (*tp++ = c[i++]) != '\0';);
3077
3078                 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
3079
3080                 execve(global_env.linep, v, envp);
3081
3082                 switch (errno) {
3083                 case ENOEXEC:
3084                         *v = global_env.linep;
3085                         tp = *--v;
3086                         *v = global_env.linep;
3087                         execve(DEFAULT_SHELL, v, envp);
3088                         *v = tp;
3089                         return "no Shell";
3090
3091                 case ENOMEM:
3092                         return (char *) bb_msg_memory_exhausted;
3093
3094                 case E2BIG:
3095                         return "argument list too long";
3096                 }
3097         }
3098         return errno == ENOENT ? "not found" : "cannot execute";
3099 }
3100
3101 /*
3102  * Run the command produced by generator `f'
3103  * applied to stream `arg'.
3104  */
3105 static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3106 {
3107         struct op *otree;
3108         struct wdblock *swdlist;
3109         struct wdblock *siolist;
3110         jmp_buf ev, rt;
3111         xint *ofail;
3112         int rv;
3113
3114 #if __GNUC__
3115         /* Avoid longjmp clobbering */
3116         (void) &rv;
3117 #endif
3118
3119         DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3120                            areanum, outtree, failpt));
3121
3122         areanum++;
3123         swdlist = wdlist;
3124         siolist = iolist;
3125         otree = outtree;
3126         ofail = failpt;
3127         rv = -1;
3128
3129         errpt = ev;
3130         if (newenv(setjmp(errpt)) == 0) {
3131                 wdlist = 0;
3132                 iolist = 0;
3133                 pushio(argp, f);
3134                 global_env.iobase = global_env.iop;
3135                 yynerrs = 0;
3136                 failpt = rt;
3137                 if (setjmp(failpt) == 0 && yyparse() == 0)
3138                         rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
3139                 quitenv();
3140         } else {
3141                 DBGPRINTF(("RUN: error from newenv()!\n"));
3142         }
3143
3144         wdlist = swdlist;
3145         iolist = siolist;
3146         failpt = ofail;
3147         outtree = otree;
3148         freearea(areanum--);
3149
3150         return rv;
3151 }
3152
3153 /* -------- do.c -------- */
3154
3155 /*
3156  * built-in commands: doX
3157  */
3158
3159 static int dohelp(struct op *t)
3160 {
3161         int col;
3162         const struct builtincmd *x;
3163
3164         puts("\nBuilt-in commands:\n"
3165              "-------------------");
3166
3167         col = 0;
3168         x = builtincmds;
3169         while (x->name) {
3170                 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
3171                 if (col > 60) {
3172                         bb_putchar('\n');
3173                         col = 0;
3174                 }
3175                 x++;
3176         }
3177 #if ENABLE_FEATURE_SH_STANDALONE
3178         {
3179                 const char *applet = applet_names;
3180
3181                 while (*applet) {
3182                         col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
3183                         if (col > 60) {
3184                                 bb_putchar('\n');
3185                                 col = 0;
3186                         }
3187                         applet += strlen(applet) + 1;
3188                 }
3189         }
3190 #endif
3191         puts("\n");
3192         return EXIT_SUCCESS;
3193 }
3194
3195 static int dolabel(struct op *t)
3196 {
3197         return 0;
3198 }
3199
3200 static int dochdir(struct op *t)
3201 {
3202         const char *cp, *er;
3203
3204         cp = t->words[1];
3205         if (cp == NULL) {
3206                 cp = homedir->value;
3207                 if (cp != NULL)
3208                         goto do_cd;
3209                 er = ": no home directory";
3210         } else {
3211  do_cd:
3212                 if (chdir(cp) >= 0)
3213                         return 0;
3214                 er = ": bad directory";
3215         }
3216         prs(cp != NULL ? cp : "cd");
3217         err(er);
3218         return 1;
3219 }
3220
3221 static int doshift(struct op *t)
3222 {
3223         int n;
3224
3225         n = t->words[1] ? getn(t->words[1]) : 1;
3226         if (dolc < n) {
3227                 err("nothing to shift");
3228                 return 1;
3229         }
3230         dolv[n] = dolv[0];
3231         dolv += n;
3232         dolc -= n;
3233         setval(lookup("#"), putn(dolc));
3234         return 0;
3235 }
3236
3237 /*
3238  * execute login and newgrp directly
3239  */
3240 static int dologin(struct op *t)
3241 {
3242         const char *cp;
3243
3244         if (interactive) {
3245                 signal(SIGINT, SIG_DFL);
3246                 signal(SIGQUIT, SIG_DFL);
3247         }
3248         cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3249         prs(t->words[0]);
3250         prs(": ");
3251         err(cp);
3252         return 1;
3253 }
3254
3255 static int doumask(struct op *t)
3256 {
3257         int i;
3258         char *cp;
3259
3260         cp = t->words[1];
3261         if (cp == NULL) {
3262                 i = umask(0);
3263                 umask(i);
3264                 printf("%04o\n", i);
3265         } else {
3266                 i = bb_strtou(cp, NULL, 8);
3267                 if (errno) {
3268                         err("umask: bad octal number");
3269                         return 1;
3270                 }
3271                 umask(i);
3272         }
3273         return 0;
3274 }
3275
3276 static int doexec(struct op *t)
3277 {
3278         int i;
3279         jmp_buf ex;
3280         xint *ofail;
3281
3282         t->ioact = NULL;
3283         for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++)
3284                 continue;
3285         if (i == 0)
3286                 return 1;
3287         execflg = 1;
3288         ofail = failpt;
3289         failpt = ex;
3290         if (setjmp(failpt) == 0)
3291                 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
3292         failpt = ofail;
3293         execflg = 0;
3294         return 1;
3295 }
3296
3297 static int dodot(struct op *t)
3298 {
3299         int i;
3300         const char *sp;
3301         char *tp;
3302         char *cp;
3303         int maltmp;
3304
3305         DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3306                 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3307
3308         cp = t->words[1];
3309         if (cp == NULL) {
3310                 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3311                 return 0;
3312         }
3313         DBGPRINTF(("DODOT: cp is %s\n", cp));
3314
3315         sp = any('/', cp) ? ":" : path->value;
3316
3317         DBGPRINTF(("DODOT: sp is %s,  global_env.linep is %s\n",
3318                            ((sp == NULL) ? "NULL" : sp),
3319                            ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
3320
3321         while (*sp) {
3322                 tp = global_env.linep;
3323                 while (*sp && (*tp = *sp++) != ':')
3324                         tp++;
3325                 if (tp != global_env.linep)
3326                         *tp++ = '/';
3327
3328                 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3329
3330                 /* Original code */
3331                 i = open(global_env.linep, O_RDONLY);
3332                 if (i >= 0) {
3333                         exstat = 0;
3334                         maltmp = remap(i);
3335                         DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3336                                 maltmp, exstat, global_env.iofd, i, global_env.linep));
3337
3338                         next(maltmp);           /* Basically a PUSHIO */
3339
3340                         DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3341
3342                         return exstat;
3343                 }
3344         } /* while */
3345
3346         prs(cp);
3347         err(": not found");
3348
3349         return -1;
3350 }
3351
3352 static int dowait(struct op *t)
3353 {
3354         int i;
3355         char *cp;
3356
3357         cp = t->words[1];
3358         if (cp != NULL) {
3359                 i = getn(cp);
3360                 if (i == 0)
3361                         return 0;
3362         } else
3363                 i = -1;
3364         setstatus(waitfor(i, 1));
3365         return 0;
3366 }
3367
3368 static int doread(struct op *t)
3369 {
3370         char *cp, **wp;
3371         int nb = 0;
3372         int nl = 0;
3373
3374         if (t->words[1] == NULL) {
3375                 err("Usage: read name ...");
3376                 return 1;
3377         }
3378         for (wp = t->words + 1; *wp; wp++) {
3379                 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
3380                         nb = nonblock_safe_read(0, cp, sizeof(*cp));
3381                         if (nb != sizeof(*cp))
3382                                 break;
3383                         nl = (*cp == '\n');
3384                         if (nl || (wp[1] && any(*cp, ifs->value)))
3385                                 break;
3386                 }
3387                 *cp = '\0';
3388                 if (nb <= 0)
3389                         break;
3390                 setval(lookup(*wp), global_env.linep);
3391         }
3392         return nb <= 0;
3393 }
3394
3395 static int doeval(struct op *t)
3396 {
3397         return RUN(awordlist, t->words + 1, wdchar);
3398 }
3399
3400 static int dotrap(struct op *t)
3401 {
3402         int n, i;
3403         int resetsig;
3404
3405         if (t->words[1] == NULL) {
3406                 for (i = 0; i <= _NSIG; i++)
3407                         if (trap[i]) {
3408                                 prn(i);
3409                                 prs(": ");
3410                                 prs(trap[i]);
3411                                 prs("\n");
3412                         }
3413                 return 0;
3414         }
3415         resetsig = isdigit(*t->words[1]);
3416         for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3417                 n = getsig(t->words[i]);
3418                 freecell(trap[n]);
3419                 trap[n] = 0;
3420                 if (!resetsig) {
3421                         if (*t->words[1] != '\0') {
3422                                 trap[n] = strsave(t->words[1], 0);
3423                                 setsig(n, sig);
3424                         } else
3425                                 setsig(n, SIG_IGN);
3426                 } else {
3427                         if (interactive) {
3428                                 if (n == SIGINT)
3429                                         setsig(n, onintr);
3430                                 else
3431                                         setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3432                         } else
3433                                 setsig(n, SIG_DFL);
3434                 }
3435         }
3436         return 0;
3437 }
3438
3439 static int getsig(char *s)
3440 {
3441         int n;
3442
3443         n = getn(s);
3444         if (n < 0 || n > _NSIG) {
3445                 err("trap: bad signal number");
3446                 n = 0;
3447         }
3448         return n;
3449 }
3450
3451 static void setsig(int n, sighandler_t f)
3452 {
3453         if (n == 0)
3454                 return;
3455         if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3456                 ourtrap[n] = 1;
3457                 signal(n, f);
3458         }
3459 }
3460
3461 static int getn(char *as)
3462 {
3463         char *s;
3464         int n, m;
3465
3466         s = as;
3467         m = 1;
3468         if (*s == '-') {
3469                 m = -1;
3470                 s++;
3471         }
3472         for (n = 0; isdigit(*s); s++)
3473                 n = (n * 10) + (*s - '0');
3474         if (*s) {
3475                 prs(as);
3476                 err(": bad number");
3477         }
3478         return n * m;
3479 }
3480
3481 static int dobreak(struct op *t)
3482 {
3483         return brkcontin(t->words[1], 1);
3484 }
3485
3486 static int docontinue(struct op *t)
3487 {
3488         return brkcontin(t->words[1], 0);
3489 }
3490
3491 static int brkcontin(char *cp, int val)
3492 {
3493         struct brkcon *bc;
3494         int nl;
3495
3496         nl = cp == NULL ? 1 : getn(cp);
3497         if (nl <= 0)
3498                 nl = 999;
3499         do {
3500                 bc = brklist;
3501                 if (bc == NULL)
3502                         break;
3503                 brklist = bc->nextlev;
3504         } while (--nl);
3505         if (nl) {
3506                 err("bad break/continue level");
3507                 return 1;
3508         }
3509         isbreak = (val != 0);
3510         longjmp(bc->brkpt, 1);
3511         /* NOTREACHED */
3512 }
3513
3514 static int doexit(struct op *t)
3515 {
3516         char *cp;
3517
3518         execflg = 0;
3519         cp = t->words[1];
3520         if (cp != NULL)
3521                 setstatus(getn(cp));
3522
3523         DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3524
3525         leave();
3526         /* NOTREACHED */
3527         return 0;
3528 }
3529
3530 static int doexport(struct op *t)
3531 {
3532         rdexp(t->words + 1, export, EXPORT);
3533         return 0;
3534 }
3535
3536 static int doreadonly(struct op *t)
3537 {
3538         rdexp(t->words + 1, ronly, RONLY);
3539         return 0;
3540 }
3541
3542 static void rdexp(char **wp, void (*f) (struct var *), int key)
3543 {
3544         DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3545         DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3546
3547         if (*wp != NULL) {
3548                 for (; *wp != NULL; wp++) {
3549                         if (isassign(*wp)) {
3550                                 char *cp;
3551
3552                                 assign(*wp, COPYV);
3553                                 for (cp = *wp; *cp != '='; cp++);
3554                                 *cp = '\0';
3555                         }
3556                         if (checkname(*wp))
3557                                 (*f) (lookup(*wp));
3558                         else
3559                                 badid(*wp);
3560                 }
3561         } else
3562                 putvlist(key, 1);
3563 }
3564
3565 static void badid(char *s)
3566 {
3567         prs(s);
3568         err(": bad identifier");
3569 }
3570
3571 static int doset(struct op *t)
3572 {
3573         struct var *vp;
3574         char *cp;
3575         int n;
3576
3577         cp = t->words[1];
3578         if (cp == NULL) {
3579                 for (vp = vlist; vp; vp = vp->next)
3580                         varput(vp->name, 1);
3581                 return 0;
3582         }
3583         if (*cp == '-') {
3584                 /* bad: t->words++; */
3585                 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3586                 if (*++cp == 0)
3587                         FLAG['x'] = FLAG['v'] = 0;
3588                 else {
3589                         for (; *cp; cp++) {
3590                                 switch (*cp) {
3591                                 case 'e':
3592                                         if (!interactive)
3593                                                 FLAG['e']++;
3594                                         break;
3595
3596                                 default:
3597                                         if (*cp >= 'a' && *cp <= 'z')
3598                                                 FLAG[(int) *cp]++;
3599                                         break;
3600                                 }
3601                         }
3602                 }
3603                 setdash();
3604         }
3605         if (t->words[1]) {
3606                 t->words[0] = dolv[0];
3607                 for (n = 1; t->words[n]; n++)
3608                         setarea((char *) t->words[n], 0);
3609                 dolc = n - 1;
3610                 dolv = t->words;
3611                 setval(lookup("#"), putn(dolc));
3612                 setarea((char *) (dolv - 1), 0);
3613         }
3614         return 0;
3615 }
3616
3617 static void varput(char *s, int out)
3618 {
3619         if (isalnum(*s) || *s == '_') {
3620                 write(out, s, strlen(s));
3621                 write(out, "\n", 1);
3622         }
3623 }
3624
3625
3626 /*
3627  * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3628  * This file contains code for the times builtin.
3629  */
3630 static int dotimes(struct op *t)
3631 {
3632         struct tms buf;
3633         long clk_tck = sysconf(_SC_CLK_TCK);
3634
3635         times(&buf);
3636         printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3637                    (int) (buf.tms_utime / clk_tck / 60),
3638                    ((double) buf.tms_utime) / clk_tck,
3639                    (int) (buf.tms_stime / clk_tck / 60),
3640                    ((double) buf.tms_stime) / clk_tck,
3641                    (int) (buf.tms_cutime / clk_tck / 60),
3642                    ((double) buf.tms_cutime) / clk_tck,
3643                    (int) (buf.tms_cstime / clk_tck / 60),
3644                    ((double) buf.tms_cstime) / clk_tck);
3645         return 0;
3646 }
3647
3648
3649 /* -------- eval.c -------- */
3650
3651 /*
3652  * ${}
3653  * `command`
3654  * blank interpretation
3655  * quoting
3656  * glob
3657  */
3658
3659 static char **eval(char **ap, int f)
3660 {
3661         struct wdblock *wb;
3662         char **wp;
3663         char **wf;
3664         jmp_buf ev;
3665
3666 #if __GNUC__
3667         /* Avoid longjmp clobbering */
3668         (void) &wp;
3669         (void) &ap;
3670 #endif
3671
3672         DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3673
3674         wp = NULL;
3675         wb = NULL;
3676         wf = NULL;
3677         errpt = ev;
3678         if (newenv(setjmp(errpt)) == 0) {
3679                 while (*ap && isassign(*ap))
3680                         expand(*ap++, &wb, f & ~DOGLOB);
3681                 if (FLAG['k']) {
3682                         for (wf = ap; *wf; wf++) {
3683                                 if (isassign(*wf))
3684                                         expand(*wf, &wb, f & ~DOGLOB);
3685                         }
3686                 }
3687                 for (wb = addword((char *) NULL, wb); *ap; ap++) {
3688                         if (!FLAG['k'] || !isassign(*ap))
3689                                 expand(*ap, &wb, f & ~DOKEY);
3690                 }
3691                 wb = addword((char *) 0, wb);
3692                 wp = getwords(wb);
3693                 quitenv();
3694         } else
3695                 gflg = 1;
3696
3697         return gflg ? (char **) NULL : wp;
3698 }
3699
3700
3701 /*
3702  * Make the exported environment from the exported
3703  * names in the dictionary. Keyword assignments
3704  * will already have been done.
3705  */
3706 static char **makenv(int all, struct wdblock *wb)
3707 {
3708         struct var *vp;
3709
3710         DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3711
3712         for (vp = vlist; vp; vp = vp->next)
3713                 if (all || vp->status & EXPORT)
3714                         wb = addword(vp->name, wb);
3715         wb = addword((char *) 0, wb);
3716         return getwords(wb);
3717 }
3718
3719 static int expand(const char *cp, struct wdblock **wbp, int f)
3720 {
3721         jmp_buf ev;
3722         char *xp;
3723
3724 #if __GNUC__
3725         /* Avoid longjmp clobbering */
3726         (void) &cp;
3727 #endif
3728
3729         DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3730
3731         gflg = 0;
3732
3733         if (cp == NULL)
3734                 return 0;
3735
3736         if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3737          && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3738         ) {
3739                 xp = strsave(cp, areanum);
3740                 if (f & DOTRIM)
3741                         unquote(xp);
3742                 *wbp = addword(xp, *wbp);
3743                 return 1;
3744         }
3745         errpt = ev;
3746         if (newenv(setjmp(errpt)) == 0) {
3747                 PUSHIO(aword, cp, strchar);
3748                 global_env.iobase = global_env.iop;
3749                 while ((xp = blank(f)) && gflg == 0) {
3750                         global_env.linep = xp;
3751                         xp = strsave(xp, areanum);
3752                         if ((f & DOGLOB) == 0) {
3753                                 if (f & DOTRIM)
3754                                         unquote(xp);
3755                                 *wbp = addword(xp, *wbp);
3756                         } else
3757                                 *wbp = glob(xp, *wbp);
3758                 }
3759                 quitenv();
3760         } else
3761                 gflg = 1;
3762         return gflg == 0;
3763 }
3764
3765 static char *evalstr(char *cp, int f)
3766 {
3767         struct wdblock *wb;
3768
3769         DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3770
3771         wb = NULL;
3772         if (expand(cp, &wb, f)) {
3773                 if (wb == NULL || wb->w_nword == 0
3774                  || (cp = wb->w_words[0]) == NULL
3775                 ) {
3776 // TODO: I suspect that
3777 // char *evalstr(char *cp, int f)  is actually
3778 // const char *evalstr(const char *cp, int f)!
3779                         cp = (char*)"";
3780                 }
3781                 DELETE(wb);
3782         } else
3783                 cp = NULL;
3784         return cp;
3785 }
3786
3787
3788 /*
3789  * Blank interpretation and quoting
3790  */
3791 static char *blank(int f)
3792 {
3793         int c, c1;
3794         char *sp;
3795         int scanequals, foundequals;
3796
3797         DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3798
3799         sp = global_env.linep;
3800         scanequals = f & DOKEY;
3801         foundequals = 0;
3802
3803  loop:
3804         c = subgetc('"', foundequals);
3805         switch (c) {
3806         case 0:
3807                 if (sp == global_env.linep)
3808                         return 0;
3809                 *global_env.linep++ = 0;
3810                 return sp;
3811
3812         default:
3813                 if (f & DOBLANK && any(c, ifs->value))
3814                         goto loop;
3815                 break;
3816
3817         case '"':
3818         case '\'':
3819                 scanequals = 0;
3820                 if (INSUB())
3821                         break;
3822                 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3823                         if (c == 0)
3824                                 break;
3825                         if (c == '\'' || !any(c, "$`\""))
3826                                 c |= QUOTE;
3827                         *global_env.linep++ = c;
3828                 }
3829                 c = 0;
3830         }
3831         unget(c);
3832         if (!isalpha(c) && c != '_')
3833                 scanequals = 0;
3834         for (;;) {
3835                 c = subgetc('"', foundequals);
3836                 if (c == 0 ||
3837                         f & (DOBLANK && any(c, ifs->value)) ||
3838                         (!INSUB() && any(c, "\"'"))) {
3839                         scanequals = 0;
3840                         unget(c);
3841                         if (any(c, "\"'"))
3842                                 goto loop;
3843                         break;
3844                 }
3845                 if (scanequals) {
3846                         if (c == '=') {
3847                                 foundequals = 1;
3848                                 scanequals = 0;
3849                         } else if (!isalnum(c) && c != '_')
3850                                 scanequals = 0;
3851                 }
3852                 *global_env.linep++ = c;
3853         }
3854         *global_env.linep++ = 0;
3855         return sp;
3856 }
3857
3858 /*
3859  * Get characters, substituting for ` and $
3860  */
3861 static int subgetc(char ec, int quoted)
3862 {
3863         char c;
3864
3865         DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
3866
3867  again:
3868         c = my_getc(ec);
3869         if (!INSUB() && ec != '\'') {
3870                 if (c == '`') {
3871                         if (grave(quoted) == 0)
3872                                 return 0;
3873                         global_env.iop->task = XGRAVE;
3874                         goto again;
3875                 }
3876                 if (c == '$') {
3877                         c = dollar(quoted);
3878                         if (c == 0) {
3879                                 global_env.iop->task = XDOLL;
3880                                 goto again;
3881                         }
3882                 }
3883         }
3884         return c;
3885 }
3886
3887 /*
3888  * Prepare to generate the string returned by ${} substitution.
3889  */
3890 static int dollar(int quoted)
3891 {
3892         int otask;
3893         struct io *oiop;
3894         char *dolp;
3895         char *s, c, *cp = NULL;
3896         struct var *vp;
3897
3898         DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3899
3900         c = readc();
3901         s = global_env.linep;
3902         if (c != '{') {
3903                 *global_env.linep++ = c;
3904                 if (isalpha(c) || c == '_') {
3905                         while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
3906                                 if (global_env.linep < elinep)
3907                                         *global_env.linep++ = c;
3908                         unget(c);
3909                 }
3910                 c = 0;
3911         } else {
3912                 oiop = global_env.iop;
3913                 otask = global_env.iop->task;
3914
3915                 global_env.iop->task = XOTHER;
3916                 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
3917                         if (global_env.linep < elinep)
3918                                 *global_env.linep++ = c;
3919                 if (oiop == global_env.iop)
3920                         global_env.iop->task = otask;
3921                 if (c != '}') {
3922                         err("unclosed ${");
3923                         gflg = 1;
3924                         return c;
3925                 }
3926         }
3927         if (global_env.linep >= elinep) {
3928                 err("string in ${} too long");
3929                 gflg = 1;
3930                 global_env.linep -= 10;
3931         }
3932         *global_env.linep = 0;
3933         if (*s)
3934                 for (cp = s + 1; *cp; cp++)
3935                         if (any(*cp, "=-+?")) {
3936                                 c = *cp;
3937                                 *cp++ = 0;
3938                                 break;
3939                         }
3940         if (s[1] == 0 && (*s == '*' || *s == '@')) {
3941                 if (dolc > 1) {
3942                         /* currently this does not distinguish $* and $@ */
3943                         /* should check dollar */
3944                         global_env.linep = s;
3945                         PUSHIO(awordlist, dolv + 1, dolchar);
3946                         return 0;
3947                 } else {                                /* trap the nasty ${=} */
3948                         s[0] = '1';
3949                         s[1] = '\0';
3950                 }
3951         }
3952         vp = lookup(s);
3953         dolp = vp->value;
3954         if (dolp == null) {
3955                 switch (c) {
3956                 case '=':
3957                         if (isdigit(*s)) {
3958                                 err("cannot use ${...=...} with $n");
3959                                 gflg = 1;
3960                                 break;
3961                         }
3962                         setval(vp, cp);
3963                         dolp = vp->value;
3964                         break;
3965
3966                 case '-':
3967                         dolp = strsave(cp, areanum);
3968                         break;
3969
3970                 case '?':
3971                         if (*cp == 0) {
3972                                 prs("missing value for ");
3973                                 err(s);
3974                         } else
3975                                 err(cp);
3976                         gflg = 1;
3977                         break;
3978                 }
3979         } else if (c == '+')
3980                 dolp = strsave(cp, areanum);
3981         if (FLAG['u'] && dolp == null) {
3982                 prs("unset variable: ");
3983                 err(s);
3984                 gflg = 1;
3985         }
3986         global_env.linep = s;
3987         PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
3988         return 0;
3989 }
3990
3991 /*
3992  * Run the command in `...` and read its output.
3993  */
3994
3995 static int grave(int quoted)
3996 {
3997         /* moved to G: static char child_cmd[LINELIM]; */
3998
3999         const char *cp;
4000         int i;
4001         int j;
4002         int pf[2];
4003         const char *src;
4004         char *dest;
4005         int count;
4006         int ignore;
4007         int ignore_once;
4008         char *argument_list[4];
4009         struct wdblock *wb = NULL;
4010
4011 #if __GNUC__
4012         /* Avoid longjmp clobbering */
4013         (void) &cp;
4014 #endif
4015
4016         for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
4017                 if (*cp == 0) {
4018                         err("no closing `");
4019                         return 0;
4020                 }
4021         }
4022
4023         /* string copy with dollar expansion */
4024         src = global_env.iop->argp->aword;
4025         dest = child_cmd;
4026         count = 0;
4027         ignore = 0;
4028         ignore_once = 0;
4029         while ((*src != '`') && (count < LINELIM)) {
4030                 if (*src == '\'')
4031                         ignore = !ignore;
4032                 if (*src == '\\')
4033                         ignore_once = 1;
4034                 if (*src == '$' && !ignore && !ignore_once) {
4035                         struct var *vp;
4036                         /* moved to G to reduce stack usage
4037                         char var_name[LINELIM];
4038                         char alt_value[LINELIM];
4039                         */
4040 #define var_name (G.grave__var_name)
4041 #define alt_value (G.grave__alt_value)
4042                         int var_index = 0;
4043                         int alt_index = 0;
4044                         char operator = 0;
4045                         int braces = 0;
4046                         char *value;
4047
4048                         src++;
4049                         if (*src == '{') {
4050                                 braces = 1;
4051                                 src++;
4052                         }
4053
4054                         var_name[var_index++] = *src++;
4055                         while (isalnum(*src) || *src=='_')
4056                                 var_name[var_index++] = *src++;
4057                         var_name[var_index] = 0;
4058
4059                         if (braces) {
4060                                 switch (*src) {
4061                                 case '}':
4062                                         break;
4063                                 case '-':
4064                                 case '=':
4065                                 case '+':
4066                                 case '?':
4067                                         operator = * src;
4068                                         break;
4069                                 default:
4070                                         err("unclosed ${\n");
4071                                         return 0;
4072                                 }
4073                                 if (operator) {
4074                                         src++;
4075                                         while (*src && (*src != '}')) {
4076                                                 alt_value[alt_index++] = *src++;
4077                                         }
4078                                         alt_value[alt_index] = 0;
4079                                         if (*src != '}') {
4080                                                 err("unclosed ${\n");
4081                                                 return 0;
4082                                         }
4083                                 }
4084                                 src++;
4085                         }
4086
4087                         if (isalpha(*var_name)) {
4088                                 /* let subshell handle it instead */
4089
4090                                 char *namep = var_name;
4091
4092                                 *dest++ = '$';
4093                                 if (braces)
4094                                         *dest++ = '{';
4095                                 while (*namep)
4096                                         *dest++ = *namep++;
4097                                 if (operator) {
4098                                         char *altp = alt_value;
4099                                         *dest++ = operator;
4100                                         while (*altp)
4101                                                 *dest++ = *altp++;
4102                                 }
4103                                 if (braces)
4104                                         *dest++ = '}';
4105
4106                                 wb = addword(lookup(var_name)->name, wb);
4107                         } else {
4108                                 /* expand */
4109
4110                                 vp = lookup(var_name);
4111                                 if (vp->value != null)
4112                                         value = (operator == '+') ?
4113                                                 alt_value : vp->value;
4114                                 else if (operator == '?') {
4115                                         err(alt_value);
4116                                         return 0;
4117                                 } else if (alt_index && (operator != '+')) {
4118                                         value = alt_value;
4119                                         if (operator == '=')
4120                                                 setval(vp, value);
4121                                 } else
4122                                         continue;
4123
4124                                 while (*value && (count < LINELIM)) {
4125                                         *dest++ = *value++;
4126                                         count++;
4127                                 }
4128                         }
4129 #undef var_name
4130 #undef alt_value
4131                 } else {
4132                         *dest++ = *src++;
4133                         count++;
4134                         ignore_once = 0;
4135                 }
4136         }
4137         *dest = '\0';
4138
4139         if (openpipe(pf) < 0)
4140                 return 0;
4141
4142         while ((i = vfork()) == -1 && errno == EAGAIN);
4143
4144         DBGPRINTF3(("GRAVE: i is %p\n", io));
4145
4146         if (i < 0) {
4147                 closepipe(pf);
4148                 err((char *) bb_msg_memory_exhausted);
4149                 return 0;
4150         }
4151         if (i != 0) {
4152                 waitpid(i, NULL, 0); // safe_waitpid?
4153                 global_env.iop->argp->aword = ++cp;
4154                 close(pf[1]);
4155                 PUSHIO(afile, remap(pf[0]),
4156                         (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
4157                 return 1;
4158         }
4159         /* allow trapped signals */
4160         /* XXX - Maybe this signal stuff should go as well? */
4161         for (j = 0; j <= _NSIG; j++)
4162                 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4163                         signal(j, SIG_DFL);
4164
4165         /* Testcase where below checks are needed:
4166          * close stdout & run this script:
4167          *  files=`ls`
4168          *  echo "$files" >zz
4169          */
4170         xmove_fd(pf[1], 1);
4171         if (pf[0] != 1)
4172                 close(pf[0]);
4173
4174         argument_list[0] = (char *) DEFAULT_SHELL;
4175         argument_list[1] = (char *) "-c";
4176         argument_list[2] = child_cmd;
4177         argument_list[3] = NULL;
4178
4179         cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4180         prs(argument_list[0]);
4181         prs(": ");
4182         err(cp);
4183         _exit(1);
4184 }
4185
4186
4187 static char *unquote(char *as)
4188 {
4189         char *s;
4190
4191         s = as;
4192         if (s != NULL)
4193                 while (*s)
4194                         *s++ &= ~QUOTE;
4195         return as;
4196 }
4197
4198 /* -------- glob.c -------- */
4199
4200 /*
4201  * glob
4202  */
4203
4204 #define scopy(x) strsave((x), areanum)
4205 #define BLKSIZ  512
4206 #define NDENT   ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4207
4208 static struct wdblock *cl, *nl;
4209 static const char spcl[] ALIGN1= "[?*";
4210
4211 static struct wdblock *glob(char *cp, struct wdblock *wb)
4212 {
4213         int i;
4214         char *pp;
4215
4216         if (cp == 0)
4217                 return wb;
4218         i = 0;
4219         for (pp = cp; *pp; pp++)
4220                 if (any(*pp, spcl))
4221                         i++;
4222                 else if (!any(*pp & ~QUOTE, spcl))
4223                         *pp &= ~QUOTE;
4224         if (i != 0) {
4225                 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
4226                         nl = newword(cl->w_nword * 2);
4227                         for (i = 0; i < cl->w_nword; i++) {     /* for each argument */
4228                                 for (pp = cl->w_words[i]; *pp; pp++)
4229                                         if (any(*pp, spcl)) {
4230                                                 globname(cl->w_words[i], pp);
4231                                                 break;
4232                                         }
4233                                 if (*pp == '\0')
4234                                         nl = addword(scopy(cl->w_words[i]), nl);
4235                         }
4236                         for (i = 0; i < cl->w_nword; i++)
4237                                 DELETE(cl->w_words[i]);
4238                         DELETE(cl);
4239                 }
4240                 for (i = 0; i < cl->w_nword; i++)
4241                         unquote(cl->w_words[i]);
4242                 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4243                 if (cl->w_nword) {
4244                         for (i = 0; i < cl->w_nword; i++)
4245                                 wb = addword(cl->w_words[i], wb);
4246                         DELETE(cl);
4247                         return wb;
4248                 }
4249         }
4250         wb = addword(unquote(cp), wb);
4251         return wb;
4252 }
4253
4254 static void globname(char *we, char *pp)
4255 {
4256         char *np, *cp;
4257         char *name, *gp, *dp;
4258         int k;
4259         DIR *dirp;
4260         struct dirent *de;
4261         char dname[NAME_MAX + 1];
4262         struct stat dbuf;
4263
4264         for (np = we; np != pp; pp--)
4265                 if (pp[-1] == '/')
4266                         break;
4267         for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4268                 *cp++ = *np++;
4269         *cp++ = '.';
4270         *cp = '\0';
4271         for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4272                 *cp++ = *np++;
4273         *cp = '\0';
4274         dirp = opendir(dp);
4275         if (dirp == 0) {
4276                 DELETE(dp);
4277                 DELETE(gp);
4278                 return;
4279         }
4280         dname[NAME_MAX] = '\0';
4281         while ((de = readdir(dirp)) != NULL) {
4282                 /* XXX Hmmm... What this could be? (abial) */
4283                 /*
4284                    if (ent[j].d_ino == 0)
4285                       continue;
4286                  */
4287                 strncpy(dname, de->d_name, NAME_MAX);
4288                 if (dname[0] == '.')
4289                         if (*gp != '.')
4290                                 continue;
4291                 for (k = 0; k < NAME_MAX; k++)
4292                         if (any(dname[k], spcl))
4293                                 dname[k] |= QUOTE;
4294                 if (gmatch(dname, gp)) {
4295                         name = generate(we, pp, dname, np);
4296                         if (*np && !anys(np, spcl)) {
4297                                 if (stat(name, &dbuf)) {
4298                                         DELETE(name);
4299                                         continue;
4300                                 }
4301                         }
4302                         nl = addword(name, nl);
4303                 }
4304         }
4305         closedir(dirp);
4306         DELETE(dp);
4307         DELETE(gp);
4308 }
4309
4310 /*
4311  * generate a pathname as below.
4312  * start..end1 / middle end
4313  * the slashes come for free
4314  */
4315 static char *generate(char *start1, char *end1, char *middle, char *end)
4316 {
4317         char *p;
4318         char *op, *xp;
4319
4320         p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4321         for (xp = start1; xp != end1;)
4322                 *op++ = *xp++;
4323         for (xp = middle; (*op++ = *xp++) != '\0';);
4324         op--;
4325         for (xp = end; (*op++ = *xp++) != '\0';);
4326         return p;
4327 }
4328
4329 static int anyspcl(struct wdblock *wb)
4330 {
4331         int i;
4332         char **wd;
4333
4334         wd = wb->w_words;
4335         for (i = 0; i < wb->w_nword; i++)
4336                 if (anys(spcl, *wd++))
4337                         return 1;
4338         return 0;
4339 }
4340
4341 static int xstrcmp(char *p1, char *p2)
4342 {
4343         return strcmp(*(char **) p1, *(char **) p2);
4344 }
4345
4346
4347 /* -------- word.c -------- */
4348
4349 static struct wdblock *newword(int nw)
4350 {
4351         struct wdblock *wb;
4352
4353         wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4354         wb->w_bsize = nw;
4355         wb->w_nword = 0;
4356         return wb;
4357 }
4358
4359 static struct wdblock *addword(char *wd, struct wdblock *wb)
4360 {
4361         struct wdblock *wb2;
4362         int nw;
4363
4364         if (wb == NULL)
4365                 wb = newword(NSTART);
4366         nw = wb->w_nword;
4367         if (nw >= wb->w_bsize) {
4368                 wb2 = newword(nw * 2);
4369                 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4370                            nw * sizeof(char *));
4371                 wb2->w_nword = nw;
4372                 DELETE(wb);
4373                 wb = wb2;
4374         }
4375         wb->w_words[wb->w_nword++] = wd;
4376         return wb;
4377 }
4378
4379 static char **getwords(struct wdblock *wb)
4380 {
4381         char **wd;
4382         int nb;
4383
4384         if (wb == NULL)
4385                 return NULL;
4386         if (wb->w_nword == 0) {
4387                 DELETE(wb);
4388                 return NULL;
4389         }
4390         wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4391         memcpy((char *) wd, (char *) wb->w_words, nb);
4392         DELETE(wb);                                     /* perhaps should done by caller */
4393         return wd;
4394 }
4395
4396 static int (*func) (char *, char *);
4397 static int globv;
4398
4399 static void glob3(char *i, char *j, char *k)
4400 {
4401         char *index1, *index2, *index3;
4402         int c;
4403         int m;
4404
4405         m = globv;
4406         index1 = i;
4407         index2 = j;
4408         index3 = k;
4409         do {
4410                 c = *index1;
4411                 *index1++ = *index3;
4412                 *index3++ = *index2;
4413                 *index2++ = c;
4414         } while (--m);
4415 }
4416
4417 static void glob2(char *i, char *j)
4418 {
4419         char *index1, *index2, c;
4420         int m;
4421
4422         m = globv;
4423         index1 = i;
4424         index2 = j;
4425         do {
4426                 c = *index1;
4427                 *index1++ = *index2;
4428                 *index2++ = c;
4429         } while (--m);
4430 }
4431
4432 static void glob1(char *base, char *lim)
4433 {
4434         char *i, *j;
4435         int v2;
4436         char *lptr, *hptr;
4437         int c;
4438         unsigned n;
4439
4440         v2 = globv;
4441
4442  top:
4443         n = (int) (lim - base);
4444         if (n <= v2)
4445                 return;
4446         n = v2 * (n / (2 * v2));
4447         hptr = lptr = base + n;
4448         i = base;
4449         j = lim - v2;
4450         for (;;) {
4451                 if (i < lptr) {
4452                         c = (*func) (i, lptr);
4453                         if (c == 0) {
4454                                 lptr -= v2;
4455                                 glob2(i, lptr);
4456                                 continue;
4457                         }
4458                         if (c < 0) {
4459                                 i += v2;
4460                                 continue;
4461                         }
4462                 }
4463
4464  begin:
4465                 if (j > hptr) {
4466                         c = (*func) (hptr, j);
4467                         if (c == 0) {
4468                                 hptr += v2;
4469                                 glob2(hptr, j);
4470                                 goto begin;
4471                         }
4472                         if (c > 0) {
4473                                 if (i == lptr) {
4474                                         hptr += v2;
4475                                         glob3(i, hptr, j);
4476                                         i = (lptr += v2);
4477                                         goto begin;
4478                                 }
4479                                 glob2(i, j);
4480                                 j -= v2;
4481                                 i += v2;
4482                                 continue;
4483                         }
4484                         j -= v2;
4485                         goto begin;
4486                 }
4487
4488
4489                 if (i == lptr) {
4490                         if (lptr - base >= lim - hptr) {
4491                                 glob1(hptr + v2, lim);
4492                                 lim = lptr;
4493                         } else {
4494                                 glob1(base, lptr);
4495                                 base = hptr + v2;
4496                         }
4497                         goto top;
4498                 }
4499
4500                 lptr -= v2;
4501                 glob3(j, lptr, i);
4502                 j = (hptr -= v2);
4503         }
4504 }
4505
4506 static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4507 {
4508         func = a3;
4509         globv = a2;
4510         glob1(a0, a0 + a1 * a2);
4511 }
4512
4513
4514 /* -------- io.c -------- */
4515
4516 /*
4517  * shell IO
4518  */
4519
4520 static int my_getc(int ec)
4521 {
4522         int c;
4523
4524         if (global_env.linep > elinep) {
4525                 while ((c = readc()) != '\n' && c);
4526                 err("input line too long");
4527                 gflg = 1;
4528                 return c;
4529         }
4530         c = readc();
4531         if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
4532                 if (c == '\\') {
4533                         c = readc();
4534                         if (c == '\n' && ec != '\"')
4535                                 return my_getc(ec);
4536                         c |= QUOTE;
4537                 }
4538         }
4539         return c;
4540 }
4541
4542 static void unget(int c)
4543 {
4544         if (global_env.iop >= global_env.iobase)
4545                 global_env.iop->peekc = c;
4546 }
4547
4548 static int eofc(void)
4549 {
4550         return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
4551 }
4552
4553 static int readc(void)
4554 {
4555         int c;
4556
4557         RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
4558
4559         for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4560                 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4561                 c = global_env.iop->peekc;
4562                 if (c != '\0') {
4563                         global_env.iop->peekc = 0;
4564                         return c;
4565                 }
4566                 if (global_env.iop->prev != 0) {
4567                         c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
4568                         if (c != '\0') {
4569                                 if (c == -1) {
4570                                         global_env.iop++;
4571                                         continue;
4572                                 }
4573                                 if (global_env.iop == iostack)
4574                                         ioecho(c);
4575                                 global_env.iop->prev = c;
4576                                 return global_env.iop->prev;
4577                         }
4578                         if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4579                                 global_env.iop->prev = 0;
4580                                 if (global_env.iop == iostack)
4581                                         ioecho('\n');
4582                                 return '\n';
4583                         }
4584                 }
4585                 if (global_env.iop->task == XIO) {
4586                         if (multiline) {
4587                                 global_env.iop->prev = 0;
4588                                 return global_env.iop->prev;
4589                         }
4590                         if (interactive && global_env.iop == iostack + 1) {
4591 #if ENABLE_FEATURE_EDITING
4592                                 current_prompt = prompt->value;
4593 #else
4594                                 prs(prompt->value);
4595 #endif
4596                         }
4597                 }
4598         }                                                       /* FOR */
4599
4600         if (global_env.iop >= iostack) {
4601                 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
4602                 return 0;
4603         }
4604
4605         DBGPRINTF(("READC: leave()...\n"));
4606         leave();
4607         /* NOTREACHED */
4608         return 0;
4609 }
4610
4611 static void ioecho(char c)
4612 {
4613         if (FLAG['v'])
4614                 write(2, &c, sizeof c);
4615 }
4616
4617 static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4618 {
4619         DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4620                            argp->afid, global_env.iop));
4621
4622         /* Set env ptr for io source to next array spot and check for array overflow */
4623         if (++global_env.iop >= &iostack[NPUSH]) {
4624                 global_env.iop--;
4625                 err("Shell input nested too deeply");
4626                 gflg = 1;
4627                 return;
4628         }
4629
4630         /* We did not overflow the NPUSH array spots so setup data structs */
4631
4632         global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;       /* Store data source func ptr */
4633
4634         if (argp->afid != AFID_NOBUF)
4635                 global_env.iop->argp = argp;
4636         else {
4637
4638                 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4639                 *global_env.iop->argp = *argp;  /* copy data from temp area into stack spot */
4640
4641                 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4642
4643                 if (global_env.iop == &iostack[0])
4644                         global_env.iop->argp->afbuf = &mainbuf;
4645                 else
4646                         global_env.iop->argp->afbuf = &sharedbuf;
4647
4648                 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4649                 /* This line appears to be active when running scripts from command line */
4650                 if ((isatty(global_env.iop->argp->afile) == 0)
4651                         && (global_env.iop == &iostack[0]
4652                                 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
4653                         if (++bufid == AFID_NOBUF)      /* counter rollover check, AFID_NOBUF = 11111111  */
4654                                 bufid = AFID_ID;        /* AFID_ID = 0 */
4655
4656                         global_env.iop->argp->afid = bufid;     /* assign buffer id */
4657                 }
4658
4659                 DBGPRINTF(("PUSHIO: iostack %p,  global_env.iop %p, afbuf %p\n",
4660                                    iostack, global_env.iop, global_env.iop->argp->afbuf));
4661                 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4662                                    &mainbuf, &sharedbuf, bufid, global_env.iop));
4663
4664         }
4665
4666         global_env.iop->prev = ~'\n';
4667         global_env.iop->peekc = 0;
4668         global_env.iop->xchar = 0;
4669         global_env.iop->nlcount = 0;
4670
4671         if (fn == filechar || fn == linechar)
4672                 global_env.iop->task = XIO;
4673         else if (fn == (int (*)(struct ioarg *)) gravechar
4674          || fn == (int (*)(struct ioarg *)) qgravechar)
4675                 global_env.iop->task = XGRAVE;
4676         else
4677                 global_env.iop->task = XOTHER;
4678 }
4679
4680 static struct io *setbase(struct io *ip)
4681 {
4682         struct io *xp;
4683
4684         xp = global_env.iobase;
4685         global_env.iobase = ip;
4686         return xp;
4687 }
4688
4689 /*
4690  * Input generating functions
4691  */
4692
4693 /*
4694  * Produce the characters of a string, then a newline, then EOF.
4695  */
4696 static int nlchar(struct ioarg *ap)
4697 {
4698         int c;
4699
4700         if (ap->aword == NULL)
4701                 return 0;
4702         c = *ap->aword++;
4703         if (c == 0) {
4704                 ap->aword = NULL;
4705                 return '\n';
4706         }
4707         return c;
4708 }
4709
4710 /*
4711  * Given a list of words, produce the characters
4712  * in them, with a space after each word.
4713  */
4714 static int wdchar(struct ioarg *ap)
4715 {
4716         char c;
4717         char **wl;
4718
4719         wl = ap->awordlist;
4720         if (wl == NULL)
4721                 return 0;
4722         if (*wl != NULL) {
4723                 c = *(*wl)++;
4724                 if (c != 0)
4725                         return c & 0177;
4726                 ap->awordlist++;
4727                 return ' ';
4728         }
4729         ap->awordlist = NULL;
4730         return '\n';
4731 }
4732
4733 /*
4734  * Return the characters of a list of words,
4735  * producing a space between them.
4736  */
4737 static int dolchar(struct ioarg *ap)
4738 {
4739         char *wp;
4740
4741         wp = *ap->awordlist++;
4742         if (wp != NULL) {
4743                 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4744                 return -1;
4745         }
4746         return 0;
4747 }
4748
4749 static int xxchar(struct ioarg *ap)
4750 {
4751         int c;
4752
4753         if (ap->aword == NULL)
4754                 return 0;
4755         c = *ap->aword++;
4756         if (c == '\0') {
4757                 ap->aword = NULL;
4758                 return ' ';
4759         }
4760         return c;
4761 }
4762
4763 /*
4764  * Produce the characters from a single word (string).
4765  */
4766 static int strchar(struct ioarg *ap)
4767 {
4768         if (ap->aword == NULL)
4769                 return 0;
4770         return *ap->aword++;
4771 }
4772
4773 /*
4774  * Produce quoted characters from a single word (string).
4775  */
4776 static int qstrchar(struct ioarg *ap)
4777 {
4778         int c;
4779
4780         if (ap->aword == NULL)
4781                 return 0;
4782         c = *ap->aword++;
4783         if (c)
4784                 c |= QUOTE;
4785         return c;
4786 }
4787
4788 /*
4789  * Return the characters from a file.
4790  */
4791 static int filechar(struct ioarg *ap)
4792 {
4793         int i;
4794         char c;
4795         struct iobuf *bp = ap->afbuf;
4796
4797         if (ap->afid != AFID_NOBUF) {
4798                 i = (ap->afid != bp->id);
4799                 if (i || bp->bufp == bp->ebufp) {
4800                         if (i)
4801                                 lseek(ap->afile, ap->afpos, SEEK_SET);
4802
4803                         i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4804                         if (i <= 0) {
4805                                 closef(ap->afile);
4806                                 return 0;
4807                         }
4808
4809                         bp->id = ap->afid;
4810                         bp->bufp = bp->buf;
4811                         bp->ebufp = bp->bufp + i;
4812                 }
4813
4814                 ap->afpos++;
4815                 return *bp->bufp++ & 0177;
4816         }
4817 #if ENABLE_FEATURE_EDITING
4818         if (interactive && isatty(ap->afile)) {
4819                 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
4820                 static int position = 0, size = 0;
4821
4822                 while (size == 0 || position >= size) {
4823                         size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4824                         if (size < 0) /* Error/EOF */
4825                                 exit(0);
4826                         position = 0;
4827                         /* if Ctrl-C, size == 0 and loop will repeat */
4828                 }
4829                 c = filechar_cmdbuf[position];
4830                 position++;
4831                 return c;
4832         }
4833 #endif
4834         i = nonblock_safe_read(ap->afile, &c, sizeof(c));
4835         return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
4836 }
4837
4838 /*
4839  * Return the characters from a here temp file.
4840  */
4841 static int herechar(struct ioarg *ap)
4842 {
4843         char c;
4844
4845         if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4846                 close(ap->afile);
4847                 c = '\0';
4848         }
4849         return c;
4850 }
4851
4852 /*
4853  * Return the characters produced by a process (`...`).
4854  * Quote them if required, and remove any trailing newline characters.
4855  */
4856 static int gravechar(struct ioarg *ap, struct io *iop)
4857 {
4858         int c;
4859
4860         c = qgravechar(ap, iop) & ~QUOTE;
4861         if (c == '\n')
4862                 c = ' ';
4863         return c;
4864 }
4865
4866 static int qgravechar(struct ioarg *ap, struct io *iop)
4867 {
4868         int c;
4869
4870         DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4871
4872         if (iop->xchar) {
4873                 if (iop->nlcount) {
4874                         iop->nlcount--;
4875                         return '\n' | QUOTE;
4876                 }
4877                 c = iop->xchar;
4878                 iop->xchar = 0;
4879         } else if ((c = filechar(ap)) == '\n') {
4880                 iop->nlcount = 1;
4881                 while ((c = filechar(ap)) == '\n')
4882                         iop->nlcount++;
4883                 iop->xchar = c;
4884                 if (c == 0)
4885                         return c;
4886                 iop->nlcount--;
4887                 c = '\n';
4888         }
4889         return c != 0 ? c | QUOTE : 0;
4890 }
4891
4892 /*
4893  * Return a single command (usually the first line) from a file.
4894  */
4895 static int linechar(struct ioarg *ap)
4896 {
4897         int c;
4898
4899         c = filechar(ap);
4900         if (c == '\n') {
4901                 if (!multiline) {
4902                         closef(ap->afile);
4903                         ap->afile = -1;         /* illegal value */
4904                 }
4905         }
4906         return c;
4907 }
4908
4909 /*
4910  * remap fd into Shell's fd space
4911  */
4912 static int remap(int fd)
4913 {
4914         int i;
4915         int map[NOFILE];
4916         int newfd;
4917
4918         DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
4919
4920         if (fd < global_env.iofd) {
4921                 for (i = 0; i < NOFILE; i++)
4922                         map[i] = 0;
4923
4924                 do {
4925                         map[fd] = 1;
4926                         newfd = dup(fd);
4927                         fd = newfd;
4928                 } while (fd >= 0 && fd < global_env.iofd);
4929
4930                 for (i = 0; i < NOFILE; i++)
4931                         if (map[i])
4932                                 close(i);
4933
4934                 if (fd < 0)
4935                         err("too many files open in shell");
4936         }
4937
4938         return fd;
4939 }
4940
4941 static int openpipe(int *pv)
4942 {
4943         int i;
4944
4945         i = pipe(pv);
4946         if (i < 0)
4947                 err("can't create pipe - try again");
4948         return i;
4949 }
4950
4951 static void closepipe(int *pv)
4952 {
4953         if (pv != NULL) {
4954                 close(pv[0]);
4955                 close(pv[1]);
4956         }
4957 }
4958
4959
4960 /* -------- here.c -------- */
4961
4962 /*
4963  * here documents
4964  */
4965
4966 static void markhere(char *s, struct ioword *iop)
4967 {
4968         struct here *h, *lh;
4969
4970         DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
4971
4972         h = (struct here *) space(sizeof(struct here));
4973         if (h == NULL)
4974                 return;
4975
4976         h->h_tag = evalstr(s, DOSUB);
4977         if (h->h_tag == 0)
4978                 return;
4979
4980         h->h_iop = iop;
4981         iop->io_name = 0;
4982         h->h_next = NULL;
4983         if (inhere == 0)
4984                 inhere = h;
4985         else {
4986                 for (lh = inhere; lh != NULL; lh = lh->h_next) {
4987                         if (lh->h_next == 0) {
4988                                 lh->h_next = h;
4989                                 break;
4990                         }
4991                 }
4992         }
4993         iop->io_flag |= IOHERE | IOXHERE;
4994         for (s = h->h_tag; *s; s++) {
4995                 if (*s & QUOTE) {
4996                         iop->io_flag &= ~IOXHERE;
4997                         *s &= ~QUOTE;
4998                 }
4999         }
5000         h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
5001 }
5002
5003 static void gethere(void)
5004 {
5005         struct here *h, *hp;
5006
5007         DBGPRINTF7(("GETHERE: enter...\n"));
5008
5009         /* Scan here files first leaving inhere list in place */
5010         for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5011                 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
5012
5013         /* Make inhere list active - keep list intact for scraphere */
5014         if (hp != NULL) {
5015                 hp->h_next = acthere;
5016                 acthere = inhere;
5017                 inhere = NULL;
5018         }
5019 }
5020
5021 static void readhere(char **name, char *s, int ec)
5022 {
5023         int tf;
5024         char tname[30] = ".msh_XXXXXX";
5025         int c;
5026         jmp_buf ev;
5027         char myline[LINELIM + 1];
5028         char *thenext;
5029
5030         DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5031
5032         tf = mkstemp(tname);
5033         if (tf < 0)
5034                 return;
5035
5036         *name = strsave(tname, areanum);
5037         errpt = ev;
5038         if (newenv(setjmp(errpt)) != 0)
5039                 unlink(tname);
5040         else {
5041                 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5042                 global_env.iobase = global_env.iop;
5043                 for (;;) {
5044                         if (interactive && global_env.iop <= iostack) {
5045 #if ENABLE_FEATURE_EDITING
5046                                 current_prompt = cprompt->value;
5047 #else
5048                                 prs(cprompt->value);
5049 #endif
5050                         }
5051                         thenext = myline;
5052                         while ((c = my_getc(ec)) != '\n' && c) {
5053                                 if (ec == '\'')
5054                                         c &= ~QUOTE;
5055                                 if (thenext >= &myline[LINELIM]) {
5056                                         c = 0;
5057                                         break;
5058                                 }
5059                                 *thenext++ = c;
5060                         }
5061                         *thenext = 0;
5062                         if (strcmp(s, myline) == 0 || c == 0)
5063                                 break;
5064                         *thenext++ = '\n';
5065                         write(tf, myline, (int) (thenext - myline));
5066                 }
5067                 if (c == 0) {
5068                         prs("here document `");
5069                         prs(s);
5070                         err("' unclosed");
5071                 }
5072                 quitenv();
5073         }
5074         close(tf);
5075 }
5076
5077 /*
5078  * open here temp file.
5079  * if unquoted here, expand here temp file into second temp file.
5080  */
5081 static int herein(char *hname, int xdoll)
5082 {
5083         int hf;
5084         int tf;
5085
5086 #if __GNUC__
5087         /* Avoid longjmp clobbering */
5088         (void) &tf;
5089 #endif
5090         if (hname == NULL)
5091                 return -1;
5092
5093         DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5094
5095         hf = open(hname, O_RDONLY);
5096         if (hf < 0)
5097                 return -1;
5098
5099         if (xdoll) {
5100                 char c;
5101                 char tname[30] = ".msh_XXXXXX";
5102                 jmp_buf ev;
5103
5104                 tf = mkstemp(tname);
5105                 if (tf < 0)
5106                         return -1;
5107                 errpt = ev;
5108                 if (newenv(setjmp(errpt)) == 0) {
5109                         PUSHIO(afile, hf, herechar);
5110                         setbase(global_env.iop);
5111                         while ((c = subgetc(0, 0)) != 0) {
5112                                 c &= ~QUOTE;
5113                                 write(tf, &c, sizeof c);
5114                         }
5115                         quitenv();
5116                 } else
5117                         unlink(tname);
5118                 close(tf);
5119                 tf = open(tname, O_RDONLY);
5120                 unlink(tname);
5121                 return tf;
5122         }
5123         return hf;
5124 }
5125
5126 static void scraphere(void)
5127 {
5128         struct here *h;
5129
5130         DBGPRINTF7(("SCRAPHERE: enter...\n"));
5131
5132         for (h = inhere; h != NULL; h = h->h_next) {
5133                 if (h->h_iop && h->h_iop->io_name)
5134                         unlink(h->h_iop->io_name);
5135         }
5136         inhere = NULL;
5137 }
5138
5139 /* unlink here temp files before a freearea(area) */
5140 static void freehere(int area)
5141 {
5142         struct here *h, *hl;
5143
5144         DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5145
5146         hl = NULL;
5147         for (h = acthere; h != NULL; h = h->h_next)
5148                 if (getarea((char *) h) >= area) {
5149                         if (h->h_iop->io_name != NULL)
5150                                 unlink(h->h_iop->io_name);
5151                         if (hl == NULL)
5152                                 acthere = h->h_next;
5153                         else
5154                                 hl->h_next = h->h_next;
5155                 } else
5156                         hl = h;
5157 }
5158
5159
5160 /* -------- sh.c -------- */
5161 /*
5162  * shell
5163  */
5164
5165 int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5166 int msh_main(int argc, char **argv)
5167 {
5168         int f;
5169         char *s;
5170         int cflag;
5171         char *name, **ap;
5172         int (*iof) (struct ioarg *);
5173
5174         INIT_G();
5175
5176         sharedbuf.id = AFID_NOBUF;
5177         mainbuf.id = AFID_NOBUF;
5178         elinep = line + sizeof(line) - 5;
5179
5180 #if ENABLE_FEATURE_EDITING
5181         line_input_state = new_line_input_t(FOR_SHELL);
5182 #endif
5183
5184         DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5185
5186         initarea();
5187         ap = environ;
5188         if (ap != NULL) {
5189                 while (*ap)
5190                         assign(*ap++, !COPYV);
5191                 for (ap = environ; *ap;)
5192                         export(lookup(*ap++));
5193         }
5194         closeall();
5195         areanum = 1;
5196
5197         shell = lookup("SHELL");
5198         if (shell->value == null)
5199                 setval(shell, (char *)DEFAULT_SHELL);
5200         export(shell);
5201
5202         homedir = lookup("HOME");
5203         if (homedir->value == null)
5204                 setval(homedir, "/");
5205         export(homedir);
5206
5207         setval(lookup("$"), putn(getpid()));
5208
5209         path = lookup("PATH");
5210         if (path->value == null) {
5211                 /* Can be merged with same string elsewhere in bbox */
5212                 if (geteuid() == 0)
5213                         setval(path, bb_default_root_path);
5214                 else
5215                         setval(path, bb_default_path);
5216         }
5217         export(path);
5218
5219         ifs = lookup("IFS");
5220         if (ifs->value == null)
5221                 setval(ifs, " \t\n");
5222
5223 #ifdef MSHDEBUG
5224         mshdbg_var = lookup("MSHDEBUG");
5225         if (mshdbg_var->value == null)
5226                 setval(mshdbg_var, "0");
5227 #endif
5228
5229         prompt = lookup("PS1");
5230 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5231         if (prompt->value == null)
5232 #endif
5233                 setval(prompt, DEFAULT_USER_PROMPT);
5234         if (geteuid() == 0) {
5235                 setval(prompt, DEFAULT_ROOT_PROMPT);
5236                 prompt->status &= ~EXPORT;
5237         }
5238         cprompt = lookup("PS2");
5239 #if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5240         if (cprompt->value == null)
5241 #endif
5242                 setval(cprompt, "> ");
5243
5244         iof = filechar;
5245         cflag = 0;
5246         name = *argv++;
5247         if (--argc >= 1) {
5248                 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5249                         for (s = argv[0] + 1; *s; s++)
5250                                 switch (*s) {
5251                                 case 'c':
5252                                         prompt->status &= ~EXPORT;
5253                                         cprompt->status &= ~EXPORT;
5254                                         setval(prompt, "");
5255                                         setval(cprompt, "");
5256                                         cflag = 1;
5257                                         if (--argc > 0)
5258                                                 PUSHIO(aword, *++argv, iof = nlchar);
5259                                         break;
5260
5261                                 case 'q':
5262                                         qflag = SIG_DFL;
5263                                         break;
5264
5265                                 case 's':
5266                                         /* standard input */
5267                                         break;
5268
5269                                 case 't':
5270                                         prompt->status &= ~EXPORT;
5271                                         setval(prompt, "");
5272                                         iof = linechar;
5273                                         break;
5274
5275                                 case 'i':
5276                                         interactive = 1;
5277                                 default:
5278                                         if (*s >= 'a' && *s <= 'z')
5279                                                 FLAG[(int) *s]++;
5280                                 }
5281                 } else {
5282                         argv--;
5283                         argc++;
5284                 }
5285
5286                 if (iof == filechar && --argc > 0) {
5287                         setval(prompt, "");
5288                         setval(cprompt, "");
5289                         prompt->status &= ~EXPORT;
5290                         cprompt->status &= ~EXPORT;
5291
5292 /* Shell is non-interactive, activate printf-based debug */
5293 #ifdef MSHDEBUG
5294                         mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5295                         if (mshdbg < 0)
5296                                 mshdbg = 0;
5297 #endif
5298                         DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5299
5300                         name = *++argv;
5301                         if (newfile(name))
5302                                 exit(1);                /* Exit on error */
5303                 }
5304         }
5305
5306         setdash();
5307
5308         /* This won't be true if PUSHIO has been called, say from newfile() above */
5309         if (global_env.iop < iostack) {
5310                 PUSHIO(afile, 0, iof);
5311                 if (isatty(0) && isatty(1) && !cflag) {
5312                         interactive = 1;
5313 #if !ENABLE_FEATURE_SH_EXTRA_QUIET
5314 #ifdef MSHDEBUG
5315                         printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
5316 #else
5317                         printf("\n\n%s built-in shell (msh)\n", bb_banner);
5318 #endif
5319                         printf("Enter 'help' for a list of built-in commands.\n\n");
5320 #endif
5321                 }
5322         }
5323
5324         signal(SIGQUIT, qflag);
5325         if (name && name[0] == '-') {
5326                 interactive = 1;
5327                 f = open(".profile", O_RDONLY);
5328                 if (f >= 0)
5329                         next(remap(f));
5330                 f = open("/etc/profile", O_RDONLY);
5331                 if (f >= 0)
5332                         next(remap(f));
5333         }
5334         if (interactive)
5335                 signal(SIGTERM, sig);
5336
5337         if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5338                 signal(SIGINT, onintr);
5339
5340 /* Handle "msh SCRIPT VAR=val params..." */
5341 /* Disabled: bash does not do it! */
5342 #if 0
5343         argv++;
5344         /* skip leading args of the form VAR=val */
5345         while (*argv && assign(*argv, !COPYV)) {
5346                 argc--;
5347                 argv++;
5348         }
5349         argv--;
5350 #endif
5351         dolv = argv;
5352         dolc = argc;
5353         dolv[0] = name;
5354
5355         setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5356
5357         DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
5358
5359         for (;;) {
5360                 if (interactive && global_env.iop <= iostack) {
5361 #if ENABLE_FEATURE_EDITING
5362                         current_prompt = prompt->value;
5363 #else
5364                         prs(prompt->value);
5365 #endif
5366                 }
5367                 onecommand();
5368                 /* Ensure that getenv("PATH") stays current */
5369                 setenv("PATH", path->value, 1);
5370         }
5371
5372         DBGPRINTF(("MSH_MAIN: returning.\n"));
5373 }
5374
5375
5376 /*
5377  * Copyright (c) 1987,1997, Prentice Hall
5378  * All rights reserved.
5379  *
5380  * Redistribution and use of the MINIX operating system in source and
5381  * binary forms, with or without modification, are permitted provided
5382  * that the following conditions are met:
5383  *
5384  * Redistributions of source code must retain the above copyright
5385  * notice, this list of conditions and the following disclaimer.
5386  *
5387  * Redistributions in binary form must reproduce the above
5388  * copyright notice, this list of conditions and the following
5389  * disclaimer in the documentation and/or other materials provided
5390  * with the distribution.
5391  *
5392  * Neither the name of Prentice Hall nor the names of the software
5393  * authors or contributors may be used to endorse or promote
5394  * products derived from this software without specific prior
5395  * written permission.
5396  *
5397  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5398  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5399  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5400  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5401  * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5402  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5403  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5404  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5405  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5406  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5407  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5408  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5409  *
5410  */