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