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