blob: 22a617095365f25c4cf65f62848d161cf85aa199 [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 Andersen12de6cf2004-08-04 19:19:10 +0000302static char **makenv(int all);
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 +0000701static int expand_dotnode(struct op *);
702struct op *scantree(struct op *);
703static struct op *dowholefile(int, int);
704
Eric Andersenff9eee42001-06-29 04:57:14 +0000705/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000706extern char **environ; /* environment pointer */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000707
Eric Andersen8401eea2004-08-04 19:16:54 +0000708static char **dolv;
709static int dolc;
710static int exstat;
711static char gflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000712static int interactive = 0; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000713static int execflg;
714static int multiline; /* \n changed to ; */
715static struct op *outtree; /* result from parser */
716static xint *failpt;
717static xint *errpt;
718static struct brkcon *brklist;
719static int isbreak;
720static struct wdblock *wdlist;
721static struct wdblock *iolist;
722static char *trap[_NSIG + 1];
723static char ourtrap[_NSIG + 1];
724static int trapset; /* trap pending */
725static int yynerrs; /* yacc */
726static char line[LINELIM];
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727
728#ifdef MSHDEBUG
729static struct var *mshdbg_var;
730#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000731static struct var *vlist; /* dictionary */
732static struct var *homedir; /* home directory */
733static struct var *prompt; /* main prompt */
734static struct var *cprompt; /* continuation prompt */
735static struct var *path; /* search path for commands */
736static struct var *shell; /* shell to interpret command files */
737static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000738
Eric Andersen8401eea2004-08-04 19:16:54 +0000739static int areanum; /* current allocation area */
740static int intr;
741static int inparse;
742static char flags['z' - 'a' + 1];
743static char *flag = flags - 'a';
Eric Andersen8401eea2004-08-04 19:16:54 +0000744static char *null = "";
745static int heedint = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +0000746static void (*qflag) (int) = SIG_IGN;
747static int startl;
748static int peeksym;
749static int nlseen;
750static int iounit = IODEFAULT;
751static YYSTYPE yylval;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000752static char *elinep = line + sizeof(line) - 5;
753
754static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
755static struct ioarg ioargstack[NPUSH];
756static struct io iostack[NPUSH];
Eric Andersen8401eea2004-08-04 19:16:54 +0000757static struct iobuf sharedbuf = { AFID_NOBUF };
758static struct iobuf mainbuf = { AFID_NOBUF };
Eric Andersenff9eee42001-06-29 04:57:14 +0000759static unsigned bufid = AFID_ID; /* buffer id counter */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000760
Eric Andersen8401eea2004-08-04 19:16:54 +0000761static struct here *inhere; /* list of hear docs while parsing */
762static struct here *acthere; /* list of active here documents */
763static struct region *areabot; /* bottom of area */
764static struct region *areatop; /* top of area */
765static struct region *areanxt; /* starting point of scan */
766static void *brktop;
767static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000768
Eric Andersen12de6cf2004-08-04 19:19:10 +0000769static struct env e = {
770 line, /* linep: char ptr */
771 iostack, /* iobase: struct io ptr */
772 iostack - 1, /* iop: struct io ptr */
773 (xint *) NULL, /* errpt: void ptr for errors? */
774 FDBASE, /* iofd: file desc */
775 (struct env *) NULL /* oenv: struct env ptr */
776};
777
778#ifdef MSHDEBUG
779void print_t(struct op *t)
780{
781 DBGPRINTF(("T: t=0x%x, type %s, words=0x%x, IOword=0x%x\n", t,
782 T_CMD_NAMES[t->type], t->words, t->ioact));
783
784 if (t->words) {
785 DBGPRINTF(("T: W1: %s", t->words[0]));
786 }
787
788 return;
789}
790
791void print_tree(struct op *head)
792{
793 if (head == NULL) {
794 DBGPRINTF(("PRINT_TREE: no tree\n"));
795 return;
796 }
797
798 DBGPRINTF(("NODE: 0x%x, left 0x%x, right 0x%x\n", head, head->left,
799 head->right));
800
801 if (head->left)
802 print_tree(head->left);
803
804 if (head->right)
805 print_tree(head->right);
806
807 return;
808}
809#endif /* MSHDEBUG */
810
Eric Andersenff9eee42001-06-29 04:57:14 +0000811
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000812#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000813static char *current_prompt;
Eric Andersenff9eee42001-06-29 04:57:14 +0000814#endif
815
Eric Andersenff9eee42001-06-29 04:57:14 +0000816/* -------- sh.c -------- */
817/*
818 * shell
819 */
820
821
Matt Kraai2d91deb2001-08-01 17:21:35 +0000822extern int msh_main(int argc, char **argv)
Eric Andersenff9eee42001-06-29 04:57:14 +0000823{
Eric Andersen12de6cf2004-08-04 19:19:10 +0000824 REGISTER int f;
825 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +0000826 int cflag;
827 char *name, **ap;
Eric Andersen8401eea2004-08-04 19:16:54 +0000828 int (*iof) (struct ioarg *);
Eric Andersenff9eee42001-06-29 04:57:14 +0000829
Eric Andersen12de6cf2004-08-04 19:19:10 +0000830 DBGPRINTF(("MSH_MAIN: argc %d, environ 0x%x\n", argc, environ));
831
Eric Andersenff9eee42001-06-29 04:57:14 +0000832 initarea();
833 if ((ap = environ) != NULL) {
834 while (*ap)
835 assign(*ap++, !COPYV);
836 for (ap = environ; *ap;)
837 export(lookup(*ap++));
838 }
839 closeall();
840 areanum = 1;
841
842 shell = lookup("SHELL");
843 if (shell->value == null)
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +0000844 setval(shell, DEFAULT_SHELL);
Eric Andersenff9eee42001-06-29 04:57:14 +0000845 export(shell);
846
847 homedir = lookup("HOME");
848 if (homedir->value == null)
849 setval(homedir, "/");
850 export(homedir);
851
Eric Andersen737f5fb2003-03-14 16:05:59 +0000852 setval(lookup("$"), putn(getpid()));
Eric Andersenff9eee42001-06-29 04:57:14 +0000853
854 path = lookup("PATH");
Eric Andersen737f5fb2003-03-14 16:05:59 +0000855 if (path->value == null) {
856 if (geteuid() == 0)
857 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
858 else
859 setval(path, "/bin:/usr/bin");
860 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000861 export(path);
862
863 ifs = lookup("IFS");
864 if (ifs->value == null)
865 setval(ifs, " \t\n");
866
Eric Andersen12de6cf2004-08-04 19:19:10 +0000867#ifdef MSHDEBUG
868 mshdbg_var = lookup("MSHDEBUG");
869 if (mshdbg_var->value == null)
870 setval(mshdbg_var, "0");
871#endif
872
873
Eric Andersenff9eee42001-06-29 04:57:14 +0000874 prompt = lookup("PS1");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000875#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000876 if (prompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000877#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000878 setval(prompt, "$ ");
879 if (geteuid() == 0) {
880 setval(prompt, "# ");
881 prompt->status &= ~EXPORT;
882 }
883 cprompt = lookup("PS2");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000884#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000885 if (cprompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000886#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000887 setval(cprompt, "> ");
888
889 iof = filechar;
890 cflag = 0;
891 name = *argv++;
892 if (--argc >= 1) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000893 if (argv[0][0] == '-' && argv[0][1] != '\0') {
894 for (s = argv[0] + 1; *s; s++)
Eric Andersenff9eee42001-06-29 04:57:14 +0000895 switch (*s) {
896 case 'c':
897 prompt->status &= ~EXPORT;
898 cprompt->status &= ~EXPORT;
899 setval(prompt, "");
900 setval(cprompt, "");
901 cflag = 1;
902 if (--argc > 0)
903 PUSHIO(aword, *++argv, iof = nlchar);
904 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000905
Eric Andersenff9eee42001-06-29 04:57:14 +0000906 case 'q':
907 qflag = SIG_DFL;
908 break;
909
910 case 's':
911 /* standard input */
912 break;
913
914 case 't':
915 prompt->status &= ~EXPORT;
916 setval(prompt, "");
917 iof = linechar;
918 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000919
Eric Andersenff9eee42001-06-29 04:57:14 +0000920 case 'i':
921 interactive++;
922 default:
Eric Andersen8401eea2004-08-04 19:16:54 +0000923 if (*s >= 'a' && *s <= 'z')
924 flag[(int) *s]++;
Eric Andersenff9eee42001-06-29 04:57:14 +0000925 }
926 } else {
927 argv--;
928 argc++;
929 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000930
Eric Andersenff9eee42001-06-29 04:57:14 +0000931 if (iof == filechar && --argc > 0) {
932 setval(prompt, "");
933 setval(cprompt, "");
934 prompt->status &= ~EXPORT;
935 cprompt->status &= ~EXPORT;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000936
937/* Shell is non-interactive, activate printf-based debug */
938#ifdef MSHDEBUG
939 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
940 if (mshdbg < 0)
941 mshdbg = 0;
942#endif
943 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
944
Eric Andersenff9eee42001-06-29 04:57:14 +0000945 if (newfile(name = *++argv))
Eric Andersen12de6cf2004-08-04 19:19:10 +0000946 exit(1); /* Exit on error */
Eric Andersenff9eee42001-06-29 04:57:14 +0000947 }
948 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000949
Eric Andersenff9eee42001-06-29 04:57:14 +0000950 setdash();
Eric Andersen12de6cf2004-08-04 19:19:10 +0000951
952 /* This won't be true if PUSHIO has been called, say from newfile() above */
Eric Andersenff9eee42001-06-29 04:57:14 +0000953 if (e.iop < iostack) {
954 PUSHIO(afile, 0, iof);
Eric Andersen1c039232001-07-07 00:05:55 +0000955 if (isatty(0) && isatty(1) && !cflag) {
Eric Andersenff9eee42001-06-29 04:57:14 +0000956 interactive++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000957#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen12de6cf2004-08-04 19:19:10 +0000958#ifdef MSHDEBUG
959 printf("\n\n" BB_BANNER " Built-in shell (msh with debug)\n");
960#else
Eric Andersen8401eea2004-08-04 19:16:54 +0000961 printf("\n\n" BB_BANNER " Built-in shell (msh)\n");
Eric Andersen12de6cf2004-08-04 19:19:10 +0000962#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000963 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +0000964#endif
Eric Andersen1c039232001-07-07 00:05:55 +0000965 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000966 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000967
Eric Andersenff9eee42001-06-29 04:57:14 +0000968 signal(SIGQUIT, qflag);
969 if (name && name[0] == '-') {
970 interactive++;
971 if ((f = open(".profile", 0)) >= 0)
972 next(remap(f));
973 if ((f = open("/etc/profile", 0)) >= 0)
974 next(remap(f));
975 }
976 if (interactive)
977 signal(SIGTERM, sig);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000978
Eric Andersenff9eee42001-06-29 04:57:14 +0000979 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
980 signal(SIGINT, onintr);
981 dolv = argv;
982 dolc = argc;
983 dolv[0] = name;
984 if (dolc > 1) {
985 for (ap = ++argv; --argc > 0;) {
986 if (assign(*ap = *argv++, !COPYV)) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000987 dolc--; /* keyword */
Eric Andersenff9eee42001-06-29 04:57:14 +0000988 } else {
989 ap++;
990 }
991 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000992 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000993 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
994
Eric Andersen12de6cf2004-08-04 19:19:10 +0000995 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop 0x%x, iostack 0x%x\n", interactive, e.iop, iostack));
996
Eric Andersenff9eee42001-06-29 04:57:14 +0000997 for (;;) {
998 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000999#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00001000 current_prompt = prompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00001001#else
1002 prs(prompt->value);
1003#endif
1004 }
1005 onecommand();
Eric Andersen1c315012002-04-26 23:40:09 +00001006 /* Ensure that getenv("PATH") stays current */
1007 setenv("PATH", path->value, 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001008 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001009
1010 DBGPRINTF(("MSH_MAIN: returning.\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001011}
1012
Eric Andersen8401eea2004-08-04 19:16:54 +00001013static void setdash()
Eric Andersenff9eee42001-06-29 04:57:14 +00001014{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001015 REGISTER char *cp;
1016 REGISTER int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001017 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001018
1019 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001020 for (c = 'a'; c <= 'z'; c++)
1021 if (flag[(int) c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001022 *cp++ = c;
1023 *cp = 0;
1024 setval(lookup("-"), m);
1025}
1026
Eric Andersen8401eea2004-08-04 19:16:54 +00001027static int newfile(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001028REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001029{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001030 REGISTER int f;
1031
1032 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001033
1034 if (strcmp(s, "-") != 0) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001035 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001036 f = open(s, 0);
1037 if (f < 0) {
1038 prs(s);
1039 err(": cannot open");
Eric Andersen8401eea2004-08-04 19:16:54 +00001040 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001041 }
1042 } else
1043 f = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001044
Eric Andersenff9eee42001-06-29 04:57:14 +00001045 next(remap(f));
Eric Andersen8401eea2004-08-04 19:16:54 +00001046 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001047}
1048
Eric Andersen12de6cf2004-08-04 19:19:10 +00001049
1050static int expand_dotnode(node)
1051struct op *node;
1052{
1053 struct op *outtree_save = outtree;
1054
1055 node->type = TDOT;
1056 newfile(node->words[1]);
1057
1058 node->left = dowholefile(TDOT, 0);
1059
1060 node->right = NULL;
1061
1062 outtree = outtree_save;
1063
1064 return (1);
1065}
1066
1067struct op *scantree(head)
1068struct op *head;
1069{
1070 struct op *dotnode;
1071
1072 if (head == NULL)
1073 return (NULL);
1074
1075 if (head->left != NULL) {
1076 dotnode = scantree(head->left);
1077 if (dotnode)
1078 return (dotnode);
1079 }
1080
1081 if (head->right != NULL) {
1082 dotnode = scantree(head->right);
1083 if (dotnode)
1084 return (dotnode);
1085 }
1086
1087 if (head->words == NULL)
1088 return (NULL);
1089
1090 DBGPRINTF5(("SCANTREE: checking node 0x%x\n", head));
1091
1092 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
1093 DBGPRINTF5(("SCANTREE: dot found in node 0x%x\n", head));
1094 return (head);
1095 }
1096
1097 return (NULL);
1098}
1099
1100
Eric Andersen8401eea2004-08-04 19:16:54 +00001101static void onecommand()
Eric Andersenff9eee42001-06-29 04:57:14 +00001102{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001103 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001104 jmp_buf m1;
1105
Eric Andersen12de6cf2004-08-04 19:19:10 +00001106 DBGPRINTF(("ONECOMMAND: enter, outtree=0x%x\n", outtree));
1107
Eric Andersenff9eee42001-06-29 04:57:14 +00001108 while (e.oenv)
1109 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001110
Eric Andersenff9eee42001-06-29 04:57:14 +00001111 areanum = 1;
1112 freehere(areanum);
1113 freearea(areanum);
1114 garbage();
1115 wdlist = 0;
1116 iolist = 0;
1117 e.errpt = 0;
1118 e.linep = line;
1119 yynerrs = 0;
1120 multiline = 0;
1121 inparse = 1;
1122 intr = 0;
1123 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001124
Eric Andersen8401eea2004-08-04 19:16:54 +00001125 setjmp(failpt = m1); /* Bruce Evans' fix */
Eric Andersenff9eee42001-06-29 04:57:14 +00001126 if (setjmp(failpt = m1) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001127
1128 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1129
Eric Andersenff9eee42001-06-29 04:57:14 +00001130 while (e.oenv)
1131 quitenv();
1132 scraphere();
1133 if (!interactive && intr)
1134 leave();
1135 inparse = 0;
1136 intr = 0;
1137 return;
1138 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001139
Eric Andersenff9eee42001-06-29 04:57:14 +00001140 inparse = 0;
1141 brklist = 0;
1142 intr = 0;
1143 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001144
1145 if (!flag['n']) {
1146 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=0x%x\n",
1147 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001148 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001149 }
1150
Eric Andersenff9eee42001-06-29 04:57:14 +00001151 if (!interactive && intr) {
1152 execflg = 0;
1153 leave();
1154 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001155
Eric Andersenff9eee42001-06-29 04:57:14 +00001156 if ((i = trapset) != 0) {
1157 trapset = 0;
1158 runtrap(i);
1159 }
1160}
1161
Eric Andersen8401eea2004-08-04 19:16:54 +00001162static void fail()
Eric Andersenff9eee42001-06-29 04:57:14 +00001163{
1164 longjmp(failpt, 1);
1165 /* NOTREACHED */
1166}
1167
Eric Andersen8401eea2004-08-04 19:16:54 +00001168static void leave()
Eric Andersenff9eee42001-06-29 04:57:14 +00001169{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001170 DBGPRINTF(("LEAVE: leave called!\n"));
1171
Eric Andersenff9eee42001-06-29 04:57:14 +00001172 if (execflg)
1173 fail();
1174 scraphere();
1175 freehere(1);
1176 runtrap(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001177 _exit(exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00001178 /* NOTREACHED */
1179}
1180
Eric Andersen8401eea2004-08-04 19:16:54 +00001181static void warn(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001182REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001183{
Eric Andersen8401eea2004-08-04 19:16:54 +00001184 if (*s) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001185 prs(s);
1186 exstat = -1;
1187 }
1188 prs("\n");
1189 if (flag['e'])
1190 leave();
1191}
1192
Eric Andersen8401eea2004-08-04 19:16:54 +00001193static void err(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001194char *s;
1195{
1196 warn(s);
1197 if (flag['n'])
1198 return;
1199 if (!interactive)
1200 leave();
1201 if (e.errpt)
1202 longjmp(e.errpt, 1);
1203 closeall();
1204 e.iop = e.iobase = iostack;
1205}
1206
Eric Andersen8401eea2004-08-04 19:16:54 +00001207static int newenv(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001208int f;
1209{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001210 REGISTER struct env *ep;
1211
1212 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001213
1214 if (f) {
1215 quitenv();
Eric Andersen8401eea2004-08-04 19:16:54 +00001216 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001217 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001218
Eric Andersenff9eee42001-06-29 04:57:14 +00001219 ep = (struct env *) space(sizeof(*ep));
1220 if (ep == NULL) {
1221 while (e.oenv)
1222 quitenv();
1223 fail();
1224 }
1225 *ep = e;
1226 e.oenv = ep;
1227 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001228
Eric Andersen8401eea2004-08-04 19:16:54 +00001229 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001230}
1231
Eric Andersen8401eea2004-08-04 19:16:54 +00001232static void quitenv()
Eric Andersenff9eee42001-06-29 04:57:14 +00001233{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001234 REGISTER struct env *ep;
1235 REGISTER int fd;
1236
1237 DBGPRINTF(("QUITENV: e.oenv=0x%x\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001238
1239 if ((ep = e.oenv) != NULL) {
1240 fd = e.iofd;
1241 e = *ep;
1242 /* should close `'d files */
1243 DELETE(ep);
1244 while (--fd >= e.iofd)
1245 close(fd);
1246 }
1247}
1248
1249/*
1250 * Is any character from s1 in s2?
1251 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001252static int anys(s1, s2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001253REGISTER char *s1, *s2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001254{
1255 while (*s1)
1256 if (any(*s1++, s2))
Eric Andersen8401eea2004-08-04 19:16:54 +00001257 return (1);
1258 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001259}
1260
1261/*
1262 * Is character c in s?
1263 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001264static int any(c, s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001265REGISTER int c;
1266REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001267{
1268 while (*s)
1269 if (*s++ == c)
Eric Andersen8401eea2004-08-04 19:16:54 +00001270 return (1);
1271 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001272}
1273
Eric Andersen8401eea2004-08-04 19:16:54 +00001274static char *putn(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001275REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001276{
Eric Andersen8401eea2004-08-04 19:16:54 +00001277 return (itoa(n));
Eric Andersenff9eee42001-06-29 04:57:14 +00001278}
1279
Eric Andersen8401eea2004-08-04 19:16:54 +00001280static char *itoa(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001281REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001282{
Eric Andersenff9eee42001-06-29 04:57:14 +00001283 static char s[20];
Eric Andersen8401eea2004-08-04 19:16:54 +00001284
Eric Andersen737f5fb2003-03-14 16:05:59 +00001285 snprintf(s, sizeof(s), "%u", n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001286 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001287}
1288
Eric Andersen12de6cf2004-08-04 19:19:10 +00001289
Eric Andersen8401eea2004-08-04 19:16:54 +00001290static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001291{
1292 PUSHIO(afile, f, filechar);
1293}
1294
Eric Andersen8401eea2004-08-04 19:16:54 +00001295static void onintr(s)
1296int s; /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001297{
1298 signal(SIGINT, onintr);
1299 intr = 1;
1300 if (interactive) {
1301 if (inparse) {
1302 prs("\n");
1303 fail();
1304 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001305 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001306 execflg = 0;
1307 leave();
1308 }
1309}
1310
Eric Andersen8401eea2004-08-04 19:16:54 +00001311static char *space(n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001312int n;
1313{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001314 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001315
1316 if ((cp = getcell(n)) == 0)
1317 err("out of string space");
Eric Andersen8401eea2004-08-04 19:16:54 +00001318 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001319}
1320
Eric Andersen8401eea2004-08-04 19:16:54 +00001321static char *strsave(s, a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001323int a;
1324{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001325 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001326
Eric Andersen8401eea2004-08-04 19:16:54 +00001327 if ((cp = space(strlen(s) + 1)) != NULL) {
1328 setarea((char *) cp, a);
1329 for (xp = cp; (*xp++ = *s++) != '\0';);
1330 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001331 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001332 return ("");
Eric Andersenff9eee42001-06-29 04:57:14 +00001333}
1334
1335/*
1336 * trap handling
1337 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001338static void sig(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001339REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001340{
1341 trapset = i;
1342 signal(i, sig);
1343}
1344
1345static void runtrap(i)
1346int i;
1347{
1348 char *trapstr;
1349
1350 if ((trapstr = trap[i]) == NULL)
1351 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352
Eric Andersenff9eee42001-06-29 04:57:14 +00001353 if (i == 0)
1354 trap[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001355
Eric Andersenff9eee42001-06-29 04:57:14 +00001356 RUN(aword, trapstr, nlchar);
1357}
1358
1359/* -------- var.c -------- */
1360
1361/*
1362 * Find the given name in the dictionary
1363 * and return its value. If the name was
1364 * not previously there, enter it now and
1365 * return a null value.
1366 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001367static struct var *lookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001368REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00001369{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001370 REGISTER struct var *vp;
1371 REGISTER char *cp;
1372 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001373 static struct var dummy;
1374
1375 if (isdigit(*n)) {
1376 dummy.name = n;
1377 for (c = 0; isdigit(*n) && c < 1000; n++)
Eric Andersen8401eea2004-08-04 19:16:54 +00001378 c = c * 10 + *n - '0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001379 dummy.status = RONLY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001380 dummy.value = c <= dolc ? dolv[c] : null;
1381 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001382 }
1383 for (vp = vlist; vp; vp = vp->next)
1384 if (eqname(vp->name, n))
Eric Andersen8401eea2004-08-04 19:16:54 +00001385 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001386 cp = findeq(n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001387 vp = (struct var *) space(sizeof(*vp));
1388 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001389 dummy.name = dummy.value = "";
Eric Andersen8401eea2004-08-04 19:16:54 +00001390 return (&dummy);
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001392 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001393 if (*cp == 0)
1394 *cp = '=';
1395 *++cp = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00001396 setarea((char *) vp, 0);
1397 setarea((char *) vp->name, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001398 vp->value = null;
1399 vp->next = vlist;
1400 vp->status = GETCELL;
1401 vlist = vp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001402 return (vp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001403}
1404
1405/*
1406 * give variable at `vp' the value `val'.
1407 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001408static void setval(vp, val)
Eric Andersenff9eee42001-06-29 04:57:14 +00001409struct var *vp;
1410char *val;
1411{
Eric Andersen8401eea2004-08-04 19:16:54 +00001412 nameval(vp, val, (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001413}
1414
1415/*
1416 * if name is not NULL, it must be
1417 * a prefix of the space `val',
1418 * and end with `='.
1419 * this is all so that exporting
1420 * values is reasonably painless.
1421 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001422static void nameval(vp, val, name)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001423REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001424char *val, *name;
1425{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001426 REGISTER char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001427 char *nv;
1428 int fl;
1429
1430 if (vp->status & RONLY) {
1431 for (xp = vp->name; *xp && *xp != '=';)
1432 putc(*xp++, stderr);
1433 err(" is read-only");
1434 return;
1435 }
1436 fl = 0;
1437 if (name == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001438 xp = space(strlen(vp->name) + strlen(val) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00001439 if (xp == 0)
1440 return;
1441 /* make string: name=value */
Eric Andersen8401eea2004-08-04 19:16:54 +00001442 setarea((char *) xp, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001443 name = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001444 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001445 if (*xp++ == 0)
1446 xp[-1] = '=';
1447 nv = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001448 for (cp = val; (*xp++ = *cp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00001449 val = nv;
1450 fl = GETCELL;
1451 }
1452 if (vp->status & GETCELL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001453 freecell(vp->name); /* form new string `name=value' */
Eric Andersenff9eee42001-06-29 04:57:14 +00001454 vp->name = name;
1455 vp->value = val;
1456 vp->status |= fl;
1457}
1458
Eric Andersen8401eea2004-08-04 19:16:54 +00001459static void export(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001460struct var *vp;
1461{
1462 vp->status |= EXPORT;
1463}
1464
Eric Andersen8401eea2004-08-04 19:16:54 +00001465static void ronly(vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001466struct var *vp;
1467{
Matt Kraai69edfec2001-08-06 14:14:18 +00001468 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
Eric Andersenff9eee42001-06-29 04:57:14 +00001469 vp->status |= RONLY;
1470}
1471
Eric Andersen8401eea2004-08-04 19:16:54 +00001472static int isassign(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001473REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001474{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001475 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1476
Eric Andersen8401eea2004-08-04 19:16:54 +00001477 if (!isalpha((int) *s) && *s != '_')
1478 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001479 for (; *s != '='; s++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001480 if (*s == 0 || (!isalnum(*s) && *s != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001481 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001482
Eric Andersen8401eea2004-08-04 19:16:54 +00001483 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001484}
1485
Eric Andersen8401eea2004-08-04 19:16:54 +00001486static int assign(s, cf)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001487REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00001488int cf;
1489{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001490 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001491 struct var *vp;
1492
Eric Andersen12de6cf2004-08-04 19:19:10 +00001493 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1494
Matt Kraai69edfec2001-08-06 14:14:18 +00001495 if (!isalpha(*s) && *s != '_')
Eric Andersen8401eea2004-08-04 19:16:54 +00001496 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001497 for (cp = s; *cp != '='; cp++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001498 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
Eric Andersen8401eea2004-08-04 19:16:54 +00001499 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001500 vp = lookup(s);
Eric Andersen8401eea2004-08-04 19:16:54 +00001501 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001502 if (cf != COPYV)
1503 vp->status &= ~GETCELL;
Eric Andersen8401eea2004-08-04 19:16:54 +00001504 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001505}
1506
Eric Andersen8401eea2004-08-04 19:16:54 +00001507static int checkname(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001508REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001509{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001510 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1511
Eric Andersen8401eea2004-08-04 19:16:54 +00001512 if (!isalpha(*cp++) && *(cp - 1) != '_')
1513 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001514 while (*cp)
Eric Andersen8401eea2004-08-04 19:16:54 +00001515 if (!isalnum(*cp++) && *(cp - 1) != '_')
1516 return (0);
1517 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001518}
1519
Eric Andersen8401eea2004-08-04 19:16:54 +00001520static void putvlist(f, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001521REGISTER int f, out;
Eric Andersenff9eee42001-06-29 04:57:14 +00001522{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001523 REGISTER struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001524
1525 for (vp = vlist; vp; vp = vp->next)
Matt Kraai69edfec2001-08-06 14:14:18 +00001526 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001527 if (vp->status & EXPORT)
1528 write(out, "export ", 7);
1529 if (vp->status & RONLY)
1530 write(out, "readonly ", 9);
Eric Andersen8401eea2004-08-04 19:16:54 +00001531 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
Eric Andersenff9eee42001-06-29 04:57:14 +00001532 write(out, "\n", 1);
1533 }
1534}
1535
Eric Andersen8401eea2004-08-04 19:16:54 +00001536static int eqname(n1, n2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001537REGISTER char *n1, *n2;
Eric Andersenff9eee42001-06-29 04:57:14 +00001538{
1539 for (; *n1 != '=' && *n1 != 0; n1++)
1540 if (*n2++ != *n1)
Eric Andersen8401eea2004-08-04 19:16:54 +00001541 return (0);
1542 return (*n2 == 0 || *n2 == '=');
Eric Andersenff9eee42001-06-29 04:57:14 +00001543}
1544
Eric Andersen8401eea2004-08-04 19:16:54 +00001545static char *findeq(cp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001546REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001547{
1548 while (*cp != '\0' && *cp != '=')
1549 cp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00001550 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00001551}
1552
1553/* -------- gmatch.c -------- */
1554/*
1555 * int gmatch(string, pattern)
1556 * char *string, *pattern;
1557 *
1558 * Match a pattern as in sh(1).
1559 */
1560
1561#define CMASK 0377
1562#define QUOTE 0200
1563#define QMASK (CMASK&~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001564#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001565
Eric Andersen8401eea2004-08-04 19:16:54 +00001566static int gmatch(s, p)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001567REGISTER char *s, *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001568{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001569 REGISTER int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001570
1571 if (s == NULL || p == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001572 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001573 while ((pc = *p++ & CMASK) != '\0') {
1574 sc = *s++ & QMASK;
1575 switch (pc) {
1576 case '[':
1577 if ((p = cclass(p, sc)) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001578 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001579 break;
1580
1581 case '?':
1582 if (sc == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00001583 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001584 break;
1585
1586 case '*':
1587 s--;
1588 do {
1589 if (*p == '\0' || gmatch(s, p))
Eric Andersen8401eea2004-08-04 19:16:54 +00001590 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001591 } while (*s++ != '\0');
Eric Andersen8401eea2004-08-04 19:16:54 +00001592 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001593
1594 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001595 if (sc != (pc & ~QUOTE))
1596 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001597 }
1598 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001599 return (*s == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001600}
1601
Eric Andersen8401eea2004-08-04 19:16:54 +00001602static char *cclass(p, sub)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001603REGISTER char *p;
1604REGISTER int sub;
Eric Andersenff9eee42001-06-29 04:57:14 +00001605{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606 REGISTER int c, d, not, found;
Eric Andersenff9eee42001-06-29 04:57:14 +00001607
1608 if ((not = *p == NOT) != 0)
1609 p++;
1610 found = not;
1611 do {
1612 if (*p == '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00001613 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001614 c = *p & CMASK;
1615 if (p[1] == '-' && p[2] != ']') {
1616 d = p[2] & CMASK;
1617 p++;
1618 } else
1619 d = c;
1620 if (c == sub || (c <= sub && sub <= d))
1621 found = !not;
1622 } while (*++p != ']');
Eric Andersen8401eea2004-08-04 19:16:54 +00001623 return (found ? p + 1 : (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001624}
1625
1626
1627/* -------- area.c -------- */
1628
1629/*
1630 * All memory between (char *)areabot and (char *)(areatop+1) is
1631 * exclusively administered by the area management routines.
1632 * It is assumed that sbrk() and brk() manipulate the high end.
1633 */
1634
1635#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1636
Eric Andersen8401eea2004-08-04 19:16:54 +00001637static void initarea()
Eric Andersenff9eee42001-06-29 04:57:14 +00001638{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001639 brkaddr = malloc(AREASIZE);
1640 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001641
Eric Andersen8401eea2004-08-04 19:16:54 +00001642 while ((int) sbrk(0) & ALIGN)
Eric Andersenff9eee42001-06-29 04:57:14 +00001643 sbrk(1);
Eric Andersen8401eea2004-08-04 19:16:54 +00001644 areabot = (struct region *) sbrk(REGSIZE);
Eric Andersenff9eee42001-06-29 04:57:14 +00001645
1646 areabot->next = areabot;
1647 areabot->area = BUSY;
1648 areatop = areabot;
1649 areanxt = areabot;
1650}
1651
Eric Andersen8401eea2004-08-04 19:16:54 +00001652char *getcell(nbytes)
Eric Andersenff9eee42001-06-29 04:57:14 +00001653unsigned nbytes;
1654{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001655 REGISTER int nregio;
1656 REGISTER struct region *p, *q;
1657 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001658
1659 if (nbytes == 0) {
1660 puts("getcell(0)");
1661 abort();
Eric Andersen8401eea2004-08-04 19:16:54 +00001662 }
1663 /* silly and defeats the algorithm */
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 /*
1665 * round upwards and add administration area
1666 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001667 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001668 for (p = areanxt;;) {
1669 if (p->area > areanum) {
1670 /*
1671 * merge free cells
1672 */
1673 while ((q = p->next)->area > areanum && q != areanxt)
1674 p->next = q->next;
1675 /*
1676 * exit loop if cell big enough
1677 */
1678 if (q >= p + nregio)
1679 goto found;
1680 }
1681 p = p->next;
1682 if (p == areanxt)
1683 break;
1684 }
1685 i = nregio >= GROWBY ? nregio : GROWBY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001686 p = (struct region *) sbrk(i * REGSIZE);
1687 if (p == (struct region *) -1)
1688 return ((char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001689 p--;
1690 if (p != areatop) {
1691 puts("not contig");
Eric Andersen8401eea2004-08-04 19:16:54 +00001692 abort(); /* allocated areas are contiguous */
Eric Andersenff9eee42001-06-29 04:57:14 +00001693 }
1694 q = p + i;
1695 p->next = q;
1696 p->area = FREE;
1697 q->next = areabot;
1698 q->area = BUSY;
1699 areatop = q;
Eric Andersen8401eea2004-08-04 19:16:54 +00001700 found:
Eric Andersenff9eee42001-06-29 04:57:14 +00001701 /*
1702 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1703 */
1704 areanxt = p + nregio;
1705 if (areanxt < q) {
1706 /*
1707 * split into requested area and rest
1708 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001709 if (areanxt + 1 > q) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001710 puts("OOM");
Eric Andersen8401eea2004-08-04 19:16:54 +00001711 abort(); /* insufficient space left for admin */
Eric Andersenff9eee42001-06-29 04:57:14 +00001712 }
1713 areanxt->next = q;
1714 areanxt->area = FREE;
1715 p->next = areanxt;
1716 }
1717 p->area = areanum;
Eric Andersen8401eea2004-08-04 19:16:54 +00001718 return ((char *) (p + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001719}
1720
Eric Andersen8401eea2004-08-04 19:16:54 +00001721static void freecell(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001722char *cp;
1723{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001724 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001725
Eric Andersen8401eea2004-08-04 19:16:54 +00001726 if ((p = (struct region *) cp) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001727 p--;
1728 if (p < areanxt)
1729 areanxt = p;
1730 p->area = FREE;
1731 }
1732}
1733
Eric Andersen8401eea2004-08-04 19:16:54 +00001734static void freearea(a)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001735REGISTER int a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001736{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001737 REGISTER struct region *p, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001738
1739 top = areatop;
1740 for (p = areabot; p != top; p = p->next)
1741 if (p->area >= a)
1742 p->area = FREE;
1743}
1744
Eric Andersen8401eea2004-08-04 19:16:54 +00001745static void setarea(cp, a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001746char *cp;
1747int a;
1748{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001749 REGISTER struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001750
Eric Andersen8401eea2004-08-04 19:16:54 +00001751 if ((p = (struct region *) cp) != NULL)
1752 (p - 1)->area = a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001753}
1754
Eric Andersen8401eea2004-08-04 19:16:54 +00001755int getarea(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001756char *cp;
1757{
Eric Andersen8401eea2004-08-04 19:16:54 +00001758 return ((struct region *) cp - 1)->area;
Eric Andersenff9eee42001-06-29 04:57:14 +00001759}
1760
Eric Andersen8401eea2004-08-04 19:16:54 +00001761static void garbage()
Eric Andersenff9eee42001-06-29 04:57:14 +00001762{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001763 REGISTER struct region *p, *q, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001764
1765 top = areatop;
1766 for (p = areabot; p != top; p = p->next) {
1767 if (p->area > areanum) {
1768 while ((q = p->next)->area > areanum)
1769 p->next = q->next;
1770 areanxt = p;
1771 }
1772 }
1773#ifdef SHRINKBY
1774 if (areatop >= q + SHRINKBY && q->area > areanum) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001775 brk((char *) (q + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 q->next = areabot;
1777 q->area = BUSY;
1778 areatop = q;
1779 }
1780#endif
1781}
1782
1783/* -------- csyn.c -------- */
1784/*
1785 * shell: syntax (C version)
1786 */
1787
Eric Andersen8401eea2004-08-04 19:16:54 +00001788int yyparse()
Eric Andersenff9eee42001-06-29 04:57:14 +00001789{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001790 DBGPRINTF7(("YYPARSE: enter...\n"));
1791
Eric Andersen8401eea2004-08-04 19:16:54 +00001792 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001793 peeksym = 0;
1794 yynerrs = 0;
1795 outtree = c_list();
1796 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001797 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001798}
1799
Eric Andersen8401eea2004-08-04 19:16:54 +00001800static struct op *pipeline(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001801int cf;
1802{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001803 REGISTER struct op *t, *p;
1804 REGISTER int c;
1805
1806 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001807
1808 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001809
1810 DBGPRINTF9(("PIPELINE: t=0x%x\n", t));
1811
Eric Andersenff9eee42001-06-29 04:57:14 +00001812 if (t != NULL) {
1813 while ((c = yylex(0)) == '|') {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001814 if ((p = command(CONTIN)) == NULL) {
1815 DBGPRINTF8(("PIPELINE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001816 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001817 }
1818
Eric Andersenff9eee42001-06-29 04:57:14 +00001819 if (t->type != TPAREN && t->type != TCOM) {
1820 /* shell statement */
1821 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1822 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001823
Eric Andersenff9eee42001-06-29 04:57:14 +00001824 t = block(TPIPE, t, p, NOWORDS);
1825 }
1826 peeksym = c;
1827 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001828
1829 DBGPRINTF7(("PIPELINE: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001830 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001831}
1832
Eric Andersen8401eea2004-08-04 19:16:54 +00001833static struct op *andor()
Eric Andersenff9eee42001-06-29 04:57:14 +00001834{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001835 REGISTER struct op *t, *p;
1836 REGISTER int c;
1837
1838 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001839
1840 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001841
1842 DBGPRINTF9(("ANDOR: t=0x%x\n", t));
1843
Eric Andersenff9eee42001-06-29 04:57:14 +00001844 if (t != NULL) {
1845 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001846 if ((p = pipeline(CONTIN)) == NULL) {
1847 DBGPRINTF8(("ANDOR: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001848 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001849 }
1850
Eric Andersen8401eea2004-08-04 19:16:54 +00001851 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001852 } /* WHILE */
1853
Eric Andersenff9eee42001-06-29 04:57:14 +00001854 peeksym = c;
1855 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001856
1857 DBGPRINTF7(("ANDOR: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001858 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001859}
1860
Eric Andersen8401eea2004-08-04 19:16:54 +00001861static struct op *c_list()
Eric Andersenff9eee42001-06-29 04:57:14 +00001862{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863 REGISTER struct op *t, *p;
1864 REGISTER int c;
1865
1866 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001867
1868 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001869
Eric Andersenff9eee42001-06-29 04:57:14 +00001870 if (t != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001871 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001872 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
Eric Andersen8401eea2004-08-04 19:16:54 +00001874 while ((c = yylex(0)) == ';' || c == '&'
1875 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001876
Eric Andersenff9eee42001-06-29 04:57:14 +00001877 if ((p = andor()) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001878 return (t);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001879
Eric Andersen8401eea2004-08-04 19:16:54 +00001880 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001881 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001882
Eric Andersenff9eee42001-06-29 04:57:14 +00001883 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001884 } /* WHILE */
1885
Eric Andersenff9eee42001-06-29 04:57:14 +00001886 peeksym = c;
1887 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001888 /* IF */
1889 DBGPRINTF7(("C_LIST: returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00001890 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001891}
1892
Eric Andersen8401eea2004-08-04 19:16:54 +00001893static int synio(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001894int cf;
1895{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001896 REGISTER struct ioword *iop;
1897 REGISTER int i;
1898 REGISTER int c;
1899
1900 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001901
1902 if ((c = yylex(cf)) != '<' && c != '>') {
1903 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001904 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001906
Eric Andersenff9eee42001-06-29 04:57:14 +00001907 i = yylval.i;
1908 musthave(WORD, 0);
1909 iop = io(iounit, i, yylval.cp);
1910 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001911
Eric Andersenff9eee42001-06-29 04:57:14 +00001912 if (i & IOHERE)
1913 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001914
1915 DBGPRINTF7(("SYNIO: returning 1\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00001916 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001917}
1918
Eric Andersen8401eea2004-08-04 19:16:54 +00001919static void musthave(c, cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001920int c, cf;
1921{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001922 if ((peeksym = yylex(cf)) != c) {
1923 DBGPRINTF7(("MUSTHAVE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001924 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001925 }
1926
Eric Andersenff9eee42001-06-29 04:57:14 +00001927 peeksym = 0;
1928}
1929
Eric Andersen8401eea2004-08-04 19:16:54 +00001930static struct op *simple()
Eric Andersenff9eee42001-06-29 04:57:14 +00001931{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001932 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001933
1934 t = NULL;
1935 for (;;) {
1936 switch (peeksym = yylex(0)) {
1937 case '<':
1938 case '>':
1939 (void) synio(0);
1940 break;
1941
1942 case WORD:
1943 if (t == NULL) {
1944 t = newtp();
1945 t->type = TCOM;
1946 }
1947 peeksym = 0;
1948 word(yylval.cp);
1949 break;
1950
1951 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001952 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00001953 }
1954 }
1955}
1956
Eric Andersen8401eea2004-08-04 19:16:54 +00001957static struct op *nested(type, mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001958int type, mark;
1959{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001960 REGISTER struct op *t;
1961
1962 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001963
1964 multiline++;
1965 t = c_list();
1966 musthave(mark, 0);
1967 multiline--;
Eric Andersen8401eea2004-08-04 19:16:54 +00001968 return (block(type, t, NOBLOCK, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00001969}
1970
Eric Andersen8401eea2004-08-04 19:16:54 +00001971static struct op *command(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001972int cf;
1973{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001974 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001975 struct wdblock *iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001976 REGISTER int c;
1977
1978 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001979
1980 iosave = iolist;
1981 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001982
Eric Andersenff9eee42001-06-29 04:57:14 +00001983 if (multiline)
1984 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001985
Eric Andersenff9eee42001-06-29 04:57:14 +00001986 while (synio(cf))
1987 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001988
1989 c = yylex(cf);
1990
1991 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001992 default:
1993 peeksym = c;
1994 if ((t = simple()) == NULL) {
1995 if (iolist == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001996 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001997 t = newtp();
1998 t->type = TCOM;
1999 }
2000 break;
2001
2002 case '(':
2003 t = nested(TPAREN, ')');
2004 break;
2005
2006 case '{':
2007 t = nested(TBRACE, '}');
2008 break;
2009
2010 case FOR:
2011 t = newtp();
2012 t->type = TFOR;
2013 musthave(WORD, 0);
2014 startl = 1;
2015 t->str = yylval.cp;
2016 multiline++;
2017 t->words = wordlist();
2018 if ((c = yylex(0)) != '\n' && c != ';')
2019 peeksym = c;
2020 t->left = dogroup(0);
2021 multiline--;
2022 break;
2023
2024 case WHILE:
2025 case UNTIL:
2026 multiline++;
2027 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00002028 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002029 t->left = c_list();
2030 t->right = dogroup(1);
2031 t->words = NULL;
2032 multiline--;
2033 break;
2034
2035 case CASE:
2036 t = newtp();
2037 t->type = TCASE;
2038 musthave(WORD, 0);
2039 t->str = yylval.cp;
2040 startl++;
2041 multiline++;
2042 musthave(IN, CONTIN);
2043 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002044
Eric Andersenff9eee42001-06-29 04:57:14 +00002045 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002046
Eric Andersenff9eee42001-06-29 04:57:14 +00002047 musthave(ESAC, 0);
2048 multiline--;
2049 break;
2050
2051 case IF:
2052 multiline++;
2053 t = newtp();
2054 t->type = TIF;
2055 t->left = c_list();
2056 t->right = thenpart();
2057 musthave(FI, 0);
2058 multiline--;
2059 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002060
2061 case DOT:
2062 t = newtp();
2063 t->type = TDOT;
2064
2065 musthave(WORD, 0); /* gets name of file */
2066 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
2067
2068 word(yylval.cp); /* add word to wdlist */
2069 word(NOWORD); /* terminate wdlist */
2070 t->words = copyw(); /* dup wdlist */
2071 break;
2072
Eric Andersenff9eee42001-06-29 04:57:14 +00002073 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002074
Eric Andersen8401eea2004-08-04 19:16:54 +00002075 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002076
Eric Andersenff9eee42001-06-29 04:57:14 +00002077 t = namelist(t);
2078 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002079
2080 DBGPRINTF(("COMMAND: returning 0x%x\n", t));
2081
2082 return (t);
2083}
2084
2085static struct op *dowholefile(type, mark)
2086int type;
2087int mark;
2088{
2089 REGISTER struct op *t;
2090
2091 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
2092
2093 multiline++;
2094 t = c_list();
2095 multiline--;
2096 t = block(type, t, NOBLOCK, NOWORDS);
2097 DBGPRINTF(("DOWHOLEFILE: return t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002098 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002099}
2100
Eric Andersen8401eea2004-08-04 19:16:54 +00002101static struct op *dogroup(onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00002102int onlydone;
2103{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002104 REGISTER int c;
2105 REGISTER struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002106
2107 c = yylex(CONTIN);
2108 if (c == DONE && onlydone)
Eric Andersen8401eea2004-08-04 19:16:54 +00002109 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002110 if (c != DO)
2111 SYNTAXERR;
2112 mylist = c_list();
2113 musthave(DONE, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002114 return (mylist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002115}
2116
Eric Andersen8401eea2004-08-04 19:16:54 +00002117static struct op *thenpart()
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 if ((c = yylex(0)) != THEN) {
2123 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002124 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002125 }
2126 t = newtp();
2127 t->type = 0;
2128 t->left = c_list();
2129 if (t->left == NULL)
2130 SYNTAXERR;
2131 t->right = elsepart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002132 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002133}
2134
Eric Andersen8401eea2004-08-04 19:16:54 +00002135static struct op *elsepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002136{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002137 REGISTER int c;
2138 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002139
2140 switch (c = yylex(0)) {
2141 case ELSE:
2142 if ((t = c_list()) == NULL)
2143 SYNTAXERR;
Eric Andersen8401eea2004-08-04 19:16:54 +00002144 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002145
2146 case ELIF:
2147 t = newtp();
2148 t->type = TELIF;
2149 t->left = c_list();
2150 t->right = thenpart();
Eric Andersen8401eea2004-08-04 19:16:54 +00002151 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002152
2153 default:
2154 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002155 return ((struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002156 }
2157}
2158
Eric Andersen8401eea2004-08-04 19:16:54 +00002159static struct op *caselist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002160{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002161 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002162
2163 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002164 while ((peeksym = yylex(CONTIN)) != ESAC) {
2165 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00002166 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00002167 }
2168
2169 DBGPRINTF(("CASELIST, returning t=0x%x\n", t));
Eric Andersen8401eea2004-08-04 19:16:54 +00002170 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002171}
2172
Eric Andersen8401eea2004-08-04 19:16:54 +00002173static struct op *casepart()
Eric Andersenff9eee42001-06-29 04:57:14 +00002174{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002175 REGISTER struct op *t;
2176
2177 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002178
2179 t = newtp();
2180 t->type = TPAT;
2181 t->words = pattern();
2182 musthave(')', 0);
2183 t->left = c_list();
2184 if ((peeksym = yylex(CONTIN)) != ESAC)
2185 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002186
2187 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=0x%x)\n", t));
2188
Eric Andersen8401eea2004-08-04 19:16:54 +00002189 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002190}
2191
Eric Andersen8401eea2004-08-04 19:16:54 +00002192static char **pattern()
Eric Andersenff9eee42001-06-29 04:57:14 +00002193{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002194 REGISTER int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002195
2196 cf = CONTIN;
2197 do {
2198 musthave(WORD, cf);
2199 word(yylval.cp);
2200 cf = 0;
2201 } while ((c = yylex(0)) == '|');
2202 peeksym = c;
2203 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002204
Eric Andersen8401eea2004-08-04 19:16:54 +00002205 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002206}
2207
Eric Andersen8401eea2004-08-04 19:16:54 +00002208static char **wordlist()
Eric Andersenff9eee42001-06-29 04:57:14 +00002209{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002210 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002211
2212 if ((c = yylex(0)) != IN) {
2213 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002214 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002215 }
2216 startl = 0;
2217 while ((c = yylex(0)) == WORD)
2218 word(yylval.cp);
2219 word(NOWORD);
2220 peeksym = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00002221 return (copyw());
Eric Andersenff9eee42001-06-29 04:57:14 +00002222}
2223
2224/*
2225 * supporting functions
2226 */
Eric Andersen8401eea2004-08-04 19:16:54 +00002227static struct op *list(t1, t2)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002228REGISTER struct op *t1, *t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002229{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002230 DBGPRINTF7(("LIST: enter, t1=0x%x, t2=0x%x\n", t1, t2));
2231
Eric Andersenff9eee42001-06-29 04:57:14 +00002232 if (t1 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002233 return (t2);
Eric Andersenff9eee42001-06-29 04:57:14 +00002234 if (t2 == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002235 return (t1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002236
Eric Andersen8401eea2004-08-04 19:16:54 +00002237 return (block(TLIST, t1, t2, NOWORDS));
Eric Andersenff9eee42001-06-29 04:57:14 +00002238}
2239
Eric Andersen8401eea2004-08-04 19:16:54 +00002240static struct op *block(type, t1, t2, wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002241int type;
2242struct op *t1, *t2;
2243char **wp;
2244{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002245 REGISTER struct op *t;
2246
2247 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002248
2249 t = newtp();
2250 t->type = type;
2251 t->left = t1;
2252 t->right = t2;
2253 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002254
2255 DBGPRINTF7(("BLOCK: inserted 0x%x between 0x%x and 0x%x\n", t, t1,
2256 t2));
2257
Eric Andersen8401eea2004-08-04 19:16:54 +00002258 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002259}
2260
Eric Andersen12de6cf2004-08-04 19:19:10 +00002261/* See if given string is a shell multiline (FOR, IF, etc) */
Eric Andersen8401eea2004-08-04 19:16:54 +00002262static int rlookup(n)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002263REGISTER char *n;
Eric Andersenff9eee42001-06-29 04:57:14 +00002264{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002265 REGISTER struct res *rp;
2266
2267 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002268
2269 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002270 if (strcmp(rp->r_name, n) == 0) {
2271 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2272 return (rp->r_val); /* Return numeric code for shell multiline */
2273 }
2274
2275 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2276 return (0); /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002277}
2278
Eric Andersen8401eea2004-08-04 19:16:54 +00002279static struct op *newtp()
Eric Andersenff9eee42001-06-29 04:57:14 +00002280{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002281 REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002282
Eric Andersen8401eea2004-08-04 19:16:54 +00002283 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002284 t->type = 0;
2285 t->words = NULL;
2286 t->ioact = NULL;
2287 t->left = NULL;
2288 t->right = NULL;
2289 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002290
2291 DBGPRINTF3(("NEWTP: allocated 0x%x\n", t));
2292
Eric Andersen8401eea2004-08-04 19:16:54 +00002293 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002294}
2295
Eric Andersen8401eea2004-08-04 19:16:54 +00002296static struct op *namelist(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002297REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002298{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
2300 DBGPRINTF7(("NAMELIST: enter, t=0x%x, type %s, iolist=0x%x\n", t,
2301 T_CMD_NAMES[t->type], iolist));
2302
Eric Andersenff9eee42001-06-29 04:57:14 +00002303 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002304 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002305 t->ioact = copyio();
2306 } else
2307 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002308
Eric Andersenff9eee42001-06-29 04:57:14 +00002309 if (t->type != TCOM) {
2310 if (t->type != TPAREN && t->ioact != NULL) {
2311 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2312 t->ioact = t->left->ioact;
2313 t->left->ioact = NULL;
2314 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002315 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002316 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002317
Eric Andersenff9eee42001-06-29 04:57:14 +00002318 word(NOWORD);
2319 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002320
2321
Eric Andersen8401eea2004-08-04 19:16:54 +00002322 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002323}
2324
Eric Andersen8401eea2004-08-04 19:16:54 +00002325static char **copyw()
Eric Andersenff9eee42001-06-29 04:57:14 +00002326{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002327 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002328
2329 wd = getwords(wdlist);
2330 wdlist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002331 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002332}
2333
Eric Andersen8401eea2004-08-04 19:16:54 +00002334static void word(cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002335char *cp;
2336{
2337 wdlist = addword(cp, wdlist);
2338}
2339
Eric Andersen8401eea2004-08-04 19:16:54 +00002340static struct ioword **copyio()
Eric Andersenff9eee42001-06-29 04:57:14 +00002341{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002342 REGISTER struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002343
2344 iop = (struct ioword **) getwords(iolist);
2345 iolist = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002346 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002347}
2348
Eric Andersen8401eea2004-08-04 19:16:54 +00002349static struct ioword *io(u, f, cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002350int u;
2351int f;
2352char *cp;
2353{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354 REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002355
2356 iop = (struct ioword *) tree(sizeof(*iop));
2357 iop->io_unit = u;
2358 iop->io_flag = f;
2359 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002360 iolist = addword((char *) iop, iolist);
2361 return (iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00002362}
2363
Eric Andersen8401eea2004-08-04 19:16:54 +00002364static void zzerr()
Eric Andersenff9eee42001-06-29 04:57:14 +00002365{
2366 yyerror("syntax error");
2367}
2368
Eric Andersen8401eea2004-08-04 19:16:54 +00002369static void yyerror(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00002370char *s;
2371{
2372 yynerrs++;
2373 if (interactive && e.iop <= iostack) {
2374 multiline = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002375 while (eofc() == 0 && yylex(0) != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002376 }
2377 err(s);
2378 fail();
2379}
2380
Eric Andersen8401eea2004-08-04 19:16:54 +00002381static int yylex(cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002382int cf;
2383{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002384 REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002385 int atstart;
2386
2387 if ((c = peeksym) > 0) {
2388 peeksym = 0;
2389 if (c == '\n')
2390 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002391 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002392 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002393
2394
Eric Andersenff9eee42001-06-29 04:57:14 +00002395 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002396 atstart = startl;
2397 startl = 0;
2398 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002399 e.linep = line;
2400
2401/* MALAMO */
2402 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002403
Eric Andersen8401eea2004-08-04 19:16:54 +00002404 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002405 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2406 ;
2407
Eric Andersenff9eee42001-06-29 04:57:14 +00002408 switch (c) {
2409 default:
2410 if (any(c, "0123456789")) {
2411 unget(c1 = my_getc(0));
2412 if (c1 == '<' || c1 == '>') {
2413 iounit = c - '0';
2414 goto loop;
2415 }
2416 *e.linep++ = c;
2417 c = c1;
2418 }
2419 break;
2420
Eric Andersen12de6cf2004-08-04 19:19:10 +00002421 case '#': /* Comment, skip to next newline or End-of-string */
Eric Andersen8401eea2004-08-04 19:16:54 +00002422 while ((c = my_getc(0)) != 0 && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002423 unget(c);
2424 goto loop;
2425
2426 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002427 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Eric Andersen8401eea2004-08-04 19:16:54 +00002428 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002429
2430 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002431 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002432 *e.linep++ = c;
2433 if ((c = my_getc(0)) == '{') {
2434 if ((c = collect(c, '}')) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002435 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002436 goto pack;
2437 }
2438 break;
2439
2440 case '`':
2441 case '\'':
2442 case '"':
2443 if ((c = collect(c, c)) != '\0')
Eric Andersen8401eea2004-08-04 19:16:54 +00002444 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002445 goto pack;
2446
2447 case '|':
2448 case '&':
2449 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002450 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002451 /* If more chars process them, else return NULL char */
2452 if ((c1 = dual(c)) != '\0')
2453 return (c1);
2454 else
2455 return (c);
2456
Eric Andersenff9eee42001-06-29 04:57:14 +00002457 case '^':
2458 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002459 return ('|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002460 case '>':
2461 case '<':
2462 diag(c);
Eric Andersen8401eea2004-08-04 19:16:54 +00002463 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002464
2465 case '\n':
2466 nlseen++;
2467 gethere();
2468 startl = 1;
2469 if (multiline || cf & CONTIN) {
2470 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002471#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002472 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002473#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002474 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002475#endif
2476 }
2477 if (cf & CONTIN)
2478 goto loop;
2479 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002480 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002481
2482 case '(':
2483 case ')':
2484 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002485 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002486 }
2487
2488 unget(c);
2489
Eric Andersen8401eea2004-08-04 19:16:54 +00002490 pack:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002491 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002492 if (e.linep >= elinep)
2493 err("word too long");
2494 else
2495 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002496 };
2497
Eric Andersenff9eee42001-06-29 04:57:14 +00002498 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002499
Eric Andersen8401eea2004-08-04 19:16:54 +00002500 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002501 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002502
Eric Andersenff9eee42001-06-29 04:57:14 +00002503 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002504
Eric Andersen8401eea2004-08-04 19:16:54 +00002505 if (atstart && (c = rlookup(line)) != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002506 startl = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002507 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00002508 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002509
Eric Andersenff9eee42001-06-29 04:57:14 +00002510 yylval.cp = strsave(line, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00002511 return (WORD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002512}
2513
Eric Andersen12de6cf2004-08-04 19:19:10 +00002514
Eric Andersen8401eea2004-08-04 19:16:54 +00002515static int collect(c, c1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002516REGISTER int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002517{
2518 char s[2];
2519
Eric Andersen12de6cf2004-08-04 19:19:10 +00002520 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2521
Eric Andersenff9eee42001-06-29 04:57:14 +00002522 *e.linep++ = c;
2523 while ((c = my_getc(c1)) != c1) {
2524 if (c == 0) {
2525 unget(c);
2526 s[0] = c1;
2527 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002528 prs("no closing ");
2529 yyerror(s);
2530 return (YYERRCODE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002531 }
2532 if (interactive && c == '\n' && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002533#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002534 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002535#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002536 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002537#endif
2538 }
2539 *e.linep++ = c;
2540 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002541
Eric Andersenff9eee42001-06-29 04:57:14 +00002542 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002543
2544 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2545
Eric Andersen8401eea2004-08-04 19:16:54 +00002546 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002547}
2548
Eric Andersen12de6cf2004-08-04 19:19:10 +00002549/* "multiline commands" helper func */
2550/* see if next 2 chars form a shell multiline */
Eric Andersen8401eea2004-08-04 19:16:54 +00002551static int dual(c)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002552REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002553{
2554 char s[3];
Eric Andersen12de6cf2004-08-04 19:19:10 +00002555 REGISTER char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002556
Eric Andersen12de6cf2004-08-04 19:19:10 +00002557 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2558
2559 *cp++ = c; /* c is the given "peek" char */
2560 *cp++ = my_getc(0); /* get next char of input */
2561 *cp = 0; /* add EOS marker */
2562
2563 c = rlookup(s); /* see if 2 chars form a shell multiline */
2564 if (c == 0)
2565 unget(*--cp); /* String is not a shell multiline, put peek char back */
2566
2567 return (c); /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002568}
2569
Eric Andersen8401eea2004-08-04 19:16:54 +00002570static void diag(ec)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002571REGISTER int ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00002572{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002573 REGISTER int c;
2574
2575 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002576
2577 c = my_getc(0);
2578 if (c == '>' || c == '<') {
2579 if (c != ec)
2580 zzerr();
Eric Andersen8401eea2004-08-04 19:16:54 +00002581 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002582 c = my_getc(0);
2583 } else
Eric Andersen8401eea2004-08-04 19:16:54 +00002584 yylval.i = ec == '>' ? IOWRITE : IOREAD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002585 if (c != '&' || yylval.i == IOHERE)
2586 unget(c);
2587 else
2588 yylval.i |= IODUP;
2589}
2590
Eric Andersen8401eea2004-08-04 19:16:54 +00002591static char *tree(size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002592unsigned size;
2593{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002594 REGISTER char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002595
2596 if ((t = getcell(size)) == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002597 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002598 prs("command line too complicated\n");
2599 fail();
2600 /* NOTREACHED */
2601 }
Eric Andersen8401eea2004-08-04 19:16:54 +00002602 return (t);
Eric Andersenff9eee42001-06-29 04:57:14 +00002603}
2604
2605/* VARARGS1 */
2606/* ARGSUSED */
2607
2608/* -------- exec.c -------- */
2609
2610/*
2611 * execute tree
2612 */
2613
2614
Eric Andersen8401eea2004-08-04 19:16:54 +00002615static int execute(t, pin, pout, act)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002616REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002617int *pin, *pout;
2618int act;
2619{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002620 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002621 volatile int i, rv, a;
2622 char *cp, **wp, **wp2;
2623 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002624 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002625 struct brkcon bc;
2626
2627#if __GNUC__
2628 /* Avoid longjmp clobbering */
2629 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002630#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002631
Eric Andersen12de6cf2004-08-04 19:19:10 +00002632 if (t == NULL) {
2633 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002634 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002635 }
2636
2637 DBGPRINTF(("EXECUTE: t=0x%x, t->type=%d (%s), t->words is %s\n", t,
2638 t->type, T_CMD_NAMES[t->type],
2639 ((t->words == NULL) ? "NULL" : t->words[0])));
2640
Eric Andersenff9eee42001-06-29 04:57:14 +00002641 rv = 0;
2642 a = areanum++;
2643 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002644 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2645 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002646
Eric Andersen12de6cf2004-08-04 19:19:10 +00002647/* Hard to know how many words there are, be careful of garbage pointer values */
2648/* They are likely to cause "PCI bus fault" errors */
2649#if 0
2650 DBGPRINTF(("EXECUTE: t->left=0x%x, t->right=0x%x, t->words[1] is %s\n",
2651 t->left, t->right,
2652 ((t->words[1] == NULL) ? "NULL" : t->words[1])));
2653 DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",
2654 ((t->words[2] == NULL) ? "NULL" : t->words[2]),
2655 ((t->words[3] == NULL) ? "NULL" : t->words[3])));
2656#endif
2657
2658
Eric Andersen8401eea2004-08-04 19:16:54 +00002659 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002660 case TDOT:
2661 DBGPRINTF3(("EXECUTE: TDOT\n"));
2662
2663 outtree_save = outtree;
2664
2665 newfile(evalstr(t->words[0], DOALL));
2666
2667 t->left = dowholefile(TLIST, 0);
2668 t->right = NULL;
2669
2670 outtree = outtree_save;
2671
2672 if (t->left)
2673 rv = execute(t->left, pin, pout, 0);
2674 if (t->right)
2675 rv = execute(t->right, pin, pout, 0);
2676 break;
2677
Eric Andersenff9eee42001-06-29 04:57:14 +00002678 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002679 rv = execute(t->left, pin, pout, 0);
2680 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002681
Eric Andersenff9eee42001-06-29 04:57:14 +00002682 case TCOM:
Eric Andersen1c039232001-07-07 00:05:55 +00002683 {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002684 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002685 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002686 break;
2687
2688 case TPIPE:
2689 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002690 int pv[2];
2691
2692 if ((rv = openpipe(pv)) < 0)
2693 break;
2694 pv[0] = remap(pv[0]);
2695 pv[1] = remap(pv[1]);
2696 (void) execute(t->left, pin, pv, 0);
2697 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002698 }
2699 break;
2700
2701 case TLIST:
2702 (void) execute(t->left, pin, pout, 0);
2703 rv = execute(t->right, pin, pout, 0);
2704 break;
2705
2706 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002707 {
2708 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002709
Eric Andersen12de6cf2004-08-04 19:19:10 +00002710 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2711
Eric Andersen8401eea2004-08-04 19:16:54 +00002712 i = vfork();
2713 if (i != 0) {
2714 interactive = hinteractive;
2715 if (i != -1) {
2716 setval(lookup("!"), putn(i));
2717 if (pin != NULL)
2718 closepipe(pin);
2719 if (interactive) {
2720 prs(putn(i));
2721 prs("\n");
2722 }
2723 } else
2724 rv = -1;
2725 setstatus(rv);
2726 } else {
2727 signal(SIGINT, SIG_IGN);
2728 signal(SIGQUIT, SIG_IGN);
2729 if (interactive)
2730 signal(SIGTERM, SIG_DFL);
2731 interactive = 0;
2732 if (pin == NULL) {
2733 close(0);
2734 open("/dev/null", 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002735 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002736 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002737 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002738 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002739 break;
2740
2741 case TOR:
2742 case TAND:
2743 rv = execute(t->left, pin, pout, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002744 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002745 rv = execute(t1, pin, pout, 0);
2746 break;
2747
2748 case TFOR:
2749 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002750 wp = dolv + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002751 if ((i = dolc) < 0)
2752 i = 0;
2753 } else {
2754 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002755 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002756 }
2757 vp = lookup(t->str);
2758 while (setjmp(bc.brkpt))
2759 if (isbreak)
2760 goto broken;
2761 brkset(&bc);
2762 for (t1 = t->left; i-- && *wp != NULL;) {
2763 setval(vp, *wp++);
2764 rv = execute(t1, pin, pout, 0);
2765 }
2766 brklist = brklist->nextlev;
2767 break;
2768
2769 case TWHILE:
2770 case TUNTIL:
2771 while (setjmp(bc.brkpt))
2772 if (isbreak)
2773 goto broken;
2774 brkset(&bc);
2775 t1 = t->left;
2776 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2777 rv = execute(t->right, pin, pout, 0);
2778 brklist = brklist->nextlev;
2779 break;
2780
2781 case TIF:
2782 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002783 if (t->right != NULL) {
2784 rv = !execute(t->left, pin, pout, 0) ?
2785 execute(t->right->left, pin, pout, 0) :
2786 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002787 }
2788 break;
2789
2790 case TCASE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002791 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002792 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002793
2794 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2795 ((t->str == NULL) ? "NULL" : t->str),
2796 ((cp == NULL) ? "NULL" : cp)));
2797
2798 if ((t1 = findcase(t->left, cp)) != NULL) {
2799 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=0x%x, t1=0x%x)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002800 rv = execute(t1, pin, pout, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002801 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=0x%x, t1=0x%x)...\n", t, t1));
2802 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002803 break;
2804
2805 case TBRACE:
2806/*
2807 if (iopp = t->ioact)
2808 while (*iopp)
2809 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2810 rv = -1;
2811 break;
2812 }
2813*/
2814 if (rv >= 0 && (t1 = t->left))
2815 rv = execute(t1, pin, pout, 0);
2816 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002817
2818 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002819
Eric Andersen8401eea2004-08-04 19:16:54 +00002820 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002821 t->words = wp2;
2822 isbreak = 0;
2823 freehere(areanum);
2824 freearea(areanum);
2825 areanum = a;
2826 if (interactive && intr) {
2827 closeall();
2828 fail();
2829 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002830
Eric Andersenff9eee42001-06-29 04:57:14 +00002831 if ((i = trapset) != 0) {
2832 trapset = 0;
2833 runtrap(i);
2834 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002835
2836 DBGPRINTF(("EXECUTE: returning from t=0x%x, rv=%d\n", t, rv));
Eric Andersen8401eea2004-08-04 19:16:54 +00002837 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002838}
2839
2840static int
Eric Andersen12de6cf2004-08-04 19:19:10 +00002841forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002842{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002843 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002844 int i, rv;
Eric Andersen8401eea2004-08-04 19:16:54 +00002845 int (*shcom) (struct op *) = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002846 REGISTER int f;
Eric Andersenff9eee42001-06-29 04:57:14 +00002847 char *cp = NULL;
2848 struct ioword **iopp;
2849 int resetsig;
2850 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002851 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002852
2853 int *hpin = pin;
2854 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002855 char *hwp;
2856 int hinteractive;
2857 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002858 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002859 int hexecflg;
2860
2861#if __GNUC__
2862 /* Avoid longjmp clobbering */
2863 (void) &pin;
2864 (void) &pout;
2865 (void) &wp;
2866 (void) &shcom;
2867 (void) &cp;
2868 (void) &resetsig;
2869 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002870#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002871
Eric Andersen12de6cf2004-08-04 19:19:10 +00002872 DBGPRINTF(("FORKEXEC: t=0x%x, pin 0x%x, pout 0x%x, act %d\n", t, pin,
2873 pout, act));
2874 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2875 ((t->words == NULL) ? "NULL" : t->words[0])));
2876
2877/* Hard to know how many words there are, be careful of garbage pointer values */
2878/* They are likely to cause "PCI bus fault" errors */
2879#if 0
2880 DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2881 ((t->words == NULL) ? "NULL" : t->words[0]),
2882 ((t->words == NULL) ? "NULL" : t->words[1])));
2883 DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",
2884 ((wp == NULL) ? "NULL" : wp[0]),
2885 ((wp[1] == NULL) ? "NULL" : wp[1])));
2886 DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",
2887 ((wp[2] == NULL) ? "NULL" : wp[2]),
2888 ((wp[3] == NULL) ? "NULL" : wp[3])));
2889#endif
2890
2891
Eric Andersenff9eee42001-06-29 04:57:14 +00002892 owp = wp;
2893 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002894 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002895 if (t->type == TCOM) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002896 while ((cp = *wp++) != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002897 cp = *wp;
2898
2899 /* strip all initial assignments */
2900 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002901 if (flag['x']) {
2902 DBGPRINTF9(("FORKEXEC: echo'ing, cp=0x%x, wp=0x%x, owp=0x%x\n",
2903 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002904 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002905 }
2906#if 0
2907 DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2908 ((t->words == NULL) ? "NULL" : t->words[0]),
2909 ((t->words == NULL) ? "NULL" : t->words[1])));
2910 DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",
2911 ((wp == NULL) ? "NULL" : wp[0]),
2912 ((wp == NULL) ? "NULL" : wp[1])));
2913#endif
2914
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 if (cp == NULL && t->ioact == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002916 while ((cp = *owp++) != NULL && assign(cp, COPYV));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002917 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00002918 return (setstatus(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002919 } else if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002920 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002921 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002923
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 t->words = wp;
2925 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002926
Eric Andersen12de6cf2004-08-04 19:19:10 +00002927#if 0
2928 DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2929 ((t->words == NULL) ? "NULL" : t->words[0]),
2930 ((t->words == NULL) ? "NULL" : t->words[1])));
2931#endif
2932 DBGPRINTF(("FORKEXEC: shcom 0x%x, f&FEXEC 0x%x, owp 0x%x\n", shcom,
2933 f & FEXEC, owp));
2934
2935 if (shcom == NULL && (f & FEXEC) == 0) {
2936 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002937 hpin = pin;
2938 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002939 hwp = *wp;
2940 hinteractive = interactive;
2941 hintr = intr;
2942 hbrklist = brklist;
2943 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002944
Eric Andersen12de6cf2004-08-04 19:19:10 +00002945 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2946
2947 newpid = vfork();
2948
2949 if (newpid == -1) {
2950 DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n"));
2951 return (-1);
2952 }
2953
2954
2955 if (newpid > 0) { /* Parent */
2956
2957 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002958 pin = hpin;
2959 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002960 *wp = hwp;
2961 interactive = hinteractive;
2962 intr = hintr;
2963 brklist = hbrklist;
2964 execflg = hexecflg;
2965
Eric Andersen12de6cf2004-08-04 19:19:10 +00002966/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002967 if (i == -1)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002968 return(rv);
2969*/
2970
Eric Andersenff9eee42001-06-29 04:57:14 +00002971 if (pin != NULL)
2972 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002973
2974 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002975 }
2976
Eric Andersen12de6cf2004-08-04 19:19:10 +00002977 /* Must be the child process, pid should be 0 */
2978 DBGPRINTF(("FORKEXEC: child process, shcom=0x%x\n", shcom));
2979
Eric Andersenff9eee42001-06-29 04:57:14 +00002980 if (interactive) {
2981 signal(SIGINT, SIG_IGN);
2982 signal(SIGQUIT, SIG_IGN);
2983 resetsig = 1;
2984 }
2985 interactive = 0;
2986 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002987 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002988 brklist = 0;
2989 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002990 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002991
2992
Eric Andersenff9eee42001-06-29 04:57:14 +00002993 if (owp != NULL)
2994 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2995 if (shcom == NULL)
2996 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002997
Eric Andersenff9eee42001-06-29 04:57:14 +00002998#ifdef COMPIPE
2999 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
3000 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003001 if (forked)
3002 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003003 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003004 }
3005#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003006
Eric Andersenff9eee42001-06-29 04:57:14 +00003007 if (pin != NULL) {
3008 dup2(pin[0], 0);
3009 closepipe(pin);
3010 }
3011 if (pout != NULL) {
3012 dup2(pout[1], 1);
3013 closepipe(pout);
3014 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003015
Eric Andersenff9eee42001-06-29 04:57:14 +00003016 if ((iopp = t->ioact) != NULL) {
3017 if (shcom != NULL && shcom != doexec) {
3018 prs(cp);
3019 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003020 if (forked)
3021 _exit(-1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003022 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003023 }
3024 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003025 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
3026 if (forked)
3027 _exit(rv);
Eric Andersen8401eea2004-08-04 19:16:54 +00003028 return (rv);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003029 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003030 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003031
3032 if (shcom) {
3033 i = setstatus((*shcom) (t));
3034 if (forked)
3035 _exit(i);
3036 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
3037 return (i);
3038 }
3039
Eric Andersenff9eee42001-06-29 04:57:14 +00003040 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00003041 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003042 close(i);
3043 if (resetsig) {
3044 signal(SIGINT, SIG_DFL);
3045 signal(SIGQUIT, SIG_DFL);
3046 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003047
Eric Andersen12de6cf2004-08-04 19:19:10 +00003048 if (t->type == TPAREN)
3049 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
3050 if (wp[0] == NULL)
3051 _exit(0);
3052
3053 cp = rexecve(wp[0], wp, makenv(0));
Eric Andersen8401eea2004-08-04 19:16:54 +00003054 prs(wp[0]);
3055 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003056 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003057 if (!execflg)
3058 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003059
3060 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
3061
Eric Andersenff9eee42001-06-29 04:57:14 +00003062 leave();
3063 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003064 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003065}
3066
3067/*
3068 * 0< 1> are ignored as required
3069 * within pipelines.
3070 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003071static int iosetup(iop, pipein, pipeout)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003072REGISTER struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003073int pipein, pipeout;
3074{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003075 REGISTER int u = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003076 char *cp = NULL, *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00003077
Eric Andersen12de6cf2004-08-04 19:19:10 +00003078 DBGPRINTF(("IOSETUP: iop 0x%x, pipein 0x%x, pipeout 0x%x\n", iop,
3079 pipein, pipeout));
3080
Eric Andersenff9eee42001-06-29 04:57:14 +00003081 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00003082 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003083
Eric Andersenff9eee42001-06-29 04:57:14 +00003084 if (pipein && iop->io_unit == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003085 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003086
Eric Andersenff9eee42001-06-29 04:57:14 +00003087 if (pipeout && iop->io_unit == 1)
Eric Andersen8401eea2004-08-04 19:16:54 +00003088 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003089
Eric Andersen8401eea2004-08-04 19:16:54 +00003090 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00003091 if ((iop->io_flag & IOHERE) == 0) {
3092 cp = iop->io_name;
Eric Andersen8401eea2004-08-04 19:16:54 +00003093 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
3094 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003095 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003096
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 if (iop->io_flag & IODUP) {
3098 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
3099 prs(cp);
3100 err(": illegal >& argument");
Eric Andersen8401eea2004-08-04 19:16:54 +00003101 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003102 }
3103 if (*cp == '-')
3104 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00003105 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003106 }
3107 switch (iop->io_flag) {
3108 case IOREAD:
3109 u = open(cp, 0);
3110 break;
3111
3112 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00003113 case IOHERE | IOXHERE:
3114 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00003115 cp = "here file";
3116 break;
3117
Eric Andersen8401eea2004-08-04 19:16:54 +00003118 case IOWRITE | IOCAT:
Eric Andersenff9eee42001-06-29 04:57:14 +00003119 if ((u = open(cp, 1)) >= 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003120 lseek(u, (long) 0, 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00003121 break;
3122 }
3123 case IOWRITE:
3124 u = creat(cp, 0666);
3125 break;
3126
3127 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00003128 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00003129 break;
3130
3131 case IOCLOSE:
3132 close(iop->io_unit);
Eric Andersen8401eea2004-08-04 19:16:54 +00003133 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003134 }
3135 if (u < 0) {
3136 prs(cp);
3137 prs(": cannot ");
3138 warn(msg);
Eric Andersen8401eea2004-08-04 19:16:54 +00003139 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003140 } else {
3141 if (u != iop->io_unit) {
3142 dup2(u, iop->io_unit);
3143 close(u);
3144 }
3145 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003146 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003147}
3148
Eric Andersen8401eea2004-08-04 19:16:54 +00003149static void echo(wp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003150REGISTER char **wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003151{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003152 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003153
3154 prs("+");
Eric Andersen8401eea2004-08-04 19:16:54 +00003155 for (i = 0; wp[i]; i++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003156 if (i)
3157 prs(" ");
3158 prs(wp[i]);
3159 }
3160 prs("\n");
3161}
3162
Eric Andersen8401eea2004-08-04 19:16:54 +00003163static struct op **find1case(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003164struct op *t;
3165char *w;
3166{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003167 REGISTER struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003168 struct op **tp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003169 REGISTER char **wp, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003170
Eric Andersen12de6cf2004-08-04 19:19:10 +00003171
3172 if (t == NULL) {
3173 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003174 return ((struct op **) NULL);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003175 }
3176
3177 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3178 T_CMD_NAMES[t->type]));
3179
Eric Andersenff9eee42001-06-29 04:57:14 +00003180 if (t->type == TLIST) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003181 if ((tp = find1case(t->left, w)) != NULL) {
3182 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=0x%x\n", tp));
Eric Andersen8401eea2004-08-04 19:16:54 +00003183 return (tp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003184 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003185 t1 = t->right; /* TPAT */
Eric Andersenff9eee42001-06-29 04:57:14 +00003186 } else
3187 t1 = t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003188
Eric Andersenff9eee42001-06-29 04:57:14 +00003189 for (wp = t1->words; *wp;)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003190 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
3191 DBGPRINTF3(("FIND1CASE: returning &t1->left= 0x%x.\n",
3192 &t1->left));
Eric Andersen8401eea2004-08-04 19:16:54 +00003193 return (&t1->left);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003194 }
3195
3196 DBGPRINTF(("FIND1CASE: returning NULL\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003197 return ((struct op **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003198}
3199
Eric Andersen8401eea2004-08-04 19:16:54 +00003200static struct op *findcase(t, w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003201struct op *t;
3202char *w;
3203{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003204 REGISTER struct op **tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003205
Eric Andersen8401eea2004-08-04 19:16:54 +00003206 return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003207}
3208
3209/*
3210 * Enter a new loop level (marked for break/continue).
3211 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003212static void brkset(bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00003213struct brkcon *bc;
3214{
3215 bc->nextlev = brklist;
3216 brklist = bc;
3217}
3218
3219/*
3220 * Wait for the last process created.
3221 * Print a message for each process found
3222 * that was killed by a signal.
3223 * Ignore interrupt signals while waiting
3224 * unless `canintr' is true.
3225 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003226static int waitfor(lastpid, canintr)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003227REGISTER int lastpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00003228int canintr;
3229{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003230 REGISTER int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003231 int s;
3232 int oheedint = heedint;
3233
3234 heedint = 0;
3235 rv = 0;
3236 do {
3237 pid = wait(&s);
3238 if (pid == -1) {
3239 if (errno != EINTR || canintr)
3240 break;
3241 } else {
3242 if ((rv = WAITSIG(s)) != 0) {
3243 if (rv < NSIGNAL) {
3244 if (signame[rv] != NULL) {
3245 if (pid != lastpid) {
3246 prn(pid);
3247 prs(": ");
3248 }
3249 prs(signame[rv]);
3250 }
3251 } else {
3252 if (pid != lastpid) {
3253 prn(pid);
3254 prs(": ");
3255 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003256 prs("Signal ");
3257 prn(rv);
3258 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003259 }
3260 if (WAITCORE(s))
3261 prs(" - core dumped");
3262 if (rv >= NSIGNAL || signame[rv])
3263 prs("\n");
3264 rv = -1;
3265 } else
3266 rv = WAITVAL(s);
3267 }
3268 } while (pid != lastpid);
3269 heedint = oheedint;
3270 if (intr) {
3271 if (interactive) {
3272 if (canintr)
3273 intr = 0;
3274 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003275 if (exstat == 0)
3276 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003277 onintr(0);
3278 }
3279 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003280 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003281}
3282
Eric Andersen8401eea2004-08-04 19:16:54 +00003283static int setstatus(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003284REGISTER int s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003285{
3286 exstat = s;
3287 setval(lookup("?"), putn(s));
Eric Andersen8401eea2004-08-04 19:16:54 +00003288 return (s);
Eric Andersenff9eee42001-06-29 04:57:14 +00003289}
3290
3291/*
3292 * PATH-searching interface to execve.
3293 * If getenv("PATH") were kept up-to-date,
3294 * execvp might be used.
3295 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003296static char *rexecve(c, v, envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003297char *c, **v, **envp;
3298{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003299 REGISTER int i;
3300 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003301 int eacces = 0, asis = 0;
3302
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003303#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003304 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003305
Eric Andersen1c039232001-07-07 00:05:55 +00003306 optind = 1;
3307 if (find_applet_by_name(name)) {
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003308 /* We have to exec here since we vforked. Running
Eric Andersen1c039232001-07-07 00:05:55 +00003309 * run_applet_by_name() won't work and bad things
3310 * will happen. */
3311 execve("/proc/self/exe", v, envp);
3312 execve("busybox", v, envp);
3313 }
3314#endif
3315
Eric Andersen12de6cf2004-08-04 19:19:10 +00003316 DBGPRINTF(("REXECVE: c=0x%x, v=0x%x, envp=0x%x\n", c, v, envp));
3317
Eric Andersen8401eea2004-08-04 19:16:54 +00003318 sp = any('/', c) ? "" : path->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00003319 asis = *sp == '\0';
3320 while (asis || *sp != '\0') {
3321 asis = 0;
3322 tp = e.linep;
3323 for (; *sp != '\0'; tp++)
3324 if ((*tp = *sp++) == ':') {
3325 asis = *sp == '\0';
3326 break;
3327 }
3328 if (tp != e.linep)
3329 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003330 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003331
Eric Andersen12de6cf2004-08-04 19:19:10 +00003332 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3333
Eric Andersenff9eee42001-06-29 04:57:14 +00003334 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335
Eric Andersenff9eee42001-06-29 04:57:14 +00003336 switch (errno) {
3337 case ENOEXEC:
3338 *v = e.linep;
3339 tp = *--v;
3340 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003341 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003342 *v = tp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003343 return ("no Shell");
Eric Andersenff9eee42001-06-29 04:57:14 +00003344
3345 case ENOMEM:
Eric Andersen8401eea2004-08-04 19:16:54 +00003346 return ((char *) bb_msg_memory_exhausted);
Eric Andersenff9eee42001-06-29 04:57:14 +00003347
3348 case E2BIG:
Eric Andersen8401eea2004-08-04 19:16:54 +00003349 return ("argument list too long");
Eric Andersenff9eee42001-06-29 04:57:14 +00003350
3351 case EACCES:
3352 eacces++;
3353 break;
3354 }
3355 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003356 return (errno == ENOENT ? "not found" : "cannot execute");
Eric Andersenff9eee42001-06-29 04:57:14 +00003357}
3358
3359/*
3360 * Run the command produced by generator `f'
3361 * applied to stream `arg'.
3362 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003363static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003364{
3365 struct op *otree;
3366 struct wdblock *swdlist;
3367 struct wdblock *siolist;
3368 jmp_buf ev, rt;
3369 xint *ofail;
3370 int rv;
3371
3372#if __GNUC__
3373 /* Avoid longjmp clobbering */
3374 (void) &rv;
3375#endif
3376
Eric Andersen12de6cf2004-08-04 19:19:10 +00003377 DBGPRINTF(("RUN: enter, areanum %d, outtree 0x%x, failpt 0x%x\n",
3378 areanum, outtree, failpt));
3379
Eric Andersenff9eee42001-06-29 04:57:14 +00003380 areanum++;
3381 swdlist = wdlist;
3382 siolist = iolist;
3383 otree = outtree;
3384 ofail = failpt;
3385 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003386
Eric Andersenff9eee42001-06-29 04:57:14 +00003387 if (newenv(setjmp(errpt = ev)) == 0) {
3388 wdlist = 0;
3389 iolist = 0;
3390 pushio(argp, f);
3391 e.iobase = e.iop;
3392 yynerrs = 0;
3393 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3394 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3395 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003396 } else {
3397 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003398 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003399
Eric Andersenff9eee42001-06-29 04:57:14 +00003400 wdlist = swdlist;
3401 iolist = siolist;
3402 failpt = ofail;
3403 outtree = otree;
3404 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003405
Eric Andersen8401eea2004-08-04 19:16:54 +00003406 return (rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00003407}
3408
3409/* -------- do.c -------- */
3410
3411/*
3412 * built-in commands: doX
3413 */
3414
Eric Andersen8401eea2004-08-04 19:16:54 +00003415static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003416{
3417 int col;
3418 const struct builtincmd *x;
3419
3420 printf("\nBuilt-in commands:\n");
3421 printf("-------------------\n");
3422
Eric Andersen8401eea2004-08-04 19:16:54 +00003423 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003424 if (!x->name)
3425 continue;
3426 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3427 if (col > 60) {
3428 printf("\n");
3429 col = 0;
3430 }
3431 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003432#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003433 {
3434 int i;
3435 const struct BB_applet *applet;
3436 extern const struct BB_applet applets[];
3437 extern const size_t NUM_APPLETS;
3438
Eric Andersen8401eea2004-08-04 19:16:54 +00003439 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003440 if (!applet->name)
3441 continue;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003442
Eric Andersen8401eea2004-08-04 19:16:54 +00003443 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003444 if (col > 60) {
3445 printf("\n");
3446 col = 0;
3447 }
3448 }
3449 }
3450#endif
3451 printf("\n\n");
3452 return EXIT_SUCCESS;
3453}
3454
3455
3456
Eric Andersen8401eea2004-08-04 19:16:54 +00003457static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003458{
Eric Andersen8401eea2004-08-04 19:16:54 +00003459 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003460}
3461
Eric Andersen8401eea2004-08-04 19:16:54 +00003462static int dochdir(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003463REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003464{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003465 REGISTER char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003466
3467 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3468 er = ": no home directory";
Eric Andersen8401eea2004-08-04 19:16:54 +00003469 else if (chdir(cp) < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003470 er = ": bad directory";
3471 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003472 return (0);
3473 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003474 err(er);
Eric Andersen8401eea2004-08-04 19:16:54 +00003475 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003476}
3477
Eric Andersen8401eea2004-08-04 19:16:54 +00003478static int doshift(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003479REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003480{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003481 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003482
Eric Andersen8401eea2004-08-04 19:16:54 +00003483 n = t->words[1] ? getn(t->words[1]) : 1;
3484 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003485 err("nothing to shift");
Eric Andersen8401eea2004-08-04 19:16:54 +00003486 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003487 }
3488 dolv[n] = dolv[0];
3489 dolv += n;
3490 dolc -= n;
3491 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003492 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003493}
3494
3495/*
3496 * execute login and newgrp directly
3497 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003498static int dologin(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003499struct op *t;
3500{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003501 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003502
3503 if (interactive) {
3504 signal(SIGINT, SIG_DFL);
3505 signal(SIGQUIT, SIG_DFL);
3506 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003507 cp = rexecve(t->words[0], t->words, makenv(0));
Eric Andersen8401eea2004-08-04 19:16:54 +00003508 prs(t->words[0]);
3509 prs(": ");
3510 err(cp);
3511 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003512}
3513
Eric Andersen8401eea2004-08-04 19:16:54 +00003514static int doumask(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003515REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003516{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003517 REGISTER int i, n;
3518 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003519
3520 if ((cp = t->words[1]) == NULL) {
3521 i = umask(0);
3522 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003523 for (n = 3 * 4; (n -= 3) >= 0;)
3524 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003525 putc('\n', stderr);
3526 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003527 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3528 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003529 umask(n);
3530 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003531 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003532}
3533
Eric Andersen8401eea2004-08-04 19:16:54 +00003534static int doexec(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003535REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003536{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003537 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003538 jmp_buf ex;
3539 xint *ofail;
3540
3541 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003542 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003543 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003544 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003545 execflg = 1;
3546 ofail = failpt;
3547 if (setjmp(failpt = ex) == 0)
3548 execute(t, NOPIPE, NOPIPE, FEXEC);
3549 failpt = ofail;
3550 execflg = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003551 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003552}
3553
Eric Andersen8401eea2004-08-04 19:16:54 +00003554static int dodot(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003555struct op *t;
3556{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003557 REGISTER int i;
3558 REGISTER char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003559 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003560 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003561
Eric Andersen12de6cf2004-08-04 19:19:10 +00003562 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)));
3563
3564 if ((cp = t->words[1]) == NULL) {
3565 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Eric Andersen8401eea2004-08-04 19:16:54 +00003566 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003567 } else {
3568 DBGPRINTF(("DODOT: cp is %s\n", cp));
3569 }
3570
Eric Andersen8401eea2004-08-04 19:16:54 +00003571 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003572
3573 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3574 ((sp == NULL) ? "NULL" : sp),
3575 ((e.linep == NULL) ? "NULL" : e.linep)));
3576
Eric Andersenff9eee42001-06-29 04:57:14 +00003577 while (*sp) {
3578 tp = e.linep;
3579 while (*sp && (*tp = *sp++) != ':')
3580 tp++;
3581 if (tp != e.linep)
3582 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003583
Eric Andersen8401eea2004-08-04 19:16:54 +00003584 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003585
3586 /* Original code */
Eric Andersenff9eee42001-06-29 04:57:14 +00003587 if ((i = open(e.linep, 0)) >= 0) {
3588 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003589 maltmp = remap(i);
3590 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3591
3592 next(maltmp); /* Basically a PUSHIO */
3593
3594 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3595
Eric Andersen8401eea2004-08-04 19:16:54 +00003596 return (exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00003597 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003598
3599 } /* While */
3600
Eric Andersenff9eee42001-06-29 04:57:14 +00003601 prs(cp);
3602 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003603
Eric Andersen8401eea2004-08-04 19:16:54 +00003604 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003605}
3606
Eric Andersen8401eea2004-08-04 19:16:54 +00003607static int dowait(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003608struct op *t;
3609{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003610 REGISTER int i;
3611 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003612
3613 if ((cp = t->words[1]) != NULL) {
3614 i = getn(cp);
3615 if (i == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003616 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003617 } else
3618 i = -1;
3619 setstatus(waitfor(i, 1));
Eric Andersen8401eea2004-08-04 19:16:54 +00003620 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003621}
3622
Eric Andersen8401eea2004-08-04 19:16:54 +00003623static int doread(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003624struct op *t;
3625{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003626 REGISTER char *cp, **wp;
3627 REGISTER int nb = 0;
3628 REGISTER int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003629
3630 if (t->words[1] == NULL) {
3631 err("Usage: read name ...");
Eric Andersen8401eea2004-08-04 19:16:54 +00003632 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003633 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003634 for (wp = t->words + 1; *wp; wp++) {
3635 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003636 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003637 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
Eric Andersenff9eee42001-06-29 04:57:14 +00003638 break;
3639 *cp = 0;
3640 if (nb <= 0)
3641 break;
3642 setval(lookup(*wp), e.linep);
3643 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003644 return (nb <= 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003645}
3646
Eric Andersen8401eea2004-08-04 19:16:54 +00003647static int doeval(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003648REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003649{
Eric Andersen8401eea2004-08-04 19:16:54 +00003650 return (RUN(awordlist, t->words + 1, wdchar));
Eric Andersenff9eee42001-06-29 04:57:14 +00003651}
3652
Eric Andersen8401eea2004-08-04 19:16:54 +00003653static int dotrap(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003654REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003655{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003656 REGISTER int n, i;
3657 REGISTER int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003658
3659 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003660 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003661 if (trap[i]) {
3662 prn(i);
3663 prs(": ");
3664 prs(trap[i]);
3665 prs("\n");
3666 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003667 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003668 }
3669 resetsig = isdigit(*t->words[1]);
3670 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3671 n = getsig(t->words[i]);
3672 freecell(trap[n]);
3673 trap[n] = 0;
3674 if (!resetsig) {
3675 if (*t->words[1] != '\0') {
3676 trap[n] = strsave(t->words[1], 0);
3677 setsig(n, sig);
3678 } else
3679 setsig(n, SIG_IGN);
3680 } else {
3681 if (interactive)
3682 if (n == SIGINT)
3683 setsig(n, onintr);
3684 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003685 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003686 else
3687 setsig(n, SIG_DFL);
3688 }
3689 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003690 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003691}
3692
Eric Andersen8401eea2004-08-04 19:16:54 +00003693static int getsig(s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003694char *s;
3695{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003696 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003697
3698 if ((n = getn(s)) < 0 || n > _NSIG) {
3699 err("trap: bad signal number");
3700 n = 0;
3701 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003702 return (n);
Eric Andersenff9eee42001-06-29 04:57:14 +00003703}
3704
Eric Andersen12de6cf2004-08-04 19:19:10 +00003705static void setsig(REGISTER int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003706{
3707 if (n == 0)
3708 return;
3709 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3710 ourtrap[n] = 1;
3711 signal(n, f);
3712 }
3713}
3714
Eric Andersen8401eea2004-08-04 19:16:54 +00003715static int getn(as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003716char *as;
3717{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003718 REGISTER char *s;
3719 REGISTER int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003720
3721 s = as;
3722 m = 1;
3723 if (*s == '-') {
3724 m = -1;
3725 s++;
3726 }
3727 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003728 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003729 if (*s) {
3730 prs(as);
3731 err(": bad number");
3732 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003733 return (n * m);
Eric Andersenff9eee42001-06-29 04:57:14 +00003734}
3735
Eric Andersen8401eea2004-08-04 19:16:54 +00003736static int dobreak(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003737struct op *t;
3738{
Eric Andersen8401eea2004-08-04 19:16:54 +00003739 return (brkcontin(t->words[1], 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00003740}
3741
Eric Andersen8401eea2004-08-04 19:16:54 +00003742static int docontinue(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003743struct op *t;
3744{
Eric Andersen8401eea2004-08-04 19:16:54 +00003745 return (brkcontin(t->words[1], 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00003746}
3747
Eric Andersen8401eea2004-08-04 19:16:54 +00003748static int brkcontin(cp, val)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003749REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003750int val;
3751{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003752 REGISTER struct brkcon *bc;
3753 REGISTER int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003754
Eric Andersen8401eea2004-08-04 19:16:54 +00003755 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003756 if (nl <= 0)
3757 nl = 999;
3758 do {
3759 if ((bc = brklist) == NULL)
3760 break;
3761 brklist = bc->nextlev;
3762 } while (--nl);
3763 if (nl) {
3764 err("bad break/continue level");
Eric Andersen8401eea2004-08-04 19:16:54 +00003765 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 }
3767 isbreak = val;
3768 longjmp(bc->brkpt, 1);
3769 /* NOTREACHED */
3770}
3771
Eric Andersen8401eea2004-08-04 19:16:54 +00003772static int doexit(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003773struct op *t;
3774{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003775 REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003776
3777 execflg = 0;
3778 if ((cp = t->words[1]) != NULL)
3779 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003780
3781 DBGPRINTF(("DOEXIT: calling leave(), t=0x%x\n", t));
3782
Eric Andersenff9eee42001-06-29 04:57:14 +00003783 leave();
3784 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00003785 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003786}
3787
Eric Andersen8401eea2004-08-04 19:16:54 +00003788static int doexport(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003789struct op *t;
3790{
Eric Andersen8401eea2004-08-04 19:16:54 +00003791 rdexp(t->words + 1, export, EXPORT);
3792 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003793}
3794
Eric Andersen8401eea2004-08-04 19:16:54 +00003795static int doreadonly(t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003796struct op *t;
3797{
Eric Andersen8401eea2004-08-04 19:16:54 +00003798 rdexp(t->words + 1, ronly, RONLY);
3799 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003800}
3801
Eric Andersen8401eea2004-08-04 19:16:54 +00003802static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003803{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003804 DBGPRINTF6(("RDEXP: enter, wp=0x%x, func=0x%x, key=%d\n", wp, f, key));
3805 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3806
Eric Andersenff9eee42001-06-29 04:57:14 +00003807 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003808 for (; *wp != NULL; wp++) {
3809 if (isassign(*wp)) {
3810 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003811
Matt Kraaif69bfc72001-07-12 19:39:59 +00003812 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003813 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003814 *cp = '\0';
3815 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003816 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003817 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003818 else
3819 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003820 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003821 } else
3822 putvlist(key, 1);
3823}
3824
Eric Andersen8401eea2004-08-04 19:16:54 +00003825static void badid(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003826REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003827{
3828 prs(s);
3829 err(": bad identifier");
3830}
3831
Eric Andersen8401eea2004-08-04 19:16:54 +00003832static int doset(t)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003833REGISTER struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00003834{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003835 REGISTER struct var *vp;
3836 REGISTER char *cp;
3837 REGISTER int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003838
3839 if ((cp = t->words[1]) == NULL) {
3840 for (vp = vlist; vp; vp = vp->next)
3841 varput(vp->name, 1);
Eric Andersen8401eea2004-08-04 19:16:54 +00003842 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003843 }
3844 if (*cp == '-') {
3845 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003846 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003847 if (*++cp == 0)
3848 flag['x'] = flag['v'] = 0;
3849 else
3850 for (; *cp; cp++)
3851 switch (*cp) {
3852 case 'e':
3853 if (!interactive)
3854 flag['e']++;
3855 break;
3856
3857 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003858 if (*cp >= 'a' && *cp <= 'z')
3859 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003860 break;
3861 }
3862 setdash();
3863 }
3864 if (t->words[1]) {
3865 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003866 for (n = 1; t->words[n]; n++)
3867 setarea((char *) t->words[n], 0);
3868 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003869 dolv = t->words;
3870 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003871 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003872 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003873 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003874}
3875
Eric Andersen8401eea2004-08-04 19:16:54 +00003876static void varput(s, out)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003877REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003878int out;
3879{
Matt Kraai69edfec2001-08-06 14:14:18 +00003880 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003881 write(out, s, strlen(s));
3882 write(out, "\n", 1);
3883 }
3884}
3885
3886
3887/*
3888 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3889 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003890 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003891static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003892{
3893 struct tms buf;
3894 long int clk_tck = sysconf(_SC_CLK_TCK);
3895
3896 times(&buf);
3897 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003898 (int) (buf.tms_utime / clk_tck / 60),
3899 ((double) buf.tms_utime) / clk_tck,
3900 (int) (buf.tms_stime / clk_tck / 60),
3901 ((double) buf.tms_stime) / clk_tck,
3902 (int) (buf.tms_cutime / clk_tck / 60),
3903 ((double) buf.tms_cutime) / clk_tck,
3904 (int) (buf.tms_cstime / clk_tck / 60),
3905 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003906 return 0;
3907}
3908
3909
Eric Andersen8401eea2004-08-04 19:16:54 +00003910static int (*inbuilt(char *s)) (struct op *) {
Eric Andersen1c039232001-07-07 00:05:55 +00003911 const struct builtincmd *bp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003912
Eric Andersen1c039232001-07-07 00:05:55 +00003913 for (bp = builtincmds; bp->name != NULL; bp++)
3914 if (strcmp(bp->name, s) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00003915 return (bp->builtinfunc);
Eric Andersen1c039232001-07-07 00:05:55 +00003916
Eric Andersen8401eea2004-08-04 19:16:54 +00003917 return (NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003918}
3919
3920/* -------- eval.c -------- */
3921
3922/*
3923 * ${}
3924 * `command`
3925 * blank interpretation
3926 * quoting
3927 * glob
3928 */
3929
Eric Andersen8401eea2004-08-04 19:16:54 +00003930static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003931{
3932 struct wdblock *wb;
3933 char **wp;
3934 char **wf;
3935 jmp_buf ev;
3936
3937#if __GNUC__
3938 /* Avoid longjmp clobbering */
3939 (void) &wp;
3940 (void) &ap;
3941#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003942
3943 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3944
Eric Andersenff9eee42001-06-29 04:57:14 +00003945 wp = NULL;
3946 wb = NULL;
3947 wf = NULL;
3948 if (newenv(setjmp(errpt = ev)) == 0) {
3949 while (*ap && isassign(*ap))
3950 expand(*ap++, &wb, f & ~DOGLOB);
3951 if (flag['k']) {
3952 for (wf = ap; *wf; wf++) {
3953 if (isassign(*wf))
3954 expand(*wf, &wb, f & ~DOGLOB);
3955 }
3956 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003957 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003958 if (!flag['k'] || !isassign(*ap))
3959 expand(*ap, &wb, f & ~DOKEY);
3960 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003961 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003962 wp = getwords(wb);
3963 quitenv();
3964 } else
3965 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003966
Eric Andersen8401eea2004-08-04 19:16:54 +00003967 return (gflg ? (char **) NULL : wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003968}
3969
3970/*
3971 * Make the exported environment from the exported
3972 * names in the dictionary. Keyword assignments
3973 * will already have been done.
3974 */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003975static char **makenv(int all)
Eric Andersenff9eee42001-06-29 04:57:14 +00003976{
Eric Andersen12de6cf2004-08-04 19:19:10 +00003977 REGISTER struct wdblock *wb;
3978 REGISTER struct var *vp;
3979
3980 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003981
3982 wb = NULL;
3983 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003984 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003985 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003986 wb = addword((char *) 0, wb);
3987 return (getwords(wb));
Eric Andersenff9eee42001-06-29 04:57:14 +00003988}
3989
Eric Andersen8401eea2004-08-04 19:16:54 +00003990static char *evalstr(cp, f)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003991REGISTER char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003992int f;
3993{
3994 struct wdblock *wb;
3995
Eric Andersen12de6cf2004-08-04 19:19:10 +00003996 DBGPRINTF6(("EVALSTR: enter, cp=0x%x, f=%d\n", cp, f));
3997
Eric Andersenff9eee42001-06-29 04:57:14 +00003998 wb = NULL;
3999 if (expand(cp, &wb, f)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004000 if (wb == NULL || wb->w_nword == 0
4001 || (cp = wb->w_words[0]) == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004002 cp = "";
4003 DELETE(wb);
4004 } else
4005 cp = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004006 return (cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004007}
4008
Eric Andersen12de6cf2004-08-04 19:19:10 +00004009static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00004010{
4011 jmp_buf ev;
4012
4013#if __GNUC__
4014 /* Avoid longjmp clobbering */
4015 (void) &cp;
4016#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00004017
4018 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
4019
Eric Andersenff9eee42001-06-29 04:57:14 +00004020 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004021
Eric Andersenff9eee42001-06-29 04:57:14 +00004022 if (cp == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004023 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004024
Eric Andersenff9eee42001-06-29 04:57:14 +00004025 if (!anys("$`'\"", cp) &&
Eric Andersen8401eea2004-08-04 19:16:54 +00004026 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004027 cp = strsave(cp, areanum);
4028 if (f & DOTRIM)
4029 unquote(cp);
4030 *wbp = addword(cp, *wbp);
Eric Andersen8401eea2004-08-04 19:16:54 +00004031 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004032 }
4033 if (newenv(setjmp(errpt = ev)) == 0) {
4034 PUSHIO(aword, cp, strchar);
4035 e.iobase = e.iop;
4036 while ((cp = blank(f)) && gflg == 0) {
4037 e.linep = cp;
4038 cp = strsave(cp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00004039 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004040 if (f & DOTRIM)
4041 unquote(cp);
4042 *wbp = addword(cp, *wbp);
4043 } else
4044 *wbp = glob(cp, *wbp);
4045 }
4046 quitenv();
4047 } else
4048 gflg = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004049 return (gflg == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004050}
4051
4052/*
4053 * Blank interpretation and quoting
4054 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004055static char *blank(f)
Eric Andersenff9eee42001-06-29 04:57:14 +00004056int f;
4057{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004058 REGISTER int c, c1;
4059 REGISTER char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004060 int scanequals, foundequals;
4061
Eric Andersen12de6cf2004-08-04 19:19:10 +00004062 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
4063
Eric Andersenff9eee42001-06-29 04:57:14 +00004064 sp = e.linep;
4065 scanequals = f & DOKEY;
4066 foundequals = 0;
4067
Eric Andersen8401eea2004-08-04 19:16:54 +00004068 loop:
Eric Andersenff9eee42001-06-29 04:57:14 +00004069 switch (c = subgetc('"', foundequals)) {
4070 case 0:
4071 if (sp == e.linep)
Eric Andersen8401eea2004-08-04 19:16:54 +00004072 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004073 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004074 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004075
4076 default:
4077 if (f & DOBLANK && any(c, ifs->value))
4078 goto loop;
4079 break;
4080
4081 case '"':
4082 case '\'':
4083 scanequals = 0;
4084 if (INSUB())
4085 break;
4086 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
4087 if (c == 0)
4088 break;
4089 if (c == '\'' || !any(c, "$`\""))
4090 c |= QUOTE;
4091 *e.linep++ = c;
4092 }
4093 c = 0;
4094 }
4095 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00004096 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004097 scanequals = 0;
4098 for (;;) {
4099 c = subgetc('"', foundequals);
4100 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00004101 f & (DOBLANK && any(c, ifs->value)) ||
4102 (!INSUB() && any(c, "\"'"))) {
4103 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004104 unget(c);
4105 if (any(c, "\"'"))
4106 goto loop;
4107 break;
4108 }
4109 if (scanequals) {
4110 if (c == '=') {
4111 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00004112 scanequals = 0;
4113 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00004114 scanequals = 0;
4115 }
4116 *e.linep++ = c;
4117 }
4118 *e.linep++ = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004119 return (sp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004120}
4121
4122/*
4123 * Get characters, substituting for ` and $
4124 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004125static int subgetc(ec, quoted)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004126REGISTER char ec;
Eric Andersenff9eee42001-06-29 04:57:14 +00004127int quoted;
4128{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004129 REGISTER char c;
4130
4131 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00004132
Eric Andersen8401eea2004-08-04 19:16:54 +00004133 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00004134 c = my_getc(ec);
4135 if (!INSUB() && ec != '\'') {
4136 if (c == '`') {
4137 if (grave(quoted) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004138 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004139 e.iop->task = XGRAVE;
4140 goto again;
4141 }
4142 if (c == '$' && (c = dollar(quoted)) == 0) {
4143 e.iop->task = XDOLL;
4144 goto again;
4145 }
4146 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004147 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004148}
4149
4150/*
4151 * Prepare to generate the string returned by ${} substitution.
4152 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004153static int dollar(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004154int quoted;
4155{
4156 int otask;
4157 struct io *oiop;
4158 char *dolp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004159 REGISTER char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004160 struct var *vp;
4161
Eric Andersen12de6cf2004-08-04 19:19:10 +00004162 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
4163
Eric Andersenff9eee42001-06-29 04:57:14 +00004164 c = readc();
4165 s = e.linep;
4166 if (c != '{') {
4167 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00004168 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00004169 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00004170 if (e.linep < elinep)
4171 *e.linep++ = c;
4172 unget(c);
4173 }
4174 c = 0;
4175 } else {
4176 oiop = e.iop;
4177 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004178
Eric Andersenff9eee42001-06-29 04:57:14 +00004179 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00004180 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004181 if (e.linep < elinep)
4182 *e.linep++ = c;
4183 if (oiop == e.iop)
4184 e.iop->task = otask;
4185 if (c != '}') {
4186 err("unclosed ${");
4187 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004188 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004189 }
4190 }
4191 if (e.linep >= elinep) {
4192 err("string in ${} too long");
4193 gflg++;
4194 e.linep -= 10;
4195 }
4196 *e.linep = 0;
4197 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00004198 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004199 if (any(*cp, "=-+?")) {
4200 c = *cp;
4201 *cp++ = 0;
4202 break;
4203 }
4204 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4205 if (dolc > 1) {
4206 /* currently this does not distinguish $* and $@ */
4207 /* should check dollar */
4208 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00004209 PUSHIO(awordlist, dolv + 1, dolchar);
4210 return (0);
4211 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00004212 s[0] = '1';
4213 s[1] = 0;
4214 }
4215 }
4216 vp = lookup(s);
4217 if ((dolp = vp->value) == null) {
4218 switch (c) {
4219 case '=':
4220 if (isdigit(*s)) {
4221 err("cannot use ${...=...} with $n");
4222 gflg++;
4223 break;
4224 }
4225 setval(vp, cp);
4226 dolp = vp->value;
4227 break;
4228
4229 case '-':
4230 dolp = strsave(cp, areanum);
4231 break;
4232
4233 case '?':
4234 if (*cp == 0) {
4235 prs("missing value for ");
4236 err(s);
4237 } else
4238 err(cp);
4239 gflg++;
4240 break;
4241 }
4242 } else if (c == '+')
4243 dolp = strsave(cp, areanum);
4244 if (flag['u'] && dolp == null) {
4245 prs("unset variable: ");
4246 err(s);
4247 gflg++;
4248 }
4249 e.linep = s;
4250 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Eric Andersen8401eea2004-08-04 19:16:54 +00004251 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004252}
4253
4254/*
4255 * Run the command in `...` and read its output.
4256 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004257
Eric Andersen8401eea2004-08-04 19:16:54 +00004258static int grave(quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004259int quoted;
4260{
Eric Andersenff9eee42001-06-29 04:57:14 +00004261 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004262 REGISTER int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004263 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004264 int pf[2];
Eric Andersen737f5fb2003-03-14 16:05:59 +00004265 static char child_cmd[LINELIM];
4266 char *src;
4267 char *dest;
4268 int count;
4269 int ignore;
4270 int ignore_once;
4271 char *argument_list[4];
Eric Andersenff9eee42001-06-29 04:57:14 +00004272
4273#if __GNUC__
4274 /* Avoid longjmp clobbering */
4275 (void) &cp;
4276#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004277
Eric Andersenff9eee42001-06-29 04:57:14 +00004278 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4279 if (*cp == 0) {
4280 err("no closing `");
Eric Andersen8401eea2004-08-04 19:16:54 +00004281 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004283
4284 /* string copy with dollar expansion */
4285 src = e.iop->argp->aword;
4286 dest = child_cmd;
4287 count = 0;
4288 ignore = 0;
4289 ignore_once = 0;
4290 while ((*src != '`') && (count < LINELIM)) {
4291 if (*src == '\'')
4292 ignore = !ignore;
4293 if (*src == '\\')
4294 ignore_once = 1;
4295 if (*src == '$' && !ignore && !ignore_once) {
4296 struct var *vp;
4297 char var_name[LINELIM];
4298 char alt_value[LINELIM];
4299 int var_index = 0;
4300 int alt_index = 0;
4301 char operator = 0;
4302 int braces = 0;
4303 char *value;
4304
4305 src++;
4306 if (*src == '{') {
4307 braces = 1;
4308 src++;
4309 }
4310
4311 var_name[var_index++] = *src++;
4312 while (isalnum(*src))
4313 var_name[var_index++] = *src++;
4314 var_name[var_index] = 0;
4315
4316 if (braces) {
4317 switch (*src) {
4318 case '}':
4319 break;
4320 case '-':
4321 case '=':
4322 case '+':
4323 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004324 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004325 break;
4326 default:
4327 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004328 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004329 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004330 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004331 src++;
4332 while (*src && (*src != '}')) {
4333 alt_value[alt_index++] = *src++;
4334 }
4335 alt_value[alt_index] = 0;
4336 if (*src != '}') {
4337 err("unclosed ${\n");
Eric Andersen8401eea2004-08-04 19:16:54 +00004338 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004339 }
4340 }
4341 src++;
4342 }
4343
4344 vp = lookup(var_name);
4345 if (vp->value != null)
Eric Andersen8401eea2004-08-04 19:16:54 +00004346 value = (operator == '+') ? alt_value : vp->value;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004347 else if (operator == '?') {
4348 err(alt_value);
Eric Andersen8401eea2004-08-04 19:16:54 +00004349 return (0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004350 } else if (alt_index && (operator != '+')) {
4351 value = alt_value;
4352 if (operator == '=')
4353 setval(vp, value);
4354 } else
4355 continue;
4356
4357 while (*value && (count < LINELIM)) {
4358 *dest++ = *value++;
4359 count++;
4360 }
4361 } else {
4362 *dest++ = *src++;
4363 count++;
4364 ignore_once = 0;
4365 }
4366 }
4367 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004368
Eric Andersenff9eee42001-06-29 04:57:14 +00004369 if (openpipe(pf) < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004370 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004371
Eric Andersen8401eea2004-08-04 19:16:54 +00004372 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004373
4374 DBGPRINTF3(("GRAVE: i is %d\n", io));
4375
Eric Andersen737f5fb2003-03-14 16:05:59 +00004376 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004377 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004378 err((char *) bb_msg_memory_exhausted);
4379 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004380 }
4381 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004382 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004383 e.iop->argp->aword = ++cp;
4384 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004385 PUSHIO(afile, remap(pf[0]),
4386 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4387 gravechar));
4388 return (1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004389 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004390 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004391 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004392 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004393 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4394 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004395
Eric Andersenff9eee42001-06-29 04:57:14 +00004396 dup2(pf[1], 1);
4397 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004398
Eric Andersen8401eea2004-08-04 19:16:54 +00004399 argument_list[0] = (char *) DEFAULT_SHELL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004400 argument_list[1] = "-c";
4401 argument_list[2] = child_cmd;
4402 argument_list[3] = 0;
4403
Eric Andersen12de6cf2004-08-04 19:19:10 +00004404 cp = rexecve(argument_list[0], argument_list, makenv(1));
4405 prs(argument_list[0]);
4406 prs(": ");
4407 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004408 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004409}
4410
Eric Andersen737f5fb2003-03-14 16:05:59 +00004411
Eric Andersen8401eea2004-08-04 19:16:54 +00004412static char *unquote(as)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004413REGISTER char *as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004414{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004415 REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004416
4417 if ((s = as) != NULL)
4418 while (*s)
4419 *s++ &= ~QUOTE;
Eric Andersen8401eea2004-08-04 19:16:54 +00004420 return (as);
Eric Andersenff9eee42001-06-29 04:57:14 +00004421}
4422
4423/* -------- glob.c -------- */
4424
4425/*
4426 * glob
4427 */
4428
4429#define scopy(x) strsave((x), areanum)
4430#define BLKSIZ 512
4431#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4432
Eric Andersen8401eea2004-08-04 19:16:54 +00004433static struct wdblock *cl, *nl;
4434static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004435
Eric Andersen8401eea2004-08-04 19:16:54 +00004436static struct wdblock *glob(cp, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004437char *cp;
4438struct wdblock *wb;
4439{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004440 REGISTER int i;
4441 REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004442
4443 if (cp == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004444 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004445 i = 0;
4446 for (pp = cp; *pp; pp++)
4447 if (any(*pp, spcl))
4448 i++;
4449 else if (!any(*pp & ~QUOTE, spcl))
4450 *pp &= ~QUOTE;
4451 if (i != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004452 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4453 cl = nl) {
4454 nl = newword(cl->w_nword * 2);
4455 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004456 for (pp = cl->w_words[i]; *pp; pp++)
4457 if (any(*pp, spcl)) {
4458 globname(cl->w_words[i], pp);
4459 break;
4460 }
4461 if (*pp == '\0')
4462 nl = addword(scopy(cl->w_words[i]), nl);
4463 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004464 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004465 DELETE(cl->w_words[i]);
4466 DELETE(cl);
4467 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004468 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004469 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004470 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004471 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004472 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004473 wb = addword(cl->w_words[i], wb);
4474 DELETE(cl);
Eric Andersen8401eea2004-08-04 19:16:54 +00004475 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004476 }
4477 }
4478 wb = addword(unquote(cp), wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004479 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004480}
4481
Eric Andersen8401eea2004-08-04 19:16:54 +00004482static void globname(we, pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004483char *we;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004484REGISTER char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004485{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004486 REGISTER char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004487 char *name, *gp, *dp;
4488 int k;
4489 DIR *dirp;
4490 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004491 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004492 struct stat dbuf;
4493
4494 for (np = we; np != pp; pp--)
4495 if (pp[-1] == '/')
4496 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004497 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004498 *cp++ = *np++;
4499 *cp++ = '.';
4500 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004501 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004502 *cp++ = *np++;
4503 *cp = '\0';
4504 dirp = opendir(dp);
4505 if (dirp == 0) {
4506 DELETE(dp);
4507 DELETE(gp);
4508 return;
4509 }
4510 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004511 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004512 /* XXX Hmmm... What this could be? (abial) */
4513 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004514 if (ent[j].d_ino == 0)
4515 continue;
4516 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004517 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004518 if (dname[0] == '.')
4519 if (*gp != '.')
4520 continue;
4521 for (k = 0; k < NAME_MAX; k++)
4522 if (any(dname[k], spcl))
4523 dname[k] |= QUOTE;
4524 if (gmatch(dname, gp)) {
4525 name = generate(we, pp, dname, np);
4526 if (*np && !anys(np, spcl)) {
4527 if (stat(name, &dbuf)) {
4528 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004529 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004530 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004531 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004532 nl = addword(name, nl);
4533 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004534 }
4535 closedir(dirp);
4536 DELETE(dp);
4537 DELETE(gp);
4538}
4539
4540/*
4541 * generate a pathname as below.
4542 * start..end1 / middle end
4543 * the slashes come for free
4544 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004545static char *generate(start1, end1, middle, end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004546char *start1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004547REGISTER char *end1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004548char *middle, *end;
4549{
4550 char *p;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004551 REGISTER char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004552
Eric Andersen8401eea2004-08-04 19:16:54 +00004553 p = op =
4554 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004555 for (xp = start1; xp != end1;)
4556 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004557 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004558 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004559 for (xp = end; (*op++ = *xp++) != '\0';);
4560 return (p);
Eric Andersenff9eee42001-06-29 04:57:14 +00004561}
4562
Eric Andersen8401eea2004-08-04 19:16:54 +00004563static int anyspcl(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004564REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004565{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004566 REGISTER int i;
4567 REGISTER char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004568
4569 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004570 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004571 if (anys(spcl, *wd++))
Eric Andersen8401eea2004-08-04 19:16:54 +00004572 return (1);
4573 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004574}
4575
Eric Andersen8401eea2004-08-04 19:16:54 +00004576static int xstrcmp(p1, p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004577char *p1, *p2;
4578{
Eric Andersen8401eea2004-08-04 19:16:54 +00004579 return (strcmp(*(char **) p1, *(char **) p2));
Eric Andersenff9eee42001-06-29 04:57:14 +00004580}
4581
4582/* -------- word.c -------- */
4583
Eric Andersen8401eea2004-08-04 19:16:54 +00004584static struct wdblock *newword(nw)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004585REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004586{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004587 REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004588
Eric Andersen8401eea2004-08-04 19:16:54 +00004589 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004590 wb->w_bsize = nw;
4591 wb->w_nword = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004592 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004593}
4594
Eric Andersen8401eea2004-08-04 19:16:54 +00004595static struct wdblock *addword(wd, wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004596char *wd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004597REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004598{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004599 REGISTER struct wdblock *wb2;
4600 REGISTER int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004601
4602 if (wb == NULL)
4603 wb = newword(NSTART);
4604 if ((nw = wb->w_nword) >= wb->w_bsize) {
4605 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004606 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4607 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004608 wb2->w_nword = nw;
4609 DELETE(wb);
4610 wb = wb2;
4611 }
4612 wb->w_words[wb->w_nword++] = wd;
Eric Andersen8401eea2004-08-04 19:16:54 +00004613 return (wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00004614}
Eric Andersen8401eea2004-08-04 19:16:54 +00004615
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004616static
Eric Andersen8401eea2004-08-04 19:16:54 +00004617char **getwords(wb)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004618REGISTER struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004619{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004620 REGISTER char **wd;
4621 REGISTER int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004622
4623 if (wb == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004624 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004625 if (wb->w_nword == 0) {
4626 DELETE(wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00004627 return ((char **) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00004628 }
4629 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004630 memcpy((char *) wd, (char *) wb->w_words, nb);
4631 DELETE(wb); /* perhaps should done by caller */
4632 return (wd);
Eric Andersenff9eee42001-06-29 04:57:14 +00004633}
4634
Eric Andersen8401eea2004-08-04 19:16:54 +00004635int (*func) (char *, char *);
4636int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004637
Eric Andersen8401eea2004-08-04 19:16:54 +00004638static void glob0(a0, a1, a2, a3)
Eric Andersenff9eee42001-06-29 04:57:14 +00004639char *a0;
4640unsigned a1;
4641int a2;
4642int (*a3) (char *, char *);
4643{
4644 func = a3;
4645 globv = a2;
4646 glob1(a0, a0 + a1 * a2);
4647}
4648
Eric Andersen8401eea2004-08-04 19:16:54 +00004649static void glob1(base, lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004650char *base, *lim;
4651{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004652 REGISTER char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004653 int v2;
4654 char *lptr, *hptr;
4655 int c;
4656 unsigned n;
4657
4658
4659 v2 = globv;
4660
Eric Andersen8401eea2004-08-04 19:16:54 +00004661 top:
4662 if ((n = (int) (lim - base)) <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004663 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004664 n = v2 * (n / (2 * v2));
4665 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004666 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004667 j = lim - v2;
4668 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 if (i < lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004670 if ((c = (*func) (i, lptr)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004671 glob2(i, lptr -= v2);
4672 continue;
4673 }
4674 if (c < 0) {
4675 i += v2;
4676 continue;
4677 }
4678 }
4679
Eric Andersen8401eea2004-08-04 19:16:54 +00004680 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004681 if (j > hptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004682 if ((c = (*func) (hptr, j)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004683 glob2(hptr += v2, j);
4684 goto begin;
4685 }
4686 if (c > 0) {
4687 if (i == lptr) {
4688 glob3(i, hptr += v2, j);
4689 i = lptr += v2;
4690 goto begin;
4691 }
4692 glob2(i, j);
4693 j -= v2;
4694 i += v2;
4695 continue;
4696 }
4697 j -= v2;
4698 goto begin;
4699 }
4700
4701
4702 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004703 if (lptr - base >= lim - hptr) {
4704 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004705 lim = lptr;
4706 } else {
4707 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004708 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004709 }
4710 goto top;
4711 }
4712
4713
4714 glob3(j, lptr -= v2, i);
4715 j = hptr -= v2;
4716 }
4717}
4718
Eric Andersen8401eea2004-08-04 19:16:54 +00004719static void glob2(i, j)
Eric Andersenff9eee42001-06-29 04:57:14 +00004720char *i, *j;
4721{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004722 REGISTER char *index1, *index2, c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004723 int m;
4724
4725 m = globv;
4726 index1 = i;
4727 index2 = j;
4728 do {
4729 c = *index1;
4730 *index1++ = *index2;
4731 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004732 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004733}
4734
Eric Andersen8401eea2004-08-04 19:16:54 +00004735static void glob3(i, j, k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004736char *i, *j, *k;
4737{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004738 REGISTER char *index1, *index2, *index3;
Eric Andersenff9eee42001-06-29 04:57:14 +00004739 int c;
4740 int m;
4741
4742 m = globv;
4743 index1 = i;
4744 index2 = j;
4745 index3 = k;
4746 do {
4747 c = *index1;
4748 *index1++ = *index3;
4749 *index3++ = *index2;
4750 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004751 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004752}
4753
4754/* -------- io.c -------- */
4755
4756/*
4757 * shell IO
4758 */
4759
Eric Andersen8401eea2004-08-04 19:16:54 +00004760static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004761{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004762 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004763
Eric Andersen8401eea2004-08-04 19:16:54 +00004764 if (e.linep > elinep) {
4765 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004766 err("input line too long");
4767 gflg++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004768 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004769 }
4770 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004771 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004772 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004773 c = readc();
4774 if (c == '\n' && ec != '\"')
Eric Andersen8401eea2004-08-04 19:16:54 +00004775 return (my_getc(ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00004776 c |= QUOTE;
4777 }
4778 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004779 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004780}
4781
Eric Andersen8401eea2004-08-04 19:16:54 +00004782static void unget(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004783int c;
4784{
4785 if (e.iop >= e.iobase)
4786 e.iop->peekc = c;
4787}
4788
Eric Andersen8401eea2004-08-04 19:16:54 +00004789static int eofc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004790{
Eric Andersen8401eea2004-08-04 19:16:54 +00004791 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004792}
4793
Eric Andersen8401eea2004-08-04 19:16:54 +00004794static int readc()
Eric Andersenff9eee42001-06-29 04:57:14 +00004795{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004796 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004797
Eric Andersen12de6cf2004-08-04 19:19:10 +00004798 RCPRINTF(("READC: e.iop 0x%x, e.iobase 0x%x\n", e.iop, e.iobase));
4799
4800 for (; e.iop >= e.iobase; e.iop--) {
4801 RCPRINTF(("READC: e.iop 0x%x, peekc 0x%x\n", e.iop, e.iop->peekc));
Eric Andersenff9eee42001-06-29 04:57:14 +00004802 if ((c = e.iop->peekc) != '\0') {
4803 e.iop->peekc = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004804 return (c);
4805 } else {
4806 if (e.iop->prev != 0) {
4807 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4808 if (c == -1) {
4809 e.iop++;
4810 continue;
4811 }
4812 if (e.iop == iostack)
4813 ioecho(c);
4814 return (e.iop->prev = c);
4815 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4816 e.iop->prev = 0;
4817 if (e.iop == iostack)
4818 ioecho('\n');
4819 return '\n';
4820 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004821 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004822 if (e.iop->task == XIO) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004823 if (multiline) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004824 return e.iop->prev = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004825 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004826 if (interactive && e.iop == iostack + 1) {
4827#ifdef CONFIG_FEATURE_COMMAND_EDITING
4828 current_prompt = prompt->value;
4829#else
4830 prs(prompt->value);
4831#endif
4832 }
4833 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004834 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004835
4836 } /* FOR */
4837
4838 if (e.iop >= iostack) {
4839 RCPRINTF(("READC: return 0, e.iop 0x%x\n", e.iop));
Eric Andersen8401eea2004-08-04 19:16:54 +00004840 return (0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004841 }
4842
4843 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004844 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004845
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 /* NOTREACHED */
Eric Andersen8401eea2004-08-04 19:16:54 +00004847 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004848}
4849
Eric Andersen8401eea2004-08-04 19:16:54 +00004850static void ioecho(c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004851char c;
4852{
4853 if (flag['v'])
4854 write(2, &c, sizeof c);
4855}
4856
Eric Andersen12de6cf2004-08-04 19:19:10 +00004857
Eric Andersen8401eea2004-08-04 19:16:54 +00004858static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004859{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004860 DBGPRINTF(("PUSHIO: argp 0x%x, argp->afid 0x%x, e.iop 0x%x\n", argp,
4861 argp->afid, e.iop));
4862
4863 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004864 if (++e.iop >= &iostack[NPUSH]) {
4865 e.iop--;
4866 err("Shell input nested too deeply");
4867 gflg++;
4868 return;
4869 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004870
4871 /* We did not overflow the NPUSH array spots so setup data structs */
4872
4873 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004874
4875 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004876 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004877 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004878
4879 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4880 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4881
4882 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4883
4884 if (e.iop == &iostack[0])
4885 e.iop->argp->afbuf = &mainbuf;
4886 else
4887 e.iop->argp->afbuf = &sharedbuf;
4888
4889 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4890 /* This line appears to be active when running scripts from command line */
4891 if ((isatty(e.iop->argp->afile) == 0)
4892 && (e.iop == &iostack[0]
4893 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4894 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4895 bufid = AFID_ID; /* AFID_ID = 0 */
4896
4897 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004898 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004899
4900 DBGPRINTF(("PUSHIO: iostack 0x%x, e.iop 0x%x, afbuf 0x%x\n",
4901 iostack, e.iop, e.iop->argp->afbuf));
4902 DBGPRINTF(("PUSHIO: mbuf 0x%x, sbuf 0x%x, bid %d, e.iop 0x%x\n",
4903 &mainbuf, &sharedbuf, bufid, e.iop));
4904
Eric Andersenff9eee42001-06-29 04:57:14 +00004905 }
4906
Eric Andersen8401eea2004-08-04 19:16:54 +00004907 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004908 e.iop->peekc = 0;
4909 e.iop->xchar = 0;
4910 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004911
Eric Andersenff9eee42001-06-29 04:57:14 +00004912 if (fn == filechar || fn == linechar)
4913 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004914 else if (fn == (int (*)(struct ioarg *)) gravechar
4915 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004916 e.iop->task = XGRAVE;
4917 else
4918 e.iop->task = XOTHER;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004919
4920 return;
Eric Andersenff9eee42001-06-29 04:57:14 +00004921}
4922
Eric Andersen8401eea2004-08-04 19:16:54 +00004923static struct io *setbase(ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004924struct io *ip;
4925{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004926 REGISTER struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004927
4928 xp = e.iobase;
4929 e.iobase = ip;
Eric Andersen8401eea2004-08-04 19:16:54 +00004930 return (xp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004931}
4932
4933/*
4934 * Input generating functions
4935 */
4936
4937/*
4938 * Produce the characters of a string, then a newline, then EOF.
4939 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004940static int nlchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004941REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004942{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004943 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004944
4945 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004946 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004947 if ((c = *ap->aword++) == 0) {
4948 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004949 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004950 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004951 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004952}
4953
4954/*
4955 * Given a list of words, produce the characters
4956 * in them, with a space after each word.
4957 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004958static int wdchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004959REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004960{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004961 REGISTER char c;
4962 REGISTER char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004963
4964 if ((wl = ap->awordlist) == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004965 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004966 if (*wl != NULL) {
4967 if ((c = *(*wl)++) != 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00004968 return (c & 0177);
Eric Andersenff9eee42001-06-29 04:57:14 +00004969 ap->awordlist++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004970 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00004971 }
4972 ap->awordlist = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00004973 return ('\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00004974}
4975
4976/*
4977 * Return the characters of a list of words,
4978 * producing a space between them.
4979 */
Eric Andersen8401eea2004-08-04 19:16:54 +00004980static int dolchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004981REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004982{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004983 REGISTER char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004984
4985 if ((wp = *ap->awordlist++) != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004986 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4987 return (-1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004988 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004989 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004990}
4991
Eric Andersen8401eea2004-08-04 19:16:54 +00004992static int xxchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00004993REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00004994{
Eric Andersen12de6cf2004-08-04 19:19:10 +00004995 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004996
4997 if (ap->aword == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00004998 return (0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004999 if ((c = *ap->aword++) == '\0') {
5000 ap->aword = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00005001 return (' ');
Eric Andersenff9eee42001-06-29 04:57:14 +00005002 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005003 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005004}
5005
5006/*
5007 * Produce the characters from a single word (string).
5008 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005009static int strchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005010REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005011{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005012 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005013
5014 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005015 return (0);
5016 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005017}
5018
5019/*
5020 * Produce quoted characters from a single word (string).
5021 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005022static int qstrchar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005023REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005024{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005025 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005026
5027 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005028 return (0);
5029 return (c | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005030}
5031
5032/*
5033 * Return the characters from a file.
5034 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005035static int filechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005036REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005037{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005038 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005039 char c;
5040 struct iobuf *bp = ap->afbuf;
5041
5042 if (ap->afid != AFID_NOBUF) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005043 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00005044
Eric Andersen8401eea2004-08-04 19:16:54 +00005045 if (i)
5046 lseek(ap->afile, ap->afpos, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005047
Eric Andersen8401eea2004-08-04 19:16:54 +00005048 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005049
Eric Andersen8401eea2004-08-04 19:16:54 +00005050 if (i <= 0) {
5051 closef(ap->afile);
5052 return 0;
5053 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005054
Eric Andersen8401eea2004-08-04 19:16:54 +00005055 bp->id = ap->afid;
5056 bp->ebufp = (bp->bufp = bp->buf) + i;
5057 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005058
Eric Andersen8401eea2004-08-04 19:16:54 +00005059 ap->afpos++;
5060 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00005061 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005062#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00005063 if (interactive && isatty(ap->afile)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005064 static char mycommand[BUFSIZ];
5065 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00005066
Eric Andersen8401eea2004-08-04 19:16:54 +00005067 while (size == 0 || position >= size) {
5068 cmdedit_read_input(current_prompt, mycommand);
5069 size = strlen(mycommand);
5070 position = 0;
5071 }
5072 c = mycommand[position];
5073 position++;
5074 return (c);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005075 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00005076#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005077
Eric Andersenff9eee42001-06-29 04:57:14 +00005078 {
Eric Andersen7467c8d2001-07-12 20:26:32 +00005079 i = safe_read(ap->afile, &c, sizeof(c));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005080 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
Eric Andersenff9eee42001-06-29 04:57:14 +00005081 }
5082}
5083
5084/*
5085 * Return the characters from a here temp file.
5086 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005087static int herechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005088REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005089{
5090 char c;
5091
5092
5093 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
5094 close(ap->afile);
5095 c = 0;
5096 }
5097 return (c);
5098
5099}
5100
5101/*
5102 * Return the characters produced by a process (`...`).
5103 * Quote them if required, and remove any trailing newline characters.
5104 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005105static int gravechar(ap, iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00005106struct ioarg *ap;
5107struct io *iop;
5108{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005109 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005110
Eric Andersen8401eea2004-08-04 19:16:54 +00005111 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00005112 c = ' ';
Eric Andersen8401eea2004-08-04 19:16:54 +00005113 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005114}
5115
Eric Andersen8401eea2004-08-04 19:16:54 +00005116static int qgravechar(ap, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005117REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005118struct io *iop;
5119{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005120 REGISTER int c;
5121
5122 DBGPRINTF3(("QGRAVECHAR: enter, ap=0x%x, iop=0x%x\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00005123
5124 if (iop->xchar) {
5125 if (iop->nlcount) {
5126 iop->nlcount--;
Eric Andersen8401eea2004-08-04 19:16:54 +00005127 return ('\n' | QUOTE);
Eric Andersenff9eee42001-06-29 04:57:14 +00005128 }
5129 c = iop->xchar;
5130 iop->xchar = 0;
5131 } else if ((c = filechar(ap)) == '\n') {
5132 iop->nlcount = 1;
5133 while ((c = filechar(ap)) == '\n')
5134 iop->nlcount++;
5135 iop->xchar = c;
5136 if (c == 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00005137 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005138 iop->nlcount--;
5139 c = '\n';
5140 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005141 return (c != 0 ? c | QUOTE : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00005142}
5143
5144/*
5145 * Return a single command (usually the first line) from a file.
5146 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005147static int linechar(ap)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005148REGISTER struct ioarg *ap;
Eric Andersenff9eee42001-06-29 04:57:14 +00005149{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005150 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005151
5152 if ((c = filechar(ap)) == '\n') {
5153 if (!multiline) {
5154 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00005155 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00005156 }
5157 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005158 return (c);
Eric Andersenff9eee42001-06-29 04:57:14 +00005159}
5160
Eric Andersen8401eea2004-08-04 19:16:54 +00005161static void prs(s)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005162REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005163{
5164 if (*s)
5165 write(2, s, strlen(s));
5166}
5167
Eric Andersen8401eea2004-08-04 19:16:54 +00005168static void prn(u)
Eric Andersenff9eee42001-06-29 04:57:14 +00005169unsigned u;
5170{
Eric Andersen737f5fb2003-03-14 16:05:59 +00005171 prs(itoa(u));
Eric Andersenff9eee42001-06-29 04:57:14 +00005172}
5173
Eric Andersen8401eea2004-08-04 19:16:54 +00005174static void closef(i)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005175REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005176{
5177 if (i > 2)
5178 close(i);
5179}
5180
Eric Andersen8401eea2004-08-04 19:16:54 +00005181static void closeall()
Eric Andersenff9eee42001-06-29 04:57:14 +00005182{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005183 REGISTER int u;
Eric Andersenff9eee42001-06-29 04:57:14 +00005184
Eric Andersen8401eea2004-08-04 19:16:54 +00005185 for (u = NUFILE; u < NOFILE;)
Eric Andersenff9eee42001-06-29 04:57:14 +00005186 close(u++);
5187}
5188
Eric Andersen12de6cf2004-08-04 19:19:10 +00005189
Eric Andersenff9eee42001-06-29 04:57:14 +00005190/*
5191 * remap fd into Shell's fd space
5192 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005193static int remap(fd)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005194REGISTER int fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005195{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005196 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005197 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00005198 int newfd;
5199
5200
5201 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00005202
5203 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005204 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005205 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005206
Eric Andersenff9eee42001-06-29 04:57:14 +00005207 do {
5208 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005209 newfd = dup(fd);
5210 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00005211 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005212
Eric Andersen8401eea2004-08-04 19:16:54 +00005213 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00005214 if (map[i])
5215 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005216
Eric Andersenff9eee42001-06-29 04:57:14 +00005217 if (fd < 0)
5218 err("too many files open in shell");
5219 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00005220
Eric Andersen8401eea2004-08-04 19:16:54 +00005221 return (fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00005222}
5223
Eric Andersen8401eea2004-08-04 19:16:54 +00005224static int openpipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005225REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005226{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005227 REGISTER int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005228
5229 if ((i = pipe(pv)) < 0)
5230 err("can't create pipe - try again");
Eric Andersen8401eea2004-08-04 19:16:54 +00005231 return (i);
Eric Andersenff9eee42001-06-29 04:57:14 +00005232}
5233
Eric Andersen8401eea2004-08-04 19:16:54 +00005234static void closepipe(pv)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005235REGISTER int *pv;
Eric Andersenff9eee42001-06-29 04:57:14 +00005236{
5237 if (pv != NULL) {
5238 close(*pv++);
5239 close(*pv);
5240 }
5241}
5242
5243/* -------- here.c -------- */
5244
5245/*
5246 * here documents
5247 */
5248
Eric Andersen8401eea2004-08-04 19:16:54 +00005249static void markhere(s, iop)
Eric Andersen12de6cf2004-08-04 19:19:10 +00005250REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005251struct ioword *iop;
5252{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005253 REGISTER struct here *h, *lh;
5254
5255 DBGPRINTF7(("MARKHERE: enter, s=0x%x\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00005256
5257 h = (struct here *) space(sizeof(struct here));
5258 if (h == 0)
5259 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005260
Eric Andersenff9eee42001-06-29 04:57:14 +00005261 h->h_tag = evalstr(s, DOSUB);
5262 if (h->h_tag == 0)
5263 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005264
Eric Andersenff9eee42001-06-29 04:57:14 +00005265 h->h_iop = iop;
5266 iop->io_name = 0;
5267 h->h_next = NULL;
5268 if (inhere == 0)
5269 inhere = h;
5270 else
Eric Andersen8401eea2004-08-04 19:16:54 +00005271 for (lh = inhere; lh != NULL; lh = lh->h_next)
Eric Andersenff9eee42001-06-29 04:57:14 +00005272 if (lh->h_next == 0) {
5273 lh->h_next = h;
5274 break;
5275 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005276 iop->io_flag |= IOHERE | IOXHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005277 for (s = h->h_tag; *s; s++)
5278 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005279 iop->io_flag &= ~IOXHERE;
5280 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005281 }
5282 h->h_dosub = iop->io_flag & IOXHERE;
5283}
5284
Eric Andersen8401eea2004-08-04 19:16:54 +00005285static void gethere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005286{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005287 REGISTER struct here *h, *hp;
5288
5289 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005290
5291 /* Scan here files first leaving inhere list in place */
5292 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005293 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005294
5295 /* Make inhere list active - keep list intact for scraphere */
5296 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005297 hp->h_next = acthere;
5298 acthere = inhere;
5299 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005300 }
5301}
5302
Eric Andersen8401eea2004-08-04 19:16:54 +00005303static void readhere(name, s, ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005304char **name;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005305REGISTER char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00005306int ec;
5307{
5308 int tf;
5309 char tname[30] = ".msh_XXXXXX";
Eric Andersen12de6cf2004-08-04 19:19:10 +00005310 REGISTER int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005311 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005312 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005313 char *thenext;
5314
Eric Andersen12de6cf2004-08-04 19:19:10 +00005315 DBGPRINTF7(("READHERE: enter, name=0x%x, s=0x%x\n", name, s));
5316
Eric Andersenff9eee42001-06-29 04:57:14 +00005317 tf = mkstemp(tname);
5318 if (tf < 0)
5319 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005320
Eric Andersenff9eee42001-06-29 04:57:14 +00005321 *name = strsave(tname, areanum);
5322 if (newenv(setjmp(errpt = ev)) != 0)
5323 unlink(tname);
5324 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005325 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005326 e.iobase = e.iop;
5327 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005328 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005329#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005330 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005331#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005332 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005333#endif
5334 }
5335 thenext = myline;
5336 while ((c = my_getc(ec)) != '\n' && c) {
5337 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005338 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005339 if (thenext >= &myline[LINELIM]) {
5340 c = 0;
5341 break;
5342 }
5343 *thenext++ = c;
5344 }
5345 *thenext = 0;
5346 if (strcmp(s, myline) == 0 || c == 0)
5347 break;
5348 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005349 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005350 }
5351 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005352 prs("here document `");
5353 prs(s);
5354 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005355 }
5356 quitenv();
5357 }
5358 close(tf);
5359}
5360
5361/*
5362 * open here temp file.
5363 * if unquoted here, expand here temp file into second temp file.
5364 */
Eric Andersen8401eea2004-08-04 19:16:54 +00005365static int herein(hname, xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005366char *hname;
5367int xdoll;
5368{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005369 REGISTER int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005370 int tf;
5371
5372#if __GNUC__
5373 /* Avoid longjmp clobbering */
5374 (void) &tf;
5375#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005376 if (hname == NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00005377 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005378
5379 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5380
Eric Andersenff9eee42001-06-29 04:57:14 +00005381 hf = open(hname, 0);
5382 if (hf < 0)
5383 return (-1);
Eric Andersen12de6cf2004-08-04 19:19:10 +00005384
Eric Andersenff9eee42001-06-29 04:57:14 +00005385 if (xdoll) {
5386 char c;
5387 char tname[30] = ".msh_XXXXXX";
5388 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005389
Eric Andersenff9eee42001-06-29 04:57:14 +00005390 tf = mkstemp(tname);
5391 if (tf < 0)
5392 return (-1);
5393 if (newenv(setjmp(errpt = ev)) == 0) {
5394 PUSHIO(afile, hf, herechar);
5395 setbase(e.iop);
5396 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005397 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005398 write(tf, &c, sizeof c);
5399 }
5400 quitenv();
5401 } else
5402 unlink(tname);
5403 close(tf);
5404 tf = open(tname, 0);
5405 unlink(tname);
5406 return (tf);
5407 } else
5408 return (hf);
5409}
5410
Eric Andersen8401eea2004-08-04 19:16:54 +00005411static void scraphere()
Eric Andersenff9eee42001-06-29 04:57:14 +00005412{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005413 REGISTER struct here *h;
5414
5415 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005416
5417 for (h = inhere; h != NULL; h = h->h_next) {
5418 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005419 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005420 }
5421 inhere = NULL;
5422}
5423
5424/* unlink here temp files before a freearea(area) */
Eric Andersen8401eea2004-08-04 19:16:54 +00005425static void freehere(area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005426int area;
5427{
Eric Andersen12de6cf2004-08-04 19:19:10 +00005428 REGISTER struct here *h, *hl;
5429
5430 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005431
5432 hl = NULL;
5433 for (h = acthere; h != NULL; h = h->h_next)
5434 if (getarea((char *) h) >= area) {
5435 if (h->h_iop->io_name != NULL)
5436 unlink(h->h_iop->io_name);
5437 if (hl == NULL)
5438 acthere = h->h_next;
5439 else
5440 hl->h_next = h->h_next;
5441 } else
5442 hl = h;
5443}
5444
5445
5446
5447/*
5448 * Copyright (c) 1987,1997, Prentice Hall
5449 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005450 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005451 * Redistribution and use of the MINIX operating system in source and
5452 * binary forms, with or without modification, are permitted provided
5453 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005454 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005455 * Redistributions of source code must retain the above copyright
5456 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005457 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005458 * Redistributions in binary form must reproduce the above
5459 * copyright notice, this list of conditions and the following
5460 * disclaimer in the documentation and/or other materials provided
5461 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005462 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005463 * Neither the name of Prentice Hall nor the names of the software
5464 * authors or contributors may be used to endorse or promote
5465 * products derived from this software without specific prior
5466 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005467 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005468 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5469 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5470 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5471 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5472 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5473 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5474 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5475 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5476 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5477 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5478 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5479 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5480 *
5481 */