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