blob: 2fb0df739fd5cb3b3c918d8c076bff07f8894b23 [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 */
165char *T_CMD_NAMES[] = {
166 "PLACEHOLDER",
167 "TCOM",
168 "TPAREN",
169 "TPIPE",
170 "TLIST",
171 "TOR",
172 "TAND",
173 "TFOR",
174 "TDO",
175 "TCASE",
176 "TIF",
177 "TWHILE",
178 "TUNTIL",
179 "TELIF",
180 "TPAT",
181 "TBRACE",
182 "TASYNC",
183 "TDOT",
184};
185
Eric Andersenff9eee42001-06-29 04:57:14 +0000186
187/*
188 * actions determining the environment of a process
189 */
190#define BIT(i) (1<<(i))
Eric Andersen8401eea2004-08-04 19:16:54 +0000191#define FEXEC BIT(0) /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000192
Eric Andersen12de6cf2004-08-04 19:19:10 +0000193#if 0 /* Original value */
194#define AREASIZE (65000)
195#else
196#define AREASIZE (90000)
197#endif
198
Eric Andersenff9eee42001-06-29 04:57:14 +0000199/*
200 * flags to control evaluation of words
201 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000202#define DOSUB 1 /* interpret $, `, and quotes */
203#define DOBLANK 2 /* perform blank interpretation */
204#define DOGLOB 4 /* interpret [?* */
205#define DOKEY 8 /* move words with `=' to 2nd arg. list */
206#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000207
208#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
209
Eric Andersenff9eee42001-06-29 04:57:14 +0000210
Eric Andersen12de6cf2004-08-04 19:19:10 +0000211/* PROTOTYPES */
Eric Andersenff9eee42001-06-29 04:57:14 +0000212static int newfile(char *s);
213static char *findeq(char *cp);
214static char *cclass(char *p, int sub);
215static void initarea(void);
Matt Kraai2d91deb2001-08-01 17:21:35 +0000216extern int msh_main(int argc, char **argv);
Eric Andersenff9eee42001-06-29 04:57:14 +0000217
218
Eric Andersen8401eea2004-08-04 19:16:54 +0000219struct brkcon {
220 jmp_buf brkpt;
221 struct brkcon *nextlev;
222};
Eric Andersenff9eee42001-06-29 04:57:14 +0000223
Eric Andersen12de6cf2004-08-04 19:19:10 +0000224
Eric Andersenff9eee42001-06-29 04:57:14 +0000225/*
226 * redirection
227 */
228struct ioword {
Eric Andersen8401eea2004-08-04 19:16:54 +0000229 short io_unit; /* unit affected */
230 short io_flag; /* action (below) */
231 char *io_name; /* file name */
Eric Andersenff9eee42001-06-29 04:57:14 +0000232};
Eric Andersenff9eee42001-06-29 04:57:14 +0000233
Eric Andersen12de6cf2004-08-04 19:19:10 +0000234#define IOREAD 1 /* < */
235#define IOHERE 2 /* << (here file) */
236#define IOWRITE 4 /* > */
237#define IOCAT 8 /* >> */
238#define IOXHERE 16 /* ${}, ` in << */
239#define IODUP 32 /* >&digit */
240#define IOCLOSE 64 /* >&- */
Eric Andersenff9eee42001-06-29 04:57:14 +0000241
Eric Andersen8401eea2004-08-04 19:16:54 +0000242#define IODEFAULT (-1) /* token for default IO unit */
243
Eric Andersen12de6cf2004-08-04 19:19:10 +0000244
Eric Andersenff9eee42001-06-29 04:57:14 +0000245
246/*
247 * parsing & execution environment
248 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000249static struct env {
250 char *linep;
251 struct io *iobase;
252 struct io *iop;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000253 xint *errpt; /* void * */
Eric Andersen8401eea2004-08-04 19:16:54 +0000254 int iofd;
255 struct env *oenv;
Eric Andersenff9eee42001-06-29 04:57:14 +0000256} e;
257
258/*
259 * flags:
260 * -e: quit on error
261 * -k: look for name=value everywhere on command line
262 * -n: no execution
263 * -t: exit after reading and executing one command
264 * -v: echo as read
265 * -x: trace
266 * -u: unset variables net diagnostic
267 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000268static char *flag;
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Eric Andersen8401eea2004-08-04 19:16:54 +0000270static char *null; /* null value for variable */
271static int intr; /* interrupt pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000272
Eric Andersen8401eea2004-08-04 19:16:54 +0000273static char *trap[_NSIG + 1];
274static char ourtrap[_NSIG + 1];
275static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000276
Eric Andersen8401eea2004-08-04 19:16:54 +0000277static int heedint; /* heed interrupt signals */
Eric Andersenff9eee42001-06-29 04:57:14 +0000278
Eric Andersen8401eea2004-08-04 19:16:54 +0000279static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000280
Eric Andersen8401eea2004-08-04 19:16:54 +0000281static char line[LINELIM];
282static char *elinep;
Eric Andersenff9eee42001-06-29 04:57:14 +0000283
Eric Andersen12de6cf2004-08-04 19:19:10 +0000284
Eric Andersenff9eee42001-06-29 04:57:14 +0000285/*
286 * other functions
287 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000288static int (*inbuilt(char *s)) (struct op *);
Eric Andersen392947c2002-12-11 07:42:46 +0000289
Eric Andersen8401eea2004-08-04 19:16:54 +0000290static char *rexecve(char *c, char **v, char **envp);
291static char *space(int n);
292static char *strsave(char *s, int a);
293static char *evalstr(char *cp, int f);
294static char *putn(int n);
295static char *itoa(int n);
296static char *unquote(char *as);
297static struct var *lookup(char *n);
298static int rlookup(char *n);
299static struct wdblock *glob(char *cp, struct wdblock *wb);
300static int my_getc(int ec);
301static int subgetc(int ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000302static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000303static char **eval(char **ap, int f);
304static int setstatus(int s);
305static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000306
Eric Andersen8401eea2004-08-04 19:16:54 +0000307static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000308
Eric Andersen8401eea2004-08-04 19:16:54 +0000309static int newenv(int f);
310static void quitenv(void);
311static void err(char *s);
312static int anys(char *s1, char *s2);
313static int any(int c, char *s);
314static void next(int f);
315static void setdash(void);
316static void onecommand(void);
317static void runtrap(int i);
318static int gmatch(char *s, char *p);
Eric Andersenff9eee42001-06-29 04:57:14 +0000319
Eric Andersen12de6cf2004-08-04 19:19:10 +0000320
Eric Andersenff9eee42001-06-29 04:57:14 +0000321/*
322 * error handling
323 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000324static void leave(void); /* abort shell (or fail in subshell) */
325static void fail(void); /* fail but return to process next command */
326static void warn(char *s);
327static void sig(int i); /* default signal handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000328
329
330
331/* -------- area stuff -------- */
332
Eric Andersen12de6cf2004-08-04 19:19:10 +0000333#define REGSIZE sizeof(struct region)
334#define GROWBY (256)
335/* #define SHRINKBY (64) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000336#undef SHRINKBY
Eric Andersen12de6cf2004-08-04 19:19:10 +0000337#define FREE (32767)
338#define BUSY (0)
339#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000340
341
342struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000343 struct region *next;
344 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000345};
346
347
348
349/* -------- grammar stuff -------- */
350typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000351 char *cp;
352 char **wp;
353 int i;
354 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000355} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000356
Eric Andersenff9eee42001-06-29 04:57:14 +0000357#define WORD 256
358#define LOGAND 257
359#define LOGOR 258
360#define BREAK 259
Eric Andersen12de6cf2004-08-04 19:19:10 +0000361#define IF 260
Eric Andersenff9eee42001-06-29 04:57:14 +0000362#define THEN 261
363#define ELSE 262
364#define ELIF 263
Eric Andersen12de6cf2004-08-04 19:19:10 +0000365#define FI 264
Eric Andersenff9eee42001-06-29 04:57:14 +0000366#define CASE 265
367#define ESAC 266
Eric Andersen12de6cf2004-08-04 19:19:10 +0000368#define FOR 267
Eric Andersenff9eee42001-06-29 04:57:14 +0000369#define WHILE 268
370#define UNTIL 269
Eric Andersen12de6cf2004-08-04 19:19:10 +0000371#define DO 270
Eric Andersenff9eee42001-06-29 04:57:14 +0000372#define DONE 271
Eric Andersen12de6cf2004-08-04 19:19:10 +0000373#define IN 272
374/* Added for "." file expansion */
375#define DOT 273
376
Eric Andersenff9eee42001-06-29 04:57:14 +0000377#define YYERRCODE 300
378
379/* flags to yylex */
Eric Andersen8401eea2004-08-04 19:16:54 +0000380#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000381
382#define SYNTAXERR zzerr()
Eric Andersen12de6cf2004-08-04 19:19:10 +0000383
Eric Andersen8401eea2004-08-04 19:16:54 +0000384static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000385static struct op *andor(void);
386static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000387static int synio(int cf);
388static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000389static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000390static struct op *nested(int type, int mark);
391static struct op *command(int cf);
392static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000393static struct op *thenpart(void);
394static struct op *elsepart(void);
395static struct op *caselist(void);
396static struct op *casepart(void);
397static char **pattern(void);
398static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000399static struct op *list(struct op *t1, struct op *t2);
400static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000401static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000402static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000403static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000404static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000405static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000406static struct ioword *io(int u, int f, char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000407static void zzerr(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000408static void yyerror(char *s);
409static int yylex(int cf);
410static int collect(int c, int c1);
411static int dual(int c);
412static void diag(int ec);
413static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000414
415/* -------- var.h -------- */
416
Eric Andersen8401eea2004-08-04 19:16:54 +0000417struct var {
418 char *value;
419 char *name;
420 struct var *next;
421 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000422};
Eric Andersenff9eee42001-06-29 04:57:14 +0000423
Eric Andersen8401eea2004-08-04 19:16:54 +0000424#define COPYV 1 /* flag to setval, suggesting copy */
425#define RONLY 01 /* variable is read-only */
426#define EXPORT 02 /* variable is to be exported */
427#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000428
Eric Andersen8401eea2004-08-04 19:16:54 +0000429static int yyparse(void);
430static struct var *lookup(char *n);
431static void setval(struct var *vp, char *val);
432static void nameval(struct var *vp, char *val, char *name);
433static void export(struct var *vp);
434static void ronly(struct var *vp);
435static int isassign(char *s);
436static int checkname(char *cp);
437static int assign(char *s, int cf);
438static void putvlist(int f, int out);
439static int eqname(char *n1, char *n2);
440
441static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000442
Eric Andersen12de6cf2004-08-04 19:19:10 +0000443
Eric Andersenff9eee42001-06-29 04:57:14 +0000444/* -------- io.h -------- */
445/* io buffer */
446struct iobuf {
Eric Andersen8401eea2004-08-04 19:16:54 +0000447 unsigned id; /* buffer id */
448 char buf[512]; /* buffer */
449 char *bufp; /* pointer into buffer */
450 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000451};
452
453/* possible arguments to an IO function */
454struct ioarg {
Eric Andersen8401eea2004-08-04 19:16:54 +0000455 char *aword;
456 char **awordlist;
457 int afile; /* file descriptor */
458 unsigned afid; /* buffer id */
459 long afpos; /* file position */
460 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000461};
Eric Andersen8401eea2004-08-04 19:16:54 +0000462
Eric Andersenff9eee42001-06-29 04:57:14 +0000463//static struct ioarg ioargstack[NPUSH];
464#define AFID_NOBUF (~0)
465#define AFID_ID 0
466
467/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000468struct io {
469 int (*iofn) (struct ioarg *, struct io *);
470 struct ioarg *argp;
471 int peekc;
472 char prev; /* previous character read by readc() */
473 char nlcount; /* for `'s */
474 char xchar; /* for `'s */
475 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000476};
Eric Andersen8401eea2004-08-04 19:16:54 +0000477
478//static struct io iostack[NPUSH];
479#define XOTHER 0 /* none of the below */
480#define XDOLL 1 /* expanding ${} */
481#define XGRAVE 2 /* expanding `'s */
482#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000483
484/* in substitution */
485#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
486
Eric Andersen12de6cf2004-08-04 19:19:10 +0000487
Eric Andersenff9eee42001-06-29 04:57:14 +0000488/*
489 * input generators for IO structure
490 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000491static int nlchar(struct ioarg *ap);
492static int strchar(struct ioarg *ap);
493static int qstrchar(struct ioarg *ap);
494static int filechar(struct ioarg *ap);
495static int herechar(struct ioarg *ap);
496static int linechar(struct ioarg *ap);
497static int gravechar(struct ioarg *ap, struct io *iop);
498static int qgravechar(struct ioarg *ap, struct io *iop);
499static int dolchar(struct ioarg *ap);
500static int wdchar(struct ioarg *ap);
501static void scraphere(void);
502static void freehere(int area);
503static void gethere(void);
504static void markhere(char *s, struct ioword *iop);
505static int herein(char *hname, int xdoll);
506static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000507
Eric Andersen12de6cf2004-08-04 19:19:10 +0000508
Eric Andersenff9eee42001-06-29 04:57:14 +0000509/*
510 * IO functions
511 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000512static int eofc(void);
513static int readc(void);
514static void unget(int c);
515static void ioecho(int c);
516static void prs(char *s);
517static void prn(unsigned u);
518static void closef(int i);
519static void closeall(void);
Eric Andersenff9eee42001-06-29 04:57:14 +0000520
Eric Andersen12de6cf2004-08-04 19:19:10 +0000521
Eric Andersenff9eee42001-06-29 04:57:14 +0000522/*
523 * IO control
524 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000525static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
526static int remap(int fd);
527static int openpipe(int *pv);
528static void closepipe(int *pv);
529static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000530
Eric Andersenff9eee42001-06-29 04:57:14 +0000531#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
532#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
533
534/* -------- word.h -------- */
535
Eric Andersen8401eea2004-08-04 19:16:54 +0000536#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000537
Eric Andersen8401eea2004-08-04 19:16:54 +0000538struct wdblock {
539 short w_bsize;
540 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000541 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000542 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000543};
544
Eric Andersen8401eea2004-08-04 19:16:54 +0000545static struct wdblock *addword(char *wd, struct wdblock *wb);
546static struct wdblock *newword(int nw);
547static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000548
549/* -------- area.h -------- */
550
551/*
552 * storage allocation
553 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000554static char *getcell(unsigned nbytes);
555static void garbage(void);
556static void setarea(char *cp, int a);
557static int getarea(char *cp);
558static void freearea(int a);
559static void freecell(char *cp);
560static int areanum; /* current allocation area */
Eric Andersenff9eee42001-06-29 04:57:14 +0000561
Eric Andersen12de6cf2004-08-04 19:19:10 +0000562#define NEW(type) (type *)getcell(sizeof(type))
Eric Andersenff9eee42001-06-29 04:57:14 +0000563#define DELETE(obj) freecell((char *)obj)
564
565
566/* -------- misc stuff -------- */
567
Eric Andersen12de6cf2004-08-04 19:19:10 +0000568static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000569static int iosetup(struct ioword *iop, int pipein, int pipeout);
570static void echo(char **wp);
571static struct op **find1case(struct op *t, char *w);
572static struct op *findcase(struct op *t, char *w);
573static void brkset(struct brkcon *bc);
574static int dolabel(struct op *t);
575static int dohelp(struct op *t);
576static int dochdir(struct op *t);
577static int doshift(struct op *t);
578static int dologin(struct op *t);
579static int doumask(struct op *t);
580static int doexec(struct op *t);
581static int dodot(struct op *t);
582static int dowait(struct op *t);
583static int doread(struct op *t);
584static int doeval(struct op *t);
585static int dotrap(struct op *t);
586static int getsig(char *s);
587static void setsig(int n, sighandler_t f);
588static int getn(char *as);
589static int dobreak(struct op *t);
590static int docontinue(struct op *t);
591static int brkcontin(char *cp, int val);
592static int doexit(struct op *t);
593static int doexport(struct op *t);
594static int doreadonly(struct op *t);
595static void rdexp(char **wp, void (*f) (struct var *), int key);
596static void badid(char *s);
597static int doset(struct op *t);
598static void varput(char *s, int out);
599static int dotimes(struct op *t);
600static int expand(char *cp, struct wdblock **wbp, int f);
601static char *blank(int f);
602static int dollar(int quoted);
603static int grave(int quoted);
604static void globname(char *we, char *pp);
605static char *generate(char *start1, char *end1, char *middle, char *end);
606static int anyspcl(struct wdblock *wb);
607static int xstrcmp(char *p1, char *p2);
608static void glob0(char *a0, unsigned int a1, int a2,
609 int (*a3) (char *, char *));
610static void glob1(char *base, char *lim);
611static void glob2(char *i, char *j);
612static void glob3(char *i, char *j, char *k);
613static void readhere(char **name, char *s, int ec);
614static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
615static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000616
Eric Andersen8401eea2004-08-04 19:16:54 +0000617struct here {
618 char *h_tag;
619 int h_dosub;
620 struct ioword *h_iop;
621 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000622};
623
Eric Andersen8401eea2004-08-04 19:16:54 +0000624static char *signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000625 "Signal 0",
626 "Hangup",
Eric Andersen8401eea2004-08-04 19:16:54 +0000627 (char *) NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000628 "Quit",
629 "Illegal instruction",
630 "Trace/BPT trap",
631 "Abort",
632 "Bus error",
633 "Floating Point Exception",
634 "Killed",
635 "SIGUSR1",
636 "SIGSEGV",
637 "SIGUSR2",
Eric Andersen8401eea2004-08-04 19:16:54 +0000638 (char *) NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000639 "Alarm clock",
640 "Terminated",
641};
Eric Andersen8401eea2004-08-04 19:16:54 +0000642
Eric Andersenff9eee42001-06-29 04:57:14 +0000643#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
644
645struct res {
646 char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000647 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000648};
649static struct res restab[] = {
Eric Andersen8401eea2004-08-04 19:16:54 +0000650 {"for", FOR},
651 {"case", CASE},
652 {"esac", ESAC},
653 {"while", WHILE},
654 {"do", DO},
655 {"done", DONE},
656 {"if", IF},
657 {"in", IN},
658 {"then", THEN},
659 {"else", ELSE},
660 {"elif", ELIF},
661 {"until", UNTIL},
662 {"fi", FI},
Eric Andersen8401eea2004-08-04 19:16:54 +0000663 {";;", BREAK},
664 {"||", LOGOR},
665 {"&&", LOGAND},
666 {"{", '{'},
667 {"}", '}'},
Eric Andersen12de6cf2004-08-04 19:19:10 +0000668 {".", DOT},
Eric Andersen8401eea2004-08-04 19:16:54 +0000669 {0, 0},
Eric Andersenff9eee42001-06-29 04:57:14 +0000670};
671
672
Eric Andersen1c039232001-07-07 00:05:55 +0000673struct builtincmd {
674 const char *name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000675 int (*builtinfunc) (struct op * t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000676};
Eric Andersen8401eea2004-08-04 19:16:54 +0000677static const struct builtincmd builtincmds[] = {
678 {".", dodot},
679 {":", dolabel},
680 {"break", dobreak},
681 {"cd", dochdir},
682 {"continue", docontinue},
683 {"eval", doeval},
684 {"exec", doexec},
685 {"exit", doexit},
686 {"export", doexport},
687 {"help", dohelp},
688 {"login", dologin},
689 {"newgrp", dologin},
690 {"read", doread},
691 {"readonly", doreadonly},
692 {"set", doset},
693 {"shift", doshift},
694 {"times", dotimes},
695 {"trap", dotrap},
696 {"umask", doumask},
697 {"wait", dowait},
698 {0, 0}
Eric Andersenff9eee42001-06-29 04:57:14 +0000699};
700
Eric Andersen12de6cf2004-08-04 19:19:10 +0000701struct op *scantree(struct op *);
702static struct op *dowholefile(int, int);
703
Eric Andersenff9eee42001-06-29 04:57:14 +0000704/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000705extern char **environ; /* environment pointer */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000706
Eric Andersen8401eea2004-08-04 19:16:54 +0000707static char **dolv;
708static int dolc;
709static int exstat;
710static char gflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000711static int interactive = 0; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000712static int execflg;
713static int multiline; /* \n changed to ; */
714static struct op *outtree; /* result from parser */
715static xint *failpt;
716static xint *errpt;
717static struct brkcon *brklist;
718static int isbreak;
719static struct wdblock *wdlist;
720static struct wdblock *iolist;
721static char *trap[_NSIG + 1];
722static char ourtrap[_NSIG + 1];
723static int trapset; /* trap pending */
724static int yynerrs; /* yacc */
725static char line[LINELIM];
Eric Andersen12de6cf2004-08-04 19:19:10 +0000726
727#ifdef MSHDEBUG
728static struct var *mshdbg_var;
729#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000730static struct var *vlist; /* dictionary */
731static struct var *homedir; /* home directory */
732static struct var *prompt; /* main prompt */
733static struct var *cprompt; /* continuation prompt */
734static struct var *path; /* search path for commands */
735static struct var *shell; /* shell to interpret command files */
736static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000737
Eric Andersen8401eea2004-08-04 19:16:54 +0000738static int areanum; /* current allocation area */
739static int intr;
740static int inparse;
741static char flags['z' - 'a' + 1];
742static char *flag = flags - 'a';
Eric Andersen8401eea2004-08-04 19:16:54 +0000743static char *null = "";
744static int heedint = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +0000745static void (*qflag) (int) = SIG_IGN;
746static int startl;
747static int peeksym;
748static int nlseen;
749static int iounit = IODEFAULT;
750static YYSTYPE yylval;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000751static char *elinep = line + sizeof(line) - 5;
752
753static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
754static struct ioarg ioargstack[NPUSH];
755static struct io iostack[NPUSH];
Eric Andersen8401eea2004-08-04 19:16:54 +0000756static struct iobuf sharedbuf = { AFID_NOBUF };
757static struct iobuf mainbuf = { AFID_NOBUF };
Eric Andersenff9eee42001-06-29 04:57:14 +0000758static unsigned bufid = AFID_ID; /* buffer id counter */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000759
Eric Andersen8401eea2004-08-04 19:16:54 +0000760static struct here *inhere; /* list of hear docs while parsing */
761static struct here *acthere; /* list of active here documents */
762static struct region *areabot; /* bottom of area */
763static struct region *areatop; /* top of area */
764static struct region *areanxt; /* starting point of scan */
765static void *brktop;
766static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000767
Eric Andersen12de6cf2004-08-04 19:19:10 +0000768static struct env e = {
769 line, /* linep: char ptr */
770 iostack, /* iobase: struct io ptr */
771 iostack - 1, /* iop: struct io ptr */
772 (xint *) NULL, /* errpt: void ptr for errors? */
773 FDBASE, /* iofd: file desc */
774 (struct env *) NULL /* oenv: struct env ptr */
775};
776
777#ifdef MSHDEBUG
778void print_t(struct op *t)
779{
780 DBGPRINTF(("T: t=0x%x, type %s, words=0x%x, IOword=0x%x\n", t,
781 T_CMD_NAMES[t->type], t->words, t->ioact));
782
783 if (t->words) {
784 DBGPRINTF(("T: W1: %s", t->words[0]));
785 }
786
787 return;
788}
789
790void print_tree(struct op *head)
791{
792 if (head == NULL) {
793 DBGPRINTF(("PRINT_TREE: no tree\n"));
794 return;
795 }
796
797 DBGPRINTF(("NODE: 0x%x, left 0x%x, right 0x%x\n", head, head->left,
798 head->right));
799
800 if (head->left)
801 print_tree(head->left);
802
803 if (head->right)
804 print_tree(head->right);
805
806 return;
807}
808#endif /* MSHDEBUG */
809
Eric Andersenff9eee42001-06-29 04:57:14 +0000810
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000811#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000812static char *current_prompt;
Eric Andersenff9eee42001-06-29 04:57:14 +0000813#endif
814
Eric Andersenff9eee42001-06-29 04:57:14 +0000815/* -------- sh.c -------- */
816/*
817 * shell
818 */
819
820
Matt Kraai2d91deb2001-08-01 17:21:35 +0000821extern int msh_main(int argc, char **argv)
Eric Andersenff9eee42001-06-29 04:57:14 +0000822{
Eric Andersen12de6cf2004-08-04 19:19:10 +0000823 REGISTER int f;
824 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +0000825 int cflag;
826 char *name, **ap;
Eric Andersen8401eea2004-08-04 19:16:54 +0000827 int (*iof) (struct ioarg *);
Eric Andersenff9eee42001-06-29 04:57:14 +0000828
Eric Andersen12de6cf2004-08-04 19:19:10 +0000829 DBGPRINTF(("MSH_MAIN: argc %d, environ 0x%x\n", argc, environ));
830
Eric Andersenff9eee42001-06-29 04:57:14 +0000831 initarea();
832 if ((ap = environ) != NULL) {
833 while (*ap)
834 assign(*ap++, !COPYV);
835 for (ap = environ; *ap;)
836 export(lookup(*ap++));
837 }
838 closeall();
839 areanum = 1;
840
841 shell = lookup("SHELL");
842 if (shell->value == null)
Eric Andersen78500142004-08-27 19:55:28 +0000843 setval(shell, (char *)DEFAULT_SHELL);
Eric Andersenff9eee42001-06-29 04:57:14 +0000844 export(shell);
845
846 homedir = lookup("HOME");
847 if (homedir->value == null)
848 setval(homedir, "/");
849 export(homedir);
850
Eric Andersen737f5fb2003-03-14 16:05:59 +0000851 setval(lookup("$"), putn(getpid()));
Eric Andersenff9eee42001-06-29 04:57:14 +0000852
853 path = lookup("PATH");
Eric Andersen737f5fb2003-03-14 16:05:59 +0000854 if (path->value == null) {
855 if (geteuid() == 0)
856 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
857 else
858 setval(path, "/bin:/usr/bin");
859 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000860 export(path);
861
862 ifs = lookup("IFS");
863 if (ifs->value == null)
864 setval(ifs, " \t\n");
865
Eric Andersen12de6cf2004-08-04 19:19:10 +0000866#ifdef MSHDEBUG
867 mshdbg_var = lookup("MSHDEBUG");
868 if (mshdbg_var->value == null)
869 setval(mshdbg_var, "0");
870#endif
871
872
Eric Andersenff9eee42001-06-29 04:57:14 +0000873 prompt = lookup("PS1");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000874#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000875 if (prompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000876#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000877 setval(prompt, "$ ");
878 if (geteuid() == 0) {
879 setval(prompt, "# ");
880 prompt->status &= ~EXPORT;
881 }
882 cprompt = lookup("PS2");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000883#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000884 if (cprompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000885#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000886 setval(cprompt, "> ");
887
888 iof = filechar;
889 cflag = 0;
890 name = *argv++;
891 if (--argc >= 1) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000892 if (argv[0][0] == '-' && argv[0][1] != '\0') {
893 for (s = argv[0] + 1; *s; s++)
Eric Andersenff9eee42001-06-29 04:57:14 +0000894 switch (*s) {
895 case 'c':
896 prompt->status &= ~EXPORT;
897 cprompt->status &= ~EXPORT;
898 setval(prompt, "");
899 setval(cprompt, "");
900 cflag = 1;
901 if (--argc > 0)
902 PUSHIO(aword, *++argv, iof = nlchar);
903 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000904
Eric Andersenff9eee42001-06-29 04:57:14 +0000905 case 'q':
906 qflag = SIG_DFL;
907 break;
908
909 case 's':
910 /* standard input */
911 break;
912
913 case 't':
914 prompt->status &= ~EXPORT;
915 setval(prompt, "");
916 iof = linechar;
917 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000918
Eric Andersenff9eee42001-06-29 04:57:14 +0000919 case 'i':
920 interactive++;
921 default:
Eric Andersen8401eea2004-08-04 19:16:54 +0000922 if (*s >= 'a' && *s <= 'z')
923 flag[(int) *s]++;
Eric Andersenff9eee42001-06-29 04:57:14 +0000924 }
925 } else {
926 argv--;
927 argc++;
928 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000929
Eric Andersenff9eee42001-06-29 04:57:14 +0000930 if (iof == filechar && --argc > 0) {
931 setval(prompt, "");
932 setval(cprompt, "");
933 prompt->status &= ~EXPORT;
934 cprompt->status &= ~EXPORT;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000935
936/* Shell is non-interactive, activate printf-based debug */
937#ifdef MSHDEBUG
938 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
939 if (mshdbg < 0)
940 mshdbg = 0;
941#endif
942 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
943
Eric Andersenff9eee42001-06-29 04:57:14 +0000944 if (newfile(name = *++argv))
Eric Andersen12de6cf2004-08-04 19:19:10 +0000945 exit(1); /* Exit on error */
Eric Andersenff9eee42001-06-29 04:57:14 +0000946 }
947 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000948
Eric Andersenff9eee42001-06-29 04:57:14 +0000949 setdash();
Eric Andersen12de6cf2004-08-04 19:19:10 +0000950
951 /* This won't be true if PUSHIO has been called, say from newfile() above */
Eric Andersenff9eee42001-06-29 04:57:14 +0000952 if (e.iop < iostack) {
953 PUSHIO(afile, 0, iof);
Eric Andersen1c039232001-07-07 00:05:55 +0000954 if (isatty(0) && isatty(1) && !cflag) {
Eric Andersenff9eee42001-06-29 04:57:14 +0000955 interactive++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000956#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen12de6cf2004-08-04 19:19:10 +0000957#ifdef MSHDEBUG
958 printf("\n\n" BB_BANNER " Built-in shell (msh with debug)\n");
959#else
Eric Andersen8401eea2004-08-04 19:16:54 +0000960 printf("\n\n" BB_BANNER " Built-in shell (msh)\n");
Eric Andersen12de6cf2004-08-04 19:19:10 +0000961#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000962 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +0000963#endif
Eric Andersen1c039232001-07-07 00:05:55 +0000964 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000965 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000966
Eric Andersenff9eee42001-06-29 04:57:14 +0000967 signal(SIGQUIT, qflag);
968 if (name && name[0] == '-') {
969 interactive++;
970 if ((f = open(".profile", 0)) >= 0)
971 next(remap(f));
972 if ((f = open("/etc/profile", 0)) >= 0)
973 next(remap(f));
974 }
975 if (interactive)
976 signal(SIGTERM, sig);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000977
Eric Andersenff9eee42001-06-29 04:57:14 +0000978 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
979 signal(SIGINT, onintr);
980 dolv = argv;
981 dolc = argc;
982 dolv[0] = name;
983 if (dolc > 1) {
984 for (ap = ++argv; --argc > 0;) {
985 if (assign(*ap = *argv++, !COPYV)) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000986 dolc--; /* keyword */
Eric Andersenff9eee42001-06-29 04:57:14 +0000987 } else {
988 ap++;
989 }
990 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000991 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000992 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
993
Eric Andersen12de6cf2004-08-04 19:19:10 +0000994 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop 0x%x, iostack 0x%x\n", interactive, e.iop, iostack));
995
Eric Andersenff9eee42001-06-29 04:57:14 +0000996 for (;;) {
997 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000998#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000999 current_prompt = prompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00001000#else
1001 prs(prompt->value);
1002#endif
1003 }
1004 onecommand();
Eric Andersen1c315012002-04-26 23:40:09 +00001005 /* Ensure that getenv("PATH") stays current */
1006 setenv("PATH", path->value, 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001007 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001008
1009 DBGPRINTF(("MSH_MAIN: returning.\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001010}
1011
Eric Andersen8401eea2004-08-04 19:16:54 +00001012static void setdash()
Eric Andersenff9eee42001-06-29 04:57:14 +00001013{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001014 REGISTER char *cp;
1015 REGISTER int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001016 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001017
1018 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001019 for (c = 'a'; c <= 'z'; c++)
1020 if (flag[(int) c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001021 *cp++ = c;
1022 *cp = 0;
1023 setval(lookup("-"), m);
1024}
1025
Eric Andersen8401eea2004-08-04 19:16:54 +00001026static int newfile(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001027REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001028{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001029 REGISTER int f;
1030
1031 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001032
1033 if (strcmp(s, "-") != 0) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001034 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001035 f = open(s, 0);
1036 if (f < 0) {
1037 prs(s);
1038 err(": cannot open");
Eric Andersen8401eea2004-08-04 19:16:54 +00001039 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001040 }
1041 } else
1042 f = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001043
Eric Andersenff9eee42001-06-29 04:57:14 +00001044 next(remap(f));
Eric Andersen8401eea2004-08-04 19:16:54 +00001045 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001046}
1047
Eric Andersen12de6cf2004-08-04 19:19:10 +00001048
Eric Andersen12de6cf2004-08-04 19:19:10 +00001049struct op *scantree(head)
1050struct op *head;
1051{
1052 struct op *dotnode;
1053
1054 if (head == NULL)
1055 return (NULL);
1056
1057 if (head->left != NULL) {
1058 dotnode = scantree(head->left);
1059 if (dotnode)
1060 return (dotnode);
1061 }
1062
1063 if (head->right != NULL) {
1064 dotnode = scantree(head->right);
1065 if (dotnode)
1066 return (dotnode);
1067 }
1068
1069 if (head->words == NULL)
1070 return (NULL);
1071
1072 DBGPRINTF5(("SCANTREE: checking node 0x%x\n", head));
1073
1074 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
1075 DBGPRINTF5(("SCANTREE: dot found in node 0x%x\n", head));
1076 return (head);
1077 }
1078
1079 return (NULL);
1080}
1081
1082
Eric Andersen8401eea2004-08-04 19:16:54 +00001083static void onecommand()
Eric Andersenff9eee42001-06-29 04:57:14 +00001084{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001085 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001086 jmp_buf m1;
1087
Eric Andersen12de6cf2004-08-04 19:19:10 +00001088 DBGPRINTF(("ONECOMMAND: enter, outtree=0x%x\n", outtree));
1089
Eric Andersenff9eee42001-06-29 04:57:14 +00001090 while (e.oenv)
1091 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001092
Eric Andersenff9eee42001-06-29 04:57:14 +00001093 areanum = 1;
1094 freehere(areanum);
1095 freearea(areanum);
1096 garbage();
1097 wdlist = 0;
1098 iolist = 0;
1099 e.errpt = 0;
1100 e.linep = line;
1101 yynerrs = 0;
1102 multiline = 0;
1103 inparse = 1;
1104 intr = 0;
1105 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001106
Eric Andersen8401eea2004-08-04 19:16:54 +00001107 setjmp(failpt = m1); /* Bruce Evans' fix */
Eric Andersenff9eee42001-06-29 04:57:14 +00001108 if (setjmp(failpt = m1) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001109
1110 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1111
Eric Andersenff9eee42001-06-29 04:57:14 +00001112 while (e.oenv)
1113 quitenv();
1114 scraphere();
1115 if (!interactive && intr)
1116 leave();
1117 inparse = 0;
1118 intr = 0;
1119 return;
1120 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001121
Eric Andersenff9eee42001-06-29 04:57:14 +00001122 inparse = 0;
1123 brklist = 0;
1124 intr = 0;
1125 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001126
1127 if (!flag['n']) {
1128 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=0x%x\n",
1129 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001130 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001131 }
1132
Eric Andersenff9eee42001-06-29 04:57:14 +00001133 if (!interactive && intr) {
1134 execflg = 0;
1135 leave();
1136 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001137
Eric Andersenff9eee42001-06-29 04:57:14 +00001138 if ((i = trapset) != 0) {
1139 trapset = 0;
1140 runtrap(i);
1141 }
1142}
1143
Eric Andersen8401eea2004-08-04 19:16:54 +00001144static void fail()
Eric Andersenff9eee42001-06-29 04:57:14 +00001145{
1146 longjmp(failpt, 1);
1147 /* NOTREACHED */
1148}
1149
Eric Andersen8401eea2004-08-04 19:16:54 +00001150static void leave()
Eric Andersenff9eee42001-06-29 04:57:14 +00001151{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001152 DBGPRINTF(("LEAVE: leave called!\n"));
1153
Eric Andersenff9eee42001-06-29 04:57:14 +00001154 if (execflg)
1155 fail();
1156 scraphere();
1157 freehere(1);
1158 runtrap(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001159 _exit(exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00001160 /* NOTREACHED */
1161}
1162
Eric Andersen8401eea2004-08-04 19:16:54 +00001163static void warn(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001164REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001165{
Eric Andersen8401eea2004-08-04 19:16:54 +00001166 if (*s) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001167 prs(s);
1168 exstat = -1;
1169 }
1170 prs("\n");
1171 if (flag['e'])
1172 leave();
1173}
1174
Eric Andersen8401eea2004-08-04 19:16:54 +00001175static void err(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001176char *s;
1177{
1178 warn(s);
1179 if (flag['n'])
1180 return;
1181 if (!interactive)
1182 leave();
1183 if (e.errpt)
1184 longjmp(e.errpt, 1);
1185 closeall();
1186 e.iop = e.iobase = iostack;
1187}
1188
Eric Andersen8401eea2004-08-04 19:16:54 +00001189static int newenv(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001190int f;
1191{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001192 REGISTER struct env *ep;
1193
1194 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001195
1196 if (f) {
1197 quitenv();
Eric Andersen8401eea2004-08-04 19:16:54 +00001198 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001199 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001200
Eric Andersenff9eee42001-06-29 04:57:14 +00001201 ep = (struct env *) space(sizeof(*ep));
1202 if (ep == NULL) {
1203 while (e.oenv)
1204 quitenv();
1205 fail();
1206 }
1207 *ep = e;
1208 e.oenv = ep;
1209 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001210
Eric Andersen8401eea2004-08-04 19:16:54 +00001211 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001212}
1213
Eric Andersen8401eea2004-08-04 19:16:54 +00001214static void quitenv()
Eric Andersenff9eee42001-06-29 04:57:14 +00001215{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001216 REGISTER struct env *ep;
1217 REGISTER int fd;
1218
1219 DBGPRINTF(("QUITENV: e.oenv=0x%x\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001220
1221 if ((ep = e.oenv) != NULL) {
1222 fd = e.iofd;
1223 e = *ep;
1224 /* should close `'d files */
1225 DELETE(ep);
1226 while (--fd >= e.iofd)
1227 close(fd);
1228 }
1229}
1230
1231/*
1232 * Is any character from s1 in s2?
1233 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001234static int anys(s1, s2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001235REGISTER char *s1, *s2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001236{
1237 while (*s1)
1238 if (any(*s1++, s2))
Eric Andersen8401eea2004-08-04 19:16:54 +00001239 return (1);
1240 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001241}
1242
1243/*
1244 * Is character c in s?
1245 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001246static int any(c, s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001247REGISTER int c;
1248REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001249{
1250 while (*s)
1251 if (*s++ == c)
Eric Andersen8401eea2004-08-04 19:16:54 +00001252 return (1);
1253 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001254}
1255
Eric Andersen8401eea2004-08-04 19:16:54 +00001256static char *putn(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001257REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001258{
Eric Andersen8401eea2004-08-04 19:16:54 +00001259 return (itoa(n));
Eric Andersenff9eee42001-06-29 04:57:14 +00001260}
1261
Eric Andersen8401eea2004-08-04 19:16:54 +00001262static char *itoa(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001263REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001264{
Eric Andersenff9eee42001-06-29 04:57:14 +00001265 static char s[20];
Eric Andersen8401eea2004-08-04 19:16:54 +00001266
Eric Andersen737f5fb2003-03-14 16:05:59 +00001267 snprintf(s, sizeof(s), "%u", n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001268 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001269}
1270
Eric Andersen12de6cf2004-08-04 19:19:10 +00001271
Eric Andersen8401eea2004-08-04 19:16:54 +00001272static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001273{
1274 PUSHIO(afile, f, filechar);
1275}
1276
Eric Andersen8401eea2004-08-04 19:16:54 +00001277static void onintr(s)
1278int s; /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001279{
1280 signal(SIGINT, onintr);
1281 intr = 1;
1282 if (interactive) {
1283 if (inparse) {
1284 prs("\n");
1285 fail();
1286 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001287 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001288 execflg = 0;
1289 leave();
1290 }
1291}
1292
Eric Andersen8401eea2004-08-04 19:16:54 +00001293static char *space(n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001294int n;
1295{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001296 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001297
1298 if ((cp = getcell(n)) == 0)
1299 err("out of string space");
Eric Andersen8401eea2004-08-04 19:16:54 +00001300 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001301}
1302
Eric Andersen8401eea2004-08-04 19:16:54 +00001303static char *strsave(s, a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001304REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001305int a;
1306{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001307 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001308
Eric Andersen8401eea2004-08-04 19:16:54 +00001309 if ((cp = space(strlen(s) + 1)) != NULL) {
1310 setarea((char *) cp, a);
1311 for (xp = cp; (*xp++ = *s++) != '\0';);
1312 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001313 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001314 return ("");
Eric Andersenff9eee42001-06-29 04:57:14 +00001315}
1316
1317/*
1318 * trap handling
1319 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001320static void sig(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001322{
1323 trapset = i;
1324 signal(i, sig);
1325}
1326
1327static void runtrap(i)
1328int i;
1329{
1330 char *trapstr;
1331
1332 if ((trapstr = trap[i]) == NULL)
1333 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001334
Eric Andersenff9eee42001-06-29 04:57:14 +00001335 if (i == 0)
1336 trap[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001337
Eric Andersenff9eee42001-06-29 04:57:14 +00001338 RUN(aword, trapstr, nlchar);
1339}
1340
1341/* -------- var.c -------- */
1342
1343/*
1344 * Find the given name in the dictionary
1345 * and return its value. If the name was
1346 * not previously there, enter it now and
1347 * return a null value.
1348 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001349static struct var *lookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001350REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001351{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352 REGISTER struct var *vp;
1353 REGISTER char *cp;
1354 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001355 static struct var dummy;
1356
1357 if (isdigit(*n)) {
1358 dummy.name = n;
1359 for (c = 0; isdigit(*n) && c < 1000; n++)
Eric Andersen8401eea2004-08-04 19:16:54 +00001360 c = c * 10 + *n - '0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001361 dummy.status = RONLY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001362 dummy.value = c <= dolc ? dolv[c] : null;
1363 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001364 }
1365 for (vp = vlist; vp; vp = vp->next)
1366 if (eqname(vp->name, n))
Eric Andersen8401eea2004-08-04 19:16:54 +00001367 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001368 cp = findeq(n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001369 vp = (struct var *) space(sizeof(*vp));
1370 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001371 dummy.name = dummy.value = "";
Eric Andersen8401eea2004-08-04 19:16:54 +00001372 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001373 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001374 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001375 if (*cp == 0)
1376 *cp = '=';
1377 *++cp = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00001378 setarea((char *) vp, 0);
1379 setarea((char *) vp->name, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001380 vp->value = null;
1381 vp->next = vlist;
1382 vp->status = GETCELL;
1383 vlist = vp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001384 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001385}
1386
1387/*
1388 * give variable at `vp' the value `val'.
1389 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001390static void setval(vp, val)
Eric Andersenff9eee42001-06-29 04:57:14 +00001391struct var *vp;
1392char *val;
1393{
Eric Andersen8401eea2004-08-04 19:16:54 +00001394 nameval(vp, val, (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001395}
1396
1397/*
1398 * if name is not NULL, it must be
1399 * a prefix of the space `val',
1400 * and end with `='.
1401 * this is all so that exporting
1402 * values is reasonably painless.
1403 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001404static void nameval(vp, val, name)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001405REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001406char *val, *name;
1407{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001408 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001409 char *nv;
1410 int fl;
1411
1412 if (vp->status & RONLY) {
1413 for (xp = vp->name; *xp && *xp != '=';)
1414 putc(*xp++, stderr);
1415 err(" is read-only");
1416 return;
1417 }
1418 fl = 0;
1419 if (name == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001420 xp = space(strlen(vp->name) + strlen(val) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00001421 if (xp == 0)
1422 return;
1423 /* make string: name=value */
Eric Andersen8401eea2004-08-04 19:16:54 +00001424 setarea((char *) xp, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001425 name = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001426 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001427 if (*xp++ == 0)
1428 xp[-1] = '=';
1429 nv = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001430 for (cp = val; (*xp++ = *cp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00001431 val = nv;
1432 fl = GETCELL;
1433 }
1434 if (vp->status & GETCELL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001435 freecell(vp->name); /* form new string `name=value' */
Eric Andersenff9eee42001-06-29 04:57:14 +00001436 vp->name = name;
1437 vp->value = val;
1438 vp->status |= fl;
1439}
1440
Eric Andersen8401eea2004-08-04 19:16:54 +00001441static void export(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001442struct var *vp;
1443{
1444 vp->status |= EXPORT;
1445}
1446
Eric Andersen8401eea2004-08-04 19:16:54 +00001447static void ronly(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001448struct var *vp;
1449{
Matt Kraai69edfec2001-08-06 14:14:18 +00001450 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
Eric Andersenff9eee42001-06-29 04:57:14 +00001451 vp->status |= RONLY;
1452}
1453
Eric Andersen8401eea2004-08-04 19:16:54 +00001454static int isassign(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001455REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001456{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001457 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1458
Eric Andersen8401eea2004-08-04 19:16:54 +00001459 if (!isalpha((int) *s) && *s != '_')
1460 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001461 for (; *s != '='; s++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001462 if (*s == 0 || (!isalnum(*s) && *s != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001463 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001464
Eric Andersen8401eea2004-08-04 19:16:54 +00001465 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001466}
1467
Eric Andersen8401eea2004-08-04 19:16:54 +00001468static int assign(s, cf)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001469REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001470int cf;
1471{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001472 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001473 struct var *vp;
1474
Eric Andersen12de6cf2004-08-04 19:19:10 +00001475 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1476
Matt Kraai69edfec2001-08-06 14:14:18 +00001477 if (!isalpha(*s) && *s != '_')
Eric Andersen8401eea2004-08-04 19:16:54 +00001478 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001479 for (cp = s; *cp != '='; cp++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001480 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001481 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001482 vp = lookup(s);
Eric Andersen8401eea2004-08-04 19:16:54 +00001483 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001484 if (cf != COPYV)
1485 vp->status &= ~GETCELL;
Eric Andersen8401eea2004-08-04 19:16:54 +00001486 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001487}
1488
Eric Andersen8401eea2004-08-04 19:16:54 +00001489static int checkname(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001490REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001491{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001492 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1493
Eric Andersen8401eea2004-08-04 19:16:54 +00001494 if (!isalpha(*cp++) && *(cp - 1) != '_')
1495 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001496 while (*cp)
Eric Andersen8401eea2004-08-04 19:16:54 +00001497 if (!isalnum(*cp++) && *(cp - 1) != '_')
1498 return (0);
1499 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001500}
1501
Eric Andersen8401eea2004-08-04 19:16:54 +00001502static void putvlist(f, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001503REGISTER int f, out;
Eric Andersenff9eee42001-06-29 04:57:14 +00001504{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001505 REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001506
1507 for (vp = vlist; vp; vp = vp->next)
Matt Kraai69edfec2001-08-06 14:14:18 +00001508 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001509 if (vp->status & EXPORT)
1510 write(out, "export ", 7);
1511 if (vp->status & RONLY)
1512 write(out, "readonly ", 9);
Eric Andersen8401eea2004-08-04 19:16:54 +00001513 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
Eric Andersenff9eee42001-06-29 04:57:14 +00001514 write(out, "\n", 1);
1515 }
1516}
1517
Eric Andersen8401eea2004-08-04 19:16:54 +00001518static int eqname(n1, n2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001519REGISTER char *n1, *n2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001520{
1521 for (; *n1 != '=' && *n1 != 0; n1++)
1522 if (*n2++ != *n1)
Eric Andersen8401eea2004-08-04 19:16:54 +00001523 return (0);
1524 return (*n2 == 0 || *n2 == '=');
Eric Andersenff9eee42001-06-29 04:57:14 +00001525}
1526
Eric Andersen8401eea2004-08-04 19:16:54 +00001527static char *findeq(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001528REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001529{
1530 while (*cp != '\0' && *cp != '=')
1531 cp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00001532 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001533}
1534
1535/* -------- gmatch.c -------- */
1536/*
1537 * int gmatch(string, pattern)
1538 * char *string, *pattern;
1539 *
1540 * Match a pattern as in sh(1).
1541 */
1542
1543#define CMASK 0377
1544#define QUOTE 0200
1545#define QMASK (CMASK&~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001546#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001547
Eric Andersen8401eea2004-08-04 19:16:54 +00001548static int gmatch(s, p)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001549REGISTER char *s, *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001550{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001551 REGISTER int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001552
1553 if (s == NULL || p == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001554 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001555 while ((pc = *p++ & CMASK) != '\0') {
1556 sc = *s++ & QMASK;
1557 switch (pc) {
1558 case '[':
1559 if ((p = cclass(p, sc)) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001560 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001561 break;
1562
1563 case '?':
1564 if (sc == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00001565 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001566 break;
1567
1568 case '*':
1569 s--;
1570 do {
1571 if (*p == '\0' || gmatch(s, p))
Eric Andersen8401eea2004-08-04 19:16:54 +00001572 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001573 } while (*s++ != '\0');
Eric Andersen8401eea2004-08-04 19:16:54 +00001574 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001575
1576 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001577 if (sc != (pc & ~QUOTE))
1578 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001579 }
1580 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001581 return (*s == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001582}
1583
Eric Andersen8401eea2004-08-04 19:16:54 +00001584static char *cclass(p, sub)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001585REGISTER char *p;
1586REGISTER int sub;
Eric Andersenff9eee42001-06-29 04:57:14 +00001587{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001588 REGISTER int c, d, not, found;
Eric Andersenff9eee42001-06-29 04:57:14 +00001589
1590 if ((not = *p == NOT) != 0)
1591 p++;
1592 found = not;
1593 do {
1594 if (*p == '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00001595 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001596 c = *p & CMASK;
1597 if (p[1] == '-' && p[2] != ']') {
1598 d = p[2] & CMASK;
1599 p++;
1600 } else
1601 d = c;
1602 if (c == sub || (c <= sub && sub <= d))
1603 found = !not;
1604 } while (*++p != ']');
Eric Andersen8401eea2004-08-04 19:16:54 +00001605 return (found ? p + 1 : (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001606}
1607
1608
1609/* -------- area.c -------- */
1610
1611/*
1612 * All memory between (char *)areabot and (char *)(areatop+1) is
1613 * exclusively administered by the area management routines.
1614 * It is assumed that sbrk() and brk() manipulate the high end.
1615 */
1616
1617#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1618
Eric Andersen8401eea2004-08-04 19:16:54 +00001619static void initarea()
Eric Andersenff9eee42001-06-29 04:57:14 +00001620{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001621 brkaddr = malloc(AREASIZE);
1622 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001623
Eric Andersen8401eea2004-08-04 19:16:54 +00001624 while ((int) sbrk(0) & ALIGN)
Eric Andersenff9eee42001-06-29 04:57:14 +00001625 sbrk(1);
Eric Andersen8401eea2004-08-04 19:16:54 +00001626 areabot = (struct region *) sbrk(REGSIZE);
Eric Andersenff9eee42001-06-29 04:57:14 +00001627
1628 areabot->next = areabot;
1629 areabot->area = BUSY;
1630 areatop = areabot;
1631 areanxt = areabot;
1632}
1633
Eric Andersen8401eea2004-08-04 19:16:54 +00001634char *getcell(nbytes)
Eric Andersenff9eee42001-06-29 04:57:14 +00001635unsigned nbytes;
1636{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001637 REGISTER int nregio;
1638 REGISTER struct region *p, *q;
1639 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001640
1641 if (nbytes == 0) {
1642 puts("getcell(0)");
1643 abort();
Eric Andersen8401eea2004-08-04 19:16:54 +00001644 }
1645 /* silly and defeats the algorithm */
Eric Andersenff9eee42001-06-29 04:57:14 +00001646 /*
1647 * round upwards and add administration area
1648 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001649 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001650 for (p = areanxt;;) {
1651 if (p->area > areanum) {
1652 /*
1653 * merge free cells
1654 */
1655 while ((q = p->next)->area > areanum && q != areanxt)
1656 p->next = q->next;
1657 /*
1658 * exit loop if cell big enough
1659 */
1660 if (q >= p + nregio)
1661 goto found;
1662 }
1663 p = p->next;
1664 if (p == areanxt)
1665 break;
1666 }
1667 i = nregio >= GROWBY ? nregio : GROWBY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001668 p = (struct region *) sbrk(i * REGSIZE);
1669 if (p == (struct region *) -1)
1670 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001671 p--;
1672 if (p != areatop) {
1673 puts("not contig");
Eric Andersen8401eea2004-08-04 19:16:54 +00001674 abort(); /* allocated areas are contiguous */
Eric Andersenff9eee42001-06-29 04:57:14 +00001675 }
1676 q = p + i;
1677 p->next = q;
1678 p->area = FREE;
1679 q->next = areabot;
1680 q->area = BUSY;
1681 areatop = q;
Eric Andersen8401eea2004-08-04 19:16:54 +00001682 found:
Eric Andersenff9eee42001-06-29 04:57:14 +00001683 /*
1684 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1685 */
1686 areanxt = p + nregio;
1687 if (areanxt < q) {
1688 /*
1689 * split into requested area and rest
1690 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001691 if (areanxt + 1 > q) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001692 puts("OOM");
Eric Andersen8401eea2004-08-04 19:16:54 +00001693 abort(); /* insufficient space left for admin */
Eric Andersenff9eee42001-06-29 04:57:14 +00001694 }
1695 areanxt->next = q;
1696 areanxt->area = FREE;
1697 p->next = areanxt;
1698 }
1699 p->area = areanum;
Eric Andersen8401eea2004-08-04 19:16:54 +00001700 return ((char *) (p + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001701}
1702
Eric Andersen8401eea2004-08-04 19:16:54 +00001703static void freecell(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001704char *cp;
1705{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001707
Eric Andersen8401eea2004-08-04 19:16:54 +00001708 if ((p = (struct region *) cp) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001709 p--;
1710 if (p < areanxt)
1711 areanxt = p;
1712 p->area = FREE;
1713 }
1714}
1715
Eric Andersen8401eea2004-08-04 19:16:54 +00001716static void freearea(a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001717REGISTER int a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001718{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001719 REGISTER struct region *p, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001720
1721 top = areatop;
1722 for (p = areabot; p != top; p = p->next)
1723 if (p->area >= a)
1724 p->area = FREE;
1725}
1726
Eric Andersen8401eea2004-08-04 19:16:54 +00001727static void setarea(cp, a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001728char *cp;
1729int a;
1730{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001731 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001732
Eric Andersen8401eea2004-08-04 19:16:54 +00001733 if ((p = (struct region *) cp) != NULL)
1734 (p - 1)->area = a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001735}
1736
Eric Andersen8401eea2004-08-04 19:16:54 +00001737int getarea(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001738char *cp;
1739{
Eric Andersen8401eea2004-08-04 19:16:54 +00001740 return ((struct region *) cp - 1)->area;
Eric Andersenff9eee42001-06-29 04:57:14 +00001741}
1742
Eric Andersen8401eea2004-08-04 19:16:54 +00001743static void garbage()
Eric Andersenff9eee42001-06-29 04:57:14 +00001744{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001745 REGISTER struct region *p, *q, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001746
1747 top = areatop;
1748 for (p = areabot; p != top; p = p->next) {
1749 if (p->area > areanum) {
1750 while ((q = p->next)->area > areanum)
1751 p->next = q->next;
1752 areanxt = p;
1753 }
1754 }
1755#ifdef SHRINKBY
1756 if (areatop >= q + SHRINKBY && q->area > areanum) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001757 brk((char *) (q + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001758 q->next = areabot;
1759 q->area = BUSY;
1760 areatop = q;
1761 }
1762#endif
1763}
1764
1765/* -------- csyn.c -------- */
1766/*
1767 * shell: syntax (C version)
1768 */
1769
Eric Andersen8401eea2004-08-04 19:16:54 +00001770int yyparse()
Eric Andersenff9eee42001-06-29 04:57:14 +00001771{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001772 DBGPRINTF7(("YYPARSE: enter...\n"));
1773
Eric Andersen8401eea2004-08-04 19:16:54 +00001774 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 peeksym = 0;
1776 yynerrs = 0;
1777 outtree = c_list();
1778 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001779 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001780}
1781
Eric Andersen8401eea2004-08-04 19:16:54 +00001782static struct op *pipeline(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001783int cf;
1784{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001785 REGISTER struct op *t, *p;
1786 REGISTER int c;
1787
1788 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001789
1790 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001791
1792 DBGPRINTF9(("PIPELINE: t=0x%x\n", t));
1793
Eric Andersenff9eee42001-06-29 04:57:14 +00001794 if (t != NULL) {
1795 while ((c = yylex(0)) == '|') {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001796 if ((p = command(CONTIN)) == NULL) {
1797 DBGPRINTF8(("PIPELINE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001798 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001799 }
1800
Eric Andersenff9eee42001-06-29 04:57:14 +00001801 if (t->type != TPAREN && t->type != TCOM) {
1802 /* shell statement */
1803 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1804 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001805
Eric Andersenff9eee42001-06-29 04:57:14 +00001806 t = block(TPIPE, t, p, NOWORDS);
1807 }
1808 peeksym = c;
1809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001810
1811 DBGPRINTF7(("PIPELINE: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001812 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001813}
1814
Eric Andersen8401eea2004-08-04 19:16:54 +00001815static struct op *andor()
Eric Andersenff9eee42001-06-29 04:57:14 +00001816{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001817 REGISTER struct op *t, *p;
1818 REGISTER int c;
1819
1820 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001821
1822 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001823
1824 DBGPRINTF9(("ANDOR: t=0x%x\n", t));
1825
Eric Andersenff9eee42001-06-29 04:57:14 +00001826 if (t != NULL) {
1827 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001828 if ((p = pipeline(CONTIN)) == NULL) {
1829 DBGPRINTF8(("ANDOR: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001830 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001831 }
1832
Eric Andersen8401eea2004-08-04 19:16:54 +00001833 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001834 } /* WHILE */
1835
Eric Andersenff9eee42001-06-29 04:57:14 +00001836 peeksym = c;
1837 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001838
1839 DBGPRINTF7(("ANDOR: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001840 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001841}
1842
Eric Andersen8401eea2004-08-04 19:16:54 +00001843static struct op *c_list()
Eric Andersenff9eee42001-06-29 04:57:14 +00001844{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001845 REGISTER struct op *t, *p;
1846 REGISTER int c;
1847
1848 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001849
1850 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001851
Eric Andersenff9eee42001-06-29 04:57:14 +00001852 if (t != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001853 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001854 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001855
Eric Andersen8401eea2004-08-04 19:16:54 +00001856 while ((c = yylex(0)) == ';' || c == '&'
1857 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001858
Eric Andersenff9eee42001-06-29 04:57:14 +00001859 if ((p = andor()) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001860 return (t);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001861
Eric Andersen8401eea2004-08-04 19:16:54 +00001862 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001863 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001864
Eric Andersenff9eee42001-06-29 04:57:14 +00001865 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001866 } /* WHILE */
1867
Eric Andersenff9eee42001-06-29 04:57:14 +00001868 peeksym = c;
1869 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870 /* IF */
1871 DBGPRINTF7(("C_LIST: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001872 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001873}
1874
Eric Andersen8401eea2004-08-04 19:16:54 +00001875static int synio(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001876int cf;
1877{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001878 REGISTER struct ioword *iop;
1879 REGISTER int i;
1880 REGISTER int c;
1881
1882 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001883
1884 if ((c = yylex(cf)) != '<' && c != '>') {
1885 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001886 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001887 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001888
Eric Andersenff9eee42001-06-29 04:57:14 +00001889 i = yylval.i;
1890 musthave(WORD, 0);
1891 iop = io(iounit, i, yylval.cp);
1892 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001893
Eric Andersenff9eee42001-06-29 04:57:14 +00001894 if (i & IOHERE)
1895 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001896
1897 DBGPRINTF7(("SYNIO: returning 1\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00001898 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001899}
1900
Eric Andersen8401eea2004-08-04 19:16:54 +00001901static void musthave(c, cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001902int c, cf;
1903{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001904 if ((peeksym = yylex(cf)) != c) {
1905 DBGPRINTF7(("MUSTHAVE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001906 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001907 }
1908
Eric Andersenff9eee42001-06-29 04:57:14 +00001909 peeksym = 0;
1910}
1911
Eric Andersen8401eea2004-08-04 19:16:54 +00001912static struct op *simple()
Eric Andersenff9eee42001-06-29 04:57:14 +00001913{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001914 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001915
1916 t = NULL;
1917 for (;;) {
1918 switch (peeksym = yylex(0)) {
1919 case '<':
1920 case '>':
1921 (void) synio(0);
1922 break;
1923
1924 case WORD:
1925 if (t == NULL) {
1926 t = newtp();
1927 t->type = TCOM;
1928 }
1929 peeksym = 0;
1930 word(yylval.cp);
1931 break;
1932
1933 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001934 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001935 }
1936 }
1937}
1938
Eric Andersen8401eea2004-08-04 19:16:54 +00001939static struct op *nested(type, mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001940int type, mark;
1941{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001942 REGISTER struct op *t;
1943
1944 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001945
1946 multiline++;
1947 t = c_list();
1948 musthave(mark, 0);
1949 multiline--;
Eric Andersen8401eea2004-08-04 19:16:54 +00001950 return (block(type, t, NOBLOCK, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00001951}
1952
Eric Andersen8401eea2004-08-04 19:16:54 +00001953static struct op *command(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001954int cf;
1955{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001956 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001957 struct wdblock *iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001958 REGISTER int c;
1959
1960 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001961
1962 iosave = iolist;
1963 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001964
Eric Andersenff9eee42001-06-29 04:57:14 +00001965 if (multiline)
1966 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001967
Eric Andersenff9eee42001-06-29 04:57:14 +00001968 while (synio(cf))
1969 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
1971 c = yylex(cf);
1972
1973 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001974 default:
1975 peeksym = c;
1976 if ((t = simple()) == NULL) {
1977 if (iolist == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001978 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001979 t = newtp();
1980 t->type = TCOM;
1981 }
1982 break;
1983
1984 case '(':
1985 t = nested(TPAREN, ')');
1986 break;
1987
1988 case '{':
1989 t = nested(TBRACE, '}');
1990 break;
1991
1992 case FOR:
1993 t = newtp();
1994 t->type = TFOR;
1995 musthave(WORD, 0);
1996 startl = 1;
1997 t->str = yylval.cp;
1998 multiline++;
1999 t->words = wordlist();
2000 if ((c = yylex(0)) != '\n' && c != ';')
2001 peeksym = c;
2002 t->left = dogroup(0);
2003 multiline--;
2004 break;
2005
2006 case WHILE:
2007 case UNTIL:
2008 multiline++;
2009 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00002010 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002011 t->left = c_list();
2012 t->right = dogroup(1);
2013 t->words = NULL;
2014 multiline--;
2015 break;
2016
2017 case CASE:
2018 t = newtp();
2019 t->type = TCASE;
2020 musthave(WORD, 0);
2021 t->str = yylval.cp;
2022 startl++;
2023 multiline++;
2024 musthave(IN, CONTIN);
2025 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
Eric Andersenff9eee42001-06-29 04:57:14 +00002027 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002028
Eric Andersenff9eee42001-06-29 04:57:14 +00002029 musthave(ESAC, 0);
2030 multiline--;
2031 break;
2032
2033 case IF:
2034 multiline++;
2035 t = newtp();
2036 t->type = TIF;
2037 t->left = c_list();
2038 t->right = thenpart();
2039 musthave(FI, 0);
2040 multiline--;
2041 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002042
2043 case DOT:
2044 t = newtp();
2045 t->type = TDOT;
2046
2047 musthave(WORD, 0); /* gets name of file */
2048 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
2049
2050 word(yylval.cp); /* add word to wdlist */
2051 word(NOWORD); /* terminate wdlist */
2052 t->words = copyw(); /* dup wdlist */
2053 break;
2054
Eric Andersenff9eee42001-06-29 04:57:14 +00002055 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002056
Eric Andersen8401eea2004-08-04 19:16:54 +00002057 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002058
Eric Andersenff9eee42001-06-29 04:57:14 +00002059 t = namelist(t);
2060 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002061
2062 DBGPRINTF(("COMMAND: returning 0x%x\n", t));
2063
2064 return (t);
2065}
2066
2067static struct op *dowholefile(type, mark)
2068int type;
2069int mark;
2070{
2071 REGISTER struct op *t;
2072
2073 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
2074
2075 multiline++;
2076 t = c_list();
2077 multiline--;
2078 t = block(type, t, NOBLOCK, NOWORDS);
2079 DBGPRINTF(("DOWHOLEFILE: return t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002080 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002081}
2082
Eric Andersen8401eea2004-08-04 19:16:54 +00002083static struct op *dogroup(onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00002084int onlydone;
2085{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002086 REGISTER int c;
2087 REGISTER struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002088
2089 c = yylex(CONTIN);
2090 if (c == DONE && onlydone)
Eric Andersen8401eea2004-08-04 19:16:54 +00002091 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002092 if (c != DO)
2093 SYNTAXERR;
2094 mylist = c_list();
2095 musthave(DONE, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002096 return (mylist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002097}
2098
Eric Andersen8401eea2004-08-04 19:16:54 +00002099static struct op *thenpart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002100{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002101 REGISTER int c;
2102 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002103
2104 if ((c = yylex(0)) != THEN) {
2105 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002106 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002107 }
2108 t = newtp();
2109 t->type = 0;
2110 t->left = c_list();
2111 if (t->left == NULL)
2112 SYNTAXERR;
2113 t->right = elsepart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002114 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002115}
2116
Eric Andersen8401eea2004-08-04 19:16:54 +00002117static struct op *elsepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002118{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002119 REGISTER int c;
2120 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002121
2122 switch (c = yylex(0)) {
2123 case ELSE:
2124 if ((t = c_list()) == NULL)
2125 SYNTAXERR;
Eric Andersen8401eea2004-08-04 19:16:54 +00002126 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002127
2128 case ELIF:
2129 t = newtp();
2130 t->type = TELIF;
2131 t->left = c_list();
2132 t->right = thenpart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002133 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002134
2135 default:
2136 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002137 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002138 }
2139}
2140
Eric Andersen8401eea2004-08-04 19:16:54 +00002141static struct op *caselist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002142{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002143 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002144
2145 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002146 while ((peeksym = yylex(CONTIN)) != ESAC) {
2147 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00002148 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00002149 }
2150
2151 DBGPRINTF(("CASELIST, returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002152 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002153}
2154
Eric Andersen8401eea2004-08-04 19:16:54 +00002155static struct op *casepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002156{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002157 REGISTER struct op *t;
2158
2159 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002160
2161 t = newtp();
2162 t->type = TPAT;
2163 t->words = pattern();
2164 musthave(')', 0);
2165 t->left = c_list();
2166 if ((peeksym = yylex(CONTIN)) != ESAC)
2167 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002168
2169 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=0x%x)\n", t));
2170
Eric Andersen8401eea2004-08-04 19:16:54 +00002171 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002172}
2173
Eric Andersen8401eea2004-08-04 19:16:54 +00002174static char **pattern()
Eric Andersenff9eee42001-06-29 04:57:14 +00002175{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002176 REGISTER int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002177
2178 cf = CONTIN;
2179 do {
2180 musthave(WORD, cf);
2181 word(yylval.cp);
2182 cf = 0;
2183 } while ((c = yylex(0)) == '|');
2184 peeksym = c;
2185 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002186
Eric Andersen8401eea2004-08-04 19:16:54 +00002187 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002188}
2189
Eric Andersen8401eea2004-08-04 19:16:54 +00002190static char **wordlist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002191{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002192 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002193
2194 if ((c = yylex(0)) != IN) {
2195 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002196 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002197 }
2198 startl = 0;
2199 while ((c = yylex(0)) == WORD)
2200 word(yylval.cp);
2201 word(NOWORD);
2202 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002203 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002204}
2205
2206/*
2207 * supporting functions
2208 */
Eric Andersen8401eea2004-08-04 19:16:54 +00002209static struct op *list(t1, t2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002210REGISTER struct op *t1, *t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002211{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002212 DBGPRINTF7(("LIST: enter, t1=0x%x, t2=0x%x\n", t1, t2));
2213
Eric Andersenff9eee42001-06-29 04:57:14 +00002214 if (t1 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002215 return (t2);
Eric Andersenff9eee42001-06-29 04:57:14 +00002216 if (t2 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002217 return (t1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002218
Eric Andersen8401eea2004-08-04 19:16:54 +00002219 return (block(TLIST, t1, t2, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00002220}
2221
Eric Andersen8401eea2004-08-04 19:16:54 +00002222static struct op *block(type, t1, t2, wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002223int type;
2224struct op *t1, *t2;
2225char **wp;
2226{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002227 REGISTER struct op *t;
2228
2229 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002230
2231 t = newtp();
2232 t->type = type;
2233 t->left = t1;
2234 t->right = t2;
2235 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002236
2237 DBGPRINTF7(("BLOCK: inserted 0x%x between 0x%x and 0x%x\n", t, t1,
2238 t2));
2239
Eric Andersen8401eea2004-08-04 19:16:54 +00002240 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002241}
2242
Eric Andersen12de6cf2004-08-04 19:19:10 +00002243/* See if given string is a shell multiline (FOR, IF, etc) */
Eric Andersen8401eea2004-08-04 19:16:54 +00002244static int rlookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002245REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00002246{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002247 REGISTER struct res *rp;
2248
2249 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002250
2251 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002252 if (strcmp(rp->r_name, n) == 0) {
2253 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2254 return (rp->r_val); /* Return numeric code for shell multiline */
2255 }
2256
2257 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2258 return (0); /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002259}
2260
Eric Andersen8401eea2004-08-04 19:16:54 +00002261static struct op *newtp()
Eric Andersenff9eee42001-06-29 04:57:14 +00002262{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002263 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002264
Eric Andersen8401eea2004-08-04 19:16:54 +00002265 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002266 t->type = 0;
2267 t->words = NULL;
2268 t->ioact = NULL;
2269 t->left = NULL;
2270 t->right = NULL;
2271 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002272
2273 DBGPRINTF3(("NEWTP: allocated 0x%x\n", t));
2274
Eric Andersen8401eea2004-08-04 19:16:54 +00002275 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002276}
2277
Eric Andersen8401eea2004-08-04 19:16:54 +00002278static struct op *namelist(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002279REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002280{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002281
2282 DBGPRINTF7(("NAMELIST: enter, t=0x%x, type %s, iolist=0x%x\n", t,
2283 T_CMD_NAMES[t->type], iolist));
2284
Eric Andersenff9eee42001-06-29 04:57:14 +00002285 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002286 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002287 t->ioact = copyio();
2288 } else
2289 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002290
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 if (t->type != TCOM) {
2292 if (t->type != TPAREN && t->ioact != NULL) {
2293 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2294 t->ioact = t->left->ioact;
2295 t->left->ioact = NULL;
2296 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002297 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002298 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
Eric Andersenff9eee42001-06-29 04:57:14 +00002300 word(NOWORD);
2301 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002302
2303
Eric Andersen8401eea2004-08-04 19:16:54 +00002304 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002305}
2306
Eric Andersen8401eea2004-08-04 19:16:54 +00002307static char **copyw()
Eric Andersenff9eee42001-06-29 04:57:14 +00002308{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002309 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002310
2311 wd = getwords(wdlist);
2312 wdlist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002313 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002314}
2315
Eric Andersen8401eea2004-08-04 19:16:54 +00002316static void word(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002317char *cp;
2318{
2319 wdlist = addword(cp, wdlist);
2320}
2321
Eric Andersen8401eea2004-08-04 19:16:54 +00002322static struct ioword **copyio()
Eric Andersenff9eee42001-06-29 04:57:14 +00002323{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002324 REGISTER struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002325
2326 iop = (struct ioword **) getwords(iolist);
2327 iolist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002328 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002329}
2330
Eric Andersen8401eea2004-08-04 19:16:54 +00002331static struct ioword *io(u, f, cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002332int u;
2333int f;
2334char *cp;
2335{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002336 REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002337
2338 iop = (struct ioword *) tree(sizeof(*iop));
2339 iop->io_unit = u;
2340 iop->io_flag = f;
2341 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002342 iolist = addword((char *) iop, iolist);
2343 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002344}
2345
Eric Andersen8401eea2004-08-04 19:16:54 +00002346static void zzerr()
Eric Andersenff9eee42001-06-29 04:57:14 +00002347{
2348 yyerror("syntax error");
2349}
2350
Eric Andersen8401eea2004-08-04 19:16:54 +00002351static void yyerror(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00002352char *s;
2353{
2354 yynerrs++;
2355 if (interactive && e.iop <= iostack) {
2356 multiline = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002357 while (eofc() == 0 && yylex(0) != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002358 }
2359 err(s);
2360 fail();
2361}
2362
Eric Andersen8401eea2004-08-04 19:16:54 +00002363static int yylex(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002364int cf;
2365{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002366 REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002367 int atstart;
2368
2369 if ((c = peeksym) > 0) {
2370 peeksym = 0;
2371 if (c == '\n')
2372 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002373 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002374 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002375
2376
Eric Andersenff9eee42001-06-29 04:57:14 +00002377 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 atstart = startl;
2379 startl = 0;
2380 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002381 e.linep = line;
2382
2383/* MALAMO */
2384 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002385
Eric Andersen8401eea2004-08-04 19:16:54 +00002386 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002387 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2388 ;
2389
Eric Andersenff9eee42001-06-29 04:57:14 +00002390 switch (c) {
2391 default:
2392 if (any(c, "0123456789")) {
2393 unget(c1 = my_getc(0));
2394 if (c1 == '<' || c1 == '>') {
2395 iounit = c - '0';
2396 goto loop;
2397 }
2398 *e.linep++ = c;
2399 c = c1;
2400 }
2401 break;
2402
Eric Andersen12de6cf2004-08-04 19:19:10 +00002403 case '#': /* Comment, skip to next newline or End-of-string */
Eric Andersen8401eea2004-08-04 19:16:54 +00002404 while ((c = my_getc(0)) != 0 && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002405 unget(c);
2406 goto loop;
2407
2408 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002409 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Eric Andersen8401eea2004-08-04 19:16:54 +00002410 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002411
2412 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002413 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002414 *e.linep++ = c;
2415 if ((c = my_getc(0)) == '{') {
2416 if ((c = collect(c, '}')) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002417 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002418 goto pack;
2419 }
2420 break;
2421
2422 case '`':
2423 case '\'':
2424 case '"':
2425 if ((c = collect(c, c)) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002426 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002427 goto pack;
2428
2429 case '|':
2430 case '&':
2431 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002432 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002433 /* If more chars process them, else return NULL char */
2434 if ((c1 = dual(c)) != '\0')
2435 return (c1);
2436 else
2437 return (c);
2438
Eric Andersenff9eee42001-06-29 04:57:14 +00002439 case '^':
2440 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002441 return ('|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002442 case '>':
2443 case '<':
2444 diag(c);
Eric Andersen8401eea2004-08-04 19:16:54 +00002445 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002446
2447 case '\n':
2448 nlseen++;
2449 gethere();
2450 startl = 1;
2451 if (multiline || cf & CONTIN) {
2452 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002453#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002454 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002455#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002456 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002457#endif
2458 }
2459 if (cf & CONTIN)
2460 goto loop;
2461 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002462 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002463
2464 case '(':
2465 case ')':
2466 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002467 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002468 }
2469
2470 unget(c);
2471
Eric Andersen8401eea2004-08-04 19:16:54 +00002472 pack:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002474 if (e.linep >= elinep)
2475 err("word too long");
2476 else
2477 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002478 };
2479
Eric Andersenff9eee42001-06-29 04:57:14 +00002480 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481
Eric Andersen8401eea2004-08-04 19:16:54 +00002482 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002483 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002484
Eric Andersenff9eee42001-06-29 04:57:14 +00002485 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002486
Eric Andersen8401eea2004-08-04 19:16:54 +00002487 if (atstart && (c = rlookup(line)) != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002488 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002489 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002490 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002491
Eric Andersenff9eee42001-06-29 04:57:14 +00002492 yylval.cp = strsave(line, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00002493 return (WORD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002494}
2495
Eric Andersen12de6cf2004-08-04 19:19:10 +00002496
Eric Andersen8401eea2004-08-04 19:16:54 +00002497static int collect(c, c1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002498REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002499{
2500 char s[2];
2501
Eric Andersen12de6cf2004-08-04 19:19:10 +00002502 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2503
Eric Andersenff9eee42001-06-29 04:57:14 +00002504 *e.linep++ = c;
2505 while ((c = my_getc(c1)) != c1) {
2506 if (c == 0) {
2507 unget(c);
2508 s[0] = c1;
2509 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002510 prs("no closing ");
2511 yyerror(s);
2512 return (YYERRCODE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002513 }
2514 if (interactive && c == '\n' && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002515#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002516 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002517#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002518 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002519#endif
2520 }
2521 *e.linep++ = c;
2522 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002523
Eric Andersenff9eee42001-06-29 04:57:14 +00002524 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002525
2526 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2527
Eric Andersen8401eea2004-08-04 19:16:54 +00002528 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002529}
2530
Eric Andersen12de6cf2004-08-04 19:19:10 +00002531/* "multiline commands" helper func */
2532/* see if next 2 chars form a shell multiline */
Eric Andersen8401eea2004-08-04 19:16:54 +00002533static int dual(c)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002534REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002535{
2536 char s[3];
Eric Andersen12de6cf2004-08-04 19:19:10 +00002537 REGISTER char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002538
Eric Andersen12de6cf2004-08-04 19:19:10 +00002539 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2540
2541 *cp++ = c; /* c is the given "peek" char */
2542 *cp++ = my_getc(0); /* get next char of input */
2543 *cp = 0; /* add EOS marker */
2544
2545 c = rlookup(s); /* see if 2 chars form a shell multiline */
2546 if (c == 0)
2547 unget(*--cp); /* String is not a shell multiline, put peek char back */
2548
2549 return (c); /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002550}
2551
Eric Andersen8401eea2004-08-04 19:16:54 +00002552static void diag(ec)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002553REGISTER int ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00002554{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002555 REGISTER int c;
2556
2557 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002558
2559 c = my_getc(0);
2560 if (c == '>' || c == '<') {
2561 if (c != ec)
2562 zzerr();
Eric Andersen8401eea2004-08-04 19:16:54 +00002563 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002564 c = my_getc(0);
2565 } else
Eric Andersen8401eea2004-08-04 19:16:54 +00002566 yylval.i = ec == '>' ? IOWRITE : IOREAD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002567 if (c != '&' || yylval.i == IOHERE)
2568 unget(c);
2569 else
2570 yylval.i |= IODUP;
2571}
2572
Eric Andersen8401eea2004-08-04 19:16:54 +00002573static char *tree(size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002574unsigned size;
2575{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002576 REGISTER char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002577
2578 if ((t = getcell(size)) == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002579 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002580 prs("command line too complicated\n");
2581 fail();
2582 /* NOTREACHED */
2583 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002584 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002585}
2586
2587/* VARARGS1 */
2588/* ARGSUSED */
2589
2590/* -------- exec.c -------- */
2591
2592/*
2593 * execute tree
2594 */
2595
2596
Eric Andersen8401eea2004-08-04 19:16:54 +00002597static int execute(t, pin, pout, act)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002598REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002599int *pin, *pout;
2600int act;
2601{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002602 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002603 volatile int i, rv, a;
2604 char *cp, **wp, **wp2;
2605 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002606 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002607 struct brkcon bc;
2608
2609#if __GNUC__
2610 /* Avoid longjmp clobbering */
2611 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002612#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002613
Eric Andersen12de6cf2004-08-04 19:19:10 +00002614 if (t == NULL) {
2615 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002616 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002617 }
2618
2619 DBGPRINTF(("EXECUTE: t=0x%x, t->type=%d (%s), t->words is %s\n", t,
2620 t->type, T_CMD_NAMES[t->type],
2621 ((t->words == NULL) ? "NULL" : t->words[0])));
2622
Eric Andersenff9eee42001-06-29 04:57:14 +00002623 rv = 0;
2624 a = areanum++;
2625 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002626 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2627 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002628
Eric Andersen12de6cf2004-08-04 19:19:10 +00002629/* Hard to know how many words there are, be careful of garbage pointer values */
2630/* They are likely to cause "PCI bus fault" errors */
2631#if 0
2632 DBGPRINTF(("EXECUTE: t->left=0x%x, t->right=0x%x, t->words[1] is %s\n",
2633 t->left, t->right,
2634 ((t->words[1] == NULL) ? "NULL" : t->words[1])));
2635 DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",
2636 ((t->words[2] == NULL) ? "NULL" : t->words[2]),
2637 ((t->words[3] == NULL) ? "NULL" : t->words[3])));
2638#endif
2639
2640
Eric Andersen8401eea2004-08-04 19:16:54 +00002641 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002642 case TDOT:
2643 DBGPRINTF3(("EXECUTE: TDOT\n"));
2644
2645 outtree_save = outtree;
2646
2647 newfile(evalstr(t->words[0], DOALL));
2648
2649 t->left = dowholefile(TLIST, 0);
2650 t->right = NULL;
2651
2652 outtree = outtree_save;
2653
2654 if (t->left)
2655 rv = execute(t->left, pin, pout, 0);
2656 if (t->right)
2657 rv = execute(t->right, pin, pout, 0);
2658 break;
2659
Eric Andersenff9eee42001-06-29 04:57:14 +00002660 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002661 rv = execute(t->left, pin, pout, 0);
2662 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002663
Eric Andersenff9eee42001-06-29 04:57:14 +00002664 case TCOM:
Eric Andersen1c039232001-07-07 00:05:55 +00002665 {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002666 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002667 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002668 break;
2669
2670 case TPIPE:
2671 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002672 int pv[2];
2673
2674 if ((rv = openpipe(pv)) < 0)
2675 break;
2676 pv[0] = remap(pv[0]);
2677 pv[1] = remap(pv[1]);
2678 (void) execute(t->left, pin, pv, 0);
2679 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002680 }
2681 break;
2682
2683 case TLIST:
2684 (void) execute(t->left, pin, pout, 0);
2685 rv = execute(t->right, pin, pout, 0);
2686 break;
2687
2688 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002689 {
2690 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002691
Eric Andersen12de6cf2004-08-04 19:19:10 +00002692 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2693
Eric Andersen8401eea2004-08-04 19:16:54 +00002694 i = vfork();
2695 if (i != 0) {
2696 interactive = hinteractive;
2697 if (i != -1) {
2698 setval(lookup("!"), putn(i));
2699 if (pin != NULL)
2700 closepipe(pin);
2701 if (interactive) {
2702 prs(putn(i));
2703 prs("\n");
2704 }
2705 } else
2706 rv = -1;
2707 setstatus(rv);
2708 } else {
2709 signal(SIGINT, SIG_IGN);
2710 signal(SIGQUIT, SIG_IGN);
2711 if (interactive)
2712 signal(SIGTERM, SIG_DFL);
2713 interactive = 0;
2714 if (pin == NULL) {
2715 close(0);
2716 open("/dev/null", 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002717 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002718 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002719 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002720 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002721 break;
2722
2723 case TOR:
2724 case TAND:
2725 rv = execute(t->left, pin, pout, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002726 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002727 rv = execute(t1, pin, pout, 0);
2728 break;
2729
2730 case TFOR:
2731 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002732 wp = dolv + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002733 if ((i = dolc) < 0)
2734 i = 0;
2735 } else {
2736 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002737 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002738 }
2739 vp = lookup(t->str);
2740 while (setjmp(bc.brkpt))
2741 if (isbreak)
2742 goto broken;
2743 brkset(&bc);
2744 for (t1 = t->left; i-- && *wp != NULL;) {
2745 setval(vp, *wp++);
2746 rv = execute(t1, pin, pout, 0);
2747 }
2748 brklist = brklist->nextlev;
2749 break;
2750
2751 case TWHILE:
2752 case TUNTIL:
2753 while (setjmp(bc.brkpt))
2754 if (isbreak)
2755 goto broken;
2756 brkset(&bc);
2757 t1 = t->left;
2758 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2759 rv = execute(t->right, pin, pout, 0);
2760 brklist = brklist->nextlev;
2761 break;
2762
2763 case TIF:
2764 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002765 if (t->right != NULL) {
2766 rv = !execute(t->left, pin, pout, 0) ?
2767 execute(t->right->left, pin, pout, 0) :
2768 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002769 }
2770 break;
2771
2772 case TCASE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002773 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002774 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002775
2776 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2777 ((t->str == NULL) ? "NULL" : t->str),
2778 ((cp == NULL) ? "NULL" : cp)));
2779
2780 if ((t1 = findcase(t->left, cp)) != NULL) {
2781 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=0x%x, t1=0x%x)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002782 rv = execute(t1, pin, pout, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002783 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=0x%x, t1=0x%x)...\n", t, t1));
2784 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002785 break;
2786
2787 case TBRACE:
2788/*
2789 if (iopp = t->ioact)
2790 while (*iopp)
2791 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2792 rv = -1;
2793 break;
2794 }
2795*/
2796 if (rv >= 0 && (t1 = t->left))
2797 rv = execute(t1, pin, pout, 0);
2798 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799
2800 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002801
Eric Andersen8401eea2004-08-04 19:16:54 +00002802 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002803 t->words = wp2;
2804 isbreak = 0;
2805 freehere(areanum);
2806 freearea(areanum);
2807 areanum = a;
2808 if (interactive && intr) {
2809 closeall();
2810 fail();
2811 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002812
Eric Andersenff9eee42001-06-29 04:57:14 +00002813 if ((i = trapset) != 0) {
2814 trapset = 0;
2815 runtrap(i);
2816 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002817
2818 DBGPRINTF(("EXECUTE: returning from t=0x%x, rv=%d\n", t, rv));
Eric Andersen8401eea2004-08-04 19:16:54 +00002819 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002820}
2821
2822static int
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002824{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002825 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002826 int i, rv;
Eric Andersen8401eea2004-08-04 19:16:54 +00002827 int (*shcom) (struct op *) = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002828 REGISTER int f;
Eric Andersenff9eee42001-06-29 04:57:14 +00002829 char *cp = NULL;
2830 struct ioword **iopp;
2831 int resetsig;
2832 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002833 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002834
2835 int *hpin = pin;
2836 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002837 char *hwp;
2838 int hinteractive;
2839 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002840 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002841 int hexecflg;
2842
2843#if __GNUC__
2844 /* Avoid longjmp clobbering */
2845 (void) &pin;
2846 (void) &pout;
2847 (void) &wp;
2848 (void) &shcom;
2849 (void) &cp;
2850 (void) &resetsig;
2851 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002852#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002853
Eric Andersen12de6cf2004-08-04 19:19:10 +00002854 DBGPRINTF(("FORKEXEC: t=0x%x, pin 0x%x, pout 0x%x, act %d\n", t, pin,
2855 pout, act));
2856 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2857 ((t->words == NULL) ? "NULL" : t->words[0])));
2858
2859/* Hard to know how many words there are, be careful of garbage pointer values */
2860/* They are likely to cause "PCI bus fault" errors */
2861#if 0
2862 DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2863 ((t->words == NULL) ? "NULL" : t->words[0]),
2864 ((t->words == NULL) ? "NULL" : t->words[1])));
2865 DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",
2866 ((wp == NULL) ? "NULL" : wp[0]),
2867 ((wp[1] == NULL) ? "NULL" : wp[1])));
2868 DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",
2869 ((wp[2] == NULL) ? "NULL" : wp[2]),
2870 ((wp[3] == NULL) ? "NULL" : wp[3])));
2871#endif
2872
2873
Eric Andersenff9eee42001-06-29 04:57:14 +00002874 owp = wp;
2875 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002876 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002877 if (t->type == TCOM) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002878 while ((cp = *wp++) != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002879 cp = *wp;
2880
2881 /* strip all initial assignments */
2882 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002883 if (flag['x']) {
2884 DBGPRINTF9(("FORKEXEC: echo'ing, cp=0x%x, wp=0x%x, owp=0x%x\n",
2885 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002886 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002887 }
2888#if 0
2889 DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2890 ((t->words == NULL) ? "NULL" : t->words[0]),
2891 ((t->words == NULL) ? "NULL" : t->words[1])));
2892 DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",
2893 ((wp == NULL) ? "NULL" : wp[0]),
2894 ((wp == NULL) ? "NULL" : wp[1])));
2895#endif
2896
Eric Andersenff9eee42001-06-29 04:57:14 +00002897 if (cp == NULL && t->ioact == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002898 while ((cp = *owp++) != NULL && assign(cp, COPYV));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002899 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002900 return (setstatus(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002901 } else if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002902 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002905
Eric Andersenff9eee42001-06-29 04:57:14 +00002906 t->words = wp;
2907 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002908
Eric Andersen12de6cf2004-08-04 19:19:10 +00002909#if 0
2910 DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2911 ((t->words == NULL) ? "NULL" : t->words[0]),
2912 ((t->words == NULL) ? "NULL" : t->words[1])));
2913#endif
2914 DBGPRINTF(("FORKEXEC: shcom 0x%x, f&FEXEC 0x%x, owp 0x%x\n", shcom,
2915 f & FEXEC, owp));
2916
2917 if (shcom == NULL && (f & FEXEC) == 0) {
2918 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002919 hpin = pin;
2920 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002921 hwp = *wp;
2922 hinteractive = interactive;
2923 hintr = intr;
2924 hbrklist = brklist;
2925 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002926
Eric Andersen12de6cf2004-08-04 19:19:10 +00002927 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2928
2929 newpid = vfork();
2930
2931 if (newpid == -1) {
2932 DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n"));
2933 return (-1);
2934 }
2935
2936
2937 if (newpid > 0) { /* Parent */
2938
2939 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002940 pin = hpin;
2941 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002942 *wp = hwp;
2943 interactive = hinteractive;
2944 intr = hintr;
2945 brklist = hbrklist;
2946 execflg = hexecflg;
2947
Eric Andersen12de6cf2004-08-04 19:19:10 +00002948/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002949 if (i == -1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002950 return(rv);
2951*/
2952
Eric Andersenff9eee42001-06-29 04:57:14 +00002953 if (pin != NULL)
2954 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002955
2956 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002957 }
2958
Eric Andersen12de6cf2004-08-04 19:19:10 +00002959 /* Must be the child process, pid should be 0 */
2960 DBGPRINTF(("FORKEXEC: child process, shcom=0x%x\n", shcom));
2961
Eric Andersenff9eee42001-06-29 04:57:14 +00002962 if (interactive) {
2963 signal(SIGINT, SIG_IGN);
2964 signal(SIGQUIT, SIG_IGN);
2965 resetsig = 1;
2966 }
2967 interactive = 0;
2968 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002969 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002970 brklist = 0;
2971 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002972 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002973
2974
Eric Andersenff9eee42001-06-29 04:57:14 +00002975 if (owp != NULL)
2976 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2977 if (shcom == NULL)
2978 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002979
Eric Andersenff9eee42001-06-29 04:57:14 +00002980#ifdef COMPIPE
2981 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2982 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002983 if (forked)
2984 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00002985 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002986 }
2987#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002988
Eric Andersenff9eee42001-06-29 04:57:14 +00002989 if (pin != NULL) {
2990 dup2(pin[0], 0);
2991 closepipe(pin);
2992 }
2993 if (pout != NULL) {
2994 dup2(pout[1], 1);
2995 closepipe(pout);
2996 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002997
Eric Andersenff9eee42001-06-29 04:57:14 +00002998 if ((iopp = t->ioact) != NULL) {
2999 if (shcom != NULL && shcom != doexec) {
3000 prs(cp);
3001 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003002 if (forked)
3003 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003004 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003005 }
3006 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003007 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
3008 if (forked)
3009 _exit(rv);
Eric Andersen8401eea2004-08-04 19:16:54 +00003010 return (rv);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003011 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003012 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003013
3014 if (shcom) {
3015 i = setstatus((*shcom) (t));
3016 if (forked)
3017 _exit(i);
3018 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
3019 return (i);
3020 }
3021
Eric Andersenff9eee42001-06-29 04:57:14 +00003022 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00003023 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003024 close(i);
3025 if (resetsig) {
3026 signal(SIGINT, SIG_DFL);
3027 signal(SIGQUIT, SIG_DFL);
3028 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003029
Eric Andersen12de6cf2004-08-04 19:19:10 +00003030 if (t->type == TPAREN)
3031 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
3032 if (wp[0] == NULL)
3033 _exit(0);
3034
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003035 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003036 prs(wp[0]);
3037 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003038 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003039 if (!execflg)
3040 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003041
3042 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
3043
Eric Andersenff9eee42001-06-29 04:57:14 +00003044 leave();
3045 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003046 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003047}
3048
3049/*
3050 * 0< 1> are ignored as required
3051 * within pipelines.
3052 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003053static int iosetup(iop, pipein, pipeout)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003054REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003055int pipein, pipeout;
3056{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003057 REGISTER int u = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003058 char *cp = NULL, *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00003059
Eric Andersen12de6cf2004-08-04 19:19:10 +00003060 DBGPRINTF(("IOSETUP: iop 0x%x, pipein 0x%x, pipeout 0x%x\n", iop,
3061 pipein, pipeout));
3062
Eric Andersenff9eee42001-06-29 04:57:14 +00003063 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00003064 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003065
Eric Andersenff9eee42001-06-29 04:57:14 +00003066 if (pipein && iop->io_unit == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003067 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003068
Eric Andersenff9eee42001-06-29 04:57:14 +00003069 if (pipeout && iop->io_unit == 1)
Eric Andersen8401eea2004-08-04 19:16:54 +00003070 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003071
Eric Andersen8401eea2004-08-04 19:16:54 +00003072 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00003073 if ((iop->io_flag & IOHERE) == 0) {
3074 cp = iop->io_name;
Eric Andersen8401eea2004-08-04 19:16:54 +00003075 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
3076 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003077 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003078
Eric Andersenff9eee42001-06-29 04:57:14 +00003079 if (iop->io_flag & IODUP) {
3080 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
3081 prs(cp);
3082 err(": illegal >& argument");
Eric Andersen8401eea2004-08-04 19:16:54 +00003083 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003084 }
3085 if (*cp == '-')
3086 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00003087 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 }
3089 switch (iop->io_flag) {
3090 case IOREAD:
3091 u = open(cp, 0);
3092 break;
3093
3094 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00003095 case IOHERE | IOXHERE:
3096 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 cp = "here file";
3098 break;
3099
Eric Andersen8401eea2004-08-04 19:16:54 +00003100 case IOWRITE | IOCAT:
Eric Andersenff9eee42001-06-29 04:57:14 +00003101 if ((u = open(cp, 1)) >= 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003102 lseek(u, (long) 0, 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00003103 break;
3104 }
3105 case IOWRITE:
3106 u = creat(cp, 0666);
3107 break;
3108
3109 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00003110 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00003111 break;
3112
3113 case IOCLOSE:
3114 close(iop->io_unit);
Eric Andersen8401eea2004-08-04 19:16:54 +00003115 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003116 }
3117 if (u < 0) {
3118 prs(cp);
3119 prs(": cannot ");
3120 warn(msg);
Eric Andersen8401eea2004-08-04 19:16:54 +00003121 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003122 } else {
3123 if (u != iop->io_unit) {
3124 dup2(u, iop->io_unit);
3125 close(u);
3126 }
3127 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003128 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003129}
3130
Eric Andersen8401eea2004-08-04 19:16:54 +00003131static void echo(wp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003132REGISTER char **wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003133{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003134 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003135
3136 prs("+");
Eric Andersen8401eea2004-08-04 19:16:54 +00003137 for (i = 0; wp[i]; i++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003138 if (i)
3139 prs(" ");
3140 prs(wp[i]);
3141 }
3142 prs("\n");
3143}
3144
Eric Andersen8401eea2004-08-04 19:16:54 +00003145static struct op **find1case(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003146struct op *t;
3147char *w;
3148{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003149 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003150 struct op **tp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003151 REGISTER char **wp, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003152
Eric Andersen12de6cf2004-08-04 19:19:10 +00003153
3154 if (t == NULL) {
3155 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003156 return ((struct op **) NULL);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003157 }
3158
3159 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3160 T_CMD_NAMES[t->type]));
3161
Eric Andersenff9eee42001-06-29 04:57:14 +00003162 if (t->type == TLIST) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003163 if ((tp = find1case(t->left, w)) != NULL) {
3164 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=0x%x\n", tp));
Eric Andersen8401eea2004-08-04 19:16:54 +00003165 return (tp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003166 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003167 t1 = t->right; /* TPAT */
Eric Andersenff9eee42001-06-29 04:57:14 +00003168 } else
3169 t1 = t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003170
Eric Andersenff9eee42001-06-29 04:57:14 +00003171 for (wp = t1->words; *wp;)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003172 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
3173 DBGPRINTF3(("FIND1CASE: returning &t1->left= 0x%x.\n",
3174 &t1->left));
Eric Andersen8401eea2004-08-04 19:16:54 +00003175 return (&t1->left);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003176 }
3177
3178 DBGPRINTF(("FIND1CASE: returning NULL\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003179 return ((struct op **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003180}
3181
Eric Andersen8401eea2004-08-04 19:16:54 +00003182static struct op *findcase(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003183struct op *t;
3184char *w;
3185{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003186 REGISTER struct op **tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003187
Eric Andersen8401eea2004-08-04 19:16:54 +00003188 return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003189}
3190
3191/*
3192 * Enter a new loop level (marked for break/continue).
3193 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003194static void brkset(bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00003195struct brkcon *bc;
3196{
3197 bc->nextlev = brklist;
3198 brklist = bc;
3199}
3200
3201/*
3202 * Wait for the last process created.
3203 * Print a message for each process found
3204 * that was killed by a signal.
3205 * Ignore interrupt signals while waiting
3206 * unless `canintr' is true.
3207 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003208static int waitfor(lastpid, canintr)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003209REGISTER int lastpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00003210int canintr;
3211{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003212 REGISTER int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003213 int s;
3214 int oheedint = heedint;
3215
3216 heedint = 0;
3217 rv = 0;
3218 do {
3219 pid = wait(&s);
3220 if (pid == -1) {
3221 if (errno != EINTR || canintr)
3222 break;
3223 } else {
3224 if ((rv = WAITSIG(s)) != 0) {
3225 if (rv < NSIGNAL) {
3226 if (signame[rv] != NULL) {
3227 if (pid != lastpid) {
3228 prn(pid);
3229 prs(": ");
3230 }
3231 prs(signame[rv]);
3232 }
3233 } else {
3234 if (pid != lastpid) {
3235 prn(pid);
3236 prs(": ");
3237 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003238 prs("Signal ");
3239 prn(rv);
3240 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003241 }
3242 if (WAITCORE(s))
3243 prs(" - core dumped");
3244 if (rv >= NSIGNAL || signame[rv])
3245 prs("\n");
3246 rv = -1;
3247 } else
3248 rv = WAITVAL(s);
3249 }
3250 } while (pid != lastpid);
3251 heedint = oheedint;
3252 if (intr) {
3253 if (interactive) {
3254 if (canintr)
3255 intr = 0;
3256 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003257 if (exstat == 0)
3258 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003259 onintr(0);
3260 }
3261 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003262 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003263}
3264
Eric Andersen8401eea2004-08-04 19:16:54 +00003265static int setstatus(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003266REGISTER int s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003267{
3268 exstat = s;
3269 setval(lookup("?"), putn(s));
Eric Andersen8401eea2004-08-04 19:16:54 +00003270 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00003271}
3272
3273/*
3274 * PATH-searching interface to execve.
3275 * If getenv("PATH") were kept up-to-date,
3276 * execvp might be used.
3277 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003278static char *rexecve(c, v, envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003279char *c, **v, **envp;
3280{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003281 REGISTER int i;
3282 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003283 int eacces = 0, asis = 0;
3284
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003285#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003286 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003287
Eric Andersen1c039232001-07-07 00:05:55 +00003288 optind = 1;
3289 if (find_applet_by_name(name)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003290 /* We have to exec here since we vforked. Running
Eric Andersen1c039232001-07-07 00:05:55 +00003291 * run_applet_by_name() won't work and bad things
3292 * will happen. */
3293 execve("/proc/self/exe", v, envp);
3294 execve("busybox", v, envp);
3295 }
3296#endif
3297
Eric Andersen12de6cf2004-08-04 19:19:10 +00003298 DBGPRINTF(("REXECVE: c=0x%x, v=0x%x, envp=0x%x\n", c, v, envp));
3299
Eric Andersen8401eea2004-08-04 19:16:54 +00003300 sp = any('/', c) ? "" : path->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00003301 asis = *sp == '\0';
3302 while (asis || *sp != '\0') {
3303 asis = 0;
3304 tp = e.linep;
3305 for (; *sp != '\0'; tp++)
3306 if ((*tp = *sp++) == ':') {
3307 asis = *sp == '\0';
3308 break;
3309 }
3310 if (tp != e.linep)
3311 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003312 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003313
Eric Andersen12de6cf2004-08-04 19:19:10 +00003314 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3315
Eric Andersenff9eee42001-06-29 04:57:14 +00003316 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003317
Eric Andersenff9eee42001-06-29 04:57:14 +00003318 switch (errno) {
3319 case ENOEXEC:
3320 *v = e.linep;
3321 tp = *--v;
3322 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003323 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003324 *v = tp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003325 return ("no Shell");
Eric Andersenff9eee42001-06-29 04:57:14 +00003326
3327 case ENOMEM:
Eric Andersen8401eea2004-08-04 19:16:54 +00003328 return ((char *) bb_msg_memory_exhausted);
Eric Andersenff9eee42001-06-29 04:57:14 +00003329
3330 case E2BIG:
Eric Andersen8401eea2004-08-04 19:16:54 +00003331 return ("argument list too long");
Eric Andersenff9eee42001-06-29 04:57:14 +00003332
3333 case EACCES:
3334 eacces++;
3335 break;
3336 }
3337 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003338 return (errno == ENOENT ? "not found" : "cannot execute");
Eric Andersenff9eee42001-06-29 04:57:14 +00003339}
3340
3341/*
3342 * Run the command produced by generator `f'
3343 * applied to stream `arg'.
3344 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003345static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003346{
3347 struct op *otree;
3348 struct wdblock *swdlist;
3349 struct wdblock *siolist;
3350 jmp_buf ev, rt;
3351 xint *ofail;
3352 int rv;
3353
3354#if __GNUC__
3355 /* Avoid longjmp clobbering */
3356 (void) &rv;
3357#endif
3358
Eric Andersen12de6cf2004-08-04 19:19:10 +00003359 DBGPRINTF(("RUN: enter, areanum %d, outtree 0x%x, failpt 0x%x\n",
3360 areanum, outtree, failpt));
3361
Eric Andersenff9eee42001-06-29 04:57:14 +00003362 areanum++;
3363 swdlist = wdlist;
3364 siolist = iolist;
3365 otree = outtree;
3366 ofail = failpt;
3367 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003368
Eric Andersenff9eee42001-06-29 04:57:14 +00003369 if (newenv(setjmp(errpt = ev)) == 0) {
3370 wdlist = 0;
3371 iolist = 0;
3372 pushio(argp, f);
3373 e.iobase = e.iop;
3374 yynerrs = 0;
3375 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3376 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3377 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003378 } else {
3379 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003380 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003381
Eric Andersenff9eee42001-06-29 04:57:14 +00003382 wdlist = swdlist;
3383 iolist = siolist;
3384 failpt = ofail;
3385 outtree = otree;
3386 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003387
Eric Andersen8401eea2004-08-04 19:16:54 +00003388 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003389}
3390
3391/* -------- do.c -------- */
3392
3393/*
3394 * built-in commands: doX
3395 */
3396
Eric Andersen8401eea2004-08-04 19:16:54 +00003397static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003398{
3399 int col;
3400 const struct builtincmd *x;
3401
3402 printf("\nBuilt-in commands:\n");
3403 printf("-------------------\n");
3404
Eric Andersen8401eea2004-08-04 19:16:54 +00003405 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003406 if (!x->name)
3407 continue;
3408 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3409 if (col > 60) {
3410 printf("\n");
3411 col = 0;
3412 }
3413 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003414#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003415 {
3416 int i;
3417 const struct BB_applet *applet;
3418 extern const struct BB_applet applets[];
3419 extern const size_t NUM_APPLETS;
3420
Eric Andersen8401eea2004-08-04 19:16:54 +00003421 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003422 if (!applet->name)
3423 continue;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003424
Eric Andersen8401eea2004-08-04 19:16:54 +00003425 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003426 if (col > 60) {
3427 printf("\n");
3428 col = 0;
3429 }
3430 }
3431 }
3432#endif
3433 printf("\n\n");
3434 return EXIT_SUCCESS;
3435}
3436
3437
3438
Eric Andersen8401eea2004-08-04 19:16:54 +00003439static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003440{
Eric Andersen8401eea2004-08-04 19:16:54 +00003441 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003442}
3443
Eric Andersen8401eea2004-08-04 19:16:54 +00003444static int dochdir(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003445REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003446{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003447 REGISTER char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003448
3449 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3450 er = ": no home directory";
Eric Andersen8401eea2004-08-04 19:16:54 +00003451 else if (chdir(cp) < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003452 er = ": bad directory";
3453 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003454 return (0);
3455 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003456 err(er);
Eric Andersen8401eea2004-08-04 19:16:54 +00003457 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003458}
3459
Eric Andersen8401eea2004-08-04 19:16:54 +00003460static int doshift(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003461REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003462{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003463 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003464
Eric Andersen8401eea2004-08-04 19:16:54 +00003465 n = t->words[1] ? getn(t->words[1]) : 1;
3466 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003467 err("nothing to shift");
Eric Andersen8401eea2004-08-04 19:16:54 +00003468 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003469 }
3470 dolv[n] = dolv[0];
3471 dolv += n;
3472 dolc -= n;
3473 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003474 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003475}
3476
3477/*
3478 * execute login and newgrp directly
3479 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003480static int dologin(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003481struct op *t;
3482{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003483 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003484
3485 if (interactive) {
3486 signal(SIGINT, SIG_DFL);
3487 signal(SIGQUIT, SIG_DFL);
3488 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003489 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003490 prs(t->words[0]);
3491 prs(": ");
3492 err(cp);
3493 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003494}
3495
Eric Andersen8401eea2004-08-04 19:16:54 +00003496static int doumask(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003497REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003498{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003499 REGISTER int i, n;
3500 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003501
3502 if ((cp = t->words[1]) == NULL) {
3503 i = umask(0);
3504 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003505 for (n = 3 * 4; (n -= 3) >= 0;)
3506 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003507 putc('\n', stderr);
3508 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003509 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3510 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003511 umask(n);
3512 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003513 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003514}
3515
Eric Andersen8401eea2004-08-04 19:16:54 +00003516static int doexec(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003517REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003518{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003519 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003520 jmp_buf ex;
3521 xint *ofail;
3522
3523 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003524 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003525 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003526 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003527 execflg = 1;
3528 ofail = failpt;
3529 if (setjmp(failpt = ex) == 0)
3530 execute(t, NOPIPE, NOPIPE, FEXEC);
3531 failpt = ofail;
3532 execflg = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003533 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003534}
3535
Eric Andersen8401eea2004-08-04 19:16:54 +00003536static int dodot(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537struct op *t;
3538{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003539 REGISTER int i;
3540 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003541 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003542 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003543
Eric Andersen12de6cf2004-08-04 19:19:10 +00003544 DBGPRINTF(("DODOT: enter, t=0x%x, tleft 0x%x, tright 0x%x, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3545
3546 if ((cp = t->words[1]) == NULL) {
3547 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003548 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003549 } else {
3550 DBGPRINTF(("DODOT: cp is %s\n", cp));
3551 }
3552
Eric Andersen8401eea2004-08-04 19:16:54 +00003553 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003554
3555 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3556 ((sp == NULL) ? "NULL" : sp),
3557 ((e.linep == NULL) ? "NULL" : e.linep)));
3558
Eric Andersenff9eee42001-06-29 04:57:14 +00003559 while (*sp) {
3560 tp = e.linep;
3561 while (*sp && (*tp = *sp++) != ':')
3562 tp++;
3563 if (tp != e.linep)
3564 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003565
Eric Andersen8401eea2004-08-04 19:16:54 +00003566 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003567
3568 /* Original code */
Eric Andersenff9eee42001-06-29 04:57:14 +00003569 if ((i = open(e.linep, 0)) >= 0) {
3570 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003571 maltmp = remap(i);
3572 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3573
3574 next(maltmp); /* Basically a PUSHIO */
3575
3576 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3577
Eric Andersen8401eea2004-08-04 19:16:54 +00003578 return (exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00003579 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003580
3581 } /* While */
3582
Eric Andersenff9eee42001-06-29 04:57:14 +00003583 prs(cp);
3584 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003585
Eric Andersen8401eea2004-08-04 19:16:54 +00003586 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003587}
3588
Eric Andersen8401eea2004-08-04 19:16:54 +00003589static int dowait(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003590struct op *t;
3591{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003592 REGISTER int i;
3593 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003594
3595 if ((cp = t->words[1]) != NULL) {
3596 i = getn(cp);
3597 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003598 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003599 } else
3600 i = -1;
3601 setstatus(waitfor(i, 1));
Eric Andersen8401eea2004-08-04 19:16:54 +00003602 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003603}
3604
Eric Andersen8401eea2004-08-04 19:16:54 +00003605static int doread(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003606struct op *t;
3607{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003608 REGISTER char *cp, **wp;
3609 REGISTER int nb = 0;
3610 REGISTER int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003611
3612 if (t->words[1] == NULL) {
3613 err("Usage: read name ...");
Eric Andersen8401eea2004-08-04 19:16:54 +00003614 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003615 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003616 for (wp = t->words + 1; *wp; wp++) {
3617 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003618 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003619 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
Eric Andersenff9eee42001-06-29 04:57:14 +00003620 break;
3621 *cp = 0;
3622 if (nb <= 0)
3623 break;
3624 setval(lookup(*wp), e.linep);
3625 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003626 return (nb <= 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003627}
3628
Eric Andersen8401eea2004-08-04 19:16:54 +00003629static int doeval(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003630REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003631{
Eric Andersen8401eea2004-08-04 19:16:54 +00003632 return (RUN(awordlist, t->words + 1, wdchar));
Eric Andersenff9eee42001-06-29 04:57:14 +00003633}
3634
Eric Andersen8401eea2004-08-04 19:16:54 +00003635static int dotrap(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003636REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003637{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003638 REGISTER int n, i;
3639 REGISTER int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003640
3641 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003642 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003643 if (trap[i]) {
3644 prn(i);
3645 prs(": ");
3646 prs(trap[i]);
3647 prs("\n");
3648 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003649 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003650 }
3651 resetsig = isdigit(*t->words[1]);
3652 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3653 n = getsig(t->words[i]);
3654 freecell(trap[n]);
3655 trap[n] = 0;
3656 if (!resetsig) {
3657 if (*t->words[1] != '\0') {
3658 trap[n] = strsave(t->words[1], 0);
3659 setsig(n, sig);
3660 } else
3661 setsig(n, SIG_IGN);
3662 } else {
3663 if (interactive)
3664 if (n == SIGINT)
3665 setsig(n, onintr);
3666 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003667 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003668 else
3669 setsig(n, SIG_DFL);
3670 }
3671 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003672 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003673}
3674
Eric Andersen8401eea2004-08-04 19:16:54 +00003675static int getsig(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003676char *s;
3677{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003678 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003679
3680 if ((n = getn(s)) < 0 || n > _NSIG) {
3681 err("trap: bad signal number");
3682 n = 0;
3683 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003684 return (n);
Eric Andersenff9eee42001-06-29 04:57:14 +00003685}
3686
Eric Andersen12de6cf2004-08-04 19:19:10 +00003687static void setsig(REGISTER int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003688{
3689 if (n == 0)
3690 return;
3691 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3692 ourtrap[n] = 1;
3693 signal(n, f);
3694 }
3695}
3696
Eric Andersen8401eea2004-08-04 19:16:54 +00003697static int getn(as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003698char *as;
3699{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003700 REGISTER char *s;
3701 REGISTER int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003702
3703 s = as;
3704 m = 1;
3705 if (*s == '-') {
3706 m = -1;
3707 s++;
3708 }
3709 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003710 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003711 if (*s) {
3712 prs(as);
3713 err(": bad number");
3714 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003715 return (n * m);
Eric Andersenff9eee42001-06-29 04:57:14 +00003716}
3717
Eric Andersen8401eea2004-08-04 19:16:54 +00003718static int dobreak(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003719struct op *t;
3720{
Eric Andersen8401eea2004-08-04 19:16:54 +00003721 return (brkcontin(t->words[1], 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00003722}
3723
Eric Andersen8401eea2004-08-04 19:16:54 +00003724static int docontinue(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003725struct op *t;
3726{
Eric Andersen8401eea2004-08-04 19:16:54 +00003727 return (brkcontin(t->words[1], 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00003728}
3729
Eric Andersen8401eea2004-08-04 19:16:54 +00003730static int brkcontin(cp, val)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003731REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003732int val;
3733{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003734 REGISTER struct brkcon *bc;
3735 REGISTER int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003736
Eric Andersen8401eea2004-08-04 19:16:54 +00003737 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003738 if (nl <= 0)
3739 nl = 999;
3740 do {
3741 if ((bc = brklist) == NULL)
3742 break;
3743 brklist = bc->nextlev;
3744 } while (--nl);
3745 if (nl) {
3746 err("bad break/continue level");
Eric Andersen8401eea2004-08-04 19:16:54 +00003747 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003748 }
3749 isbreak = val;
3750 longjmp(bc->brkpt, 1);
3751 /* NOTREACHED */
3752}
3753
Eric Andersen8401eea2004-08-04 19:16:54 +00003754static int doexit(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003755struct op *t;
3756{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003757 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003758
3759 execflg = 0;
3760 if ((cp = t->words[1]) != NULL)
3761 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003762
3763 DBGPRINTF(("DOEXIT: calling leave(), t=0x%x\n", t));
3764
Eric Andersenff9eee42001-06-29 04:57:14 +00003765 leave();
3766 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00003767 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003768}
3769
Eric Andersen8401eea2004-08-04 19:16:54 +00003770static int doexport(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003771struct op *t;
3772{
Eric Andersen8401eea2004-08-04 19:16:54 +00003773 rdexp(t->words + 1, export, EXPORT);
3774 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003775}
3776
Eric Andersen8401eea2004-08-04 19:16:54 +00003777static int doreadonly(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003778struct op *t;
3779{
Eric Andersen8401eea2004-08-04 19:16:54 +00003780 rdexp(t->words + 1, ronly, RONLY);
3781 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003782}
3783
Eric Andersen8401eea2004-08-04 19:16:54 +00003784static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003785{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003786 DBGPRINTF6(("RDEXP: enter, wp=0x%x, func=0x%x, key=%d\n", wp, f, key));
3787 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3788
Eric Andersenff9eee42001-06-29 04:57:14 +00003789 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003790 for (; *wp != NULL; wp++) {
3791 if (isassign(*wp)) {
3792 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003793
Matt Kraaif69bfc72001-07-12 19:39:59 +00003794 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003795 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003796 *cp = '\0';
3797 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003798 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003799 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003800 else
3801 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003802 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003803 } else
3804 putvlist(key, 1);
3805}
3806
Eric Andersen8401eea2004-08-04 19:16:54 +00003807static void badid(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003808REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003809{
3810 prs(s);
3811 err(": bad identifier");
3812}
3813
Eric Andersen8401eea2004-08-04 19:16:54 +00003814static int doset(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003815REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003816{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003817 REGISTER struct var *vp;
3818 REGISTER char *cp;
3819 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003820
3821 if ((cp = t->words[1]) == NULL) {
3822 for (vp = vlist; vp; vp = vp->next)
3823 varput(vp->name, 1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003824 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003825 }
3826 if (*cp == '-') {
3827 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003828 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003829 if (*++cp == 0)
3830 flag['x'] = flag['v'] = 0;
3831 else
3832 for (; *cp; cp++)
3833 switch (*cp) {
3834 case 'e':
3835 if (!interactive)
3836 flag['e']++;
3837 break;
3838
3839 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003840 if (*cp >= 'a' && *cp <= 'z')
3841 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003842 break;
3843 }
3844 setdash();
3845 }
3846 if (t->words[1]) {
3847 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003848 for (n = 1; t->words[n]; n++)
3849 setarea((char *) t->words[n], 0);
3850 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003851 dolv = t->words;
3852 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003853 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003854 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003855 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003856}
3857
Eric Andersen8401eea2004-08-04 19:16:54 +00003858static void varput(s, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003859REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003860int out;
3861{
Matt Kraai69edfec2001-08-06 14:14:18 +00003862 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003863 write(out, s, strlen(s));
3864 write(out, "\n", 1);
3865 }
3866}
3867
3868
3869/*
3870 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3871 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003872 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003873static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003874{
3875 struct tms buf;
3876 long int clk_tck = sysconf(_SC_CLK_TCK);
3877
3878 times(&buf);
3879 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003880 (int) (buf.tms_utime / clk_tck / 60),
3881 ((double) buf.tms_utime) / clk_tck,
3882 (int) (buf.tms_stime / clk_tck / 60),
3883 ((double) buf.tms_stime) / clk_tck,
3884 (int) (buf.tms_cutime / clk_tck / 60),
3885 ((double) buf.tms_cutime) / clk_tck,
3886 (int) (buf.tms_cstime / clk_tck / 60),
3887 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003888 return 0;
3889}
3890
3891
Eric Andersen8401eea2004-08-04 19:16:54 +00003892static int (*inbuilt(char *s)) (struct op *) {
Eric Andersen1c039232001-07-07 00:05:55 +00003893 const struct builtincmd *bp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003894
Eric Andersen1c039232001-07-07 00:05:55 +00003895 for (bp = builtincmds; bp->name != NULL; bp++)
3896 if (strcmp(bp->name, s) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003897 return (bp->builtinfunc);
Eric Andersen1c039232001-07-07 00:05:55 +00003898
Eric Andersen8401eea2004-08-04 19:16:54 +00003899 return (NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003900}
3901
3902/* -------- eval.c -------- */
3903
3904/*
3905 * ${}
3906 * `command`
3907 * blank interpretation
3908 * quoting
3909 * glob
3910 */
3911
Eric Andersen8401eea2004-08-04 19:16:54 +00003912static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003913{
3914 struct wdblock *wb;
3915 char **wp;
3916 char **wf;
3917 jmp_buf ev;
3918
3919#if __GNUC__
3920 /* Avoid longjmp clobbering */
3921 (void) &wp;
3922 (void) &ap;
3923#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003924
3925 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3926
Eric Andersenff9eee42001-06-29 04:57:14 +00003927 wp = NULL;
3928 wb = NULL;
3929 wf = NULL;
3930 if (newenv(setjmp(errpt = ev)) == 0) {
3931 while (*ap && isassign(*ap))
3932 expand(*ap++, &wb, f & ~DOGLOB);
3933 if (flag['k']) {
3934 for (wf = ap; *wf; wf++) {
3935 if (isassign(*wf))
3936 expand(*wf, &wb, f & ~DOGLOB);
3937 }
3938 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003939 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003940 if (!flag['k'] || !isassign(*ap))
3941 expand(*ap, &wb, f & ~DOKEY);
3942 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003943 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003944 wp = getwords(wb);
3945 quitenv();
3946 } else
3947 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003948
Eric Andersen8401eea2004-08-04 19:16:54 +00003949 return (gflg ? (char **) NULL : wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003950}
3951
3952/*
3953 * Make the exported environment from the exported
3954 * names in the dictionary. Keyword assignments
3955 * will already have been done.
3956 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003957static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003958{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003959 REGISTER struct var *vp;
3960
3961 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003962
Eric Andersenff9eee42001-06-29 04:57:14 +00003963 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003964 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003965 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003966 wb = addword((char *) 0, wb);
3967 return (getwords(wb));
Eric Andersenff9eee42001-06-29 04:57:14 +00003968}
3969
Eric Andersen8401eea2004-08-04 19:16:54 +00003970static char *evalstr(cp, f)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003971REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003972int f;
3973{
3974 struct wdblock *wb;
3975
Eric Andersen12de6cf2004-08-04 19:19:10 +00003976 DBGPRINTF6(("EVALSTR: enter, cp=0x%x, f=%d\n", cp, f));
3977
Eric Andersenff9eee42001-06-29 04:57:14 +00003978 wb = NULL;
3979 if (expand(cp, &wb, f)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003980 if (wb == NULL || wb->w_nword == 0
3981 || (cp = wb->w_words[0]) == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003982 cp = "";
3983 DELETE(wb);
3984 } else
3985 cp = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003986 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003987}
3988
Eric Andersen12de6cf2004-08-04 19:19:10 +00003989static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003990{
3991 jmp_buf ev;
3992
3993#if __GNUC__
3994 /* Avoid longjmp clobbering */
3995 (void) &cp;
3996#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003997
3998 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3999
Eric Andersenff9eee42001-06-29 04:57:14 +00004000 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004001
Eric Andersenff9eee42001-06-29 04:57:14 +00004002 if (cp == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004003 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004004
Eric Andersenff9eee42001-06-29 04:57:14 +00004005 if (!anys("$`'\"", cp) &&
Eric Andersen8401eea2004-08-04 19:16:54 +00004006 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004007 cp = strsave(cp, areanum);
4008 if (f & DOTRIM)
4009 unquote(cp);
4010 *wbp = addword(cp, *wbp);
Eric Andersen8401eea2004-08-04 19:16:54 +00004011 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004012 }
4013 if (newenv(setjmp(errpt = ev)) == 0) {
4014 PUSHIO(aword, cp, strchar);
4015 e.iobase = e.iop;
4016 while ((cp = blank(f)) && gflg == 0) {
4017 e.linep = cp;
4018 cp = strsave(cp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00004019 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004020 if (f & DOTRIM)
4021 unquote(cp);
4022 *wbp = addword(cp, *wbp);
4023 } else
4024 *wbp = glob(cp, *wbp);
4025 }
4026 quitenv();
4027 } else
4028 gflg = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004029 return (gflg == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004030}
4031
4032/*
4033 * Blank interpretation and quoting
4034 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004035static char *blank(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00004036int f;
4037{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004038 REGISTER int c, c1;
4039 REGISTER char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004040 int scanequals, foundequals;
4041
Eric Andersen12de6cf2004-08-04 19:19:10 +00004042 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
4043
Eric Andersenff9eee42001-06-29 04:57:14 +00004044 sp = e.linep;
4045 scanequals = f & DOKEY;
4046 foundequals = 0;
4047
Eric Andersen8401eea2004-08-04 19:16:54 +00004048 loop:
Eric Andersenff9eee42001-06-29 04:57:14 +00004049 switch (c = subgetc('"', foundequals)) {
4050 case 0:
4051 if (sp == e.linep)
Eric Andersen8401eea2004-08-04 19:16:54 +00004052 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004053 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004054 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004055
4056 default:
4057 if (f & DOBLANK && any(c, ifs->value))
4058 goto loop;
4059 break;
4060
4061 case '"':
4062 case '\'':
4063 scanequals = 0;
4064 if (INSUB())
4065 break;
4066 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
4067 if (c == 0)
4068 break;
4069 if (c == '\'' || !any(c, "$`\""))
4070 c |= QUOTE;
4071 *e.linep++ = c;
4072 }
4073 c = 0;
4074 }
4075 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00004076 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004077 scanequals = 0;
4078 for (;;) {
4079 c = subgetc('"', foundequals);
4080 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00004081 f & (DOBLANK && any(c, ifs->value)) ||
4082 (!INSUB() && any(c, "\"'"))) {
4083 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004084 unget(c);
4085 if (any(c, "\"'"))
4086 goto loop;
4087 break;
4088 }
4089 if (scanequals) {
4090 if (c == '=') {
4091 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004092 scanequals = 0;
4093 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004094 scanequals = 0;
4095 }
4096 *e.linep++ = c;
4097 }
4098 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004099 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004100}
4101
4102/*
4103 * Get characters, substituting for ` and $
4104 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004105static int subgetc(ec, quoted)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004106REGISTER char ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00004107int quoted;
4108{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004109 REGISTER char c;
4110
4111 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00004112
Eric Andersen8401eea2004-08-04 19:16:54 +00004113 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00004114 c = my_getc(ec);
4115 if (!INSUB() && ec != '\'') {
4116 if (c == '`') {
4117 if (grave(quoted) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004118 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004119 e.iop->task = XGRAVE;
4120 goto again;
4121 }
4122 if (c == '$' && (c = dollar(quoted)) == 0) {
4123 e.iop->task = XDOLL;
4124 goto again;
4125 }
4126 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004127 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004128}
4129
4130/*
4131 * Prepare to generate the string returned by ${} substitution.
4132 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004133static int dollar(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004134int quoted;
4135{
4136 int otask;
4137 struct io *oiop;
4138 char *dolp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004139 REGISTER char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004140 struct var *vp;
4141
Eric Andersen12de6cf2004-08-04 19:19:10 +00004142 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
4143
Eric Andersenff9eee42001-06-29 04:57:14 +00004144 c = readc();
4145 s = e.linep;
4146 if (c != '{') {
4147 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00004148 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00004149 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00004150 if (e.linep < elinep)
4151 *e.linep++ = c;
4152 unget(c);
4153 }
4154 c = 0;
4155 } else {
4156 oiop = e.iop;
4157 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004158
Eric Andersenff9eee42001-06-29 04:57:14 +00004159 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00004160 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004161 if (e.linep < elinep)
4162 *e.linep++ = c;
4163 if (oiop == e.iop)
4164 e.iop->task = otask;
4165 if (c != '}') {
4166 err("unclosed ${");
4167 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004168 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004169 }
4170 }
4171 if (e.linep >= elinep) {
4172 err("string in ${} too long");
4173 gflg++;
4174 e.linep -= 10;
4175 }
4176 *e.linep = 0;
4177 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00004178 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004179 if (any(*cp, "=-+?")) {
4180 c = *cp;
4181 *cp++ = 0;
4182 break;
4183 }
4184 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4185 if (dolc > 1) {
4186 /* currently this does not distinguish $* and $@ */
4187 /* should check dollar */
4188 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00004189 PUSHIO(awordlist, dolv + 1, dolchar);
4190 return (0);
4191 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00004192 s[0] = '1';
4193 s[1] = 0;
4194 }
4195 }
4196 vp = lookup(s);
4197 if ((dolp = vp->value) == null) {
4198 switch (c) {
4199 case '=':
4200 if (isdigit(*s)) {
4201 err("cannot use ${...=...} with $n");
4202 gflg++;
4203 break;
4204 }
4205 setval(vp, cp);
4206 dolp = vp->value;
4207 break;
4208
4209 case '-':
4210 dolp = strsave(cp, areanum);
4211 break;
4212
4213 case '?':
4214 if (*cp == 0) {
4215 prs("missing value for ");
4216 err(s);
4217 } else
4218 err(cp);
4219 gflg++;
4220 break;
4221 }
4222 } else if (c == '+')
4223 dolp = strsave(cp, areanum);
4224 if (flag['u'] && dolp == null) {
4225 prs("unset variable: ");
4226 err(s);
4227 gflg++;
4228 }
4229 e.linep = s;
4230 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Eric Andersen8401eea2004-08-04 19:16:54 +00004231 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004232}
4233
4234/*
4235 * Run the command in `...` and read its output.
4236 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004237
Eric Andersen8401eea2004-08-04 19:16:54 +00004238static int grave(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004239int quoted;
4240{
Eric Andersenff9eee42001-06-29 04:57:14 +00004241 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004242 REGISTER int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004243 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004244 int pf[2];
Eric Andersen737f5fb2003-03-14 16:05:59 +00004245 static char child_cmd[LINELIM];
4246 char *src;
4247 char *dest;
4248 int count;
4249 int ignore;
4250 int ignore_once;
4251 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004252 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004253
4254#if __GNUC__
4255 /* Avoid longjmp clobbering */
4256 (void) &cp;
4257#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004258
Eric Andersenff9eee42001-06-29 04:57:14 +00004259 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4260 if (*cp == 0) {
4261 err("no closing `");
Eric Andersen8401eea2004-08-04 19:16:54 +00004262 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004263 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004264
4265 /* string copy with dollar expansion */
4266 src = e.iop->argp->aword;
4267 dest = child_cmd;
4268 count = 0;
4269 ignore = 0;
4270 ignore_once = 0;
4271 while ((*src != '`') && (count < LINELIM)) {
4272 if (*src == '\'')
4273 ignore = !ignore;
4274 if (*src == '\\')
4275 ignore_once = 1;
4276 if (*src == '$' && !ignore && !ignore_once) {
4277 struct var *vp;
4278 char var_name[LINELIM];
4279 char alt_value[LINELIM];
4280 int var_index = 0;
4281 int alt_index = 0;
4282 char operator = 0;
4283 int braces = 0;
4284 char *value;
4285
4286 src++;
4287 if (*src == '{') {
4288 braces = 1;
4289 src++;
4290 }
4291
4292 var_name[var_index++] = *src++;
4293 while (isalnum(*src))
4294 var_name[var_index++] = *src++;
4295 var_name[var_index] = 0;
4296
4297 if (braces) {
4298 switch (*src) {
4299 case '}':
4300 break;
4301 case '-':
4302 case '=':
4303 case '+':
4304 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004305 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004306 break;
4307 default:
4308 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004309 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004310 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004311 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004312 src++;
4313 while (*src && (*src != '}')) {
4314 alt_value[alt_index++] = *src++;
4315 }
4316 alt_value[alt_index] = 0;
4317 if (*src != '}') {
4318 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004319 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004320 }
4321 }
4322 src++;
4323 }
4324
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004325 if (isalpha(*var_name)) {
4326 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004327
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004328 char *namep = var_name;
4329
4330 *dest++ = '$';
4331 if (braces)
4332 *dest++ = '{';
4333 while (*namep)
4334 *dest++ = *namep++;
4335 if (operator) {
4336 char *altp = alt_value;
4337 *dest++ = operator;
4338 while (*altp)
4339 *dest++ = *altp++;
4340 }
4341 if (braces)
4342 *dest++ = '}';
4343
4344 wb = addword(lookup(var_name)->name, wb);
4345 } else {
4346 /* expand */
4347
4348 vp = lookup(var_name);
4349 if (vp->value != null)
4350 value = (operator == '+') ?
4351 alt_value : vp->value;
4352 else if (operator == '?') {
4353 err(alt_value);
4354 return (0);
4355 } else if (alt_index && (operator != '+')) {
4356 value = alt_value;
4357 if (operator == '=')
4358 setval(vp, value);
4359 } else
4360 continue;
4361
4362 while (*value && (count < LINELIM)) {
4363 *dest++ = *value++;
4364 count++;
4365 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004366 }
4367 } else {
4368 *dest++ = *src++;
4369 count++;
4370 ignore_once = 0;
4371 }
4372 }
4373 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004374
Eric Andersenff9eee42001-06-29 04:57:14 +00004375 if (openpipe(pf) < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004376 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004377
Eric Andersen8401eea2004-08-04 19:16:54 +00004378 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004379
4380 DBGPRINTF3(("GRAVE: i is %d\n", io));
4381
Eric Andersen737f5fb2003-03-14 16:05:59 +00004382 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004383 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004384 err((char *) bb_msg_memory_exhausted);
4385 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004386 }
4387 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004388 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004389 e.iop->argp->aword = ++cp;
4390 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004391 PUSHIO(afile, remap(pf[0]),
4392 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4393 gravechar));
4394 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004395 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004396 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004397 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004398 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004399 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4400 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004401
Eric Andersenff9eee42001-06-29 04:57:14 +00004402 dup2(pf[1], 1);
4403 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004404
Eric Andersen8401eea2004-08-04 19:16:54 +00004405 argument_list[0] = (char *) DEFAULT_SHELL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004406 argument_list[1] = "-c";
4407 argument_list[2] = child_cmd;
4408 argument_list[3] = 0;
4409
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004410 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004411 prs(argument_list[0]);
4412 prs(": ");
4413 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004414 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004415}
4416
Eric Andersen737f5fb2003-03-14 16:05:59 +00004417
Eric Andersen8401eea2004-08-04 19:16:54 +00004418static char *unquote(as)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004419REGISTER char *as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004420{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004421 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004422
4423 if ((s = as) != NULL)
4424 while (*s)
4425 *s++ &= ~QUOTE;
Eric Andersen8401eea2004-08-04 19:16:54 +00004426 return (as);
Eric Andersenff9eee42001-06-29 04:57:14 +00004427}
4428
4429/* -------- glob.c -------- */
4430
4431/*
4432 * glob
4433 */
4434
4435#define scopy(x) strsave((x), areanum)
4436#define BLKSIZ 512
4437#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4438
Eric Andersen8401eea2004-08-04 19:16:54 +00004439static struct wdblock *cl, *nl;
4440static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004441
Eric Andersen8401eea2004-08-04 19:16:54 +00004442static struct wdblock *glob(cp, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004443char *cp;
4444struct wdblock *wb;
4445{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004446 REGISTER int i;
4447 REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004448
4449 if (cp == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004450 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004451 i = 0;
4452 for (pp = cp; *pp; pp++)
4453 if (any(*pp, spcl))
4454 i++;
4455 else if (!any(*pp & ~QUOTE, spcl))
4456 *pp &= ~QUOTE;
4457 if (i != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004458 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4459 cl = nl) {
4460 nl = newword(cl->w_nword * 2);
4461 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004462 for (pp = cl->w_words[i]; *pp; pp++)
4463 if (any(*pp, spcl)) {
4464 globname(cl->w_words[i], pp);
4465 break;
4466 }
4467 if (*pp == '\0')
4468 nl = addword(scopy(cl->w_words[i]), nl);
4469 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004470 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004471 DELETE(cl->w_words[i]);
4472 DELETE(cl);
4473 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004474 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004475 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004476 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004477 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004478 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004479 wb = addword(cl->w_words[i], wb);
4480 DELETE(cl);
Eric Andersen8401eea2004-08-04 19:16:54 +00004481 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004482 }
4483 }
4484 wb = addword(unquote(cp), wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004485 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004486}
4487
Eric Andersen8401eea2004-08-04 19:16:54 +00004488static void globname(we, pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004489char *we;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004490REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004491{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004492 REGISTER char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004493 char *name, *gp, *dp;
4494 int k;
4495 DIR *dirp;
4496 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004497 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004498 struct stat dbuf;
4499
4500 for (np = we; np != pp; pp--)
4501 if (pp[-1] == '/')
4502 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004503 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004504 *cp++ = *np++;
4505 *cp++ = '.';
4506 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004508 *cp++ = *np++;
4509 *cp = '\0';
4510 dirp = opendir(dp);
4511 if (dirp == 0) {
4512 DELETE(dp);
4513 DELETE(gp);
4514 return;
4515 }
4516 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004517 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004518 /* XXX Hmmm... What this could be? (abial) */
4519 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004520 if (ent[j].d_ino == 0)
4521 continue;
4522 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004523 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004524 if (dname[0] == '.')
4525 if (*gp != '.')
4526 continue;
4527 for (k = 0; k < NAME_MAX; k++)
4528 if (any(dname[k], spcl))
4529 dname[k] |= QUOTE;
4530 if (gmatch(dname, gp)) {
4531 name = generate(we, pp, dname, np);
4532 if (*np && !anys(np, spcl)) {
4533 if (stat(name, &dbuf)) {
4534 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004535 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004537 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004538 nl = addword(name, nl);
4539 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004540 }
4541 closedir(dirp);
4542 DELETE(dp);
4543 DELETE(gp);
4544}
4545
4546/*
4547 * generate a pathname as below.
4548 * start..end1 / middle end
4549 * the slashes come for free
4550 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004551static char *generate(start1, end1, middle, end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004552char *start1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004553REGISTER char *end1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004554char *middle, *end;
4555{
4556 char *p;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004557 REGISTER char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004558
Eric Andersen8401eea2004-08-04 19:16:54 +00004559 p = op =
4560 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004561 for (xp = start1; xp != end1;)
4562 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004563 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004564 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004565 for (xp = end; (*op++ = *xp++) != '\0';);
4566 return (p);
Eric Andersenff9eee42001-06-29 04:57:14 +00004567}
4568
Eric Andersen8401eea2004-08-04 19:16:54 +00004569static int anyspcl(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004570REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004571{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004572 REGISTER int i;
4573 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004574
4575 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004576 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004577 if (anys(spcl, *wd++))
Eric Andersen8401eea2004-08-04 19:16:54 +00004578 return (1);
4579 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004580}
4581
Eric Andersen8401eea2004-08-04 19:16:54 +00004582static int xstrcmp(p1, p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004583char *p1, *p2;
4584{
Eric Andersen8401eea2004-08-04 19:16:54 +00004585 return (strcmp(*(char **) p1, *(char **) p2));
Eric Andersenff9eee42001-06-29 04:57:14 +00004586}
4587
4588/* -------- word.c -------- */
4589
Eric Andersen8401eea2004-08-04 19:16:54 +00004590static struct wdblock *newword(nw)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004591REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004592{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004593 REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004594
Eric Andersen8401eea2004-08-04 19:16:54 +00004595 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004596 wb->w_bsize = nw;
4597 wb->w_nword = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004598 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004599}
4600
Eric Andersen8401eea2004-08-04 19:16:54 +00004601static struct wdblock *addword(wd, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004602char *wd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004603REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004604{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004605 REGISTER struct wdblock *wb2;
4606 REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004607
4608 if (wb == NULL)
4609 wb = newword(NSTART);
4610 if ((nw = wb->w_nword) >= wb->w_bsize) {
4611 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004612 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4613 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004614 wb2->w_nword = nw;
4615 DELETE(wb);
4616 wb = wb2;
4617 }
4618 wb->w_words[wb->w_nword++] = wd;
Eric Andersen8401eea2004-08-04 19:16:54 +00004619 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004620}
Eric Andersen8401eea2004-08-04 19:16:54 +00004621
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004622static
Eric Andersen8401eea2004-08-04 19:16:54 +00004623char **getwords(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004624REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004625{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004626 REGISTER char **wd;
4627 REGISTER int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004628
4629 if (wb == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004630 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004631 if (wb->w_nword == 0) {
4632 DELETE(wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004633 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004634 }
4635 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004636 memcpy((char *) wd, (char *) wb->w_words, nb);
4637 DELETE(wb); /* perhaps should done by caller */
4638 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00004639}
4640
Eric Andersen8401eea2004-08-04 19:16:54 +00004641int (*func) (char *, char *);
4642int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004643
Eric Andersen8401eea2004-08-04 19:16:54 +00004644static void glob0(a0, a1, a2, a3)
Eric Andersenff9eee42001-06-29 04:57:14 +00004645char *a0;
4646unsigned a1;
4647int a2;
4648int (*a3) (char *, char *);
4649{
4650 func = a3;
4651 globv = a2;
4652 glob1(a0, a0 + a1 * a2);
4653}
4654
Eric Andersen8401eea2004-08-04 19:16:54 +00004655static void glob1(base, lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004656char *base, *lim;
4657{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004658 REGISTER char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004659 int v2;
4660 char *lptr, *hptr;
4661 int c;
4662 unsigned n;
4663
4664
4665 v2 = globv;
4666
Eric Andersen8401eea2004-08-04 19:16:54 +00004667 top:
4668 if ((n = (int) (lim - base)) <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004670 n = v2 * (n / (2 * v2));
4671 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004672 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004673 j = lim - v2;
4674 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004675 if (i < lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004676 if ((c = (*func) (i, lptr)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004677 glob2(i, lptr -= v2);
4678 continue;
4679 }
4680 if (c < 0) {
4681 i += v2;
4682 continue;
4683 }
4684 }
4685
Eric Andersen8401eea2004-08-04 19:16:54 +00004686 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004687 if (j > hptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004688 if ((c = (*func) (hptr, j)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004689 glob2(hptr += v2, j);
4690 goto begin;
4691 }
4692 if (c > 0) {
4693 if (i == lptr) {
4694 glob3(i, hptr += v2, j);
4695 i = lptr += v2;
4696 goto begin;
4697 }
4698 glob2(i, j);
4699 j -= v2;
4700 i += v2;
4701 continue;
4702 }
4703 j -= v2;
4704 goto begin;
4705 }
4706
4707
4708 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004709 if (lptr - base >= lim - hptr) {
4710 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004711 lim = lptr;
4712 } else {
4713 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004714 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004715 }
4716 goto top;
4717 }
4718
4719
4720 glob3(j, lptr -= v2, i);
4721 j = hptr -= v2;
4722 }
4723}
4724
Eric Andersen8401eea2004-08-04 19:16:54 +00004725static void glob2(i, j)
Eric Andersenff9eee42001-06-29 04:57:14 +00004726char *i, *j;
4727{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004728 REGISTER char *index1, *index2, c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004729 int m;
4730
4731 m = globv;
4732 index1 = i;
4733 index2 = j;
4734 do {
4735 c = *index1;
4736 *index1++ = *index2;
4737 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004738 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004739}
4740
Eric Andersen8401eea2004-08-04 19:16:54 +00004741static void glob3(i, j, k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004742char *i, *j, *k;
4743{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004744 REGISTER char *index1, *index2, *index3;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745 int c;
4746 int m;
4747
4748 m = globv;
4749 index1 = i;
4750 index2 = j;
4751 index3 = k;
4752 do {
4753 c = *index1;
4754 *index1++ = *index3;
4755 *index3++ = *index2;
4756 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004757 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004758}
4759
4760/* -------- io.c -------- */
4761
4762/*
4763 * shell IO
4764 */
4765
Eric Andersen8401eea2004-08-04 19:16:54 +00004766static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004767{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004768 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004769
Eric Andersen8401eea2004-08-04 19:16:54 +00004770 if (e.linep > elinep) {
4771 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004772 err("input line too long");
4773 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004774 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004775 }
4776 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004777 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004778 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004779 c = readc();
4780 if (c == '\n' && ec != '\"')
Eric Andersen8401eea2004-08-04 19:16:54 +00004781 return (my_getc(ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00004782 c |= QUOTE;
4783 }
4784 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004785 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004786}
4787
Eric Andersen8401eea2004-08-04 19:16:54 +00004788static void unget(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004789int c;
4790{
4791 if (e.iop >= e.iobase)
4792 e.iop->peekc = c;
4793}
4794
Eric Andersen8401eea2004-08-04 19:16:54 +00004795static int eofc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004796{
Eric Andersen8401eea2004-08-04 19:16:54 +00004797 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004798}
4799
Eric Andersen8401eea2004-08-04 19:16:54 +00004800static int readc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004801{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004802 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004803
Eric Andersen12de6cf2004-08-04 19:19:10 +00004804 RCPRINTF(("READC: e.iop 0x%x, e.iobase 0x%x\n", e.iop, e.iobase));
4805
4806 for (; e.iop >= e.iobase; e.iop--) {
4807 RCPRINTF(("READC: e.iop 0x%x, peekc 0x%x\n", e.iop, e.iop->peekc));
Eric Andersenff9eee42001-06-29 04:57:14 +00004808 if ((c = e.iop->peekc) != '\0') {
4809 e.iop->peekc = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004810 return (c);
4811 } else {
4812 if (e.iop->prev != 0) {
4813 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4814 if (c == -1) {
4815 e.iop++;
4816 continue;
4817 }
4818 if (e.iop == iostack)
4819 ioecho(c);
4820 return (e.iop->prev = c);
4821 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4822 e.iop->prev = 0;
4823 if (e.iop == iostack)
4824 ioecho('\n');
4825 return '\n';
4826 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004827 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004828 if (e.iop->task == XIO) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004829 if (multiline) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004830 return e.iop->prev = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004831 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004832 if (interactive && e.iop == iostack + 1) {
4833#ifdef CONFIG_FEATURE_COMMAND_EDITING
4834 current_prompt = prompt->value;
4835#else
4836 prs(prompt->value);
4837#endif
4838 }
4839 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004840 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004841
4842 } /* FOR */
4843
4844 if (e.iop >= iostack) {
4845 RCPRINTF(("READC: return 0, e.iop 0x%x\n", e.iop));
Eric Andersen8401eea2004-08-04 19:16:54 +00004846 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004847 }
4848
4849 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004850 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004851
Eric Andersenff9eee42001-06-29 04:57:14 +00004852 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00004853 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004854}
4855
Eric Andersen8401eea2004-08-04 19:16:54 +00004856static void ioecho(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004857char c;
4858{
4859 if (flag['v'])
4860 write(2, &c, sizeof c);
4861}
4862
Eric Andersen12de6cf2004-08-04 19:19:10 +00004863
Eric Andersen8401eea2004-08-04 19:16:54 +00004864static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004865{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004866 DBGPRINTF(("PUSHIO: argp 0x%x, argp->afid 0x%x, e.iop 0x%x\n", argp,
4867 argp->afid, e.iop));
4868
4869 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004870 if (++e.iop >= &iostack[NPUSH]) {
4871 e.iop--;
4872 err("Shell input nested too deeply");
4873 gflg++;
4874 return;
4875 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004876
4877 /* We did not overflow the NPUSH array spots so setup data structs */
4878
4879 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004880
4881 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004882 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004883 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004884
4885 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4886 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4887
4888 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4889
4890 if (e.iop == &iostack[0])
4891 e.iop->argp->afbuf = &mainbuf;
4892 else
4893 e.iop->argp->afbuf = &sharedbuf;
4894
4895 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4896 /* This line appears to be active when running scripts from command line */
4897 if ((isatty(e.iop->argp->afile) == 0)
4898 && (e.iop == &iostack[0]
4899 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4900 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4901 bufid = AFID_ID; /* AFID_ID = 0 */
4902
4903 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004904 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004905
4906 DBGPRINTF(("PUSHIO: iostack 0x%x, e.iop 0x%x, afbuf 0x%x\n",
4907 iostack, e.iop, e.iop->argp->afbuf));
4908 DBGPRINTF(("PUSHIO: mbuf 0x%x, sbuf 0x%x, bid %d, e.iop 0x%x\n",
4909 &mainbuf, &sharedbuf, bufid, e.iop));
4910
Eric Andersenff9eee42001-06-29 04:57:14 +00004911 }
4912
Eric Andersen8401eea2004-08-04 19:16:54 +00004913 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004914 e.iop->peekc = 0;
4915 e.iop->xchar = 0;
4916 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004917
Eric Andersenff9eee42001-06-29 04:57:14 +00004918 if (fn == filechar || fn == linechar)
4919 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004920 else if (fn == (int (*)(struct ioarg *)) gravechar
4921 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004922 e.iop->task = XGRAVE;
4923 else
4924 e.iop->task = XOTHER;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004925
4926 return;
Eric Andersenff9eee42001-06-29 04:57:14 +00004927}
4928
Eric Andersen8401eea2004-08-04 19:16:54 +00004929static struct io *setbase(ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004930struct io *ip;
4931{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004932 REGISTER struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004933
4934 xp = e.iobase;
4935 e.iobase = ip;
Eric Andersen8401eea2004-08-04 19:16:54 +00004936 return (xp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004937}
4938
4939/*
4940 * Input generating functions
4941 */
4942
4943/*
4944 * Produce the characters of a string, then a newline, then EOF.
4945 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004946static int nlchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004947REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004948{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004949 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004950
4951 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004952 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004953 if ((c = *ap->aword++) == 0) {
4954 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004955 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004956 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004957 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004958}
4959
4960/*
4961 * Given a list of words, produce the characters
4962 * in them, with a space after each word.
4963 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004964static int wdchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004965REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004966{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004967 REGISTER char c;
4968 REGISTER char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004969
4970 if ((wl = ap->awordlist) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004971 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004972 if (*wl != NULL) {
4973 if ((c = *(*wl)++) != 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004974 return (c & 0177);
Eric Andersenff9eee42001-06-29 04:57:14 +00004975 ap->awordlist++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004976 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00004977 }
4978 ap->awordlist = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004979 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004980}
4981
4982/*
4983 * Return the characters of a list of words,
4984 * producing a space between them.
4985 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004986static int dolchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004987REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004988{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004989 REGISTER char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004990
4991 if ((wp = *ap->awordlist++) != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004992 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4993 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004994 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004995 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004996}
4997
Eric Andersen8401eea2004-08-04 19:16:54 +00004998static int xxchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004999REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005000{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005001 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005002
5003 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00005004 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00005005 if ((c = *ap->aword++) == '\0') {
5006 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00005007 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00005008 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005009 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005010}
5011
5012/*
5013 * Produce the characters from a single word (string).
5014 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005015static int strchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005016REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005017{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005018 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005019
5020 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005021 return (0);
5022 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005023}
5024
5025/*
5026 * Produce quoted characters from a single word (string).
5027 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005028static int qstrchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005029REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005030{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005031 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005032
5033 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005034 return (0);
5035 return (c | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005036}
5037
5038/*
5039 * Return the characters from a file.
5040 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005041static int filechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005042REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005043{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005044 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005045 char c;
5046 struct iobuf *bp = ap->afbuf;
5047
5048 if (ap->afid != AFID_NOBUF) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005049 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00005050
Eric Andersen8401eea2004-08-04 19:16:54 +00005051 if (i)
5052 lseek(ap->afile, ap->afpos, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005053
Eric Andersen8401eea2004-08-04 19:16:54 +00005054 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005055
Eric Andersen8401eea2004-08-04 19:16:54 +00005056 if (i <= 0) {
5057 closef(ap->afile);
5058 return 0;
5059 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005060
Eric Andersen8401eea2004-08-04 19:16:54 +00005061 bp->id = ap->afid;
5062 bp->ebufp = (bp->bufp = bp->buf) + i;
5063 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005064
Eric Andersen8401eea2004-08-04 19:16:54 +00005065 ap->afpos++;
5066 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00005067 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005068#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00005069 if (interactive && isatty(ap->afile)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005070 static char mycommand[BUFSIZ];
5071 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00005072
Eric Andersen8401eea2004-08-04 19:16:54 +00005073 while (size == 0 || position >= size) {
5074 cmdedit_read_input(current_prompt, mycommand);
5075 size = strlen(mycommand);
5076 position = 0;
5077 }
5078 c = mycommand[position];
5079 position++;
5080 return (c);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005081 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00005082#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005083
Eric Andersenff9eee42001-06-29 04:57:14 +00005084 {
Eric Andersen7467c8d2001-07-12 20:26:32 +00005085 i = safe_read(ap->afile, &c, sizeof(c));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005086 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00005087 }
5088}
5089
5090/*
5091 * Return the characters from a here temp file.
5092 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005093static int herechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005094REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005095{
5096 char c;
5097
5098
5099 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
5100 close(ap->afile);
5101 c = 0;
5102 }
5103 return (c);
5104
5105}
5106
5107/*
5108 * Return the characters produced by a process (`...`).
5109 * Quote them if required, and remove any trailing newline characters.
5110 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005111static int gravechar(ap, iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00005112struct ioarg *ap;
5113struct io *iop;
5114{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005115 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005116
Eric Andersen8401eea2004-08-04 19:16:54 +00005117 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00005118 c = ' ';
Eric Andersen8401eea2004-08-04 19:16:54 +00005119 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005120}
5121
Eric Andersen8401eea2004-08-04 19:16:54 +00005122static int qgravechar(ap, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005123REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005124struct io *iop;
5125{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005126 REGISTER int c;
5127
5128 DBGPRINTF3(("QGRAVECHAR: enter, ap=0x%x, iop=0x%x\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00005129
5130 if (iop->xchar) {
5131 if (iop->nlcount) {
5132 iop->nlcount--;
Eric Andersen8401eea2004-08-04 19:16:54 +00005133 return ('\n' | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005134 }
5135 c = iop->xchar;
5136 iop->xchar = 0;
5137 } else if ((c = filechar(ap)) == '\n') {
5138 iop->nlcount = 1;
5139 while ((c = filechar(ap)) == '\n')
5140 iop->nlcount++;
5141 iop->xchar = c;
5142 if (c == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005143 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005144 iop->nlcount--;
5145 c = '\n';
5146 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005147 return (c != 0 ? c | QUOTE : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00005148}
5149
5150/*
5151 * Return a single command (usually the first line) from a file.
5152 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005153static int linechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005154REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005155{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005156 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005157
5158 if ((c = filechar(ap)) == '\n') {
5159 if (!multiline) {
5160 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00005161 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00005162 }
5163 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005164 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005165}
5166
Eric Andersen8401eea2004-08-04 19:16:54 +00005167static void prs(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005168REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005169{
5170 if (*s)
5171 write(2, s, strlen(s));
5172}
5173
Eric Andersen8401eea2004-08-04 19:16:54 +00005174static void prn(u)
Eric Andersenff9eee42001-06-29 04:57:14 +00005175unsigned u;
5176{
Eric Andersen737f5fb2003-03-14 16:05:59 +00005177 prs(itoa(u));
Eric Andersenff9eee42001-06-29 04:57:14 +00005178}
5179
Eric Andersen8401eea2004-08-04 19:16:54 +00005180static void closef(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005181REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005182{
5183 if (i > 2)
5184 close(i);
5185}
5186
Eric Andersen8401eea2004-08-04 19:16:54 +00005187static void closeall()
Eric Andersenff9eee42001-06-29 04:57:14 +00005188{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005189 REGISTER int u;
Eric Andersenff9eee42001-06-29 04:57:14 +00005190
Eric Andersen8401eea2004-08-04 19:16:54 +00005191 for (u = NUFILE; u < NOFILE;)
Eric Andersenff9eee42001-06-29 04:57:14 +00005192 close(u++);
5193}
5194
Eric Andersen12de6cf2004-08-04 19:19:10 +00005195
Eric Andersenff9eee42001-06-29 04:57:14 +00005196/*
5197 * remap fd into Shell's fd space
5198 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005199static int remap(fd)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005200REGISTER int fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005201{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005202 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005203 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00005204 int newfd;
5205
5206
5207 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00005208
5209 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005210 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005211 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005212
Eric Andersenff9eee42001-06-29 04:57:14 +00005213 do {
5214 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005215 newfd = dup(fd);
5216 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005217 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005218
Eric Andersen8401eea2004-08-04 19:16:54 +00005219 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005220 if (map[i])
5221 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005222
Eric Andersenff9eee42001-06-29 04:57:14 +00005223 if (fd < 0)
5224 err("too many files open in shell");
5225 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005226
Eric Andersen8401eea2004-08-04 19:16:54 +00005227 return (fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00005228}
5229
Eric Andersen8401eea2004-08-04 19:16:54 +00005230static int openpipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005231REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005232{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005233 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005234
5235 if ((i = pipe(pv)) < 0)
5236 err("can't create pipe - try again");
Eric Andersen8401eea2004-08-04 19:16:54 +00005237 return (i);
Eric Andersenff9eee42001-06-29 04:57:14 +00005238}
5239
Eric Andersen8401eea2004-08-04 19:16:54 +00005240static void closepipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005241REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005242{
5243 if (pv != NULL) {
5244 close(*pv++);
5245 close(*pv);
5246 }
5247}
5248
5249/* -------- here.c -------- */
5250
5251/*
5252 * here documents
5253 */
5254
Eric Andersen8401eea2004-08-04 19:16:54 +00005255static void markhere(s, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005256REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005257struct ioword *iop;
5258{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005259 REGISTER struct here *h, *lh;
5260
5261 DBGPRINTF7(("MARKHERE: enter, s=0x%x\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00005262
5263 h = (struct here *) space(sizeof(struct here));
5264 if (h == 0)
5265 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005266
Eric Andersenff9eee42001-06-29 04:57:14 +00005267 h->h_tag = evalstr(s, DOSUB);
5268 if (h->h_tag == 0)
5269 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005270
Eric Andersenff9eee42001-06-29 04:57:14 +00005271 h->h_iop = iop;
5272 iop->io_name = 0;
5273 h->h_next = NULL;
5274 if (inhere == 0)
5275 inhere = h;
5276 else
Eric Andersen8401eea2004-08-04 19:16:54 +00005277 for (lh = inhere; lh != NULL; lh = lh->h_next)
Eric Andersenff9eee42001-06-29 04:57:14 +00005278 if (lh->h_next == 0) {
5279 lh->h_next = h;
5280 break;
5281 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005282 iop->io_flag |= IOHERE | IOXHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005283 for (s = h->h_tag; *s; s++)
5284 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005285 iop->io_flag &= ~IOXHERE;
5286 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005287 }
5288 h->h_dosub = iop->io_flag & IOXHERE;
5289}
5290
Eric Andersen8401eea2004-08-04 19:16:54 +00005291static void gethere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005292{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005293 REGISTER struct here *h, *hp;
5294
5295 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005296
5297 /* Scan here files first leaving inhere list in place */
5298 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005299 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005300
5301 /* Make inhere list active - keep list intact for scraphere */
5302 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005303 hp->h_next = acthere;
5304 acthere = inhere;
5305 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005306 }
5307}
5308
Eric Andersen8401eea2004-08-04 19:16:54 +00005309static void readhere(name, s, ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005310char **name;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005311REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005312int ec;
5313{
5314 int tf;
5315 char tname[30] = ".msh_XXXXXX";
Eric Andersen12de6cf2004-08-04 19:19:10 +00005316 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005317 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005318 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005319 char *thenext;
5320
Eric Andersen12de6cf2004-08-04 19:19:10 +00005321 DBGPRINTF7(("READHERE: enter, name=0x%x, s=0x%x\n", name, s));
5322
Eric Andersenff9eee42001-06-29 04:57:14 +00005323 tf = mkstemp(tname);
5324 if (tf < 0)
5325 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005326
Eric Andersenff9eee42001-06-29 04:57:14 +00005327 *name = strsave(tname, areanum);
5328 if (newenv(setjmp(errpt = ev)) != 0)
5329 unlink(tname);
5330 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005331 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005332 e.iobase = e.iop;
5333 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005334 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005335#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005336 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005337#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005338 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005339#endif
5340 }
5341 thenext = myline;
5342 while ((c = my_getc(ec)) != '\n' && c) {
5343 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005344 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005345 if (thenext >= &myline[LINELIM]) {
5346 c = 0;
5347 break;
5348 }
5349 *thenext++ = c;
5350 }
5351 *thenext = 0;
5352 if (strcmp(s, myline) == 0 || c == 0)
5353 break;
5354 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005355 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005356 }
5357 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005358 prs("here document `");
5359 prs(s);
5360 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005361 }
5362 quitenv();
5363 }
5364 close(tf);
5365}
5366
5367/*
5368 * open here temp file.
5369 * if unquoted here, expand here temp file into second temp file.
5370 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005371static int herein(hname, xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005372char *hname;
5373int xdoll;
5374{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005375 REGISTER int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005376 int tf;
5377
5378#if __GNUC__
5379 /* Avoid longjmp clobbering */
5380 (void) &tf;
5381#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005382 if (hname == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00005383 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005384
5385 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5386
Eric Andersenff9eee42001-06-29 04:57:14 +00005387 hf = open(hname, 0);
5388 if (hf < 0)
5389 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005390
Eric Andersenff9eee42001-06-29 04:57:14 +00005391 if (xdoll) {
5392 char c;
5393 char tname[30] = ".msh_XXXXXX";
5394 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005395
Eric Andersenff9eee42001-06-29 04:57:14 +00005396 tf = mkstemp(tname);
5397 if (tf < 0)
5398 return (-1);
5399 if (newenv(setjmp(errpt = ev)) == 0) {
5400 PUSHIO(afile, hf, herechar);
5401 setbase(e.iop);
5402 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005403 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005404 write(tf, &c, sizeof c);
5405 }
5406 quitenv();
5407 } else
5408 unlink(tname);
5409 close(tf);
5410 tf = open(tname, 0);
5411 unlink(tname);
5412 return (tf);
5413 } else
5414 return (hf);
5415}
5416
Eric Andersen8401eea2004-08-04 19:16:54 +00005417static void scraphere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005418{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005419 REGISTER struct here *h;
5420
5421 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005422
5423 for (h = inhere; h != NULL; h = h->h_next) {
5424 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005425 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005426 }
5427 inhere = NULL;
5428}
5429
5430/* unlink here temp files before a freearea(area) */
Eric Andersen8401eea2004-08-04 19:16:54 +00005431static void freehere(area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005432int area;
5433{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005434 REGISTER struct here *h, *hl;
5435
5436 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005437
5438 hl = NULL;
5439 for (h = acthere; h != NULL; h = h->h_next)
5440 if (getarea((char *) h) >= area) {
5441 if (h->h_iop->io_name != NULL)
5442 unlink(h->h_iop->io_name);
5443 if (hl == NULL)
5444 acthere = h->h_next;
5445 else
5446 hl->h_next = h->h_next;
5447 } else
5448 hl = h;
5449}
5450
5451
5452
5453/*
5454 * Copyright (c) 1987,1997, Prentice Hall
5455 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005456 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005457 * Redistribution and use of the MINIX operating system in source and
5458 * binary forms, with or without modification, are permitted provided
5459 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005460 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005461 * Redistributions of source code must retain the above copyright
5462 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005463 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005464 * Redistributions in binary form must reproduce the above
5465 * copyright notice, this list of conditions and the following
5466 * disclaimer in the documentation and/or other materials provided
5467 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005468 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005469 * Neither the name of Prentice Hall nor the names of the software
5470 * authors or contributors may be used to endorse or promote
5471 * products derived from this software without specific prior
5472 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005473 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005474 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5475 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5476 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5477 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5478 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5479 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5480 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5481 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5482 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5483 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5484 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5485 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5486 *
5487 */