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