blob: b3bb06b28fb45df90430ad8dea2bf35550754c99 [file] [log] [blame]
Eric Andersenff9eee42001-06-29 04:57:14 +00001/* 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
Eric Andersencb81e642003-07-14 21:21:08 +00006 * by Erik Andersen <andersen@codepoet.org>
Eric Andersenff9eee42001-06-29 04:57:14 +00007 *
Eric Andersen737f5fb2003-03-14 16:05:59 +00008 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
Eric Andersencb81e642003-07-14 21:21:08 +000011 * Erik Andersen <andersen@codepoet.org>
Eric Andersen737f5fb2003-03-14 16:05:59 +000012 *
Eric Andersenff9eee42001-06-29 04:57:14 +000013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Eric Andersenc7bda1c2004-03-15 08:29:22 +000026 *
Eric Andersenff9eee42001-06-29 04:57:14 +000027 * Original copyright notice is retained at the end of this file.
28 */
29
30#include <ctype.h>
31#include <dirent.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <limits.h>
35#include <setjmp.h>
36#include <signal.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include <unistd.h>
43#include <sys/stat.h>
44#include <sys/times.h>
45#include <sys/types.h>
46#include <sys/wait.h>
47
48#include "cmdedit.h"
49#include "busybox.h"
50
51
Eric Andersen12de6cf2004-08-04 19:19:10 +000052/* Conditional use of "register" keyword */
53#define REGISTER register
54
55
56/*#define MSHDEBUG 1*/
57
58#ifdef MSHDEBUG
59int mshdbg = 0;
60
61#define DBGPRINTF(x) if(mshdbg>0)printf x
62#define DBGPRINTF0(x) if(mshdbg>0)printf x
63#define DBGPRINTF1(x) if(mshdbg>1)printf x
64#define DBGPRINTF2(x) if(mshdbg>2)printf x
65#define DBGPRINTF3(x) if(mshdbg>3)printf x
66#define DBGPRINTF4(x) if(mshdbg>4)printf x
67#define DBGPRINTF5(x) if(mshdbg>5)printf x
68#define DBGPRINTF6(x) if(mshdbg>6)printf x
69#define DBGPRINTF7(x) if(mshdbg>7)printf x
70#define DBGPRINTF8(x) if(mshdbg>8)printf x
71#define DBGPRINTF9(x) if(mshdbg>9)printf x
72
73int mshdbg_rc = 0;
74
75#define RCPRINTF(x) if(mshdbg_rc)printf x
76
77#else
78
79#define DBGPRINTF(x)
80#define DBGPRINTF0(x)
81#define DBGPRINTF1(x)
82#define DBGPRINTF2(x)
83#define DBGPRINTF3(x)
84#define DBGPRINTF4(x)
85#define DBGPRINTF5(x)
86#define DBGPRINTF6(x)
87#define DBGPRINTF7(x)
88#define DBGPRINTF8(x)
89#define DBGPRINTF9(x)
90
91#define RCPRINTF(x)
92
93#endif /* MSHDEBUG */
94
95
Eric Andersenff9eee42001-06-29 04:57:14 +000096/* -------- sh.h -------- */
97/*
98 * shell
99 */
100
Eric Andersen12de6cf2004-08-04 19:19:10 +0000101#define LINELIM 2100
102#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000103
Eric Andersen392947c2002-12-11 07:42:46 +0000104#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000105#define NOFILE 20 /* Number of open files */
106#define NUFILE 10 /* Number of user-accessible files */
107#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000108
109/*
110 * values returned by wait
111 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000112#define WAITSIG(s) ((s)&0177)
113#define WAITVAL(s) (((s)>>8)&0377)
Eric Andersenff9eee42001-06-29 04:57:14 +0000114#define WAITCORE(s) (((s)&0200)!=0)
115
116/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000117 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000118 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000119typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000120
121/*
122 * shell components
123 */
124
125#define QUOTE 0200
126
127#define NOBLOCK ((struct op *)NULL)
128#define NOWORD ((char *)NULL)
129#define NOWORDS ((char **)NULL)
130#define NOPIPE ((int *)NULL)
131
132/*
133 * Description of a command or an operation on commands.
134 * Might eventually use a union.
135 */
136struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000137 int type; /* operation type, see below */
138 char **words; /* arguments to a command */
139 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000140 struct op *left;
141 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000142 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000143};
144
Eric Andersen8401eea2004-08-04 19:16:54 +0000145#define TCOM 1 /* command */
146#define TPAREN 2 /* (c-list) */
147#define TPIPE 3 /* a | b */
148#define TLIST 4 /* a [&;] b */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000149#define TOR 5 /* || */
Eric Andersen8401eea2004-08-04 19:16:54 +0000150#define TAND 6 /* && */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151#define TFOR 7
Eric Andersen12de6cf2004-08-04 19:19:10 +0000152#define TDO 8
Eric Andersenff9eee42001-06-29 04:57:14 +0000153#define TCASE 9
Eric Andersen12de6cf2004-08-04 19:19:10 +0000154#define TIF 10
Eric Andersenff9eee42001-06-29 04:57:14 +0000155#define TWHILE 11
156#define TUNTIL 12
157#define TELIF 13
Eric Andersen8401eea2004-08-04 19:16:54 +0000158#define TPAT 14 /* pattern in case */
159#define TBRACE 15 /* {c-list} */
160#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000161/* Added to support "." file expansion */
162#define TDOT 17
163
164/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000165#ifdef MSHDEBUG
166static char *T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000167 "PLACEHOLDER",
168 "TCOM",
169 "TPAREN",
170 "TPIPE",
171 "TLIST",
172 "TOR",
173 "TAND",
174 "TFOR",
175 "TDO",
176 "TCASE",
177 "TIF",
178 "TWHILE",
179 "TUNTIL",
180 "TELIF",
181 "TPAT",
182 "TBRACE",
183 "TASYNC",
184 "TDOT",
185};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000186#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000187
188/*
189 * actions determining the environment of a process
190 */
191#define BIT(i) (1<<(i))
Eric Andersen8401eea2004-08-04 19:16:54 +0000192#define FEXEC BIT(0) /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000193
Eric Andersen12de6cf2004-08-04 19:19:10 +0000194#if 0 /* Original value */
195#define AREASIZE (65000)
196#else
197#define AREASIZE (90000)
198#endif
199
Eric Andersenff9eee42001-06-29 04:57:14 +0000200/*
201 * flags to control evaluation of words
202 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000203#define DOSUB 1 /* interpret $, `, and quotes */
204#define DOBLANK 2 /* perform blank interpretation */
205#define DOGLOB 4 /* interpret [?* */
206#define DOKEY 8 /* move words with `=' to 2nd arg. list */
207#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000208
209#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
210
Eric Andersenff9eee42001-06-29 04:57:14 +0000211
Eric Andersen12de6cf2004-08-04 19:19:10 +0000212/* PROTOTYPES */
Eric Andersenff9eee42001-06-29 04:57:14 +0000213static int newfile(char *s);
214static char *findeq(char *cp);
215static char *cclass(char *p, int sub);
216static void initarea(void);
Matt Kraai2d91deb2001-08-01 17:21:35 +0000217extern int msh_main(int argc, char **argv);
Eric Andersenff9eee42001-06-29 04:57:14 +0000218
219
Eric Andersen8401eea2004-08-04 19:16:54 +0000220struct brkcon {
221 jmp_buf brkpt;
222 struct brkcon *nextlev;
223};
Eric Andersenff9eee42001-06-29 04:57:14 +0000224
Eric Andersen12de6cf2004-08-04 19:19:10 +0000225
Eric Andersenff9eee42001-06-29 04:57:14 +0000226/*
227 * redirection
228 */
229struct ioword {
Eric Andersen8401eea2004-08-04 19:16:54 +0000230 short io_unit; /* unit affected */
231 short io_flag; /* action (below) */
232 char *io_name; /* file name */
Eric Andersenff9eee42001-06-29 04:57:14 +0000233};
Eric Andersenff9eee42001-06-29 04:57:14 +0000234
Eric Andersen12de6cf2004-08-04 19:19:10 +0000235#define IOREAD 1 /* < */
236#define IOHERE 2 /* << (here file) */
237#define IOWRITE 4 /* > */
238#define IOCAT 8 /* >> */
239#define IOXHERE 16 /* ${}, ` in << */
240#define IODUP 32 /* >&digit */
241#define IOCLOSE 64 /* >&- */
Eric Andersenff9eee42001-06-29 04:57:14 +0000242
Eric Andersen8401eea2004-08-04 19:16:54 +0000243#define IODEFAULT (-1) /* token for default IO unit */
244
Eric Andersen12de6cf2004-08-04 19:19:10 +0000245
Eric Andersenff9eee42001-06-29 04:57:14 +0000246
247/*
248 * parsing & execution environment
249 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000250static struct env {
251 char *linep;
252 struct io *iobase;
253 struct io *iop;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000254 xint *errpt; /* void * */
Eric Andersen8401eea2004-08-04 19:16:54 +0000255 int iofd;
256 struct env *oenv;
Eric Andersenff9eee42001-06-29 04:57:14 +0000257} e;
258
259/*
260 * flags:
261 * -e: quit on error
262 * -k: look for name=value everywhere on command line
263 * -n: no execution
264 * -t: exit after reading and executing one command
265 * -v: echo as read
266 * -x: trace
267 * -u: unset variables net diagnostic
268 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000269static char *flag;
Eric Andersenff9eee42001-06-29 04:57:14 +0000270
Eric Andersen8401eea2004-08-04 19:16:54 +0000271static char *null; /* null value for variable */
272static int intr; /* interrupt pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000273
Eric Andersen8401eea2004-08-04 19:16:54 +0000274static char *trap[_NSIG + 1];
275static char ourtrap[_NSIG + 1];
276static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000277
Eric Andersen8401eea2004-08-04 19:16:54 +0000278static int heedint; /* heed interrupt signals */
Eric Andersenff9eee42001-06-29 04:57:14 +0000279
Eric Andersen8401eea2004-08-04 19:16:54 +0000280static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000281
Eric Andersen8401eea2004-08-04 19:16:54 +0000282static char line[LINELIM];
283static char *elinep;
Eric Andersenff9eee42001-06-29 04:57:14 +0000284
Eric Andersen12de6cf2004-08-04 19:19:10 +0000285
Eric Andersenff9eee42001-06-29 04:57:14 +0000286/*
287 * other functions
288 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000289static int (*inbuilt(char *s)) (struct op *);
Eric Andersen392947c2002-12-11 07:42:46 +0000290
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static char *rexecve(char *c, char **v, char **envp);
292static char *space(int n);
293static char *strsave(char *s, int a);
294static char *evalstr(char *cp, int f);
295static char *putn(int n);
296static char *itoa(int n);
297static char *unquote(char *as);
298static struct var *lookup(char *n);
299static int rlookup(char *n);
300static struct wdblock *glob(char *cp, struct wdblock *wb);
301static int my_getc(int ec);
302static int subgetc(int ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000303static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000304static char **eval(char **ap, int f);
305static int setstatus(int s);
306static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000307
Eric Andersen8401eea2004-08-04 19:16:54 +0000308static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000309
Eric Andersen8401eea2004-08-04 19:16:54 +0000310static int newenv(int f);
311static void quitenv(void);
312static void err(char *s);
313static int anys(char *s1, char *s2);
314static int any(int c, char *s);
315static void next(int f);
316static void setdash(void);
317static void onecommand(void);
318static void runtrap(int i);
319static int gmatch(char *s, char *p);
Eric Andersenff9eee42001-06-29 04:57:14 +0000320
Eric Andersen12de6cf2004-08-04 19:19:10 +0000321
Eric Andersenff9eee42001-06-29 04:57:14 +0000322/*
323 * error handling
324 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000325static void leave(void); /* abort shell (or fail in subshell) */
326static void fail(void); /* fail but return to process next command */
327static void warn(char *s);
328static void sig(int i); /* default signal handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000329
330
331
332/* -------- area stuff -------- */
333
Eric Andersen12de6cf2004-08-04 19:19:10 +0000334#define REGSIZE sizeof(struct region)
335#define GROWBY (256)
336/* #define SHRINKBY (64) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000337#undef SHRINKBY
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000338#define FREE (32767)
339#define BUSY (0)
340#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000341
342
343struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000344 struct region *next;
345 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000346};
347
348
349
350/* -------- grammar stuff -------- */
351typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000352 char *cp;
353 char **wp;
354 int i;
355 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000356} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000357
Eric Andersenff9eee42001-06-29 04:57:14 +0000358#define WORD 256
359#define LOGAND 257
360#define LOGOR 258
361#define BREAK 259
Eric Andersen12de6cf2004-08-04 19:19:10 +0000362#define IF 260
Eric Andersenff9eee42001-06-29 04:57:14 +0000363#define THEN 261
364#define ELSE 262
365#define ELIF 263
Eric Andersen12de6cf2004-08-04 19:19:10 +0000366#define FI 264
Eric Andersenff9eee42001-06-29 04:57:14 +0000367#define CASE 265
368#define ESAC 266
Eric Andersen12de6cf2004-08-04 19:19:10 +0000369#define FOR 267
Eric Andersenff9eee42001-06-29 04:57:14 +0000370#define WHILE 268
371#define UNTIL 269
Eric Andersen12de6cf2004-08-04 19:19:10 +0000372#define DO 270
Eric Andersenff9eee42001-06-29 04:57:14 +0000373#define DONE 271
Eric Andersen12de6cf2004-08-04 19:19:10 +0000374#define IN 272
375/* Added for "." file expansion */
376#define DOT 273
377
Eric Andersenff9eee42001-06-29 04:57:14 +0000378#define YYERRCODE 300
379
380/* flags to yylex */
Eric Andersen8401eea2004-08-04 19:16:54 +0000381#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000382
383#define SYNTAXERR zzerr()
Eric Andersen12de6cf2004-08-04 19:19:10 +0000384
Eric Andersen8401eea2004-08-04 19:16:54 +0000385static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000386static struct op *andor(void);
387static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000388static int synio(int cf);
389static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000390static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000391static struct op *nested(int type, int mark);
392static struct op *command(int cf);
393static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000394static struct op *thenpart(void);
395static struct op *elsepart(void);
396static struct op *caselist(void);
397static struct op *casepart(void);
398static char **pattern(void);
399static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000400static struct op *list(struct op *t1, struct op *t2);
401static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000402static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000403static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000404static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000405static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000406static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000407static struct ioword *io(int u, int f, char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000408static void zzerr(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000409static void yyerror(char *s);
410static int yylex(int cf);
411static int collect(int c, int c1);
412static int dual(int c);
413static void diag(int ec);
414static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000415
416/* -------- var.h -------- */
417
Eric Andersen8401eea2004-08-04 19:16:54 +0000418struct var {
419 char *value;
420 char *name;
421 struct var *next;
422 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000423};
Eric Andersenff9eee42001-06-29 04:57:14 +0000424
Eric Andersen8401eea2004-08-04 19:16:54 +0000425#define COPYV 1 /* flag to setval, suggesting copy */
426#define RONLY 01 /* variable is read-only */
427#define EXPORT 02 /* variable is to be exported */
428#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000429
Eric Andersen8401eea2004-08-04 19:16:54 +0000430static int yyparse(void);
431static struct var *lookup(char *n);
432static void setval(struct var *vp, char *val);
433static void nameval(struct var *vp, char *val, char *name);
434static void export(struct var *vp);
435static void ronly(struct var *vp);
436static int isassign(char *s);
437static int checkname(char *cp);
438static int assign(char *s, int cf);
439static void putvlist(int f, int out);
440static int eqname(char *n1, char *n2);
441
442static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000443
Eric Andersen12de6cf2004-08-04 19:19:10 +0000444
Eric Andersenff9eee42001-06-29 04:57:14 +0000445/* -------- io.h -------- */
446/* io buffer */
447struct iobuf {
Eric Andersen8401eea2004-08-04 19:16:54 +0000448 unsigned id; /* buffer id */
449 char buf[512]; /* buffer */
450 char *bufp; /* pointer into buffer */
451 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000452};
453
454/* possible arguments to an IO function */
455struct ioarg {
Eric Andersen8401eea2004-08-04 19:16:54 +0000456 char *aword;
457 char **awordlist;
458 int afile; /* file descriptor */
459 unsigned afid; /* buffer id */
460 long afpos; /* file position */
461 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000462};
Eric Andersen8401eea2004-08-04 19:16:54 +0000463
Eric Andersenff9eee42001-06-29 04:57:14 +0000464//static struct ioarg ioargstack[NPUSH];
465#define AFID_NOBUF (~0)
466#define AFID_ID 0
467
468/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000469struct io {
470 int (*iofn) (struct ioarg *, struct io *);
471 struct ioarg *argp;
472 int peekc;
473 char prev; /* previous character read by readc() */
474 char nlcount; /* for `'s */
475 char xchar; /* for `'s */
476 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000477};
Eric Andersen8401eea2004-08-04 19:16:54 +0000478
479//static struct io iostack[NPUSH];
480#define XOTHER 0 /* none of the below */
481#define XDOLL 1 /* expanding ${} */
482#define XGRAVE 2 /* expanding `'s */
483#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000484
485/* in substitution */
486#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
487
Eric Andersen12de6cf2004-08-04 19:19:10 +0000488
Eric Andersenff9eee42001-06-29 04:57:14 +0000489/*
490 * input generators for IO structure
491 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000492static int nlchar(struct ioarg *ap);
493static int strchar(struct ioarg *ap);
494static int qstrchar(struct ioarg *ap);
495static int filechar(struct ioarg *ap);
496static int herechar(struct ioarg *ap);
497static int linechar(struct ioarg *ap);
498static int gravechar(struct ioarg *ap, struct io *iop);
499static int qgravechar(struct ioarg *ap, struct io *iop);
500static int dolchar(struct ioarg *ap);
501static int wdchar(struct ioarg *ap);
502static void scraphere(void);
503static void freehere(int area);
504static void gethere(void);
505static void markhere(char *s, struct ioword *iop);
506static int herein(char *hname, int xdoll);
507static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000508
Eric Andersen12de6cf2004-08-04 19:19:10 +0000509
Eric Andersenff9eee42001-06-29 04:57:14 +0000510/*
511 * IO functions
512 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000513static int eofc(void);
514static int readc(void);
515static void unget(int c);
516static void ioecho(int c);
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000517static void prs(const char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000518static void prn(unsigned u);
519static void closef(int i);
520static void closeall(void);
Eric Andersenff9eee42001-06-29 04:57:14 +0000521
Eric Andersen12de6cf2004-08-04 19:19:10 +0000522
Eric Andersenff9eee42001-06-29 04:57:14 +0000523/*
524 * IO control
525 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000526static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
527static int remap(int fd);
528static int openpipe(int *pv);
529static void closepipe(int *pv);
530static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000531
Eric Andersenff9eee42001-06-29 04:57:14 +0000532#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
533#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
534
535/* -------- word.h -------- */
536
Eric Andersen8401eea2004-08-04 19:16:54 +0000537#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000538
Eric Andersen8401eea2004-08-04 19:16:54 +0000539struct wdblock {
540 short w_bsize;
541 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000542 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000543 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000544};
545
Eric Andersen8401eea2004-08-04 19:16:54 +0000546static struct wdblock *addword(char *wd, struct wdblock *wb);
547static struct wdblock *newword(int nw);
548static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000549
550/* -------- area.h -------- */
551
552/*
553 * storage allocation
554 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000555static char *getcell(unsigned nbytes);
556static void garbage(void);
557static void setarea(char *cp, int a);
558static int getarea(char *cp);
559static void freearea(int a);
560static void freecell(char *cp);
561static int areanum; /* current allocation area */
Eric Andersenff9eee42001-06-29 04:57:14 +0000562
Eric Andersen12de6cf2004-08-04 19:19:10 +0000563#define NEW(type) (type *)getcell(sizeof(type))
Eric Andersenff9eee42001-06-29 04:57:14 +0000564#define DELETE(obj) freecell((char *)obj)
565
566
567/* -------- misc stuff -------- */
568
Eric Andersen12de6cf2004-08-04 19:19:10 +0000569static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000570static int iosetup(struct ioword *iop, int pipein, int pipeout);
571static void echo(char **wp);
572static struct op **find1case(struct op *t, char *w);
573static struct op *findcase(struct op *t, char *w);
574static void brkset(struct brkcon *bc);
575static int dolabel(struct op *t);
576static int dohelp(struct op *t);
577static int dochdir(struct op *t);
578static int doshift(struct op *t);
579static int dologin(struct op *t);
580static int doumask(struct op *t);
581static int doexec(struct op *t);
582static int dodot(struct op *t);
583static int dowait(struct op *t);
584static int doread(struct op *t);
585static int doeval(struct op *t);
586static int dotrap(struct op *t);
587static int getsig(char *s);
588static void setsig(int n, sighandler_t f);
589static int getn(char *as);
590static int dobreak(struct op *t);
591static int docontinue(struct op *t);
592static int brkcontin(char *cp, int val);
593static int doexit(struct op *t);
594static int doexport(struct op *t);
595static int doreadonly(struct op *t);
596static void rdexp(char **wp, void (*f) (struct var *), int key);
597static void badid(char *s);
598static int doset(struct op *t);
599static void varput(char *s, int out);
600static int dotimes(struct op *t);
601static int expand(char *cp, struct wdblock **wbp, int f);
602static char *blank(int f);
603static int dollar(int quoted);
604static int grave(int quoted);
605static void globname(char *we, char *pp);
606static char *generate(char *start1, char *end1, char *middle, char *end);
607static int anyspcl(struct wdblock *wb);
608static int xstrcmp(char *p1, char *p2);
609static void glob0(char *a0, unsigned int a1, int a2,
610 int (*a3) (char *, char *));
611static void glob1(char *base, char *lim);
612static void glob2(char *i, char *j);
613static void glob3(char *i, char *j, char *k);
614static void readhere(char **name, char *s, int ec);
615static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
616static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000617
Eric Andersen8401eea2004-08-04 19:16:54 +0000618struct here {
619 char *h_tag;
620 int h_dosub;
621 struct ioword *h_iop;
622 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000623};
624
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000625static const char * const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000626 "Signal 0",
627 "Hangup",
Eric Andersen8401eea2004-08-04 19:16:54 +0000628 (char *) NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000629 "Quit",
630 "Illegal instruction",
631 "Trace/BPT trap",
632 "Abort",
633 "Bus error",
634 "Floating Point Exception",
635 "Killed",
636 "SIGUSR1",
637 "SIGSEGV",
638 "SIGUSR2",
Eric Andersen8401eea2004-08-04 19:16:54 +0000639 (char *) NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000640 "Alarm clock",
641 "Terminated",
642};
Eric Andersen8401eea2004-08-04 19:16:54 +0000643
Eric Andersenff9eee42001-06-29 04:57:14 +0000644#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
645
646struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000647 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000648 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000649};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000650static const struct res restab[] = {
Eric Andersen8401eea2004-08-04 19:16:54 +0000651 {"for", FOR},
652 {"case", CASE},
653 {"esac", ESAC},
654 {"while", WHILE},
655 {"do", DO},
656 {"done", DONE},
657 {"if", IF},
658 {"in", IN},
659 {"then", THEN},
660 {"else", ELSE},
661 {"elif", ELIF},
662 {"until", UNTIL},
663 {"fi", FI},
Eric Andersen8401eea2004-08-04 19:16:54 +0000664 {";;", BREAK},
665 {"||", LOGOR},
666 {"&&", LOGAND},
667 {"{", '{'},
668 {"}", '}'},
Eric Andersen12de6cf2004-08-04 19:19:10 +0000669 {".", DOT},
Eric Andersen8401eea2004-08-04 19:16:54 +0000670 {0, 0},
Eric Andersenff9eee42001-06-29 04:57:14 +0000671};
672
673
Eric Andersen1c039232001-07-07 00:05:55 +0000674struct builtincmd {
675 const char *name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000676 int (*builtinfunc) (struct op * t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000677};
Eric Andersen8401eea2004-08-04 19:16:54 +0000678static const struct builtincmd builtincmds[] = {
679 {".", dodot},
680 {":", dolabel},
681 {"break", dobreak},
682 {"cd", dochdir},
683 {"continue", docontinue},
684 {"eval", doeval},
685 {"exec", doexec},
686 {"exit", doexit},
687 {"export", doexport},
688 {"help", dohelp},
689 {"login", dologin},
690 {"newgrp", dologin},
691 {"read", doread},
692 {"readonly", doreadonly},
693 {"set", doset},
694 {"shift", doshift},
695 {"times", dotimes},
696 {"trap", dotrap},
697 {"umask", doumask},
698 {"wait", dowait},
699 {0, 0}
Eric Andersenff9eee42001-06-29 04:57:14 +0000700};
701
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000702static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000703static struct op *dowholefile(int, int);
704
Eric Andersenff9eee42001-06-29 04:57:14 +0000705/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000706extern char **environ; /* environment pointer */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000707
Eric Andersen8401eea2004-08-04 19:16:54 +0000708static char **dolv;
709static int dolc;
710static int exstat;
711static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000712static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000713static int execflg;
714static int multiline; /* \n changed to ; */
715static struct op *outtree; /* result from parser */
716static xint *failpt;
717static xint *errpt;
718static struct brkcon *brklist;
719static int isbreak;
720static struct wdblock *wdlist;
721static struct wdblock *iolist;
722static char *trap[_NSIG + 1];
723static char ourtrap[_NSIG + 1];
724static int trapset; /* trap pending */
725static int yynerrs; /* yacc */
726static char line[LINELIM];
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727
728#ifdef MSHDEBUG
729static struct var *mshdbg_var;
730#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000731static struct var *vlist; /* dictionary */
732static struct var *homedir; /* home directory */
733static struct var *prompt; /* main prompt */
734static struct var *cprompt; /* continuation prompt */
735static struct var *path; /* search path for commands */
736static struct var *shell; /* shell to interpret command files */
737static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000738
Eric Andersen8401eea2004-08-04 19:16:54 +0000739static int areanum; /* current allocation area */
740static int intr;
741static int inparse;
742static char flags['z' - 'a' + 1];
743static char *flag = flags - 'a';
Eric Andersen8401eea2004-08-04 19:16:54 +0000744static char *null = "";
745static int heedint = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +0000746static void (*qflag) (int) = SIG_IGN;
747static int startl;
748static int peeksym;
749static int nlseen;
750static int iounit = IODEFAULT;
751static YYSTYPE yylval;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000752static char *elinep = line + sizeof(line) - 5;
753
754static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
755static struct ioarg ioargstack[NPUSH];
756static struct io iostack[NPUSH];
Eric Andersen8401eea2004-08-04 19:16:54 +0000757static struct iobuf sharedbuf = { AFID_NOBUF };
758static struct iobuf mainbuf = { AFID_NOBUF };
Eric Andersenff9eee42001-06-29 04:57:14 +0000759static unsigned bufid = AFID_ID; /* buffer id counter */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000760
Eric Andersen8401eea2004-08-04 19:16:54 +0000761static struct here *inhere; /* list of hear docs while parsing */
762static struct here *acthere; /* list of active here documents */
763static struct region *areabot; /* bottom of area */
764static struct region *areatop; /* top of area */
765static struct region *areanxt; /* starting point of scan */
766static void *brktop;
767static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000768
Eric Andersen12de6cf2004-08-04 19:19:10 +0000769static struct env e = {
770 line, /* linep: char ptr */
771 iostack, /* iobase: struct io ptr */
772 iostack - 1, /* iop: struct io ptr */
773 (xint *) NULL, /* errpt: void ptr for errors? */
774 FDBASE, /* iofd: file desc */
775 (struct env *) NULL /* oenv: struct env ptr */
776};
777
778#ifdef MSHDEBUG
779void print_t(struct op *t)
780{
781 DBGPRINTF(("T: t=0x%x, type %s, words=0x%x, IOword=0x%x\n", t,
782 T_CMD_NAMES[t->type], t->words, t->ioact));
783
784 if (t->words) {
785 DBGPRINTF(("T: W1: %s", t->words[0]));
786 }
787
788 return;
789}
790
791void print_tree(struct op *head)
792{
793 if (head == NULL) {
794 DBGPRINTF(("PRINT_TREE: no tree\n"));
795 return;
796 }
797
798 DBGPRINTF(("NODE: 0x%x, left 0x%x, right 0x%x\n", head, head->left,
799 head->right));
800
801 if (head->left)
802 print_tree(head->left);
803
804 if (head->right)
805 print_tree(head->right);
806
807 return;
808}
809#endif /* MSHDEBUG */
810
Eric Andersenff9eee42001-06-29 04:57:14 +0000811
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000812#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000813static char *current_prompt;
Eric Andersenff9eee42001-06-29 04:57:14 +0000814#endif
815
Eric Andersenff9eee42001-06-29 04:57:14 +0000816/* -------- sh.c -------- */
817/*
818 * shell
819 */
820
821
Rob Landleydfba7412006-03-06 20:47:33 +0000822int msh_main(int argc, char **argv)
Eric Andersenff9eee42001-06-29 04:57:14 +0000823{
Eric Andersen12de6cf2004-08-04 19:19:10 +0000824 REGISTER int f;
825 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +0000826 int cflag;
827 char *name, **ap;
Eric Andersen8401eea2004-08-04 19:16:54 +0000828 int (*iof) (struct ioarg *);
Eric Andersenff9eee42001-06-29 04:57:14 +0000829
Eric Andersen12de6cf2004-08-04 19:19:10 +0000830 DBGPRINTF(("MSH_MAIN: argc %d, environ 0x%x\n", argc, environ));
831
Eric Andersenff9eee42001-06-29 04:57:14 +0000832 initarea();
833 if ((ap = environ) != NULL) {
834 while (*ap)
835 assign(*ap++, !COPYV);
836 for (ap = environ; *ap;)
837 export(lookup(*ap++));
838 }
839 closeall();
840 areanum = 1;
841
842 shell = lookup("SHELL");
843 if (shell->value == null)
Eric Andersen78500142004-08-27 19:55:28 +0000844 setval(shell, (char *)DEFAULT_SHELL);
Eric Andersenff9eee42001-06-29 04:57:14 +0000845 export(shell);
846
847 homedir = lookup("HOME");
848 if (homedir->value == null)
849 setval(homedir, "/");
850 export(homedir);
851
Eric Andersen737f5fb2003-03-14 16:05:59 +0000852 setval(lookup("$"), putn(getpid()));
Eric Andersenff9eee42001-06-29 04:57:14 +0000853
854 path = lookup("PATH");
Eric Andersen737f5fb2003-03-14 16:05:59 +0000855 if (path->value == null) {
856 if (geteuid() == 0)
857 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
858 else
859 setval(path, "/bin:/usr/bin");
860 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000861 export(path);
862
863 ifs = lookup("IFS");
864 if (ifs->value == null)
865 setval(ifs, " \t\n");
866
Eric Andersen12de6cf2004-08-04 19:19:10 +0000867#ifdef MSHDEBUG
868 mshdbg_var = lookup("MSHDEBUG");
869 if (mshdbg_var->value == null)
870 setval(mshdbg_var, "0");
871#endif
872
873
Eric Andersenff9eee42001-06-29 04:57:14 +0000874 prompt = lookup("PS1");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000875#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000876 if (prompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000877#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000878 setval(prompt, "$ ");
879 if (geteuid() == 0) {
880 setval(prompt, "# ");
881 prompt->status &= ~EXPORT;
882 }
883 cprompt = lookup("PS2");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000884#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000885 if (cprompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000886#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000887 setval(cprompt, "> ");
888
889 iof = filechar;
890 cflag = 0;
891 name = *argv++;
892 if (--argc >= 1) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000893 if (argv[0][0] == '-' && argv[0][1] != '\0') {
894 for (s = argv[0] + 1; *s; s++)
Eric Andersenff9eee42001-06-29 04:57:14 +0000895 switch (*s) {
896 case 'c':
897 prompt->status &= ~EXPORT;
898 cprompt->status &= ~EXPORT;
899 setval(prompt, "");
900 setval(cprompt, "");
901 cflag = 1;
902 if (--argc > 0)
903 PUSHIO(aword, *++argv, iof = nlchar);
904 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000905
Eric Andersenff9eee42001-06-29 04:57:14 +0000906 case 'q':
907 qflag = SIG_DFL;
908 break;
909
910 case 's':
911 /* standard input */
912 break;
913
914 case 't':
915 prompt->status &= ~EXPORT;
916 setval(prompt, "");
917 iof = linechar;
918 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000919
Eric Andersenff9eee42001-06-29 04:57:14 +0000920 case 'i':
921 interactive++;
922 default:
Eric Andersen8401eea2004-08-04 19:16:54 +0000923 if (*s >= 'a' && *s <= 'z')
924 flag[(int) *s]++;
Eric Andersenff9eee42001-06-29 04:57:14 +0000925 }
926 } else {
927 argv--;
928 argc++;
929 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000930
Eric Andersenff9eee42001-06-29 04:57:14 +0000931 if (iof == filechar && --argc > 0) {
932 setval(prompt, "");
933 setval(cprompt, "");
934 prompt->status &= ~EXPORT;
935 cprompt->status &= ~EXPORT;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000936
937/* Shell is non-interactive, activate printf-based debug */
938#ifdef MSHDEBUG
939 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
940 if (mshdbg < 0)
941 mshdbg = 0;
942#endif
943 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
944
Eric Andersenff9eee42001-06-29 04:57:14 +0000945 if (newfile(name = *++argv))
Eric Andersen12de6cf2004-08-04 19:19:10 +0000946 exit(1); /* Exit on error */
Eric Andersenff9eee42001-06-29 04:57:14 +0000947 }
948 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000949
Eric Andersenff9eee42001-06-29 04:57:14 +0000950 setdash();
Eric Andersen12de6cf2004-08-04 19:19:10 +0000951
952 /* This won't be true if PUSHIO has been called, say from newfile() above */
Eric Andersenff9eee42001-06-29 04:57:14 +0000953 if (e.iop < iostack) {
954 PUSHIO(afile, 0, iof);
Eric Andersen1c039232001-07-07 00:05:55 +0000955 if (isatty(0) && isatty(1) && !cflag) {
Eric Andersenff9eee42001-06-29 04:57:14 +0000956 interactive++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000957#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen12de6cf2004-08-04 19:19:10 +0000958#ifdef MSHDEBUG
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000959 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000960#else
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000961 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000962#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000963 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +0000964#endif
Eric Andersen1c039232001-07-07 00:05:55 +0000965 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000966 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000967
Eric Andersenff9eee42001-06-29 04:57:14 +0000968 signal(SIGQUIT, qflag);
969 if (name && name[0] == '-') {
970 interactive++;
971 if ((f = open(".profile", 0)) >= 0)
972 next(remap(f));
973 if ((f = open("/etc/profile", 0)) >= 0)
974 next(remap(f));
975 }
976 if (interactive)
977 signal(SIGTERM, sig);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000978
Eric Andersenff9eee42001-06-29 04:57:14 +0000979 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
980 signal(SIGINT, onintr);
981 dolv = argv;
982 dolc = argc;
983 dolv[0] = name;
984 if (dolc > 1) {
985 for (ap = ++argv; --argc > 0;) {
986 if (assign(*ap = *argv++, !COPYV)) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000987 dolc--; /* keyword */
Eric Andersenff9eee42001-06-29 04:57:14 +0000988 } else {
989 ap++;
990 }
991 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000992 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000993 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
994
Eric Andersen12de6cf2004-08-04 19:19:10 +0000995 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop 0x%x, iostack 0x%x\n", interactive, e.iop, iostack));
996
Eric Andersenff9eee42001-06-29 04:57:14 +0000997 for (;;) {
998 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000999#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00001000 current_prompt = prompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00001001#else
1002 prs(prompt->value);
1003#endif
1004 }
1005 onecommand();
Eric Andersen1c315012002-04-26 23:40:09 +00001006 /* Ensure that getenv("PATH") stays current */
1007 setenv("PATH", path->value, 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001008 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001009
1010 DBGPRINTF(("MSH_MAIN: returning.\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001011}
1012
Eric Andersen8401eea2004-08-04 19:16:54 +00001013static void setdash()
Eric Andersenff9eee42001-06-29 04:57:14 +00001014{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001015 REGISTER char *cp;
1016 REGISTER int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001017 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001018
1019 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001020 for (c = 'a'; c <= 'z'; c++)
1021 if (flag[(int) c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001022 *cp++ = c;
1023 *cp = 0;
1024 setval(lookup("-"), m);
1025}
1026
Eric Andersen8401eea2004-08-04 19:16:54 +00001027static int newfile(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001028REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001029{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001030 REGISTER int f;
1031
1032 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001033
1034 if (strcmp(s, "-") != 0) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001035 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001036 f = open(s, 0);
1037 if (f < 0) {
1038 prs(s);
1039 err(": cannot open");
Eric Andersen8401eea2004-08-04 19:16:54 +00001040 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001041 }
1042 } else
1043 f = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001044
Eric Andersenff9eee42001-06-29 04:57:14 +00001045 next(remap(f));
Eric Andersen8401eea2004-08-04 19:16:54 +00001046 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001047}
1048
Eric Andersen12de6cf2004-08-04 19:19:10 +00001049
Eric Andersen12de6cf2004-08-04 19:19:10 +00001050struct op *scantree(head)
1051struct op *head;
1052{
1053 struct op *dotnode;
1054
1055 if (head == NULL)
1056 return (NULL);
1057
1058 if (head->left != NULL) {
1059 dotnode = scantree(head->left);
1060 if (dotnode)
1061 return (dotnode);
1062 }
1063
1064 if (head->right != NULL) {
1065 dotnode = scantree(head->right);
1066 if (dotnode)
1067 return (dotnode);
1068 }
1069
1070 if (head->words == NULL)
1071 return (NULL);
1072
1073 DBGPRINTF5(("SCANTREE: checking node 0x%x\n", head));
1074
1075 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
1076 DBGPRINTF5(("SCANTREE: dot found in node 0x%x\n", head));
1077 return (head);
1078 }
1079
1080 return (NULL);
1081}
1082
1083
Eric Andersen8401eea2004-08-04 19:16:54 +00001084static void onecommand()
Eric Andersenff9eee42001-06-29 04:57:14 +00001085{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001086 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001087 jmp_buf m1;
1088
Eric Andersen12de6cf2004-08-04 19:19:10 +00001089 DBGPRINTF(("ONECOMMAND: enter, outtree=0x%x\n", outtree));
1090
Eric Andersenff9eee42001-06-29 04:57:14 +00001091 while (e.oenv)
1092 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001093
Eric Andersenff9eee42001-06-29 04:57:14 +00001094 areanum = 1;
1095 freehere(areanum);
1096 freearea(areanum);
1097 garbage();
1098 wdlist = 0;
1099 iolist = 0;
1100 e.errpt = 0;
1101 e.linep = line;
1102 yynerrs = 0;
1103 multiline = 0;
1104 inparse = 1;
1105 intr = 0;
1106 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001107
Eric Andersen8401eea2004-08-04 19:16:54 +00001108 setjmp(failpt = m1); /* Bruce Evans' fix */
Eric Andersenff9eee42001-06-29 04:57:14 +00001109 if (setjmp(failpt = m1) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001110
1111 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1112
Eric Andersenff9eee42001-06-29 04:57:14 +00001113 while (e.oenv)
1114 quitenv();
1115 scraphere();
1116 if (!interactive && intr)
1117 leave();
1118 inparse = 0;
1119 intr = 0;
1120 return;
1121 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001122
Eric Andersenff9eee42001-06-29 04:57:14 +00001123 inparse = 0;
1124 brklist = 0;
1125 intr = 0;
1126 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001127
1128 if (!flag['n']) {
1129 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=0x%x\n",
1130 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001131 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001132 }
1133
Eric Andersenff9eee42001-06-29 04:57:14 +00001134 if (!interactive && intr) {
1135 execflg = 0;
1136 leave();
1137 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001138
Eric Andersenff9eee42001-06-29 04:57:14 +00001139 if ((i = trapset) != 0) {
1140 trapset = 0;
1141 runtrap(i);
1142 }
1143}
1144
Eric Andersen8401eea2004-08-04 19:16:54 +00001145static void fail()
Eric Andersenff9eee42001-06-29 04:57:14 +00001146{
1147 longjmp(failpt, 1);
1148 /* NOTREACHED */
1149}
1150
Eric Andersen8401eea2004-08-04 19:16:54 +00001151static void leave()
Eric Andersenff9eee42001-06-29 04:57:14 +00001152{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001153 DBGPRINTF(("LEAVE: leave called!\n"));
1154
Eric Andersenff9eee42001-06-29 04:57:14 +00001155 if (execflg)
1156 fail();
1157 scraphere();
1158 freehere(1);
1159 runtrap(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001160 _exit(exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00001161 /* NOTREACHED */
1162}
1163
Eric Andersen8401eea2004-08-04 19:16:54 +00001164static void warn(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001165REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001166{
Eric Andersen8401eea2004-08-04 19:16:54 +00001167 if (*s) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001168 prs(s);
1169 exstat = -1;
1170 }
1171 prs("\n");
1172 if (flag['e'])
1173 leave();
1174}
1175
Eric Andersen8401eea2004-08-04 19:16:54 +00001176static void err(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001177char *s;
1178{
1179 warn(s);
1180 if (flag['n'])
1181 return;
1182 if (!interactive)
1183 leave();
1184 if (e.errpt)
1185 longjmp(e.errpt, 1);
1186 closeall();
1187 e.iop = e.iobase = iostack;
1188}
1189
Eric Andersen8401eea2004-08-04 19:16:54 +00001190static int newenv(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001191int f;
1192{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001193 REGISTER struct env *ep;
1194
1195 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001196
1197 if (f) {
1198 quitenv();
Eric Andersen8401eea2004-08-04 19:16:54 +00001199 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001200 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001201
Eric Andersenff9eee42001-06-29 04:57:14 +00001202 ep = (struct env *) space(sizeof(*ep));
1203 if (ep == NULL) {
1204 while (e.oenv)
1205 quitenv();
1206 fail();
1207 }
1208 *ep = e;
1209 e.oenv = ep;
1210 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001211
Eric Andersen8401eea2004-08-04 19:16:54 +00001212 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001213}
1214
Eric Andersen8401eea2004-08-04 19:16:54 +00001215static void quitenv()
Eric Andersenff9eee42001-06-29 04:57:14 +00001216{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001217 REGISTER struct env *ep;
1218 REGISTER int fd;
1219
1220 DBGPRINTF(("QUITENV: e.oenv=0x%x\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001221
1222 if ((ep = e.oenv) != NULL) {
1223 fd = e.iofd;
1224 e = *ep;
1225 /* should close `'d files */
1226 DELETE(ep);
1227 while (--fd >= e.iofd)
1228 close(fd);
1229 }
1230}
1231
1232/*
1233 * Is any character from s1 in s2?
1234 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001235static int anys(s1, s2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001236REGISTER char *s1, *s2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001237{
1238 while (*s1)
1239 if (any(*s1++, s2))
Eric Andersen8401eea2004-08-04 19:16:54 +00001240 return (1);
1241 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001242}
1243
1244/*
1245 * Is character c in s?
1246 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001247static int any(c, s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001248REGISTER int c;
1249REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001250{
1251 while (*s)
1252 if (*s++ == c)
Eric Andersen8401eea2004-08-04 19:16:54 +00001253 return (1);
1254 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001255}
1256
Eric Andersen8401eea2004-08-04 19:16:54 +00001257static char *putn(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001258REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001259{
Eric Andersen8401eea2004-08-04 19:16:54 +00001260 return (itoa(n));
Eric Andersenff9eee42001-06-29 04:57:14 +00001261}
1262
Eric Andersen8401eea2004-08-04 19:16:54 +00001263static char *itoa(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001264REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001265{
Eric Andersenff9eee42001-06-29 04:57:14 +00001266 static char s[20];
Eric Andersen8401eea2004-08-04 19:16:54 +00001267
Eric Andersen737f5fb2003-03-14 16:05:59 +00001268 snprintf(s, sizeof(s), "%u", n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001269 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001270}
1271
Eric Andersen12de6cf2004-08-04 19:19:10 +00001272
Eric Andersen8401eea2004-08-04 19:16:54 +00001273static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001274{
1275 PUSHIO(afile, f, filechar);
1276}
1277
Eric Andersen8401eea2004-08-04 19:16:54 +00001278static void onintr(s)
1279int s; /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001280{
1281 signal(SIGINT, onintr);
1282 intr = 1;
1283 if (interactive) {
1284 if (inparse) {
1285 prs("\n");
1286 fail();
1287 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001288 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001289 execflg = 0;
1290 leave();
1291 }
1292}
1293
Eric Andersen8401eea2004-08-04 19:16:54 +00001294static char *space(n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001295int n;
1296{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001297 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001298
1299 if ((cp = getcell(n)) == 0)
1300 err("out of string space");
Eric Andersen8401eea2004-08-04 19:16:54 +00001301 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001302}
1303
Eric Andersen8401eea2004-08-04 19:16:54 +00001304static char *strsave(s, a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001305REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001306int a;
1307{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001308 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001309
Eric Andersen8401eea2004-08-04 19:16:54 +00001310 if ((cp = space(strlen(s) + 1)) != NULL) {
1311 setarea((char *) cp, a);
1312 for (xp = cp; (*xp++ = *s++) != '\0';);
1313 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001314 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001315 return ("");
Eric Andersenff9eee42001-06-29 04:57:14 +00001316}
1317
1318/*
1319 * trap handling
1320 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001321static void sig(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001323{
1324 trapset = i;
1325 signal(i, sig);
1326}
1327
1328static void runtrap(i)
1329int i;
1330{
1331 char *trapstr;
1332
1333 if ((trapstr = trap[i]) == NULL)
1334 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001335
Eric Andersenff9eee42001-06-29 04:57:14 +00001336 if (i == 0)
1337 trap[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001338
Eric Andersenff9eee42001-06-29 04:57:14 +00001339 RUN(aword, trapstr, nlchar);
1340}
1341
1342/* -------- var.c -------- */
1343
1344/*
1345 * Find the given name in the dictionary
1346 * and return its value. If the name was
1347 * not previously there, enter it now and
1348 * return a null value.
1349 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001350static struct var *lookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001351REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001352{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001353 REGISTER struct var *vp;
1354 REGISTER char *cp;
1355 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001356 static struct var dummy;
1357
1358 if (isdigit(*n)) {
1359 dummy.name = n;
1360 for (c = 0; isdigit(*n) && c < 1000; n++)
Eric Andersen8401eea2004-08-04 19:16:54 +00001361 c = c * 10 + *n - '0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001362 dummy.status = RONLY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001363 dummy.value = c <= dolc ? dolv[c] : null;
1364 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 }
1366 for (vp = vlist; vp; vp = vp->next)
1367 if (eqname(vp->name, n))
Eric Andersen8401eea2004-08-04 19:16:54 +00001368 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001369 cp = findeq(n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001370 vp = (struct var *) space(sizeof(*vp));
1371 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001372 dummy.name = dummy.value = "";
Eric Andersen8401eea2004-08-04 19:16:54 +00001373 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001374 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001375 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001376 if (*cp == 0)
1377 *cp = '=';
1378 *++cp = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00001379 setarea((char *) vp, 0);
1380 setarea((char *) vp->name, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001381 vp->value = null;
1382 vp->next = vlist;
1383 vp->status = GETCELL;
1384 vlist = vp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001385 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001386}
1387
1388/*
1389 * give variable at `vp' the value `val'.
1390 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001391static void setval(vp, val)
Eric Andersenff9eee42001-06-29 04:57:14 +00001392struct var *vp;
1393char *val;
1394{
Eric Andersen8401eea2004-08-04 19:16:54 +00001395 nameval(vp, val, (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001396}
1397
1398/*
1399 * if name is not NULL, it must be
1400 * a prefix of the space `val',
1401 * and end with `='.
1402 * this is all so that exporting
1403 * values is reasonably painless.
1404 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001405static void nameval(vp, val, name)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001406REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001407char *val, *name;
1408{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001409 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001410 char *nv;
1411 int fl;
1412
1413 if (vp->status & RONLY) {
1414 for (xp = vp->name; *xp && *xp != '=';)
1415 putc(*xp++, stderr);
1416 err(" is read-only");
1417 return;
1418 }
1419 fl = 0;
1420 if (name == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001421 xp = space(strlen(vp->name) + strlen(val) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00001422 if (xp == 0)
1423 return;
1424 /* make string: name=value */
Eric Andersen8401eea2004-08-04 19:16:54 +00001425 setarea((char *) xp, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001426 name = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001427 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001428 if (*xp++ == 0)
1429 xp[-1] = '=';
1430 nv = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001431 for (cp = val; (*xp++ = *cp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00001432 val = nv;
1433 fl = GETCELL;
1434 }
1435 if (vp->status & GETCELL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001436 freecell(vp->name); /* form new string `name=value' */
Eric Andersenff9eee42001-06-29 04:57:14 +00001437 vp->name = name;
1438 vp->value = val;
1439 vp->status |= fl;
1440}
1441
Eric Andersen8401eea2004-08-04 19:16:54 +00001442static void export(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001443struct var *vp;
1444{
1445 vp->status |= EXPORT;
1446}
1447
Eric Andersen8401eea2004-08-04 19:16:54 +00001448static void ronly(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001449struct var *vp;
1450{
Matt Kraai69edfec2001-08-06 14:14:18 +00001451 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
Eric Andersenff9eee42001-06-29 04:57:14 +00001452 vp->status |= RONLY;
1453}
1454
Eric Andersen8401eea2004-08-04 19:16:54 +00001455static int isassign(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001456REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001457{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001458 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1459
Eric Andersen8401eea2004-08-04 19:16:54 +00001460 if (!isalpha((int) *s) && *s != '_')
1461 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001462 for (; *s != '='; s++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001463 if (*s == 0 || (!isalnum(*s) && *s != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001464 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001465
Eric Andersen8401eea2004-08-04 19:16:54 +00001466 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001467}
1468
Eric Andersen8401eea2004-08-04 19:16:54 +00001469static int assign(s, cf)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001470REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001471int cf;
1472{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001473 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001474 struct var *vp;
1475
Eric Andersen12de6cf2004-08-04 19:19:10 +00001476 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1477
Matt Kraai69edfec2001-08-06 14:14:18 +00001478 if (!isalpha(*s) && *s != '_')
Eric Andersen8401eea2004-08-04 19:16:54 +00001479 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001480 for (cp = s; *cp != '='; cp++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001481 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001482 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001483 vp = lookup(s);
Eric Andersen8401eea2004-08-04 19:16:54 +00001484 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001485 if (cf != COPYV)
1486 vp->status &= ~GETCELL;
Eric Andersen8401eea2004-08-04 19:16:54 +00001487 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001488}
1489
Eric Andersen8401eea2004-08-04 19:16:54 +00001490static int checkname(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001491REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001492{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001493 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1494
Eric Andersen8401eea2004-08-04 19:16:54 +00001495 if (!isalpha(*cp++) && *(cp - 1) != '_')
1496 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001497 while (*cp)
Eric Andersen8401eea2004-08-04 19:16:54 +00001498 if (!isalnum(*cp++) && *(cp - 1) != '_')
1499 return (0);
1500 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001501}
1502
Eric Andersen8401eea2004-08-04 19:16:54 +00001503static void putvlist(f, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001504REGISTER int f, out;
Eric Andersenff9eee42001-06-29 04:57:14 +00001505{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001506 REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001507
1508 for (vp = vlist; vp; vp = vp->next)
Matt Kraai69edfec2001-08-06 14:14:18 +00001509 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001510 if (vp->status & EXPORT)
1511 write(out, "export ", 7);
1512 if (vp->status & RONLY)
1513 write(out, "readonly ", 9);
Eric Andersen8401eea2004-08-04 19:16:54 +00001514 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
Eric Andersenff9eee42001-06-29 04:57:14 +00001515 write(out, "\n", 1);
1516 }
1517}
1518
Eric Andersen8401eea2004-08-04 19:16:54 +00001519static int eqname(n1, n2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001520REGISTER char *n1, *n2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001521{
1522 for (; *n1 != '=' && *n1 != 0; n1++)
1523 if (*n2++ != *n1)
Eric Andersen8401eea2004-08-04 19:16:54 +00001524 return (0);
1525 return (*n2 == 0 || *n2 == '=');
Eric Andersenff9eee42001-06-29 04:57:14 +00001526}
1527
Eric Andersen8401eea2004-08-04 19:16:54 +00001528static char *findeq(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001529REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001530{
1531 while (*cp != '\0' && *cp != '=')
1532 cp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00001533 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001534}
1535
1536/* -------- gmatch.c -------- */
1537/*
1538 * int gmatch(string, pattern)
1539 * char *string, *pattern;
1540 *
1541 * Match a pattern as in sh(1).
1542 */
1543
1544#define CMASK 0377
1545#define QUOTE 0200
1546#define QMASK (CMASK&~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001547#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001548
Eric Andersen8401eea2004-08-04 19:16:54 +00001549static int gmatch(s, p)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001550REGISTER char *s, *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001551{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001552 REGISTER int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001553
1554 if (s == NULL || p == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001555 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001556 while ((pc = *p++ & CMASK) != '\0') {
1557 sc = *s++ & QMASK;
1558 switch (pc) {
1559 case '[':
1560 if ((p = cclass(p, sc)) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001561 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001562 break;
1563
1564 case '?':
1565 if (sc == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00001566 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001567 break;
1568
1569 case '*':
1570 s--;
1571 do {
1572 if (*p == '\0' || gmatch(s, p))
Eric Andersen8401eea2004-08-04 19:16:54 +00001573 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001574 } while (*s++ != '\0');
Eric Andersen8401eea2004-08-04 19:16:54 +00001575 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001576
1577 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001578 if (sc != (pc & ~QUOTE))
1579 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001580 }
1581 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001582 return (*s == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001583}
1584
Eric Andersen8401eea2004-08-04 19:16:54 +00001585static char *cclass(p, sub)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001586REGISTER char *p;
1587REGISTER int sub;
Eric Andersenff9eee42001-06-29 04:57:14 +00001588{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001589 REGISTER int c, d, not, found;
Eric Andersenff9eee42001-06-29 04:57:14 +00001590
1591 if ((not = *p == NOT) != 0)
1592 p++;
1593 found = not;
1594 do {
1595 if (*p == '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00001596 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001597 c = *p & CMASK;
1598 if (p[1] == '-' && p[2] != ']') {
1599 d = p[2] & CMASK;
1600 p++;
1601 } else
1602 d = c;
1603 if (c == sub || (c <= sub && sub <= d))
1604 found = !not;
1605 } while (*++p != ']');
Eric Andersen8401eea2004-08-04 19:16:54 +00001606 return (found ? p + 1 : (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001607}
1608
1609
1610/* -------- area.c -------- */
1611
1612/*
1613 * All memory between (char *)areabot and (char *)(areatop+1) is
1614 * exclusively administered by the area management routines.
1615 * It is assumed that sbrk() and brk() manipulate the high end.
1616 */
1617
1618#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1619
Eric Andersen8401eea2004-08-04 19:16:54 +00001620static void initarea()
Eric Andersenff9eee42001-06-29 04:57:14 +00001621{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001622 brkaddr = malloc(AREASIZE);
1623 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001624
Eric Andersena68ea1c2006-01-30 22:48:39 +00001625 while ((long) sbrk(0) & ALIGN)
Eric Andersenff9eee42001-06-29 04:57:14 +00001626 sbrk(1);
Eric Andersen8401eea2004-08-04 19:16:54 +00001627 areabot = (struct region *) sbrk(REGSIZE);
Eric Andersenff9eee42001-06-29 04:57:14 +00001628
1629 areabot->next = areabot;
1630 areabot->area = BUSY;
1631 areatop = areabot;
1632 areanxt = areabot;
1633}
1634
Eric Andersen8401eea2004-08-04 19:16:54 +00001635char *getcell(nbytes)
Eric Andersenff9eee42001-06-29 04:57:14 +00001636unsigned nbytes;
1637{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001638 REGISTER int nregio;
1639 REGISTER struct region *p, *q;
1640 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001641
1642 if (nbytes == 0) {
1643 puts("getcell(0)");
1644 abort();
Eric Andersen8401eea2004-08-04 19:16:54 +00001645 }
1646 /* silly and defeats the algorithm */
Eric Andersenff9eee42001-06-29 04:57:14 +00001647 /*
1648 * round upwards and add administration area
1649 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001650 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001651 for (p = areanxt;;) {
1652 if (p->area > areanum) {
1653 /*
1654 * merge free cells
1655 */
1656 while ((q = p->next)->area > areanum && q != areanxt)
1657 p->next = q->next;
1658 /*
1659 * exit loop if cell big enough
1660 */
1661 if (q >= p + nregio)
1662 goto found;
1663 }
1664 p = p->next;
1665 if (p == areanxt)
1666 break;
1667 }
1668 i = nregio >= GROWBY ? nregio : GROWBY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001669 p = (struct region *) sbrk(i * REGSIZE);
1670 if (p == (struct region *) -1)
1671 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001672 p--;
1673 if (p != areatop) {
1674 puts("not contig");
Eric Andersen8401eea2004-08-04 19:16:54 +00001675 abort(); /* allocated areas are contiguous */
Eric Andersenff9eee42001-06-29 04:57:14 +00001676 }
1677 q = p + i;
1678 p->next = q;
1679 p->area = FREE;
1680 q->next = areabot;
1681 q->area = BUSY;
1682 areatop = q;
Eric Andersen8401eea2004-08-04 19:16:54 +00001683 found:
Eric Andersenff9eee42001-06-29 04:57:14 +00001684 /*
1685 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1686 */
1687 areanxt = p + nregio;
1688 if (areanxt < q) {
1689 /*
1690 * split into requested area and rest
1691 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001692 if (areanxt + 1 > q) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001693 puts("OOM");
Eric Andersen8401eea2004-08-04 19:16:54 +00001694 abort(); /* insufficient space left for admin */
Eric Andersenff9eee42001-06-29 04:57:14 +00001695 }
1696 areanxt->next = q;
1697 areanxt->area = FREE;
1698 p->next = areanxt;
1699 }
1700 p->area = areanum;
Eric Andersen8401eea2004-08-04 19:16:54 +00001701 return ((char *) (p + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001702}
1703
Eric Andersen8401eea2004-08-04 19:16:54 +00001704static void freecell(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001705char *cp;
1706{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001707 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001708
Eric Andersen8401eea2004-08-04 19:16:54 +00001709 if ((p = (struct region *) cp) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001710 p--;
1711 if (p < areanxt)
1712 areanxt = p;
1713 p->area = FREE;
1714 }
1715}
1716
Eric Andersen8401eea2004-08-04 19:16:54 +00001717static void freearea(a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001718REGISTER int a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001719{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001720 REGISTER struct region *p, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001721
1722 top = areatop;
1723 for (p = areabot; p != top; p = p->next)
1724 if (p->area >= a)
1725 p->area = FREE;
1726}
1727
Eric Andersen8401eea2004-08-04 19:16:54 +00001728static void setarea(cp, a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001729char *cp;
1730int a;
1731{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001732 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001733
Eric Andersen8401eea2004-08-04 19:16:54 +00001734 if ((p = (struct region *) cp) != NULL)
1735 (p - 1)->area = a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001736}
1737
Eric Andersen8401eea2004-08-04 19:16:54 +00001738int getarea(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001739char *cp;
1740{
Eric Andersen8401eea2004-08-04 19:16:54 +00001741 return ((struct region *) cp - 1)->area;
Eric Andersenff9eee42001-06-29 04:57:14 +00001742}
1743
Eric Andersen8401eea2004-08-04 19:16:54 +00001744static void garbage()
Eric Andersenff9eee42001-06-29 04:57:14 +00001745{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001746 REGISTER struct region *p, *q, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001747
1748 top = areatop;
1749 for (p = areabot; p != top; p = p->next) {
1750 if (p->area > areanum) {
1751 while ((q = p->next)->area > areanum)
1752 p->next = q->next;
1753 areanxt = p;
1754 }
1755 }
1756#ifdef SHRINKBY
1757 if (areatop >= q + SHRINKBY && q->area > areanum) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001758 brk((char *) (q + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001759 q->next = areabot;
1760 q->area = BUSY;
1761 areatop = q;
1762 }
1763#endif
1764}
1765
1766/* -------- csyn.c -------- */
1767/*
1768 * shell: syntax (C version)
1769 */
1770
Eric Andersen8401eea2004-08-04 19:16:54 +00001771int yyparse()
Eric Andersenff9eee42001-06-29 04:57:14 +00001772{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001773 DBGPRINTF7(("YYPARSE: enter...\n"));
1774
Eric Andersen8401eea2004-08-04 19:16:54 +00001775 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 peeksym = 0;
1777 yynerrs = 0;
1778 outtree = c_list();
1779 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001780 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001781}
1782
Eric Andersen8401eea2004-08-04 19:16:54 +00001783static struct op *pipeline(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001784int cf;
1785{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001786 REGISTER struct op *t, *p;
1787 REGISTER int c;
1788
1789 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001790
1791 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001792
1793 DBGPRINTF9(("PIPELINE: t=0x%x\n", t));
1794
Eric Andersenff9eee42001-06-29 04:57:14 +00001795 if (t != NULL) {
1796 while ((c = yylex(0)) == '|') {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001797 if ((p = command(CONTIN)) == NULL) {
1798 DBGPRINTF8(("PIPELINE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001799 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001800 }
1801
Eric Andersenff9eee42001-06-29 04:57:14 +00001802 if (t->type != TPAREN && t->type != TCOM) {
1803 /* shell statement */
1804 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1805 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001806
Eric Andersenff9eee42001-06-29 04:57:14 +00001807 t = block(TPIPE, t, p, NOWORDS);
1808 }
1809 peeksym = c;
1810 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001811
1812 DBGPRINTF7(("PIPELINE: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001813 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001814}
1815
Eric Andersen8401eea2004-08-04 19:16:54 +00001816static struct op *andor()
Eric Andersenff9eee42001-06-29 04:57:14 +00001817{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001818 REGISTER struct op *t, *p;
1819 REGISTER int c;
1820
1821 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001822
1823 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001824
1825 DBGPRINTF9(("ANDOR: t=0x%x\n", t));
1826
Eric Andersenff9eee42001-06-29 04:57:14 +00001827 if (t != NULL) {
1828 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001829 if ((p = pipeline(CONTIN)) == NULL) {
1830 DBGPRINTF8(("ANDOR: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001831 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001832 }
1833
Eric Andersen8401eea2004-08-04 19:16:54 +00001834 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001835 } /* WHILE */
1836
Eric Andersenff9eee42001-06-29 04:57:14 +00001837 peeksym = c;
1838 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001839
1840 DBGPRINTF7(("ANDOR: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001841 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001842}
1843
Eric Andersen8401eea2004-08-04 19:16:54 +00001844static struct op *c_list()
Eric Andersenff9eee42001-06-29 04:57:14 +00001845{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001846 REGISTER struct op *t, *p;
1847 REGISTER int c;
1848
1849 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001850
1851 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001852
Eric Andersenff9eee42001-06-29 04:57:14 +00001853 if (t != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001854 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001855 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001856
Eric Andersen8401eea2004-08-04 19:16:54 +00001857 while ((c = yylex(0)) == ';' || c == '&'
1858 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001859
Eric Andersenff9eee42001-06-29 04:57:14 +00001860 if ((p = andor()) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001861 return (t);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001862
Eric Andersen8401eea2004-08-04 19:16:54 +00001863 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001864 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865
Eric Andersenff9eee42001-06-29 04:57:14 +00001866 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001867 } /* WHILE */
1868
Eric Andersenff9eee42001-06-29 04:57:14 +00001869 peeksym = c;
1870 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001871 /* IF */
1872 DBGPRINTF7(("C_LIST: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001873 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001874}
1875
Eric Andersen8401eea2004-08-04 19:16:54 +00001876static int synio(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001877int cf;
1878{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001879 REGISTER struct ioword *iop;
1880 REGISTER int i;
1881 REGISTER int c;
1882
1883 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001884
1885 if ((c = yylex(cf)) != '<' && c != '>') {
1886 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001887 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001888 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001889
Eric Andersenff9eee42001-06-29 04:57:14 +00001890 i = yylval.i;
1891 musthave(WORD, 0);
1892 iop = io(iounit, i, yylval.cp);
1893 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001894
Eric Andersenff9eee42001-06-29 04:57:14 +00001895 if (i & IOHERE)
1896 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001897
1898 DBGPRINTF7(("SYNIO: returning 1\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00001899 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001900}
1901
Eric Andersen8401eea2004-08-04 19:16:54 +00001902static void musthave(c, cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001903int c, cf;
1904{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001905 if ((peeksym = yylex(cf)) != c) {
1906 DBGPRINTF7(("MUSTHAVE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001907 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001908 }
1909
Eric Andersenff9eee42001-06-29 04:57:14 +00001910 peeksym = 0;
1911}
1912
Eric Andersen8401eea2004-08-04 19:16:54 +00001913static struct op *simple()
Eric Andersenff9eee42001-06-29 04:57:14 +00001914{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001915 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001916
1917 t = NULL;
1918 for (;;) {
1919 switch (peeksym = yylex(0)) {
1920 case '<':
1921 case '>':
1922 (void) synio(0);
1923 break;
1924
1925 case WORD:
1926 if (t == NULL) {
1927 t = newtp();
1928 t->type = TCOM;
1929 }
1930 peeksym = 0;
1931 word(yylval.cp);
1932 break;
1933
1934 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001935 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001936 }
1937 }
1938}
1939
Eric Andersen8401eea2004-08-04 19:16:54 +00001940static struct op *nested(type, mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001941int type, mark;
1942{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001943 REGISTER struct op *t;
1944
1945 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001946
1947 multiline++;
1948 t = c_list();
1949 musthave(mark, 0);
1950 multiline--;
Eric Andersen8401eea2004-08-04 19:16:54 +00001951 return (block(type, t, NOBLOCK, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00001952}
1953
Eric Andersen8401eea2004-08-04 19:16:54 +00001954static struct op *command(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001955int cf;
1956{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001957 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001958 struct wdblock *iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001959 REGISTER int c;
1960
1961 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001962
1963 iosave = iolist;
1964 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001965
Eric Andersenff9eee42001-06-29 04:57:14 +00001966 if (multiline)
1967 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001968
Eric Andersenff9eee42001-06-29 04:57:14 +00001969 while (synio(cf))
1970 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001971
1972 c = yylex(cf);
1973
1974 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001975 default:
1976 peeksym = c;
1977 if ((t = simple()) == NULL) {
1978 if (iolist == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001979 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001980 t = newtp();
1981 t->type = TCOM;
1982 }
1983 break;
1984
1985 case '(':
1986 t = nested(TPAREN, ')');
1987 break;
1988
1989 case '{':
1990 t = nested(TBRACE, '}');
1991 break;
1992
1993 case FOR:
1994 t = newtp();
1995 t->type = TFOR;
1996 musthave(WORD, 0);
1997 startl = 1;
1998 t->str = yylval.cp;
1999 multiline++;
2000 t->words = wordlist();
2001 if ((c = yylex(0)) != '\n' && c != ';')
2002 peeksym = c;
2003 t->left = dogroup(0);
2004 multiline--;
2005 break;
2006
2007 case WHILE:
2008 case UNTIL:
2009 multiline++;
2010 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00002011 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002012 t->left = c_list();
2013 t->right = dogroup(1);
2014 t->words = NULL;
2015 multiline--;
2016 break;
2017
2018 case CASE:
2019 t = newtp();
2020 t->type = TCASE;
2021 musthave(WORD, 0);
2022 t->str = yylval.cp;
2023 startl++;
2024 multiline++;
2025 musthave(IN, CONTIN);
2026 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002027
Eric Andersenff9eee42001-06-29 04:57:14 +00002028 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002029
Eric Andersenff9eee42001-06-29 04:57:14 +00002030 musthave(ESAC, 0);
2031 multiline--;
2032 break;
2033
2034 case IF:
2035 multiline++;
2036 t = newtp();
2037 t->type = TIF;
2038 t->left = c_list();
2039 t->right = thenpart();
2040 musthave(FI, 0);
2041 multiline--;
2042 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002043
2044 case DOT:
2045 t = newtp();
2046 t->type = TDOT;
2047
2048 musthave(WORD, 0); /* gets name of file */
2049 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
2050
2051 word(yylval.cp); /* add word to wdlist */
2052 word(NOWORD); /* terminate wdlist */
2053 t->words = copyw(); /* dup wdlist */
2054 break;
2055
Eric Andersenff9eee42001-06-29 04:57:14 +00002056 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002057
Eric Andersen8401eea2004-08-04 19:16:54 +00002058 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002059
Eric Andersenff9eee42001-06-29 04:57:14 +00002060 t = namelist(t);
2061 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002062
2063 DBGPRINTF(("COMMAND: returning 0x%x\n", t));
2064
2065 return (t);
2066}
2067
2068static struct op *dowholefile(type, mark)
2069int type;
2070int mark;
2071{
2072 REGISTER struct op *t;
2073
2074 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
2075
2076 multiline++;
2077 t = c_list();
2078 multiline--;
2079 t = block(type, t, NOBLOCK, NOWORDS);
2080 DBGPRINTF(("DOWHOLEFILE: return t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002081 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002082}
2083
Eric Andersen8401eea2004-08-04 19:16:54 +00002084static struct op *dogroup(onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00002085int onlydone;
2086{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002087 REGISTER int c;
2088 REGISTER struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002089
2090 c = yylex(CONTIN);
2091 if (c == DONE && onlydone)
Eric Andersen8401eea2004-08-04 19:16:54 +00002092 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002093 if (c != DO)
2094 SYNTAXERR;
2095 mylist = c_list();
2096 musthave(DONE, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002097 return (mylist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002098}
2099
Eric Andersen8401eea2004-08-04 19:16:54 +00002100static struct op *thenpart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002101{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102 REGISTER int c;
2103 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002104
2105 if ((c = yylex(0)) != THEN) {
2106 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002107 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002108 }
2109 t = newtp();
2110 t->type = 0;
2111 t->left = c_list();
2112 if (t->left == NULL)
2113 SYNTAXERR;
2114 t->right = elsepart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002115 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002116}
2117
Eric Andersen8401eea2004-08-04 19:16:54 +00002118static struct op *elsepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002119{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002120 REGISTER int c;
2121 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002122
2123 switch (c = yylex(0)) {
2124 case ELSE:
2125 if ((t = c_list()) == NULL)
2126 SYNTAXERR;
Eric Andersen8401eea2004-08-04 19:16:54 +00002127 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002128
2129 case ELIF:
2130 t = newtp();
2131 t->type = TELIF;
2132 t->left = c_list();
2133 t->right = thenpart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002134 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002135
2136 default:
2137 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002138 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002139 }
2140}
2141
Eric Andersen8401eea2004-08-04 19:16:54 +00002142static struct op *caselist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002143{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002144 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002145
2146 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002147 while ((peeksym = yylex(CONTIN)) != ESAC) {
2148 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00002149 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00002150 }
2151
2152 DBGPRINTF(("CASELIST, returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002153 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002154}
2155
Eric Andersen8401eea2004-08-04 19:16:54 +00002156static struct op *casepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002157{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002158 REGISTER struct op *t;
2159
2160 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002161
2162 t = newtp();
2163 t->type = TPAT;
2164 t->words = pattern();
2165 musthave(')', 0);
2166 t->left = c_list();
2167 if ((peeksym = yylex(CONTIN)) != ESAC)
2168 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002169
2170 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=0x%x)\n", t));
2171
Eric Andersen8401eea2004-08-04 19:16:54 +00002172 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002173}
2174
Eric Andersen8401eea2004-08-04 19:16:54 +00002175static char **pattern()
Eric Andersenff9eee42001-06-29 04:57:14 +00002176{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002177 REGISTER int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002178
2179 cf = CONTIN;
2180 do {
2181 musthave(WORD, cf);
2182 word(yylval.cp);
2183 cf = 0;
2184 } while ((c = yylex(0)) == '|');
2185 peeksym = c;
2186 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002187
Eric Andersen8401eea2004-08-04 19:16:54 +00002188 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002189}
2190
Eric Andersen8401eea2004-08-04 19:16:54 +00002191static char **wordlist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002192{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002193 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002194
2195 if ((c = yylex(0)) != IN) {
2196 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002197 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002198 }
2199 startl = 0;
2200 while ((c = yylex(0)) == WORD)
2201 word(yylval.cp);
2202 word(NOWORD);
2203 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002204 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002205}
2206
2207/*
2208 * supporting functions
2209 */
Eric Andersen8401eea2004-08-04 19:16:54 +00002210static struct op *list(t1, t2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002211REGISTER struct op *t1, *t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002212{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002213 DBGPRINTF7(("LIST: enter, t1=0x%x, t2=0x%x\n", t1, t2));
2214
Eric Andersenff9eee42001-06-29 04:57:14 +00002215 if (t1 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002216 return (t2);
Eric Andersenff9eee42001-06-29 04:57:14 +00002217 if (t2 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002218 return (t1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002219
Eric Andersen8401eea2004-08-04 19:16:54 +00002220 return (block(TLIST, t1, t2, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00002221}
2222
Eric Andersen8401eea2004-08-04 19:16:54 +00002223static struct op *block(type, t1, t2, wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002224int type;
2225struct op *t1, *t2;
2226char **wp;
2227{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002228 REGISTER struct op *t;
2229
2230 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002231
2232 t = newtp();
2233 t->type = type;
2234 t->left = t1;
2235 t->right = t2;
2236 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002237
2238 DBGPRINTF7(("BLOCK: inserted 0x%x between 0x%x and 0x%x\n", t, t1,
2239 t2));
2240
Eric Andersen8401eea2004-08-04 19:16:54 +00002241 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002242}
2243
Eric Andersen12de6cf2004-08-04 19:19:10 +00002244/* See if given string is a shell multiline (FOR, IF, etc) */
Eric Andersen8401eea2004-08-04 19:16:54 +00002245static int rlookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002246REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00002247{
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +00002248 REGISTER const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002249
2250 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002251
2252 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002253 if (strcmp(rp->r_name, n) == 0) {
2254 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2255 return (rp->r_val); /* Return numeric code for shell multiline */
2256 }
2257
2258 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2259 return (0); /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002260}
2261
Eric Andersen8401eea2004-08-04 19:16:54 +00002262static struct op *newtp()
Eric Andersenff9eee42001-06-29 04:57:14 +00002263{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002264 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002265
Eric Andersen8401eea2004-08-04 19:16:54 +00002266 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002267 t->type = 0;
2268 t->words = NULL;
2269 t->ioact = NULL;
2270 t->left = NULL;
2271 t->right = NULL;
2272 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002273
2274 DBGPRINTF3(("NEWTP: allocated 0x%x\n", t));
2275
Eric Andersen8401eea2004-08-04 19:16:54 +00002276 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002277}
2278
Eric Andersen8401eea2004-08-04 19:16:54 +00002279static struct op *namelist(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002280REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002281{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002282
2283 DBGPRINTF7(("NAMELIST: enter, t=0x%x, type %s, iolist=0x%x\n", t,
2284 T_CMD_NAMES[t->type], iolist));
2285
Eric Andersenff9eee42001-06-29 04:57:14 +00002286 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002287 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002288 t->ioact = copyio();
2289 } else
2290 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002291
Eric Andersenff9eee42001-06-29 04:57:14 +00002292 if (t->type != TCOM) {
2293 if (t->type != TPAREN && t->ioact != NULL) {
2294 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2295 t->ioact = t->left->ioact;
2296 t->left->ioact = NULL;
2297 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002298 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002299 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002300
Eric Andersenff9eee42001-06-29 04:57:14 +00002301 word(NOWORD);
2302 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002303
2304
Eric Andersen8401eea2004-08-04 19:16:54 +00002305 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002306}
2307
Eric Andersen8401eea2004-08-04 19:16:54 +00002308static char **copyw()
Eric Andersenff9eee42001-06-29 04:57:14 +00002309{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002310 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002311
2312 wd = getwords(wdlist);
2313 wdlist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002314 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002315}
2316
Eric Andersen8401eea2004-08-04 19:16:54 +00002317static void word(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002318char *cp;
2319{
2320 wdlist = addword(cp, wdlist);
2321}
2322
Eric Andersen8401eea2004-08-04 19:16:54 +00002323static struct ioword **copyio()
Eric Andersenff9eee42001-06-29 04:57:14 +00002324{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002325 REGISTER struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002326
2327 iop = (struct ioword **) getwords(iolist);
2328 iolist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002329 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002330}
2331
Eric Andersen8401eea2004-08-04 19:16:54 +00002332static struct ioword *io(u, f, cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002333int u;
2334int f;
2335char *cp;
2336{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002337 REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002338
2339 iop = (struct ioword *) tree(sizeof(*iop));
2340 iop->io_unit = u;
2341 iop->io_flag = f;
2342 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002343 iolist = addword((char *) iop, iolist);
2344 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002345}
2346
Eric Andersen8401eea2004-08-04 19:16:54 +00002347static void zzerr()
Eric Andersenff9eee42001-06-29 04:57:14 +00002348{
2349 yyerror("syntax error");
2350}
2351
Eric Andersen8401eea2004-08-04 19:16:54 +00002352static void yyerror(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00002353char *s;
2354{
2355 yynerrs++;
2356 if (interactive && e.iop <= iostack) {
2357 multiline = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002358 while (eofc() == 0 && yylex(0) != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002359 }
2360 err(s);
2361 fail();
2362}
2363
Eric Andersen8401eea2004-08-04 19:16:54 +00002364static int yylex(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002365int cf;
2366{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002367 REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002368 int atstart;
2369
2370 if ((c = peeksym) > 0) {
2371 peeksym = 0;
2372 if (c == '\n')
2373 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002374 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002375 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002376
2377
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002379 atstart = startl;
2380 startl = 0;
2381 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002382 e.linep = line;
2383
2384/* MALAMO */
2385 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002386
Eric Andersen8401eea2004-08-04 19:16:54 +00002387 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002388 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2389 ;
2390
Eric Andersenff9eee42001-06-29 04:57:14 +00002391 switch (c) {
2392 default:
2393 if (any(c, "0123456789")) {
2394 unget(c1 = my_getc(0));
2395 if (c1 == '<' || c1 == '>') {
2396 iounit = c - '0';
2397 goto loop;
2398 }
2399 *e.linep++ = c;
2400 c = c1;
2401 }
2402 break;
2403
Eric Andersen12de6cf2004-08-04 19:19:10 +00002404 case '#': /* Comment, skip to next newline or End-of-string */
Eric Andersen8401eea2004-08-04 19:16:54 +00002405 while ((c = my_getc(0)) != 0 && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002406 unget(c);
2407 goto loop;
2408
2409 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002410 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Eric Andersen8401eea2004-08-04 19:16:54 +00002411 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002412
2413 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002414 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002415 *e.linep++ = c;
2416 if ((c = my_getc(0)) == '{') {
2417 if ((c = collect(c, '}')) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002418 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002419 goto pack;
2420 }
2421 break;
2422
2423 case '`':
2424 case '\'':
2425 case '"':
2426 if ((c = collect(c, c)) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002427 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002428 goto pack;
2429
2430 case '|':
2431 case '&':
2432 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002433 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002434 /* If more chars process them, else return NULL char */
2435 if ((c1 = dual(c)) != '\0')
2436 return (c1);
2437 else
2438 return (c);
2439
Eric Andersenff9eee42001-06-29 04:57:14 +00002440 case '^':
2441 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002442 return ('|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002443 case '>':
2444 case '<':
2445 diag(c);
Eric Andersen8401eea2004-08-04 19:16:54 +00002446 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002447
2448 case '\n':
2449 nlseen++;
2450 gethere();
2451 startl = 1;
2452 if (multiline || cf & CONTIN) {
2453 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002454#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002455 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002456#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002457 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002458#endif
2459 }
2460 if (cf & CONTIN)
2461 goto loop;
2462 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002463 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002464
2465 case '(':
2466 case ')':
2467 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002468 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002469 }
2470
2471 unget(c);
2472
Eric Andersen8401eea2004-08-04 19:16:54 +00002473 pack:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002474 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002475 if (e.linep >= elinep)
2476 err("word too long");
2477 else
2478 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479 };
2480
Eric Andersenff9eee42001-06-29 04:57:14 +00002481 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002482
Eric Andersen8401eea2004-08-04 19:16:54 +00002483 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002484 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002485
Eric Andersenff9eee42001-06-29 04:57:14 +00002486 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002487
Eric Andersen8401eea2004-08-04 19:16:54 +00002488 if (atstart && (c = rlookup(line)) != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002489 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002490 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002491 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002492
Eric Andersenff9eee42001-06-29 04:57:14 +00002493 yylval.cp = strsave(line, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00002494 return (WORD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002495}
2496
Eric Andersen12de6cf2004-08-04 19:19:10 +00002497
Eric Andersen8401eea2004-08-04 19:16:54 +00002498static int collect(c, c1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002499REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002500{
2501 char s[2];
2502
Eric Andersen12de6cf2004-08-04 19:19:10 +00002503 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2504
Eric Andersenff9eee42001-06-29 04:57:14 +00002505 *e.linep++ = c;
2506 while ((c = my_getc(c1)) != c1) {
2507 if (c == 0) {
2508 unget(c);
2509 s[0] = c1;
2510 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002511 prs("no closing ");
2512 yyerror(s);
2513 return (YYERRCODE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002514 }
2515 if (interactive && c == '\n' && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002516#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002517 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002518#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002519 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002520#endif
2521 }
2522 *e.linep++ = c;
2523 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002524
Eric Andersenff9eee42001-06-29 04:57:14 +00002525 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002526
2527 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2528
Eric Andersen8401eea2004-08-04 19:16:54 +00002529 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002530}
2531
Eric Andersen12de6cf2004-08-04 19:19:10 +00002532/* "multiline commands" helper func */
2533/* see if next 2 chars form a shell multiline */
Eric Andersen8401eea2004-08-04 19:16:54 +00002534static int dual(c)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002535REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002536{
2537 char s[3];
Eric Andersen12de6cf2004-08-04 19:19:10 +00002538 REGISTER char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002539
Eric Andersen12de6cf2004-08-04 19:19:10 +00002540 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2541
2542 *cp++ = c; /* c is the given "peek" char */
2543 *cp++ = my_getc(0); /* get next char of input */
2544 *cp = 0; /* add EOS marker */
2545
2546 c = rlookup(s); /* see if 2 chars form a shell multiline */
2547 if (c == 0)
2548 unget(*--cp); /* String is not a shell multiline, put peek char back */
2549
2550 return (c); /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002551}
2552
Eric Andersen8401eea2004-08-04 19:16:54 +00002553static void diag(ec)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002554REGISTER int ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00002555{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002556 REGISTER int c;
2557
2558 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002559
2560 c = my_getc(0);
2561 if (c == '>' || c == '<') {
2562 if (c != ec)
2563 zzerr();
Eric Andersen8401eea2004-08-04 19:16:54 +00002564 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 c = my_getc(0);
2566 } else
Eric Andersen8401eea2004-08-04 19:16:54 +00002567 yylval.i = ec == '>' ? IOWRITE : IOREAD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002568 if (c != '&' || yylval.i == IOHERE)
2569 unget(c);
2570 else
2571 yylval.i |= IODUP;
2572}
2573
Eric Andersen8401eea2004-08-04 19:16:54 +00002574static char *tree(size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002575unsigned size;
2576{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002577 REGISTER char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002578
2579 if ((t = getcell(size)) == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002580 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002581 prs("command line too complicated\n");
2582 fail();
2583 /* NOTREACHED */
2584 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002585 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002586}
2587
2588/* VARARGS1 */
2589/* ARGSUSED */
2590
2591/* -------- exec.c -------- */
2592
2593/*
2594 * execute tree
2595 */
2596
2597
Eric Andersen8401eea2004-08-04 19:16:54 +00002598static int execute(t, pin, pout, act)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002599REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002600int *pin, *pout;
2601int act;
2602{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002603 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002604 volatile int i, rv, a;
2605 char *cp, **wp, **wp2;
2606 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002607 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002608 struct brkcon bc;
2609
2610#if __GNUC__
2611 /* Avoid longjmp clobbering */
2612 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002613#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002614
Eric Andersen12de6cf2004-08-04 19:19:10 +00002615 if (t == NULL) {
2616 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002617 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002618 }
2619
2620 DBGPRINTF(("EXECUTE: t=0x%x, t->type=%d (%s), t->words is %s\n", t,
2621 t->type, T_CMD_NAMES[t->type],
2622 ((t->words == NULL) ? "NULL" : t->words[0])));
2623
Eric Andersenff9eee42001-06-29 04:57:14 +00002624 rv = 0;
2625 a = areanum++;
2626 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002627 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2628 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002629
Eric Andersen12de6cf2004-08-04 19:19:10 +00002630/* Hard to know how many words there are, be careful of garbage pointer values */
2631/* They are likely to cause "PCI bus fault" errors */
2632#if 0
2633 DBGPRINTF(("EXECUTE: t->left=0x%x, t->right=0x%x, t->words[1] is %s\n",
2634 t->left, t->right,
2635 ((t->words[1] == NULL) ? "NULL" : t->words[1])));
2636 DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",
2637 ((t->words[2] == NULL) ? "NULL" : t->words[2]),
2638 ((t->words[3] == NULL) ? "NULL" : t->words[3])));
2639#endif
2640
2641
Eric Andersen8401eea2004-08-04 19:16:54 +00002642 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002643 case TDOT:
2644 DBGPRINTF3(("EXECUTE: TDOT\n"));
2645
2646 outtree_save = outtree;
2647
2648 newfile(evalstr(t->words[0], DOALL));
2649
2650 t->left = dowholefile(TLIST, 0);
2651 t->right = NULL;
2652
2653 outtree = outtree_save;
2654
2655 if (t->left)
2656 rv = execute(t->left, pin, pout, 0);
2657 if (t->right)
2658 rv = execute(t->right, pin, pout, 0);
2659 break;
2660
Eric Andersenff9eee42001-06-29 04:57:14 +00002661 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002662 rv = execute(t->left, pin, pout, 0);
2663 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002664
Eric Andersenff9eee42001-06-29 04:57:14 +00002665 case TCOM:
Eric Andersen1c039232001-07-07 00:05:55 +00002666 {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002667 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002668 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002669 break;
2670
2671 case TPIPE:
2672 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002673 int pv[2];
2674
2675 if ((rv = openpipe(pv)) < 0)
2676 break;
2677 pv[0] = remap(pv[0]);
2678 pv[1] = remap(pv[1]);
2679 (void) execute(t->left, pin, pv, 0);
2680 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002681 }
2682 break;
2683
2684 case TLIST:
2685 (void) execute(t->left, pin, pout, 0);
2686 rv = execute(t->right, pin, pout, 0);
2687 break;
2688
2689 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002690 {
2691 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692
Eric Andersen12de6cf2004-08-04 19:19:10 +00002693 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2694
Eric Andersen8401eea2004-08-04 19:16:54 +00002695 i = vfork();
2696 if (i != 0) {
2697 interactive = hinteractive;
2698 if (i != -1) {
2699 setval(lookup("!"), putn(i));
2700 if (pin != NULL)
2701 closepipe(pin);
2702 if (interactive) {
2703 prs(putn(i));
2704 prs("\n");
2705 }
2706 } else
2707 rv = -1;
2708 setstatus(rv);
2709 } else {
2710 signal(SIGINT, SIG_IGN);
2711 signal(SIGQUIT, SIG_IGN);
2712 if (interactive)
2713 signal(SIGTERM, SIG_DFL);
2714 interactive = 0;
2715 if (pin == NULL) {
2716 close(0);
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +00002717 open(bb_dev_null, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002718 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002719 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002720 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002721 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002722 break;
2723
2724 case TOR:
2725 case TAND:
2726 rv = execute(t->left, pin, pout, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002727 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002728 rv = execute(t1, pin, pout, 0);
2729 break;
2730
2731 case TFOR:
2732 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002733 wp = dolv + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002734 if ((i = dolc) < 0)
2735 i = 0;
2736 } else {
2737 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002738 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002739 }
2740 vp = lookup(t->str);
2741 while (setjmp(bc.brkpt))
2742 if (isbreak)
2743 goto broken;
2744 brkset(&bc);
2745 for (t1 = t->left; i-- && *wp != NULL;) {
2746 setval(vp, *wp++);
2747 rv = execute(t1, pin, pout, 0);
2748 }
2749 brklist = brklist->nextlev;
2750 break;
2751
2752 case TWHILE:
2753 case TUNTIL:
2754 while (setjmp(bc.brkpt))
2755 if (isbreak)
2756 goto broken;
2757 brkset(&bc);
2758 t1 = t->left;
2759 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2760 rv = execute(t->right, pin, pout, 0);
2761 brklist = brklist->nextlev;
2762 break;
2763
2764 case TIF:
2765 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002766 if (t->right != NULL) {
2767 rv = !execute(t->left, pin, pout, 0) ?
2768 execute(t->right->left, pin, pout, 0) :
2769 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002770 }
2771 break;
2772
2773 case TCASE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002774 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002775 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776
2777 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2778 ((t->str == NULL) ? "NULL" : t->str),
2779 ((cp == NULL) ? "NULL" : cp)));
2780
2781 if ((t1 = findcase(t->left, cp)) != NULL) {
2782 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=0x%x, t1=0x%x)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002783 rv = execute(t1, pin, pout, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002784 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=0x%x, t1=0x%x)...\n", t, t1));
2785 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002786 break;
2787
2788 case TBRACE:
2789/*
2790 if (iopp = t->ioact)
2791 while (*iopp)
2792 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2793 rv = -1;
2794 break;
2795 }
2796*/
2797 if (rv >= 0 && (t1 = t->left))
2798 rv = execute(t1, pin, pout, 0);
2799 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002800
2801 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002802
Eric Andersen8401eea2004-08-04 19:16:54 +00002803 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 t->words = wp2;
2805 isbreak = 0;
2806 freehere(areanum);
2807 freearea(areanum);
2808 areanum = a;
2809 if (interactive && intr) {
2810 closeall();
2811 fail();
2812 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002813
Eric Andersenff9eee42001-06-29 04:57:14 +00002814 if ((i = trapset) != 0) {
2815 trapset = 0;
2816 runtrap(i);
2817 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002818
2819 DBGPRINTF(("EXECUTE: returning from t=0x%x, rv=%d\n", t, rv));
Eric Andersen8401eea2004-08-04 19:16:54 +00002820 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002821}
2822
2823static int
Eric Andersen12de6cf2004-08-04 19:19:10 +00002824forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002825{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002826 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 int i, rv;
Eric Andersen8401eea2004-08-04 19:16:54 +00002828 int (*shcom) (struct op *) = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829 REGISTER int f;
Eric Andersenff9eee42001-06-29 04:57:14 +00002830 char *cp = NULL;
2831 struct ioword **iopp;
2832 int resetsig;
2833 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002834 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002835
2836 int *hpin = pin;
2837 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002838 char *hwp;
2839 int hinteractive;
2840 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002841 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002842 int hexecflg;
2843
2844#if __GNUC__
2845 /* Avoid longjmp clobbering */
2846 (void) &pin;
2847 (void) &pout;
2848 (void) &wp;
2849 (void) &shcom;
2850 (void) &cp;
2851 (void) &resetsig;
2852 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002853#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002854
Eric Andersen12de6cf2004-08-04 19:19:10 +00002855 DBGPRINTF(("FORKEXEC: t=0x%x, pin 0x%x, pout 0x%x, act %d\n", t, pin,
2856 pout, act));
2857 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2858 ((t->words == NULL) ? "NULL" : t->words[0])));
2859
2860/* Hard to know how many words there are, be careful of garbage pointer values */
2861/* They are likely to cause "PCI bus fault" errors */
2862#if 0
2863 DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2864 ((t->words == NULL) ? "NULL" : t->words[0]),
2865 ((t->words == NULL) ? "NULL" : t->words[1])));
2866 DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",
2867 ((wp == NULL) ? "NULL" : wp[0]),
2868 ((wp[1] == NULL) ? "NULL" : wp[1])));
2869 DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",
2870 ((wp[2] == NULL) ? "NULL" : wp[2]),
2871 ((wp[3] == NULL) ? "NULL" : wp[3])));
2872#endif
2873
2874
Eric Andersenff9eee42001-06-29 04:57:14 +00002875 owp = wp;
2876 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002877 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002878 if (t->type == TCOM) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002879 while ((cp = *wp++) != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002880 cp = *wp;
2881
2882 /* strip all initial assignments */
2883 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002884 if (flag['x']) {
2885 DBGPRINTF9(("FORKEXEC: echo'ing, cp=0x%x, wp=0x%x, owp=0x%x\n",
2886 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002887 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002888 }
2889#if 0
2890 DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2891 ((t->words == NULL) ? "NULL" : t->words[0]),
2892 ((t->words == NULL) ? "NULL" : t->words[1])));
2893 DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",
2894 ((wp == NULL) ? "NULL" : wp[0]),
2895 ((wp == NULL) ? "NULL" : wp[1])));
2896#endif
2897
Eric Andersenff9eee42001-06-29 04:57:14 +00002898 if (cp == NULL && t->ioact == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002899 while ((cp = *owp++) != NULL && assign(cp, COPYV));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002900 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002901 return (setstatus(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902 } else if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002903 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002904 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002905 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002906
Eric Andersenff9eee42001-06-29 04:57:14 +00002907 t->words = wp;
2908 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002909
Eric Andersen12de6cf2004-08-04 19:19:10 +00002910#if 0
2911 DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2912 ((t->words == NULL) ? "NULL" : t->words[0]),
2913 ((t->words == NULL) ? "NULL" : t->words[1])));
2914#endif
2915 DBGPRINTF(("FORKEXEC: shcom 0x%x, f&FEXEC 0x%x, owp 0x%x\n", shcom,
2916 f & FEXEC, owp));
2917
2918 if (shcom == NULL && (f & FEXEC) == 0) {
2919 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002920 hpin = pin;
2921 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 hwp = *wp;
2923 hinteractive = interactive;
2924 hintr = intr;
2925 hbrklist = brklist;
2926 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002927
Eric Andersen12de6cf2004-08-04 19:19:10 +00002928 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2929
2930 newpid = vfork();
2931
2932 if (newpid == -1) {
2933 DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n"));
2934 return (-1);
2935 }
2936
2937
2938 if (newpid > 0) { /* Parent */
2939
2940 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002941 pin = hpin;
2942 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002943 *wp = hwp;
2944 interactive = hinteractive;
2945 intr = hintr;
2946 brklist = hbrklist;
2947 execflg = hexecflg;
2948
Eric Andersen12de6cf2004-08-04 19:19:10 +00002949/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002950 if (i == -1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002951 return(rv);
2952*/
2953
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 if (pin != NULL)
2955 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002956
2957 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002958 }
2959
Eric Andersen12de6cf2004-08-04 19:19:10 +00002960 /* Must be the child process, pid should be 0 */
2961 DBGPRINTF(("FORKEXEC: child process, shcom=0x%x\n", shcom));
2962
Eric Andersenff9eee42001-06-29 04:57:14 +00002963 if (interactive) {
2964 signal(SIGINT, SIG_IGN);
2965 signal(SIGQUIT, SIG_IGN);
2966 resetsig = 1;
2967 }
2968 interactive = 0;
2969 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002970 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002971 brklist = 0;
2972 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002973 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002974
2975
Eric Andersenff9eee42001-06-29 04:57:14 +00002976 if (owp != NULL)
2977 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2978 if (shcom == NULL)
2979 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002980
Eric Andersenff9eee42001-06-29 04:57:14 +00002981#ifdef COMPIPE
2982 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2983 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002984 if (forked)
2985 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00002986 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002987 }
2988#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002989
Eric Andersenff9eee42001-06-29 04:57:14 +00002990 if (pin != NULL) {
2991 dup2(pin[0], 0);
2992 closepipe(pin);
2993 }
2994 if (pout != NULL) {
2995 dup2(pout[1], 1);
2996 closepipe(pout);
2997 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002998
Eric Andersenff9eee42001-06-29 04:57:14 +00002999 if ((iopp = t->ioact) != NULL) {
3000 if (shcom != NULL && shcom != doexec) {
3001 prs(cp);
3002 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003003 if (forked)
3004 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003005 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003006 }
3007 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003008 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
3009 if (forked)
3010 _exit(rv);
Eric Andersen8401eea2004-08-04 19:16:54 +00003011 return (rv);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003012 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003013 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003014
3015 if (shcom) {
3016 i = setstatus((*shcom) (t));
3017 if (forked)
3018 _exit(i);
3019 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
3020 return (i);
3021 }
3022
Eric Andersenff9eee42001-06-29 04:57:14 +00003023 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00003024 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003025 close(i);
3026 if (resetsig) {
3027 signal(SIGINT, SIG_DFL);
3028 signal(SIGQUIT, SIG_DFL);
3029 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003030
Eric Andersen12de6cf2004-08-04 19:19:10 +00003031 if (t->type == TPAREN)
3032 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
3033 if (wp[0] == NULL)
3034 _exit(0);
3035
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003036 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003037 prs(wp[0]);
3038 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003039 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003040 if (!execflg)
3041 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003042
3043 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
3044
Eric Andersenff9eee42001-06-29 04:57:14 +00003045 leave();
3046 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003047 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003048}
3049
3050/*
3051 * 0< 1> are ignored as required
3052 * within pipelines.
3053 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003054static int iosetup(iop, pipein, pipeout)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003055REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003056int pipein, pipeout;
3057{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003058 REGISTER int u = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003059 char *cp = NULL, *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00003060
Eric Andersen12de6cf2004-08-04 19:19:10 +00003061 DBGPRINTF(("IOSETUP: iop 0x%x, pipein 0x%x, pipeout 0x%x\n", iop,
3062 pipein, pipeout));
3063
Eric Andersenff9eee42001-06-29 04:57:14 +00003064 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00003065 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003066
Eric Andersenff9eee42001-06-29 04:57:14 +00003067 if (pipein && iop->io_unit == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003068 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003069
Eric Andersenff9eee42001-06-29 04:57:14 +00003070 if (pipeout && iop->io_unit == 1)
Eric Andersen8401eea2004-08-04 19:16:54 +00003071 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003072
Eric Andersen8401eea2004-08-04 19:16:54 +00003073 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00003074 if ((iop->io_flag & IOHERE) == 0) {
3075 cp = iop->io_name;
Eric Andersen8401eea2004-08-04 19:16:54 +00003076 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
3077 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003078 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003079
Eric Andersenff9eee42001-06-29 04:57:14 +00003080 if (iop->io_flag & IODUP) {
3081 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
3082 prs(cp);
3083 err(": illegal >& argument");
Eric Andersen8401eea2004-08-04 19:16:54 +00003084 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003085 }
3086 if (*cp == '-')
3087 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00003088 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003089 }
3090 switch (iop->io_flag) {
3091 case IOREAD:
3092 u = open(cp, 0);
3093 break;
3094
3095 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00003096 case IOHERE | IOXHERE:
3097 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003098 cp = "here file";
3099 break;
3100
Eric Andersen8401eea2004-08-04 19:16:54 +00003101 case IOWRITE | IOCAT:
Eric Andersenff9eee42001-06-29 04:57:14 +00003102 if ((u = open(cp, 1)) >= 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003103 lseek(u, (long) 0, 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00003104 break;
3105 }
3106 case IOWRITE:
3107 u = creat(cp, 0666);
3108 break;
3109
3110 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00003111 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00003112 break;
3113
3114 case IOCLOSE:
3115 close(iop->io_unit);
Eric Andersen8401eea2004-08-04 19:16:54 +00003116 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003117 }
3118 if (u < 0) {
3119 prs(cp);
3120 prs(": cannot ");
3121 warn(msg);
Eric Andersen8401eea2004-08-04 19:16:54 +00003122 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003123 } else {
3124 if (u != iop->io_unit) {
3125 dup2(u, iop->io_unit);
3126 close(u);
3127 }
3128 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003129 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003130}
3131
Eric Andersen8401eea2004-08-04 19:16:54 +00003132static void echo(wp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003133REGISTER char **wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003134{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003135 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003136
3137 prs("+");
Eric Andersen8401eea2004-08-04 19:16:54 +00003138 for (i = 0; wp[i]; i++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003139 if (i)
3140 prs(" ");
3141 prs(wp[i]);
3142 }
3143 prs("\n");
3144}
3145
Eric Andersen8401eea2004-08-04 19:16:54 +00003146static struct op **find1case(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003147struct op *t;
3148char *w;
3149{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003150 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003151 struct op **tp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003152 REGISTER char **wp, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003153
Eric Andersen12de6cf2004-08-04 19:19:10 +00003154
3155 if (t == NULL) {
3156 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003157 return ((struct op **) NULL);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003158 }
3159
3160 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3161 T_CMD_NAMES[t->type]));
3162
Eric Andersenff9eee42001-06-29 04:57:14 +00003163 if (t->type == TLIST) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003164 if ((tp = find1case(t->left, w)) != NULL) {
3165 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=0x%x\n", tp));
Eric Andersen8401eea2004-08-04 19:16:54 +00003166 return (tp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003167 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003168 t1 = t->right; /* TPAT */
Eric Andersenff9eee42001-06-29 04:57:14 +00003169 } else
3170 t1 = t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003171
Eric Andersenff9eee42001-06-29 04:57:14 +00003172 for (wp = t1->words; *wp;)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003173 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
3174 DBGPRINTF3(("FIND1CASE: returning &t1->left= 0x%x.\n",
3175 &t1->left));
Eric Andersen8401eea2004-08-04 19:16:54 +00003176 return (&t1->left);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003177 }
3178
3179 DBGPRINTF(("FIND1CASE: returning NULL\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003180 return ((struct op **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003181}
3182
Eric Andersen8401eea2004-08-04 19:16:54 +00003183static struct op *findcase(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003184struct op *t;
3185char *w;
3186{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003187 REGISTER struct op **tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003188
Eric Andersen8401eea2004-08-04 19:16:54 +00003189 return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003190}
3191
3192/*
3193 * Enter a new loop level (marked for break/continue).
3194 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003195static void brkset(bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00003196struct brkcon *bc;
3197{
3198 bc->nextlev = brklist;
3199 brklist = bc;
3200}
3201
3202/*
3203 * Wait for the last process created.
3204 * Print a message for each process found
3205 * that was killed by a signal.
3206 * Ignore interrupt signals while waiting
3207 * unless `canintr' is true.
3208 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003209static int waitfor(lastpid, canintr)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003210REGISTER int lastpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00003211int canintr;
3212{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003213 REGISTER int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003214 int s;
3215 int oheedint = heedint;
3216
3217 heedint = 0;
3218 rv = 0;
3219 do {
3220 pid = wait(&s);
3221 if (pid == -1) {
3222 if (errno != EINTR || canintr)
3223 break;
3224 } else {
3225 if ((rv = WAITSIG(s)) != 0) {
3226 if (rv < NSIGNAL) {
3227 if (signame[rv] != NULL) {
3228 if (pid != lastpid) {
3229 prn(pid);
3230 prs(": ");
3231 }
3232 prs(signame[rv]);
3233 }
3234 } else {
3235 if (pid != lastpid) {
3236 prn(pid);
3237 prs(": ");
3238 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003239 prs("Signal ");
3240 prn(rv);
3241 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003242 }
3243 if (WAITCORE(s))
3244 prs(" - core dumped");
3245 if (rv >= NSIGNAL || signame[rv])
3246 prs("\n");
3247 rv = -1;
3248 } else
3249 rv = WAITVAL(s);
3250 }
3251 } while (pid != lastpid);
3252 heedint = oheedint;
3253 if (intr) {
3254 if (interactive) {
3255 if (canintr)
3256 intr = 0;
3257 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003258 if (exstat == 0)
3259 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003260 onintr(0);
3261 }
3262 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003263 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003264}
3265
Eric Andersen8401eea2004-08-04 19:16:54 +00003266static int setstatus(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003267REGISTER int s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003268{
3269 exstat = s;
3270 setval(lookup("?"), putn(s));
Eric Andersen8401eea2004-08-04 19:16:54 +00003271 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00003272}
3273
3274/*
3275 * PATH-searching interface to execve.
3276 * If getenv("PATH") were kept up-to-date,
3277 * execvp might be used.
3278 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003279static char *rexecve(c, v, envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003280char *c, **v, **envp;
3281{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003282 REGISTER int i;
3283 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003284 int eacces = 0, asis = 0;
3285
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003286#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003287 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003288
Eric Andersen1c039232001-07-07 00:05:55 +00003289 optind = 1;
3290 if (find_applet_by_name(name)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003291 /* We have to exec here since we vforked. Running
Eric Andersen1c039232001-07-07 00:05:55 +00003292 * run_applet_by_name() won't work and bad things
3293 * will happen. */
3294 execve("/proc/self/exe", v, envp);
3295 execve("busybox", v, envp);
3296 }
3297#endif
3298
Eric Andersen12de6cf2004-08-04 19:19:10 +00003299 DBGPRINTF(("REXECVE: c=0x%x, v=0x%x, envp=0x%x\n", c, v, envp));
3300
Eric Andersen8401eea2004-08-04 19:16:54 +00003301 sp = any('/', c) ? "" : path->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00003302 asis = *sp == '\0';
3303 while (asis || *sp != '\0') {
3304 asis = 0;
3305 tp = e.linep;
3306 for (; *sp != '\0'; tp++)
3307 if ((*tp = *sp++) == ':') {
3308 asis = *sp == '\0';
3309 break;
3310 }
3311 if (tp != e.linep)
3312 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003313 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003314
Eric Andersen12de6cf2004-08-04 19:19:10 +00003315 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3316
Eric Andersenff9eee42001-06-29 04:57:14 +00003317 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003318
Eric Andersenff9eee42001-06-29 04:57:14 +00003319 switch (errno) {
3320 case ENOEXEC:
3321 *v = e.linep;
3322 tp = *--v;
3323 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003324 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003325 *v = tp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003326 return ("no Shell");
Eric Andersenff9eee42001-06-29 04:57:14 +00003327
3328 case ENOMEM:
Eric Andersen8401eea2004-08-04 19:16:54 +00003329 return ((char *) bb_msg_memory_exhausted);
Eric Andersenff9eee42001-06-29 04:57:14 +00003330
3331 case E2BIG:
Eric Andersen8401eea2004-08-04 19:16:54 +00003332 return ("argument list too long");
Eric Andersenff9eee42001-06-29 04:57:14 +00003333
3334 case EACCES:
3335 eacces++;
3336 break;
3337 }
3338 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003339 return (errno == ENOENT ? "not found" : "cannot execute");
Eric Andersenff9eee42001-06-29 04:57:14 +00003340}
3341
3342/*
3343 * Run the command produced by generator `f'
3344 * applied to stream `arg'.
3345 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003346static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003347{
3348 struct op *otree;
3349 struct wdblock *swdlist;
3350 struct wdblock *siolist;
3351 jmp_buf ev, rt;
3352 xint *ofail;
3353 int rv;
3354
3355#if __GNUC__
3356 /* Avoid longjmp clobbering */
3357 (void) &rv;
3358#endif
3359
Eric Andersen12de6cf2004-08-04 19:19:10 +00003360 DBGPRINTF(("RUN: enter, areanum %d, outtree 0x%x, failpt 0x%x\n",
3361 areanum, outtree, failpt));
3362
Eric Andersenff9eee42001-06-29 04:57:14 +00003363 areanum++;
3364 swdlist = wdlist;
3365 siolist = iolist;
3366 otree = outtree;
3367 ofail = failpt;
3368 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003369
Eric Andersenff9eee42001-06-29 04:57:14 +00003370 if (newenv(setjmp(errpt = ev)) == 0) {
3371 wdlist = 0;
3372 iolist = 0;
3373 pushio(argp, f);
3374 e.iobase = e.iop;
3375 yynerrs = 0;
3376 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3377 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3378 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003379 } else {
3380 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003381 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003382
Eric Andersenff9eee42001-06-29 04:57:14 +00003383 wdlist = swdlist;
3384 iolist = siolist;
3385 failpt = ofail;
3386 outtree = otree;
3387 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003388
Eric Andersen8401eea2004-08-04 19:16:54 +00003389 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003390}
3391
3392/* -------- do.c -------- */
3393
3394/*
3395 * built-in commands: doX
3396 */
3397
Eric Andersen8401eea2004-08-04 19:16:54 +00003398static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003399{
3400 int col;
3401 const struct builtincmd *x;
3402
3403 printf("\nBuilt-in commands:\n");
3404 printf("-------------------\n");
3405
Eric Andersen8401eea2004-08-04 19:16:54 +00003406 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003407 if (!x->name)
3408 continue;
3409 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3410 if (col > 60) {
3411 printf("\n");
3412 col = 0;
3413 }
3414 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003415#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003416 {
3417 int i;
3418 const struct BB_applet *applet;
3419 extern const struct BB_applet applets[];
3420 extern const size_t NUM_APPLETS;
3421
Eric Andersen8401eea2004-08-04 19:16:54 +00003422 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003423 if (!applet->name)
3424 continue;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003425
Eric Andersen8401eea2004-08-04 19:16:54 +00003426 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003427 if (col > 60) {
3428 printf("\n");
3429 col = 0;
3430 }
3431 }
3432 }
3433#endif
3434 printf("\n\n");
3435 return EXIT_SUCCESS;
3436}
3437
3438
3439
Eric Andersen8401eea2004-08-04 19:16:54 +00003440static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003441{
Eric Andersen8401eea2004-08-04 19:16:54 +00003442 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003443}
3444
Eric Andersen8401eea2004-08-04 19:16:54 +00003445static int dochdir(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003446REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003447{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003448 REGISTER char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003449
3450 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3451 er = ": no home directory";
Eric Andersen8401eea2004-08-04 19:16:54 +00003452 else if (chdir(cp) < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003453 er = ": bad directory";
3454 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003455 return (0);
3456 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003457 err(er);
Eric Andersen8401eea2004-08-04 19:16:54 +00003458 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003459}
3460
Eric Andersen8401eea2004-08-04 19:16:54 +00003461static int doshift(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003462REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003463{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003464 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003465
Eric Andersen8401eea2004-08-04 19:16:54 +00003466 n = t->words[1] ? getn(t->words[1]) : 1;
3467 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003468 err("nothing to shift");
Eric Andersen8401eea2004-08-04 19:16:54 +00003469 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003470 }
3471 dolv[n] = dolv[0];
3472 dolv += n;
3473 dolc -= n;
3474 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003475 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003476}
3477
3478/*
3479 * execute login and newgrp directly
3480 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003481static int dologin(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003482struct op *t;
3483{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003484 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003485
3486 if (interactive) {
3487 signal(SIGINT, SIG_DFL);
3488 signal(SIGQUIT, SIG_DFL);
3489 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003490 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003491 prs(t->words[0]);
3492 prs(": ");
3493 err(cp);
3494 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003495}
3496
Eric Andersen8401eea2004-08-04 19:16:54 +00003497static int doumask(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003498REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003499{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003500 REGISTER int i, n;
3501 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003502
3503 if ((cp = t->words[1]) == NULL) {
3504 i = umask(0);
3505 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003506 for (n = 3 * 4; (n -= 3) >= 0;)
3507 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003508 putc('\n', stderr);
3509 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003510 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3511 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003512 umask(n);
3513 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003514 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003515}
3516
Eric Andersen8401eea2004-08-04 19:16:54 +00003517static int doexec(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003518REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003519{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003520 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003521 jmp_buf ex;
3522 xint *ofail;
3523
3524 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003525 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003526 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003527 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003528 execflg = 1;
3529 ofail = failpt;
3530 if (setjmp(failpt = ex) == 0)
3531 execute(t, NOPIPE, NOPIPE, FEXEC);
3532 failpt = ofail;
3533 execflg = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003534 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003535}
3536
Eric Andersen8401eea2004-08-04 19:16:54 +00003537static int dodot(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003538struct op *t;
3539{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003540 REGISTER int i;
3541 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003542 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003543 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003544
Eric Andersen12de6cf2004-08-04 19:19:10 +00003545 DBGPRINTF(("DODOT: enter, t=0x%x, tleft 0x%x, tright 0x%x, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3546
3547 if ((cp = t->words[1]) == NULL) {
3548 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003549 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003550 } else {
3551 DBGPRINTF(("DODOT: cp is %s\n", cp));
3552 }
3553
Eric Andersen8401eea2004-08-04 19:16:54 +00003554 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003555
3556 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3557 ((sp == NULL) ? "NULL" : sp),
3558 ((e.linep == NULL) ? "NULL" : e.linep)));
3559
Eric Andersenff9eee42001-06-29 04:57:14 +00003560 while (*sp) {
3561 tp = e.linep;
3562 while (*sp && (*tp = *sp++) != ':')
3563 tp++;
3564 if (tp != e.linep)
3565 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003566
Eric Andersen8401eea2004-08-04 19:16:54 +00003567 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003568
3569 /* Original code */
Eric Andersenff9eee42001-06-29 04:57:14 +00003570 if ((i = open(e.linep, 0)) >= 0) {
3571 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003572 maltmp = remap(i);
3573 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3574
3575 next(maltmp); /* Basically a PUSHIO */
3576
3577 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3578
Eric Andersen8401eea2004-08-04 19:16:54 +00003579 return (exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00003580 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003581
3582 } /* While */
3583
Eric Andersenff9eee42001-06-29 04:57:14 +00003584 prs(cp);
3585 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003586
Eric Andersen8401eea2004-08-04 19:16:54 +00003587 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003588}
3589
Eric Andersen8401eea2004-08-04 19:16:54 +00003590static int dowait(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003591struct op *t;
3592{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003593 REGISTER int i;
3594 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003595
3596 if ((cp = t->words[1]) != NULL) {
3597 i = getn(cp);
3598 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003599 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 } else
3601 i = -1;
3602 setstatus(waitfor(i, 1));
Eric Andersen8401eea2004-08-04 19:16:54 +00003603 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003604}
3605
Eric Andersen8401eea2004-08-04 19:16:54 +00003606static int doread(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003607struct op *t;
3608{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003609 REGISTER char *cp, **wp;
3610 REGISTER int nb = 0;
3611 REGISTER int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003612
3613 if (t->words[1] == NULL) {
3614 err("Usage: read name ...");
Eric Andersen8401eea2004-08-04 19:16:54 +00003615 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003616 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003617 for (wp = t->words + 1; *wp; wp++) {
3618 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003619 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003620 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 break;
3622 *cp = 0;
3623 if (nb <= 0)
3624 break;
3625 setval(lookup(*wp), e.linep);
3626 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003627 return (nb <= 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003628}
3629
Eric Andersen8401eea2004-08-04 19:16:54 +00003630static int doeval(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003631REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003632{
Eric Andersen8401eea2004-08-04 19:16:54 +00003633 return (RUN(awordlist, t->words + 1, wdchar));
Eric Andersenff9eee42001-06-29 04:57:14 +00003634}
3635
Eric Andersen8401eea2004-08-04 19:16:54 +00003636static int dotrap(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003637REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003638{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003639 REGISTER int n, i;
3640 REGISTER int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003641
3642 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003643 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003644 if (trap[i]) {
3645 prn(i);
3646 prs(": ");
3647 prs(trap[i]);
3648 prs("\n");
3649 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003650 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003651 }
3652 resetsig = isdigit(*t->words[1]);
3653 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3654 n = getsig(t->words[i]);
3655 freecell(trap[n]);
3656 trap[n] = 0;
3657 if (!resetsig) {
3658 if (*t->words[1] != '\0') {
3659 trap[n] = strsave(t->words[1], 0);
3660 setsig(n, sig);
3661 } else
3662 setsig(n, SIG_IGN);
3663 } else {
3664 if (interactive)
3665 if (n == SIGINT)
3666 setsig(n, onintr);
3667 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003668 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003669 else
3670 setsig(n, SIG_DFL);
3671 }
3672 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003673 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003674}
3675
Eric Andersen8401eea2004-08-04 19:16:54 +00003676static int getsig(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003677char *s;
3678{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003679 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003680
3681 if ((n = getn(s)) < 0 || n > _NSIG) {
3682 err("trap: bad signal number");
3683 n = 0;
3684 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003685 return (n);
Eric Andersenff9eee42001-06-29 04:57:14 +00003686}
3687
Eric Andersen12de6cf2004-08-04 19:19:10 +00003688static void setsig(REGISTER int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003689{
3690 if (n == 0)
3691 return;
3692 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3693 ourtrap[n] = 1;
3694 signal(n, f);
3695 }
3696}
3697
Eric Andersen8401eea2004-08-04 19:16:54 +00003698static int getn(as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003699char *as;
3700{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003701 REGISTER char *s;
3702 REGISTER int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003703
3704 s = as;
3705 m = 1;
3706 if (*s == '-') {
3707 m = -1;
3708 s++;
3709 }
3710 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003711 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003712 if (*s) {
3713 prs(as);
3714 err(": bad number");
3715 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003716 return (n * m);
Eric Andersenff9eee42001-06-29 04:57:14 +00003717}
3718
Eric Andersen8401eea2004-08-04 19:16:54 +00003719static int dobreak(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003720struct op *t;
3721{
Eric Andersen8401eea2004-08-04 19:16:54 +00003722 return (brkcontin(t->words[1], 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00003723}
3724
Eric Andersen8401eea2004-08-04 19:16:54 +00003725static int docontinue(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003726struct op *t;
3727{
Eric Andersen8401eea2004-08-04 19:16:54 +00003728 return (brkcontin(t->words[1], 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00003729}
3730
Eric Andersen8401eea2004-08-04 19:16:54 +00003731static int brkcontin(cp, val)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003732REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003733int val;
3734{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003735 REGISTER struct brkcon *bc;
3736 REGISTER int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003737
Eric Andersen8401eea2004-08-04 19:16:54 +00003738 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003739 if (nl <= 0)
3740 nl = 999;
3741 do {
3742 if ((bc = brklist) == NULL)
3743 break;
3744 brklist = bc->nextlev;
3745 } while (--nl);
3746 if (nl) {
3747 err("bad break/continue level");
Eric Andersen8401eea2004-08-04 19:16:54 +00003748 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003749 }
3750 isbreak = val;
3751 longjmp(bc->brkpt, 1);
3752 /* NOTREACHED */
3753}
3754
Eric Andersen8401eea2004-08-04 19:16:54 +00003755static int doexit(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003756struct op *t;
3757{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003758 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003759
3760 execflg = 0;
3761 if ((cp = t->words[1]) != NULL)
3762 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003763
3764 DBGPRINTF(("DOEXIT: calling leave(), t=0x%x\n", t));
3765
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 leave();
3767 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00003768 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003769}
3770
Eric Andersen8401eea2004-08-04 19:16:54 +00003771static int doexport(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003772struct op *t;
3773{
Eric Andersen8401eea2004-08-04 19:16:54 +00003774 rdexp(t->words + 1, export, EXPORT);
3775 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003776}
3777
Eric Andersen8401eea2004-08-04 19:16:54 +00003778static int doreadonly(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003779struct op *t;
3780{
Eric Andersen8401eea2004-08-04 19:16:54 +00003781 rdexp(t->words + 1, ronly, RONLY);
3782 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003783}
3784
Eric Andersen8401eea2004-08-04 19:16:54 +00003785static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003786{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003787 DBGPRINTF6(("RDEXP: enter, wp=0x%x, func=0x%x, key=%d\n", wp, f, key));
3788 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3789
Eric Andersenff9eee42001-06-29 04:57:14 +00003790 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003791 for (; *wp != NULL; wp++) {
3792 if (isassign(*wp)) {
3793 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003794
Matt Kraaif69bfc72001-07-12 19:39:59 +00003795 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003796 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003797 *cp = '\0';
3798 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003799 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003800 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003801 else
3802 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003803 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003804 } else
3805 putvlist(key, 1);
3806}
3807
Eric Andersen8401eea2004-08-04 19:16:54 +00003808static void badid(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003809REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003810{
3811 prs(s);
3812 err(": bad identifier");
3813}
3814
Eric Andersen8401eea2004-08-04 19:16:54 +00003815static int doset(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003816REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003817{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003818 REGISTER struct var *vp;
3819 REGISTER char *cp;
3820 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003821
3822 if ((cp = t->words[1]) == NULL) {
3823 for (vp = vlist; vp; vp = vp->next)
3824 varput(vp->name, 1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003825 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003826 }
3827 if (*cp == '-') {
3828 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003829 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003830 if (*++cp == 0)
3831 flag['x'] = flag['v'] = 0;
3832 else
3833 for (; *cp; cp++)
3834 switch (*cp) {
3835 case 'e':
3836 if (!interactive)
3837 flag['e']++;
3838 break;
3839
3840 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003841 if (*cp >= 'a' && *cp <= 'z')
3842 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003843 break;
3844 }
3845 setdash();
3846 }
3847 if (t->words[1]) {
3848 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003849 for (n = 1; t->words[n]; n++)
3850 setarea((char *) t->words[n], 0);
3851 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003852 dolv = t->words;
3853 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003854 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003855 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003856 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003857}
3858
Eric Andersen8401eea2004-08-04 19:16:54 +00003859static void varput(s, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003860REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003861int out;
3862{
Matt Kraai69edfec2001-08-06 14:14:18 +00003863 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003864 write(out, s, strlen(s));
3865 write(out, "\n", 1);
3866 }
3867}
3868
3869
3870/*
3871 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3872 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003873 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003874static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003875{
3876 struct tms buf;
3877 long int clk_tck = sysconf(_SC_CLK_TCK);
3878
3879 times(&buf);
3880 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003881 (int) (buf.tms_utime / clk_tck / 60),
3882 ((double) buf.tms_utime) / clk_tck,
3883 (int) (buf.tms_stime / clk_tck / 60),
3884 ((double) buf.tms_stime) / clk_tck,
3885 (int) (buf.tms_cutime / clk_tck / 60),
3886 ((double) buf.tms_cutime) / clk_tck,
3887 (int) (buf.tms_cstime / clk_tck / 60),
3888 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003889 return 0;
3890}
3891
3892
Eric Andersen8401eea2004-08-04 19:16:54 +00003893static int (*inbuilt(char *s)) (struct op *) {
Eric Andersen1c039232001-07-07 00:05:55 +00003894 const struct builtincmd *bp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003895
Eric Andersen1c039232001-07-07 00:05:55 +00003896 for (bp = builtincmds; bp->name != NULL; bp++)
3897 if (strcmp(bp->name, s) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003898 return (bp->builtinfunc);
Eric Andersen1c039232001-07-07 00:05:55 +00003899
Eric Andersen8401eea2004-08-04 19:16:54 +00003900 return (NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003901}
3902
3903/* -------- eval.c -------- */
3904
3905/*
3906 * ${}
3907 * `command`
3908 * blank interpretation
3909 * quoting
3910 * glob
3911 */
3912
Eric Andersen8401eea2004-08-04 19:16:54 +00003913static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003914{
3915 struct wdblock *wb;
3916 char **wp;
3917 char **wf;
3918 jmp_buf ev;
3919
3920#if __GNUC__
3921 /* Avoid longjmp clobbering */
3922 (void) &wp;
3923 (void) &ap;
3924#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003925
3926 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3927
Eric Andersenff9eee42001-06-29 04:57:14 +00003928 wp = NULL;
3929 wb = NULL;
3930 wf = NULL;
3931 if (newenv(setjmp(errpt = ev)) == 0) {
3932 while (*ap && isassign(*ap))
3933 expand(*ap++, &wb, f & ~DOGLOB);
3934 if (flag['k']) {
3935 for (wf = ap; *wf; wf++) {
3936 if (isassign(*wf))
3937 expand(*wf, &wb, f & ~DOGLOB);
3938 }
3939 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003940 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003941 if (!flag['k'] || !isassign(*ap))
3942 expand(*ap, &wb, f & ~DOKEY);
3943 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003944 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003945 wp = getwords(wb);
3946 quitenv();
3947 } else
3948 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003949
Eric Andersen8401eea2004-08-04 19:16:54 +00003950 return (gflg ? (char **) NULL : wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003951}
3952
3953/*
3954 * Make the exported environment from the exported
3955 * names in the dictionary. Keyword assignments
3956 * will already have been done.
3957 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003958static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003959{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003960 REGISTER struct var *vp;
3961
3962 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003963
Eric Andersenff9eee42001-06-29 04:57:14 +00003964 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003965 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003966 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003967 wb = addword((char *) 0, wb);
3968 return (getwords(wb));
Eric Andersenff9eee42001-06-29 04:57:14 +00003969}
3970
Eric Andersen8401eea2004-08-04 19:16:54 +00003971static char *evalstr(cp, f)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003972REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003973int f;
3974{
3975 struct wdblock *wb;
3976
Eric Andersen12de6cf2004-08-04 19:19:10 +00003977 DBGPRINTF6(("EVALSTR: enter, cp=0x%x, f=%d\n", cp, f));
3978
Eric Andersenff9eee42001-06-29 04:57:14 +00003979 wb = NULL;
3980 if (expand(cp, &wb, f)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003981 if (wb == NULL || wb->w_nword == 0
3982 || (cp = wb->w_words[0]) == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003983 cp = "";
3984 DELETE(wb);
3985 } else
3986 cp = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003987 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003988}
3989
Eric Andersen12de6cf2004-08-04 19:19:10 +00003990static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003991{
3992 jmp_buf ev;
3993
3994#if __GNUC__
3995 /* Avoid longjmp clobbering */
3996 (void) &cp;
3997#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003998
3999 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
4000
Eric Andersenff9eee42001-06-29 04:57:14 +00004001 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004002
Eric Andersenff9eee42001-06-29 04:57:14 +00004003 if (cp == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004004 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004005
Eric Andersenff9eee42001-06-29 04:57:14 +00004006 if (!anys("$`'\"", cp) &&
Eric Andersen8401eea2004-08-04 19:16:54 +00004007 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004008 cp = strsave(cp, areanum);
4009 if (f & DOTRIM)
4010 unquote(cp);
4011 *wbp = addword(cp, *wbp);
Eric Andersen8401eea2004-08-04 19:16:54 +00004012 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004013 }
4014 if (newenv(setjmp(errpt = ev)) == 0) {
4015 PUSHIO(aword, cp, strchar);
4016 e.iobase = e.iop;
4017 while ((cp = blank(f)) && gflg == 0) {
4018 e.linep = cp;
4019 cp = strsave(cp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00004020 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004021 if (f & DOTRIM)
4022 unquote(cp);
4023 *wbp = addword(cp, *wbp);
4024 } else
4025 *wbp = glob(cp, *wbp);
4026 }
4027 quitenv();
4028 } else
4029 gflg = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004030 return (gflg == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004031}
4032
4033/*
4034 * Blank interpretation and quoting
4035 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004036static char *blank(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00004037int f;
4038{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004039 REGISTER int c, c1;
4040 REGISTER char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004041 int scanequals, foundequals;
4042
Eric Andersen12de6cf2004-08-04 19:19:10 +00004043 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
4044
Eric Andersenff9eee42001-06-29 04:57:14 +00004045 sp = e.linep;
4046 scanequals = f & DOKEY;
4047 foundequals = 0;
4048
Eric Andersen8401eea2004-08-04 19:16:54 +00004049 loop:
Eric Andersenff9eee42001-06-29 04:57:14 +00004050 switch (c = subgetc('"', foundequals)) {
4051 case 0:
4052 if (sp == e.linep)
Eric Andersen8401eea2004-08-04 19:16:54 +00004053 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004054 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004055 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004056
4057 default:
4058 if (f & DOBLANK && any(c, ifs->value))
4059 goto loop;
4060 break;
4061
4062 case '"':
4063 case '\'':
4064 scanequals = 0;
4065 if (INSUB())
4066 break;
4067 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
4068 if (c == 0)
4069 break;
4070 if (c == '\'' || !any(c, "$`\""))
4071 c |= QUOTE;
4072 *e.linep++ = c;
4073 }
4074 c = 0;
4075 }
4076 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00004077 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004078 scanequals = 0;
4079 for (;;) {
4080 c = subgetc('"', foundequals);
4081 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00004082 f & (DOBLANK && any(c, ifs->value)) ||
4083 (!INSUB() && any(c, "\"'"))) {
4084 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004085 unget(c);
4086 if (any(c, "\"'"))
4087 goto loop;
4088 break;
4089 }
4090 if (scanequals) {
4091 if (c == '=') {
4092 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004093 scanequals = 0;
4094 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004095 scanequals = 0;
4096 }
4097 *e.linep++ = c;
4098 }
4099 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004100 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004101}
4102
4103/*
4104 * Get characters, substituting for ` and $
4105 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004106static int subgetc(ec, quoted)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004107REGISTER char ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00004108int quoted;
4109{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004110 REGISTER char c;
4111
4112 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00004113
Eric Andersen8401eea2004-08-04 19:16:54 +00004114 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00004115 c = my_getc(ec);
4116 if (!INSUB() && ec != '\'') {
4117 if (c == '`') {
4118 if (grave(quoted) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004119 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004120 e.iop->task = XGRAVE;
4121 goto again;
4122 }
4123 if (c == '$' && (c = dollar(quoted)) == 0) {
4124 e.iop->task = XDOLL;
4125 goto again;
4126 }
4127 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004128 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004129}
4130
4131/*
4132 * Prepare to generate the string returned by ${} substitution.
4133 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004134static int dollar(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004135int quoted;
4136{
4137 int otask;
4138 struct io *oiop;
4139 char *dolp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004140 REGISTER char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004141 struct var *vp;
4142
Eric Andersen12de6cf2004-08-04 19:19:10 +00004143 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
4144
Eric Andersenff9eee42001-06-29 04:57:14 +00004145 c = readc();
4146 s = e.linep;
4147 if (c != '{') {
4148 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00004149 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00004150 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00004151 if (e.linep < elinep)
4152 *e.linep++ = c;
4153 unget(c);
4154 }
4155 c = 0;
4156 } else {
4157 oiop = e.iop;
4158 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004159
Eric Andersenff9eee42001-06-29 04:57:14 +00004160 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00004161 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004162 if (e.linep < elinep)
4163 *e.linep++ = c;
4164 if (oiop == e.iop)
4165 e.iop->task = otask;
4166 if (c != '}') {
4167 err("unclosed ${");
4168 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004169 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004170 }
4171 }
4172 if (e.linep >= elinep) {
4173 err("string in ${} too long");
4174 gflg++;
4175 e.linep -= 10;
4176 }
4177 *e.linep = 0;
4178 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00004179 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004180 if (any(*cp, "=-+?")) {
4181 c = *cp;
4182 *cp++ = 0;
4183 break;
4184 }
4185 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4186 if (dolc > 1) {
4187 /* currently this does not distinguish $* and $@ */
4188 /* should check dollar */
4189 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00004190 PUSHIO(awordlist, dolv + 1, dolchar);
4191 return (0);
4192 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00004193 s[0] = '1';
4194 s[1] = 0;
4195 }
4196 }
4197 vp = lookup(s);
4198 if ((dolp = vp->value) == null) {
4199 switch (c) {
4200 case '=':
4201 if (isdigit(*s)) {
4202 err("cannot use ${...=...} with $n");
4203 gflg++;
4204 break;
4205 }
4206 setval(vp, cp);
4207 dolp = vp->value;
4208 break;
4209
4210 case '-':
4211 dolp = strsave(cp, areanum);
4212 break;
4213
4214 case '?':
4215 if (*cp == 0) {
4216 prs("missing value for ");
4217 err(s);
4218 } else
4219 err(cp);
4220 gflg++;
4221 break;
4222 }
4223 } else if (c == '+')
4224 dolp = strsave(cp, areanum);
4225 if (flag['u'] && dolp == null) {
4226 prs("unset variable: ");
4227 err(s);
4228 gflg++;
4229 }
4230 e.linep = s;
4231 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Eric Andersen8401eea2004-08-04 19:16:54 +00004232 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004233}
4234
4235/*
4236 * Run the command in `...` and read its output.
4237 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004238
Eric Andersen8401eea2004-08-04 19:16:54 +00004239static int grave(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004240int quoted;
4241{
Eric Andersenff9eee42001-06-29 04:57:14 +00004242 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004243 REGISTER int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004244 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004245 int pf[2];
Eric Andersen737f5fb2003-03-14 16:05:59 +00004246 static char child_cmd[LINELIM];
4247 char *src;
4248 char *dest;
4249 int count;
4250 int ignore;
4251 int ignore_once;
4252 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004253 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004254
4255#if __GNUC__
4256 /* Avoid longjmp clobbering */
4257 (void) &cp;
4258#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004259
Eric Andersenff9eee42001-06-29 04:57:14 +00004260 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4261 if (*cp == 0) {
4262 err("no closing `");
Eric Andersen8401eea2004-08-04 19:16:54 +00004263 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004264 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004265
4266 /* string copy with dollar expansion */
4267 src = e.iop->argp->aword;
4268 dest = child_cmd;
4269 count = 0;
4270 ignore = 0;
4271 ignore_once = 0;
4272 while ((*src != '`') && (count < LINELIM)) {
4273 if (*src == '\'')
4274 ignore = !ignore;
4275 if (*src == '\\')
4276 ignore_once = 1;
4277 if (*src == '$' && !ignore && !ignore_once) {
4278 struct var *vp;
4279 char var_name[LINELIM];
4280 char alt_value[LINELIM];
4281 int var_index = 0;
4282 int alt_index = 0;
4283 char operator = 0;
4284 int braces = 0;
4285 char *value;
4286
4287 src++;
4288 if (*src == '{') {
4289 braces = 1;
4290 src++;
4291 }
4292
4293 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004294 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004295 var_name[var_index++] = *src++;
4296 var_name[var_index] = 0;
4297
4298 if (braces) {
4299 switch (*src) {
4300 case '}':
4301 break;
4302 case '-':
4303 case '=':
4304 case '+':
4305 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004306 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004307 break;
4308 default:
4309 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004310 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004311 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004312 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004313 src++;
4314 while (*src && (*src != '}')) {
4315 alt_value[alt_index++] = *src++;
4316 }
4317 alt_value[alt_index] = 0;
4318 if (*src != '}') {
4319 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004320 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004321 }
4322 }
4323 src++;
4324 }
4325
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004326 if (isalpha(*var_name)) {
4327 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004328
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004329 char *namep = var_name;
4330
4331 *dest++ = '$';
4332 if (braces)
4333 *dest++ = '{';
4334 while (*namep)
4335 *dest++ = *namep++;
4336 if (operator) {
4337 char *altp = alt_value;
4338 *dest++ = operator;
4339 while (*altp)
4340 *dest++ = *altp++;
4341 }
4342 if (braces)
4343 *dest++ = '}';
4344
4345 wb = addword(lookup(var_name)->name, wb);
4346 } else {
4347 /* expand */
4348
4349 vp = lookup(var_name);
4350 if (vp->value != null)
4351 value = (operator == '+') ?
4352 alt_value : vp->value;
4353 else if (operator == '?') {
4354 err(alt_value);
4355 return (0);
4356 } else if (alt_index && (operator != '+')) {
4357 value = alt_value;
4358 if (operator == '=')
4359 setval(vp, value);
4360 } else
4361 continue;
4362
4363 while (*value && (count < LINELIM)) {
4364 *dest++ = *value++;
4365 count++;
4366 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004367 }
4368 } else {
4369 *dest++ = *src++;
4370 count++;
4371 ignore_once = 0;
4372 }
4373 }
4374 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004375
Eric Andersenff9eee42001-06-29 04:57:14 +00004376 if (openpipe(pf) < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004377 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004378
Eric Andersen8401eea2004-08-04 19:16:54 +00004379 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004380
4381 DBGPRINTF3(("GRAVE: i is %d\n", io));
4382
Eric Andersen737f5fb2003-03-14 16:05:59 +00004383 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004384 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004385 err((char *) bb_msg_memory_exhausted);
4386 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004387 }
4388 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004389 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004390 e.iop->argp->aword = ++cp;
4391 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004392 PUSHIO(afile, remap(pf[0]),
4393 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4394 gravechar));
4395 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004396 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004397 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004398 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004399 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004400 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4401 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004402
Eric Andersenff9eee42001-06-29 04:57:14 +00004403 dup2(pf[1], 1);
4404 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004405
Eric Andersen8401eea2004-08-04 19:16:54 +00004406 argument_list[0] = (char *) DEFAULT_SHELL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004407 argument_list[1] = "-c";
4408 argument_list[2] = child_cmd;
4409 argument_list[3] = 0;
4410
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004411 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004412 prs(argument_list[0]);
4413 prs(": ");
4414 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004415 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004416}
4417
Eric Andersen737f5fb2003-03-14 16:05:59 +00004418
Eric Andersen8401eea2004-08-04 19:16:54 +00004419static char *unquote(as)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004420REGISTER char *as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004421{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004422 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004423
4424 if ((s = as) != NULL)
4425 while (*s)
4426 *s++ &= ~QUOTE;
Eric Andersen8401eea2004-08-04 19:16:54 +00004427 return (as);
Eric Andersenff9eee42001-06-29 04:57:14 +00004428}
4429
4430/* -------- glob.c -------- */
4431
4432/*
4433 * glob
4434 */
4435
4436#define scopy(x) strsave((x), areanum)
4437#define BLKSIZ 512
4438#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4439
Eric Andersen8401eea2004-08-04 19:16:54 +00004440static struct wdblock *cl, *nl;
4441static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004442
Eric Andersen8401eea2004-08-04 19:16:54 +00004443static struct wdblock *glob(cp, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004444char *cp;
4445struct wdblock *wb;
4446{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004447 REGISTER int i;
4448 REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004449
4450 if (cp == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004451 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 i = 0;
4453 for (pp = cp; *pp; pp++)
4454 if (any(*pp, spcl))
4455 i++;
4456 else if (!any(*pp & ~QUOTE, spcl))
4457 *pp &= ~QUOTE;
4458 if (i != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004459 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4460 cl = nl) {
4461 nl = newword(cl->w_nword * 2);
4462 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004463 for (pp = cl->w_words[i]; *pp; pp++)
4464 if (any(*pp, spcl)) {
4465 globname(cl->w_words[i], pp);
4466 break;
4467 }
4468 if (*pp == '\0')
4469 nl = addword(scopy(cl->w_words[i]), nl);
4470 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004471 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004472 DELETE(cl->w_words[i]);
4473 DELETE(cl);
4474 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004475 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004476 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004477 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004478 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004479 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004480 wb = addword(cl->w_words[i], wb);
4481 DELETE(cl);
Eric Andersen8401eea2004-08-04 19:16:54 +00004482 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004483 }
4484 }
4485 wb = addword(unquote(cp), wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004486 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004487}
4488
Eric Andersen8401eea2004-08-04 19:16:54 +00004489static void globname(we, pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004490char *we;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004491REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004492{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004493 REGISTER char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004494 char *name, *gp, *dp;
4495 int k;
4496 DIR *dirp;
4497 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004498 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004499 struct stat dbuf;
4500
4501 for (np = we; np != pp; pp--)
4502 if (pp[-1] == '/')
4503 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004504 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004505 *cp++ = *np++;
4506 *cp++ = '.';
4507 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004508 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004509 *cp++ = *np++;
4510 *cp = '\0';
4511 dirp = opendir(dp);
4512 if (dirp == 0) {
4513 DELETE(dp);
4514 DELETE(gp);
4515 return;
4516 }
4517 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004518 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004519 /* XXX Hmmm... What this could be? (abial) */
4520 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004521 if (ent[j].d_ino == 0)
4522 continue;
4523 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004524 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004525 if (dname[0] == '.')
4526 if (*gp != '.')
4527 continue;
4528 for (k = 0; k < NAME_MAX; k++)
4529 if (any(dname[k], spcl))
4530 dname[k] |= QUOTE;
4531 if (gmatch(dname, gp)) {
4532 name = generate(we, pp, dname, np);
4533 if (*np && !anys(np, spcl)) {
4534 if (stat(name, &dbuf)) {
4535 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004537 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004538 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004539 nl = addword(name, nl);
4540 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004541 }
4542 closedir(dirp);
4543 DELETE(dp);
4544 DELETE(gp);
4545}
4546
4547/*
4548 * generate a pathname as below.
4549 * start..end1 / middle end
4550 * the slashes come for free
4551 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004552static char *generate(start1, end1, middle, end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004553char *start1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004554REGISTER char *end1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004555char *middle, *end;
4556{
4557 char *p;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004558 REGISTER char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004559
Eric Andersen8401eea2004-08-04 19:16:54 +00004560 p = op =
4561 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004562 for (xp = start1; xp != end1;)
4563 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004564 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004565 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004566 for (xp = end; (*op++ = *xp++) != '\0';);
4567 return (p);
Eric Andersenff9eee42001-06-29 04:57:14 +00004568}
4569
Eric Andersen8401eea2004-08-04 19:16:54 +00004570static int anyspcl(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004571REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004572{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004573 REGISTER int i;
4574 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004575
4576 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004577 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004578 if (anys(spcl, *wd++))
Eric Andersen8401eea2004-08-04 19:16:54 +00004579 return (1);
4580 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004581}
4582
Eric Andersen8401eea2004-08-04 19:16:54 +00004583static int xstrcmp(p1, p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004584char *p1, *p2;
4585{
Eric Andersen8401eea2004-08-04 19:16:54 +00004586 return (strcmp(*(char **) p1, *(char **) p2));
Eric Andersenff9eee42001-06-29 04:57:14 +00004587}
4588
4589/* -------- word.c -------- */
4590
Eric Andersen8401eea2004-08-04 19:16:54 +00004591static struct wdblock *newword(nw)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004592REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004593{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004594 REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004595
Eric Andersen8401eea2004-08-04 19:16:54 +00004596 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004597 wb->w_bsize = nw;
4598 wb->w_nword = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004599 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004600}
4601
Eric Andersen8401eea2004-08-04 19:16:54 +00004602static struct wdblock *addword(wd, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004603char *wd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004604REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004605{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004606 REGISTER struct wdblock *wb2;
4607 REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004608
4609 if (wb == NULL)
4610 wb = newword(NSTART);
4611 if ((nw = wb->w_nword) >= wb->w_bsize) {
4612 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004613 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4614 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004615 wb2->w_nword = nw;
4616 DELETE(wb);
4617 wb = wb2;
4618 }
4619 wb->w_words[wb->w_nword++] = wd;
Eric Andersen8401eea2004-08-04 19:16:54 +00004620 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004621}
Eric Andersen8401eea2004-08-04 19:16:54 +00004622
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004623static
Eric Andersen8401eea2004-08-04 19:16:54 +00004624char **getwords(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004625REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004626{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004627 REGISTER char **wd;
4628 REGISTER int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004629
4630 if (wb == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004631 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004632 if (wb->w_nword == 0) {
4633 DELETE(wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004634 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004635 }
4636 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004637 memcpy((char *) wd, (char *) wb->w_words, nb);
4638 DELETE(wb); /* perhaps should done by caller */
4639 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00004640}
4641
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004642static int (*func) (char *, char *);
4643static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004644
Eric Andersen8401eea2004-08-04 19:16:54 +00004645static void glob0(a0, a1, a2, a3)
Eric Andersenff9eee42001-06-29 04:57:14 +00004646char *a0;
4647unsigned a1;
4648int a2;
4649int (*a3) (char *, char *);
4650{
4651 func = a3;
4652 globv = a2;
4653 glob1(a0, a0 + a1 * a2);
4654}
4655
Eric Andersen8401eea2004-08-04 19:16:54 +00004656static void glob1(base, lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004657char *base, *lim;
4658{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004659 REGISTER char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004660 int v2;
4661 char *lptr, *hptr;
4662 int c;
4663 unsigned n;
4664
4665
4666 v2 = globv;
4667
Eric Andersen8401eea2004-08-04 19:16:54 +00004668 top:
4669 if ((n = (int) (lim - base)) <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004670 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004671 n = v2 * (n / (2 * v2));
4672 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004673 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004674 j = lim - v2;
4675 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004676 if (i < lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004677 if ((c = (*func) (i, lptr)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004678 glob2(i, lptr -= v2);
4679 continue;
4680 }
4681 if (c < 0) {
4682 i += v2;
4683 continue;
4684 }
4685 }
4686
Eric Andersen8401eea2004-08-04 19:16:54 +00004687 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004688 if (j > hptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004689 if ((c = (*func) (hptr, j)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004690 glob2(hptr += v2, j);
4691 goto begin;
4692 }
4693 if (c > 0) {
4694 if (i == lptr) {
4695 glob3(i, hptr += v2, j);
4696 i = lptr += v2;
4697 goto begin;
4698 }
4699 glob2(i, j);
4700 j -= v2;
4701 i += v2;
4702 continue;
4703 }
4704 j -= v2;
4705 goto begin;
4706 }
4707
4708
4709 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004710 if (lptr - base >= lim - hptr) {
4711 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004712 lim = lptr;
4713 } else {
4714 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004715 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004716 }
4717 goto top;
4718 }
4719
4720
4721 glob3(j, lptr -= v2, i);
4722 j = hptr -= v2;
4723 }
4724}
4725
Eric Andersen8401eea2004-08-04 19:16:54 +00004726static void glob2(i, j)
Eric Andersenff9eee42001-06-29 04:57:14 +00004727char *i, *j;
4728{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004729 REGISTER char *index1, *index2, c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004730 int m;
4731
4732 m = globv;
4733 index1 = i;
4734 index2 = j;
4735 do {
4736 c = *index1;
4737 *index1++ = *index2;
4738 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004739 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004740}
4741
Eric Andersen8401eea2004-08-04 19:16:54 +00004742static void glob3(i, j, k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004743char *i, *j, *k;
4744{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004745 REGISTER char *index1, *index2, *index3;
Eric Andersenff9eee42001-06-29 04:57:14 +00004746 int c;
4747 int m;
4748
4749 m = globv;
4750 index1 = i;
4751 index2 = j;
4752 index3 = k;
4753 do {
4754 c = *index1;
4755 *index1++ = *index3;
4756 *index3++ = *index2;
4757 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004758 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004759}
4760
4761/* -------- io.c -------- */
4762
4763/*
4764 * shell IO
4765 */
4766
Eric Andersen8401eea2004-08-04 19:16:54 +00004767static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004768{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004769 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004770
Eric Andersen8401eea2004-08-04 19:16:54 +00004771 if (e.linep > elinep) {
4772 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004773 err("input line too long");
4774 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004775 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004776 }
4777 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004778 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004779 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004780 c = readc();
4781 if (c == '\n' && ec != '\"')
Eric Andersen8401eea2004-08-04 19:16:54 +00004782 return (my_getc(ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00004783 c |= QUOTE;
4784 }
4785 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004786 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004787}
4788
Eric Andersen8401eea2004-08-04 19:16:54 +00004789static void unget(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004790int c;
4791{
4792 if (e.iop >= e.iobase)
4793 e.iop->peekc = c;
4794}
4795
Eric Andersen8401eea2004-08-04 19:16:54 +00004796static int eofc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004797{
Eric Andersen8401eea2004-08-04 19:16:54 +00004798 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004799}
4800
Eric Andersen8401eea2004-08-04 19:16:54 +00004801static int readc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004802{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004803 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004804
Eric Andersen12de6cf2004-08-04 19:19:10 +00004805 RCPRINTF(("READC: e.iop 0x%x, e.iobase 0x%x\n", e.iop, e.iobase));
4806
4807 for (; e.iop >= e.iobase; e.iop--) {
4808 RCPRINTF(("READC: e.iop 0x%x, peekc 0x%x\n", e.iop, e.iop->peekc));
Eric Andersenff9eee42001-06-29 04:57:14 +00004809 if ((c = e.iop->peekc) != '\0') {
4810 e.iop->peekc = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004811 return (c);
4812 } else {
4813 if (e.iop->prev != 0) {
4814 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4815 if (c == -1) {
4816 e.iop++;
4817 continue;
4818 }
4819 if (e.iop == iostack)
4820 ioecho(c);
4821 return (e.iop->prev = c);
4822 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4823 e.iop->prev = 0;
4824 if (e.iop == iostack)
4825 ioecho('\n');
4826 return '\n';
4827 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004828 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004829 if (e.iop->task == XIO) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004830 if (multiline) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004831 return e.iop->prev = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004832 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004833 if (interactive && e.iop == iostack + 1) {
4834#ifdef CONFIG_FEATURE_COMMAND_EDITING
4835 current_prompt = prompt->value;
4836#else
4837 prs(prompt->value);
4838#endif
4839 }
4840 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004841 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004842
4843 } /* FOR */
4844
4845 if (e.iop >= iostack) {
4846 RCPRINTF(("READC: return 0, e.iop 0x%x\n", e.iop));
Eric Andersen8401eea2004-08-04 19:16:54 +00004847 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004848 }
4849
4850 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004851 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004852
Eric Andersenff9eee42001-06-29 04:57:14 +00004853 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00004854 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004855}
4856
Eric Andersen8401eea2004-08-04 19:16:54 +00004857static void ioecho(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004858char c;
4859{
4860 if (flag['v'])
4861 write(2, &c, sizeof c);
4862}
4863
Eric Andersen12de6cf2004-08-04 19:19:10 +00004864
Eric Andersen8401eea2004-08-04 19:16:54 +00004865static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004866{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004867 DBGPRINTF(("PUSHIO: argp 0x%x, argp->afid 0x%x, e.iop 0x%x\n", argp,
4868 argp->afid, e.iop));
4869
4870 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004871 if (++e.iop >= &iostack[NPUSH]) {
4872 e.iop--;
4873 err("Shell input nested too deeply");
4874 gflg++;
4875 return;
4876 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004877
4878 /* We did not overflow the NPUSH array spots so setup data structs */
4879
4880 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004881
4882 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004883 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004884 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004885
4886 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4887 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4888
4889 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4890
4891 if (e.iop == &iostack[0])
4892 e.iop->argp->afbuf = &mainbuf;
4893 else
4894 e.iop->argp->afbuf = &sharedbuf;
4895
4896 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4897 /* This line appears to be active when running scripts from command line */
4898 if ((isatty(e.iop->argp->afile) == 0)
4899 && (e.iop == &iostack[0]
4900 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4901 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4902 bufid = AFID_ID; /* AFID_ID = 0 */
4903
4904 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004905 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004906
4907 DBGPRINTF(("PUSHIO: iostack 0x%x, e.iop 0x%x, afbuf 0x%x\n",
4908 iostack, e.iop, e.iop->argp->afbuf));
4909 DBGPRINTF(("PUSHIO: mbuf 0x%x, sbuf 0x%x, bid %d, e.iop 0x%x\n",
4910 &mainbuf, &sharedbuf, bufid, e.iop));
4911
Eric Andersenff9eee42001-06-29 04:57:14 +00004912 }
4913
Eric Andersen8401eea2004-08-04 19:16:54 +00004914 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004915 e.iop->peekc = 0;
4916 e.iop->xchar = 0;
4917 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004918
Eric Andersenff9eee42001-06-29 04:57:14 +00004919 if (fn == filechar || fn == linechar)
4920 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004921 else if (fn == (int (*)(struct ioarg *)) gravechar
4922 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004923 e.iop->task = XGRAVE;
4924 else
4925 e.iop->task = XOTHER;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004926
4927 return;
Eric Andersenff9eee42001-06-29 04:57:14 +00004928}
4929
Eric Andersen8401eea2004-08-04 19:16:54 +00004930static struct io *setbase(ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004931struct io *ip;
4932{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004933 REGISTER struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004934
4935 xp = e.iobase;
4936 e.iobase = ip;
Eric Andersen8401eea2004-08-04 19:16:54 +00004937 return (xp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004938}
4939
4940/*
4941 * Input generating functions
4942 */
4943
4944/*
4945 * Produce the characters of a string, then a newline, then EOF.
4946 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004947static int nlchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004948REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004949{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004950 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004951
4952 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004953 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004954 if ((c = *ap->aword++) == 0) {
4955 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004956 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004957 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004958 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004959}
4960
4961/*
4962 * Given a list of words, produce the characters
4963 * in them, with a space after each word.
4964 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004965static int wdchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004966REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004967{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004968 REGISTER char c;
4969 REGISTER char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004970
4971 if ((wl = ap->awordlist) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004972 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004973 if (*wl != NULL) {
4974 if ((c = *(*wl)++) != 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004975 return (c & 0177);
Eric Andersenff9eee42001-06-29 04:57:14 +00004976 ap->awordlist++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004977 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00004978 }
4979 ap->awordlist = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004980 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004981}
4982
4983/*
4984 * Return the characters of a list of words,
4985 * producing a space between them.
4986 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004987static int dolchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004988REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004989{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004990 REGISTER char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004991
4992 if ((wp = *ap->awordlist++) != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004993 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4994 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004995 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004996 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004997}
4998
Eric Andersen8401eea2004-08-04 19:16:54 +00004999static int xxchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005000REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005001{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005002 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005003
5004 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00005005 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00005006 if ((c = *ap->aword++) == '\0') {
5007 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00005008 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00005009 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005010 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005011}
5012
5013/*
5014 * Produce the characters from a single word (string).
5015 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005016static int strchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005017REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005018{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005019 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005020
5021 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005022 return (0);
5023 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005024}
5025
5026/*
5027 * Produce quoted characters from a single word (string).
5028 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005029static int qstrchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005030REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005031{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005032 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005033
5034 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005035 return (0);
5036 return (c | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005037}
5038
5039/*
5040 * Return the characters from a file.
5041 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005042static int filechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005043REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005044{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005045 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005046 char c;
5047 struct iobuf *bp = ap->afbuf;
5048
5049 if (ap->afid != AFID_NOBUF) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005050 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00005051
Eric Andersen8401eea2004-08-04 19:16:54 +00005052 if (i)
5053 lseek(ap->afile, ap->afpos, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005054
Eric Andersen8401eea2004-08-04 19:16:54 +00005055 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005056
Eric Andersen8401eea2004-08-04 19:16:54 +00005057 if (i <= 0) {
5058 closef(ap->afile);
5059 return 0;
5060 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005061
Eric Andersen8401eea2004-08-04 19:16:54 +00005062 bp->id = ap->afid;
5063 bp->ebufp = (bp->bufp = bp->buf) + i;
5064 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005065
Eric Andersen8401eea2004-08-04 19:16:54 +00005066 ap->afpos++;
5067 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00005068 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005069#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00005070 if (interactive && isatty(ap->afile)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005071 static char mycommand[BUFSIZ];
5072 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00005073
Eric Andersen8401eea2004-08-04 19:16:54 +00005074 while (size == 0 || position >= size) {
5075 cmdedit_read_input(current_prompt, mycommand);
5076 size = strlen(mycommand);
5077 position = 0;
5078 }
5079 c = mycommand[position];
5080 position++;
5081 return (c);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005082 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00005083#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005084
Eric Andersenff9eee42001-06-29 04:57:14 +00005085 {
Eric Andersen7467c8d2001-07-12 20:26:32 +00005086 i = safe_read(ap->afile, &c, sizeof(c));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005087 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00005088 }
5089}
5090
5091/*
5092 * Return the characters from a here temp file.
5093 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005094static int herechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005095REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005096{
5097 char c;
5098
5099
5100 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
5101 close(ap->afile);
5102 c = 0;
5103 }
5104 return (c);
5105
5106}
5107
5108/*
5109 * Return the characters produced by a process (`...`).
5110 * Quote them if required, and remove any trailing newline characters.
5111 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005112static int gravechar(ap, iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00005113struct ioarg *ap;
5114struct io *iop;
5115{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005116 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005117
Eric Andersen8401eea2004-08-04 19:16:54 +00005118 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00005119 c = ' ';
Eric Andersen8401eea2004-08-04 19:16:54 +00005120 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005121}
5122
Eric Andersen8401eea2004-08-04 19:16:54 +00005123static int qgravechar(ap, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005124REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005125struct io *iop;
5126{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005127 REGISTER int c;
5128
5129 DBGPRINTF3(("QGRAVECHAR: enter, ap=0x%x, iop=0x%x\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00005130
5131 if (iop->xchar) {
5132 if (iop->nlcount) {
5133 iop->nlcount--;
Eric Andersen8401eea2004-08-04 19:16:54 +00005134 return ('\n' | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005135 }
5136 c = iop->xchar;
5137 iop->xchar = 0;
5138 } else if ((c = filechar(ap)) == '\n') {
5139 iop->nlcount = 1;
5140 while ((c = filechar(ap)) == '\n')
5141 iop->nlcount++;
5142 iop->xchar = c;
5143 if (c == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005144 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005145 iop->nlcount--;
5146 c = '\n';
5147 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005148 return (c != 0 ? c | QUOTE : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00005149}
5150
5151/*
5152 * Return a single command (usually the first line) from a file.
5153 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005154static int linechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005155REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005156{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005157 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005158
5159 if ((c = filechar(ap)) == '\n') {
5160 if (!multiline) {
5161 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00005162 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00005163 }
5164 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005165 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005166}
5167
Eric Andersen8401eea2004-08-04 19:16:54 +00005168static void prs(s)
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +00005169REGISTER const char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005170{
5171 if (*s)
5172 write(2, s, strlen(s));
5173}
5174
Eric Andersen8401eea2004-08-04 19:16:54 +00005175static void prn(u)
Eric Andersenff9eee42001-06-29 04:57:14 +00005176unsigned u;
5177{
Eric Andersen737f5fb2003-03-14 16:05:59 +00005178 prs(itoa(u));
Eric Andersenff9eee42001-06-29 04:57:14 +00005179}
5180
Eric Andersen8401eea2004-08-04 19:16:54 +00005181static void closef(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005182REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005183{
5184 if (i > 2)
5185 close(i);
5186}
5187
Eric Andersen8401eea2004-08-04 19:16:54 +00005188static void closeall()
Eric Andersenff9eee42001-06-29 04:57:14 +00005189{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005190 REGISTER int u;
Eric Andersenff9eee42001-06-29 04:57:14 +00005191
Eric Andersen8401eea2004-08-04 19:16:54 +00005192 for (u = NUFILE; u < NOFILE;)
Eric Andersenff9eee42001-06-29 04:57:14 +00005193 close(u++);
5194}
5195
Eric Andersen12de6cf2004-08-04 19:19:10 +00005196
Eric Andersenff9eee42001-06-29 04:57:14 +00005197/*
5198 * remap fd into Shell's fd space
5199 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005200static int remap(fd)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005201REGISTER int fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005202{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005203 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005204 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00005205 int newfd;
5206
5207
5208 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00005209
5210 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005211 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005212 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005213
Eric Andersenff9eee42001-06-29 04:57:14 +00005214 do {
5215 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005216 newfd = dup(fd);
5217 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005218 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005219
Eric Andersen8401eea2004-08-04 19:16:54 +00005220 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005221 if (map[i])
5222 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005223
Eric Andersenff9eee42001-06-29 04:57:14 +00005224 if (fd < 0)
5225 err("too many files open in shell");
5226 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005227
Eric Andersen8401eea2004-08-04 19:16:54 +00005228 return (fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00005229}
5230
Eric Andersen8401eea2004-08-04 19:16:54 +00005231static int openpipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005232REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005233{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005234 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005235
5236 if ((i = pipe(pv)) < 0)
5237 err("can't create pipe - try again");
Eric Andersen8401eea2004-08-04 19:16:54 +00005238 return (i);
Eric Andersenff9eee42001-06-29 04:57:14 +00005239}
5240
Eric Andersen8401eea2004-08-04 19:16:54 +00005241static void closepipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005242REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005243{
5244 if (pv != NULL) {
5245 close(*pv++);
5246 close(*pv);
5247 }
5248}
5249
5250/* -------- here.c -------- */
5251
5252/*
5253 * here documents
5254 */
5255
Eric Andersen8401eea2004-08-04 19:16:54 +00005256static void markhere(s, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005257REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005258struct ioword *iop;
5259{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005260 REGISTER struct here *h, *lh;
5261
5262 DBGPRINTF7(("MARKHERE: enter, s=0x%x\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00005263
5264 h = (struct here *) space(sizeof(struct here));
5265 if (h == 0)
5266 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005267
Eric Andersenff9eee42001-06-29 04:57:14 +00005268 h->h_tag = evalstr(s, DOSUB);
5269 if (h->h_tag == 0)
5270 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005271
Eric Andersenff9eee42001-06-29 04:57:14 +00005272 h->h_iop = iop;
5273 iop->io_name = 0;
5274 h->h_next = NULL;
5275 if (inhere == 0)
5276 inhere = h;
5277 else
Eric Andersen8401eea2004-08-04 19:16:54 +00005278 for (lh = inhere; lh != NULL; lh = lh->h_next)
Eric Andersenff9eee42001-06-29 04:57:14 +00005279 if (lh->h_next == 0) {
5280 lh->h_next = h;
5281 break;
5282 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005283 iop->io_flag |= IOHERE | IOXHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005284 for (s = h->h_tag; *s; s++)
5285 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005286 iop->io_flag &= ~IOXHERE;
5287 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005288 }
5289 h->h_dosub = iop->io_flag & IOXHERE;
5290}
5291
Eric Andersen8401eea2004-08-04 19:16:54 +00005292static void gethere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005293{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005294 REGISTER struct here *h, *hp;
5295
5296 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005297
5298 /* Scan here files first leaving inhere list in place */
5299 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005300 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005301
5302 /* Make inhere list active - keep list intact for scraphere */
5303 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005304 hp->h_next = acthere;
5305 acthere = inhere;
5306 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005307 }
5308}
5309
Eric Andersen8401eea2004-08-04 19:16:54 +00005310static void readhere(name, s, ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005311char **name;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005312REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005313int ec;
5314{
5315 int tf;
5316 char tname[30] = ".msh_XXXXXX";
Eric Andersen12de6cf2004-08-04 19:19:10 +00005317 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005318 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005319 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005320 char *thenext;
5321
Eric Andersen12de6cf2004-08-04 19:19:10 +00005322 DBGPRINTF7(("READHERE: enter, name=0x%x, s=0x%x\n", name, s));
5323
Eric Andersenff9eee42001-06-29 04:57:14 +00005324 tf = mkstemp(tname);
5325 if (tf < 0)
5326 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005327
Eric Andersenff9eee42001-06-29 04:57:14 +00005328 *name = strsave(tname, areanum);
5329 if (newenv(setjmp(errpt = ev)) != 0)
5330 unlink(tname);
5331 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005332 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005333 e.iobase = e.iop;
5334 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005335 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005336#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005337 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005338#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005339 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005340#endif
5341 }
5342 thenext = myline;
5343 while ((c = my_getc(ec)) != '\n' && c) {
5344 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005345 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005346 if (thenext >= &myline[LINELIM]) {
5347 c = 0;
5348 break;
5349 }
5350 *thenext++ = c;
5351 }
5352 *thenext = 0;
5353 if (strcmp(s, myline) == 0 || c == 0)
5354 break;
5355 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005356 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005357 }
5358 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005359 prs("here document `");
5360 prs(s);
5361 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005362 }
5363 quitenv();
5364 }
5365 close(tf);
5366}
5367
5368/*
5369 * open here temp file.
5370 * if unquoted here, expand here temp file into second temp file.
5371 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005372static int herein(hname, xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005373char *hname;
5374int xdoll;
5375{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005376 REGISTER int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005377 int tf;
5378
5379#if __GNUC__
5380 /* Avoid longjmp clobbering */
5381 (void) &tf;
5382#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005383 if (hname == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00005384 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005385
5386 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5387
Eric Andersenff9eee42001-06-29 04:57:14 +00005388 hf = open(hname, 0);
5389 if (hf < 0)
5390 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005391
Eric Andersenff9eee42001-06-29 04:57:14 +00005392 if (xdoll) {
5393 char c;
5394 char tname[30] = ".msh_XXXXXX";
5395 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005396
Eric Andersenff9eee42001-06-29 04:57:14 +00005397 tf = mkstemp(tname);
5398 if (tf < 0)
5399 return (-1);
5400 if (newenv(setjmp(errpt = ev)) == 0) {
5401 PUSHIO(afile, hf, herechar);
5402 setbase(e.iop);
5403 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005404 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005405 write(tf, &c, sizeof c);
5406 }
5407 quitenv();
5408 } else
5409 unlink(tname);
5410 close(tf);
5411 tf = open(tname, 0);
5412 unlink(tname);
5413 return (tf);
5414 } else
5415 return (hf);
5416}
5417
Eric Andersen8401eea2004-08-04 19:16:54 +00005418static void scraphere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005419{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005420 REGISTER struct here *h;
5421
5422 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005423
5424 for (h = inhere; h != NULL; h = h->h_next) {
5425 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005426 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005427 }
5428 inhere = NULL;
5429}
5430
5431/* unlink here temp files before a freearea(area) */
Eric Andersen8401eea2004-08-04 19:16:54 +00005432static void freehere(area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005433int area;
5434{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005435 REGISTER struct here *h, *hl;
5436
5437 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005438
5439 hl = NULL;
5440 for (h = acthere; h != NULL; h = h->h_next)
5441 if (getarea((char *) h) >= area) {
5442 if (h->h_iop->io_name != NULL)
5443 unlink(h->h_iop->io_name);
5444 if (hl == NULL)
5445 acthere = h->h_next;
5446 else
5447 hl->h_next = h->h_next;
5448 } else
5449 hl = h;
5450}
5451
5452
5453
5454/*
5455 * Copyright (c) 1987,1997, Prentice Hall
5456 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005457 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005458 * Redistribution and use of the MINIX operating system in source and
5459 * binary forms, with or without modification, are permitted provided
5460 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005461 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005462 * Redistributions of source code must retain the above copyright
5463 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005464 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005465 * Redistributions in binary form must reproduce the above
5466 * copyright notice, this list of conditions and the following
5467 * disclaimer in the documentation and/or other materials provided
5468 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005469 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005470 * Neither the name of Prentice Hall nor the names of the software
5471 * authors or contributors may be used to endorse or promote
5472 * products derived from this software without specific prior
5473 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005474 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005475 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5476 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5477 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5478 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5479 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5480 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5481 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5482 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5483 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5484 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5485 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5486 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5487 *
5488 */