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