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