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