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