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