blob: 4d1e84cf0139ac5fd7fdf091fd856363eb455346 [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 *
Rob Landleyc9c1a412006-07-12 19:17:55 +000013 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenff9eee42001-06-29 04:57:14 +000014 */
15
Denis Vlasenko95cb3262007-04-09 03:06:34 +000016#include <sys/times.h>
17#include <setjmp.h>
Denis Vlasenko55f30b02007-03-24 22:42:29 +000018
Mike Frysinger67a32ad2007-03-09 08:25:24 +000019#ifdef STANDALONE
20# ifndef _GNU_SOURCE
21# define _GNU_SOURCE
22# endif
Mike Frysinger67a32ad2007-03-09 08:25:24 +000023# include <sys/types.h>
24# include <sys/stat.h>
25# include <sys/wait.h>
26# include <signal.h>
27# include <stdio.h>
28# include <stdlib.h>
29# include <unistd.h>
30# include <string.h>
31# include <errno.h>
32# include <dirent.h>
33# include <fcntl.h>
34# include <ctype.h>
35# include <assert.h>
36# define bb_dev_null "/dev/null"
37# define DEFAULT_SHELL "/proc/self/exe"
38# define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39# define BB_BANNER "busybox standalone"
Denis Vlasenko80d14be2007-04-10 23:03:30 +000040# define ENABLE_FEATURE_SH_STANDALONE 0
Mike Frysinger67a32ad2007-03-09 08:25:24 +000041# define bb_msg_memory_exhausted "memory exhausted"
42# define xmalloc(size) malloc(size)
43# define msh_main(argc,argv) main(argc,argv)
44# define safe_read(fd,buf,count) read(fd,buf,count)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
48static char *find_applet_by_name(const char *applet)
49{
50 return NULL;
51}
Denis Vlasenko10457b92007-03-27 22:01:31 +000052static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000053{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000054 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
61 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
65 }
66 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000067 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000068 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000069}
Denis Vlasenko10457b92007-03-27 22:01:31 +000070static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000071{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000072 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000077 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000078}
79static char local_buf[12];
80static char *itoa(int n)
81{
Denis Vlasenko10457b92007-03-27 22:01:31 +000082 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000083 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000084}
85#else
Mike Frysinger67a32ad2007-03-09 08:25:24 +000086# include "busybox.h"
Denis Vlasenko489f93e2007-02-01 01:43:16 +000087extern char **environ;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000088#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000089
Mike Frysinger17811882006-05-05 20:33:07 +000090/*#define MSHDEBUG 1*/
Eric Andersen12de6cf2004-08-04 19:19:10 +000091
92#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000093int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
Denis Vlasenko51742f42007-04-12 00:32:05 +000095#define DBGPRINTF(x) if (mshdbg>0) printf x
96#define DBGPRINTF0(x) if (mshdbg>0) printf x
97#define DBGPRINTF1(x) if (mshdbg>1) printf x
98#define DBGPRINTF2(x) if (mshdbg>2) printf x
99#define DBGPRINTF3(x) if (mshdbg>3) printf x
100#define DBGPRINTF4(x) if (mshdbg>4) printf x
101#define DBGPRINTF5(x) if (mshdbg>5) printf x
102#define DBGPRINTF6(x) if (mshdbg>6) printf x
103#define DBGPRINTF7(x) if (mshdbg>7) printf x
104#define DBGPRINTF8(x) if (mshdbg>8) printf x
105#define DBGPRINTF9(x) if (mshdbg>9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
107int mshdbg_rc = 0;
108
Denis Vlasenko51742f42007-04-12 00:32:05 +0000109#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000110
111#else
112
113#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000125#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
127#endif /* MSHDEBUG */
128
129
Denis Vlasenko38f63192007-01-22 09:03:07 +0000130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
Eric Andersenff9eee42001-06-29 04:57:14 +0000139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
Eric Andersen12de6cf2004-08-04 19:19:10 +0000144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000146
Eric Andersen392947c2002-12-11 07:42:46 +0000147#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151
152/*
153 * values returned by wait
154 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000155#define WAITSIG(s) ((s)&0177)
156#define WAITVAL(s) (((s)>>8)&0377)
Eric Andersenff9eee42001-06-29 04:57:14 +0000157#define WAITCORE(s) (((s)&0200)!=0)
158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000164
Eric Andersenff9eee42001-06-29 04:57:14 +0000165/*
166 * shell components
167 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000168#define NOBLOCK ((struct op *)NULL)
169#define NOWORD ((char *)NULL)
170#define NOWORDS ((char **)NULL)
171#define NOPIPE ((int *)NULL)
172
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000173
174/*
175 * redirection
176 */
177struct ioword {
178 short io_unit; /* unit affected */
179 short io_flag; /* action (below) */
180 char *io_name; /* file name */
181};
182
183#define IOREAD 1 /* < */
184#define IOHERE 2 /* << (here file) */
185#define IOWRITE 4 /* > */
186#define IOCAT 8 /* >> */
187#define IOXHERE 16 /* ${}, ` in << */
188#define IODUP 32 /* >&digit */
189#define IOCLOSE 64 /* >&- */
190
191#define IODEFAULT (-1) /* token for default IO unit */
192
193
Eric Andersenff9eee42001-06-29 04:57:14 +0000194/*
195 * Description of a command or an operation on commands.
196 * Might eventually use a union.
197 */
198struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000199 int type; /* operation type, see below */
200 char **words; /* arguments to a command */
201 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000202 struct op *left;
203 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000204 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000205};
206
Eric Andersen8401eea2004-08-04 19:16:54 +0000207#define TCOM 1 /* command */
208#define TPAREN 2 /* (c-list) */
209#define TPIPE 3 /* a | b */
210#define TLIST 4 /* a [&;] b */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000211#define TOR 5 /* || */
Eric Andersen8401eea2004-08-04 19:16:54 +0000212#define TAND 6 /* && */
Eric Andersenff9eee42001-06-29 04:57:14 +0000213#define TFOR 7
Eric Andersen12de6cf2004-08-04 19:19:10 +0000214#define TDO 8
Eric Andersenff9eee42001-06-29 04:57:14 +0000215#define TCASE 9
Eric Andersen12de6cf2004-08-04 19:19:10 +0000216#define TIF 10
Eric Andersenff9eee42001-06-29 04:57:14 +0000217#define TWHILE 11
218#define TUNTIL 12
219#define TELIF 13
Eric Andersen8401eea2004-08-04 19:16:54 +0000220#define TPAT 14 /* pattern in case */
221#define TBRACE 15 /* {c-list} */
222#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000223/* Added to support "." file expansion */
224#define TDOT 17
225
226/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000227#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000228static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000229 "PLACEHOLDER",
230 "TCOM",
231 "TPAREN",
232 "TPIPE",
233 "TLIST",
234 "TOR",
235 "TAND",
236 "TFOR",
237 "TDO",
238 "TCASE",
239 "TIF",
240 "TWHILE",
241 "TUNTIL",
242 "TELIF",
243 "TPAT",
244 "TBRACE",
245 "TASYNC",
246 "TDOT",
247};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000248#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000249
250/*
251 * actions determining the environment of a process
252 */
253#define BIT(i) (1<<(i))
Eric Andersen8401eea2004-08-04 19:16:54 +0000254#define FEXEC BIT(0) /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000255
Eric Andersen12de6cf2004-08-04 19:19:10 +0000256#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000257
Eric Andersenff9eee42001-06-29 04:57:14 +0000258/*
259 * flags to control evaluation of words
260 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000261#define DOSUB 1 /* interpret $, `, and quotes */
262#define DOBLANK 2 /* perform blank interpretation */
263#define DOGLOB 4 /* interpret [?* */
264#define DOKEY 8 /* move words with `=' to 2nd arg. list */
265#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000266
267#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
268
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Eric Andersen12de6cf2004-08-04 19:19:10 +0000270/* PROTOTYPES */
Eric Andersenff9eee42001-06-29 04:57:14 +0000271static int newfile(char *s);
Eric Andersenff9eee42001-06-29 04:57:14 +0000272
273
Eric Andersen8401eea2004-08-04 19:16:54 +0000274struct brkcon {
275 jmp_buf brkpt;
276 struct brkcon *nextlev;
277};
Eric Andersenff9eee42001-06-29 04:57:14 +0000278
Eric Andersen12de6cf2004-08-04 19:19:10 +0000279
Eric Andersenff9eee42001-06-29 04:57:14 +0000280/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000281 * flags:
282 * -e: quit on error
283 * -k: look for name=value everywhere on command line
284 * -n: no execution
285 * -t: exit after reading and executing one command
286 * -v: echo as read
287 * -x: trace
288 * -u: unset variables net diagnostic
289 */
Mike Frysinger3672fe92006-11-15 21:52:10 +0000290static char flags['z' - 'a' + 1];
291/* this looks weird, but is OK ... we index flag with 'a'...'z' */
292static char *flag = flags - 'a';
Eric Andersenff9eee42001-06-29 04:57:14 +0000293
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000294/* moved to G: static char *trap[_NSIG + 1]; */
295/* moved to G: static char ourtrap[_NSIG + 1]; */
Eric Andersen8401eea2004-08-04 19:16:54 +0000296static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000297
Eric Andersen8401eea2004-08-04 19:16:54 +0000298static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000299
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000300/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000301
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000302#if ENABLE_FEATURE_EDITING
303static char *current_prompt;
304static line_input_t *line_input_state;
305#endif
306
Eric Andersen12de6cf2004-08-04 19:19:10 +0000307
Eric Andersenff9eee42001-06-29 04:57:14 +0000308/*
309 * other functions
310 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000311static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000312static char *evalstr(char *cp, int f);
313static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000314static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000315static int rlookup(char *n);
316static struct wdblock *glob(char *cp, struct wdblock *wb);
317static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000318static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000319static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000320static char **eval(char **ap, int f);
321static int setstatus(int s);
322static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000323
Eric Andersen8401eea2004-08-04 19:16:54 +0000324static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000325
Eric Andersen8401eea2004-08-04 19:16:54 +0000326static int newenv(int f);
327static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000328static void next(int f);
329static void setdash(void);
330static void onecommand(void);
331static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000332
Eric Andersen12de6cf2004-08-04 19:19:10 +0000333
Eric Andersenff9eee42001-06-29 04:57:14 +0000334/* -------- area stuff -------- */
335
Eric Andersen12de6cf2004-08-04 19:19:10 +0000336#define REGSIZE sizeof(struct region)
337#define GROWBY (256)
338/* #define SHRINKBY (64) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000339#undef SHRINKBY
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000340#define FREE (32767)
341#define BUSY (0)
342#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000343
344
345struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000346 struct region *next;
347 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000348};
349
350
Eric Andersenff9eee42001-06-29 04:57:14 +0000351/* -------- grammar stuff -------- */
352typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000353 char *cp;
354 char **wp;
355 int i;
356 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000357} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000358
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000359#define WORD 256
360#define LOGAND 257
361#define LOGOR 258
362#define BREAK 259
363#define IF 260
364#define THEN 261
365#define ELSE 262
366#define ELIF 263
367#define FI 264
368#define CASE 265
369#define ESAC 266
370#define FOR 267
371#define WHILE 268
372#define UNTIL 269
373#define DO 270
374#define DONE 271
375#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000376/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000377#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000378
Eric Andersenff9eee42001-06-29 04:57:14 +0000379#define YYERRCODE 300
380
381/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000382#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +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 Andersen8401eea2004-08-04 19:16:54 +0000407static int yylex(int cf);
408static int collect(int c, int c1);
409static int dual(int c);
410static void diag(int ec);
411static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000412
413/* -------- var.h -------- */
414
Eric Andersen8401eea2004-08-04 19:16:54 +0000415struct var {
416 char *value;
417 char *name;
418 struct var *next;
419 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000420};
Eric Andersenff9eee42001-06-29 04:57:14 +0000421
Eric Andersen8401eea2004-08-04 19:16:54 +0000422#define COPYV 1 /* flag to setval, suggesting copy */
423#define RONLY 01 /* variable is read-only */
424#define EXPORT 02 /* variable is to be exported */
425#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000426
Eric Andersen8401eea2004-08-04 19:16:54 +0000427static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000428
429static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000430
Eric Andersen12de6cf2004-08-04 19:19:10 +0000431
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000432#define AFID_NOBUF (~0)
433#define AFID_ID 0
434
435
Eric Andersenff9eee42001-06-29 04:57:14 +0000436/* -------- io.h -------- */
437/* io buffer */
438struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000439 unsigned id; /* buffer id */
440 char buf[512]; /* buffer */
441 char *bufp; /* pointer into buffer */
442 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000443};
444
445/* possible arguments to an IO function */
446struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000447 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000448 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000449 int afile; /* file descriptor */
450 unsigned afid; /* buffer id */
451 long afpos; /* file position */
452 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000453};
Eric Andersen8401eea2004-08-04 19:16:54 +0000454
Eric Andersenff9eee42001-06-29 04:57:14 +0000455/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000456struct io {
457 int (*iofn) (struct ioarg *, struct io *);
458 struct ioarg *argp;
459 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000460 char prev; /* previous character read by readc() */
461 char nlcount; /* for `'s */
462 char xchar; /* for `'s */
463 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000464};
Eric Andersen8401eea2004-08-04 19:16:54 +0000465
Eric Andersen8401eea2004-08-04 19:16:54 +0000466#define XOTHER 0 /* none of the below */
467#define XDOLL 1 /* expanding ${} */
468#define XGRAVE 2 /* expanding `'s */
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000469#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000470
471/* in substitution */
472#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
473
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000474static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000475/* moved to G: static struct ioarg ioargstack[NPUSH]; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000476static struct io iostack[NPUSH];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000477/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
478/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000479static unsigned bufid = AFID_ID; /* buffer id counter */
480
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000481#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
482
483
484/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000485 * input generators for IO structure
486 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000487static int nlchar(struct ioarg *ap);
488static int strchar(struct ioarg *ap);
489static int qstrchar(struct ioarg *ap);
490static int filechar(struct ioarg *ap);
491static int herechar(struct ioarg *ap);
492static int linechar(struct ioarg *ap);
493static int gravechar(struct ioarg *ap, struct io *iop);
494static int qgravechar(struct ioarg *ap, struct io *iop);
495static int dolchar(struct ioarg *ap);
496static int wdchar(struct ioarg *ap);
497static void scraphere(void);
498static void freehere(int area);
499static void gethere(void);
500static void markhere(char *s, struct ioword *iop);
501static int herein(char *hname, int xdoll);
502static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000503
Eric Andersen12de6cf2004-08-04 19:19:10 +0000504
Eric Andersen8401eea2004-08-04 19:16:54 +0000505static int eofc(void);
506static int readc(void);
507static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000508static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000509
Eric Andersen12de6cf2004-08-04 19:19:10 +0000510
Eric Andersenff9eee42001-06-29 04:57:14 +0000511/*
512 * IO control
513 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000514static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000515#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000516static int remap(int fd);
517static int openpipe(int *pv);
518static void closepipe(int *pv);
519static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000520
Eric Andersenff9eee42001-06-29 04:57:14 +0000521/* -------- word.h -------- */
522
Eric Andersen8401eea2004-08-04 19:16:54 +0000523#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000524
Eric Andersen8401eea2004-08-04 19:16:54 +0000525struct wdblock {
526 short w_bsize;
527 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000528 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000529 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000530};
531
Eric Andersen8401eea2004-08-04 19:16:54 +0000532static struct wdblock *addword(char *wd, struct wdblock *wb);
533static struct wdblock *newword(int nw);
534static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000535
Eric Andersenff9eee42001-06-29 04:57:14 +0000536/* -------- misc stuff -------- */
537
Eric Andersen12de6cf2004-08-04 19:19:10 +0000538static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000539static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000540static void brkset(struct brkcon *bc);
541static int dolabel(struct op *t);
542static int dohelp(struct op *t);
543static int dochdir(struct op *t);
544static int doshift(struct op *t);
545static int dologin(struct op *t);
546static int doumask(struct op *t);
547static int doexec(struct op *t);
548static int dodot(struct op *t);
549static int dowait(struct op *t);
550static int doread(struct op *t);
551static int doeval(struct op *t);
552static int dotrap(struct op *t);
553static int getsig(char *s);
554static void setsig(int n, sighandler_t f);
555static int getn(char *as);
556static int dobreak(struct op *t);
557static int docontinue(struct op *t);
558static int brkcontin(char *cp, int val);
559static int doexit(struct op *t);
560static int doexport(struct op *t);
561static int doreadonly(struct op *t);
562static void rdexp(char **wp, void (*f) (struct var *), int key);
563static void badid(char *s);
564static int doset(struct op *t);
565static void varput(char *s, int out);
566static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000567static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000568static char *blank(int f);
569static int dollar(int quoted);
570static int grave(int quoted);
571static void globname(char *we, char *pp);
572static char *generate(char *start1, char *end1, char *middle, char *end);
573static int anyspcl(struct wdblock *wb);
574static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000575static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000576 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000577static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000578static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000579
Eric Andersen8401eea2004-08-04 19:16:54 +0000580struct here {
581 char *h_tag;
582 int h_dosub;
583 struct ioword *h_iop;
584 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000585};
586
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000587static const char * const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000588 "Signal 0",
589 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000590 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000591 "Quit",
592 "Illegal instruction",
593 "Trace/BPT trap",
594 "Abort",
595 "Bus error",
596 "Floating Point Exception",
597 "Killed",
598 "SIGUSR1",
599 "SIGSEGV",
600 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000601 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000602 "Alarm clock",
603 "Terminated",
604};
Eric Andersen8401eea2004-08-04 19:16:54 +0000605
Eric Andersenff9eee42001-06-29 04:57:14 +0000606#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
607
608struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000609 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000610 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000611};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000612static const struct res restab[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000613 { "for" , FOR },
614 { "case" , CASE },
615 { "esac" , ESAC },
616 { "while", WHILE },
617 { "do" , DO },
618 { "done" , DONE },
619 { "if" , IF },
620 { "in" , IN },
621 { "then" , THEN },
622 { "else" , ELSE },
623 { "elif" , ELIF },
624 { "until", UNTIL },
625 { "fi" , FI },
626 { ";;" , BREAK },
627 { "||" , LOGOR },
628 { "&&" , LOGAND },
629 { "{" , '{' },
630 { "}" , '}' },
631 { "." , DOT },
632 { NULL , 0 },
Eric Andersenff9eee42001-06-29 04:57:14 +0000633};
634
Eric Andersen1c039232001-07-07 00:05:55 +0000635struct builtincmd {
636 const char *name;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000637 int (*builtinfunc)(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000638};
Eric Andersen8401eea2004-08-04 19:16:54 +0000639static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000640 { "." , dodot },
641 { ":" , dolabel },
642 { "break" , dobreak },
643 { "cd" , dochdir },
644 { "continue", docontinue },
645 { "eval" , doeval },
646 { "exec" , doexec },
647 { "exit" , doexit },
648 { "export" , doexport },
649 { "help" , dohelp },
650 { "login" , dologin },
651 { "newgrp" , dologin },
652 { "read" , doread },
653 { "readonly", doreadonly },
654 { "set" , doset },
655 { "shift" , doshift },
656 { "times" , dotimes },
657 { "trap" , dotrap },
658 { "umask" , doumask },
659 { "wait" , dowait },
660 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000661};
662
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000663static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000664static struct op *dowholefile(int, int);
665
Eric Andersen12de6cf2004-08-04 19:19:10 +0000666
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000667/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000668static char **dolv;
669static int dolc;
670static int exstat;
671static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000672static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000673static int execflg;
674static int multiline; /* \n changed to ; */
675static struct op *outtree; /* result from parser */
676static xint *failpt;
677static xint *errpt;
678static struct brkcon *brklist;
679static int isbreak;
680static struct wdblock *wdlist;
681static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000682
683#ifdef MSHDEBUG
684static struct var *mshdbg_var;
685#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000686static struct var *vlist; /* dictionary */
687static struct var *homedir; /* home directory */
688static struct var *prompt; /* main prompt */
689static struct var *cprompt; /* continuation prompt */
690static struct var *path; /* search path for commands */
691static struct var *shell; /* shell to interpret command files */
692static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000693
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000694static int areanum; /* current allocation area */
695static int intr; /* interrupt pending */
Eric Andersen8401eea2004-08-04 19:16:54 +0000696static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000697static char *null = (char*)""; /* null value for variable */
698static int heedint = 1; /* heed interrupt signals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000699static void (*qflag) (int) = SIG_IGN;
700static int startl;
701static int peeksym;
702static int nlseen;
703static int iounit = IODEFAULT;
704static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000705static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000706
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000707static struct here *inhere; /* list of hear docs while parsing */
708static struct here *acthere; /* list of active here documents */
709static struct region *areabot; /* bottom of area */
710static struct region *areatop; /* top of area */
711static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000712static void *brktop;
713static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000714
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000715/*
716 * parsing & execution environment
717 */
718struct env {
719 char *linep;
720 struct io *iobase;
721 struct io *iop;
722 xint *errpt; /* void * */
723 int iofd;
724 struct env *oenv;
725};
726
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727static struct env e = {
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000728 NULL /* set to line in main() */, /* linep: char ptr */
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000729 iostack, /* iobase: struct io ptr */
730 iostack - 1, /* iop: struct io ptr */
731 (xint *) NULL, /* errpt: void ptr for errors? */
732 FDBASE, /* iofd: file desc */
733 (struct env *) NULL /* oenv: struct env ptr */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000734};
735
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000736
737struct globals {
738 char ourtrap[_NSIG + 1];
739 char *trap[_NSIG + 1];
740 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
741 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
742 struct ioarg ioargstack[NPUSH];
743 char filechar_cmdbuf[BUFSIZ];
744 char line[LINELIM];
745 char child_cmd[LINELIM];
746};
747
748#define G (*ptr_to_globals)
749#define ourtrap (G.ourtrap )
750#define trap (G.trap )
751#define sharedbuf (G.sharedbuf )
752#define mainbuf (G.mainbuf )
753#define ioargstack (G.ioargstack )
754#define filechar_cmdbuf (G.filechar_cmdbuf)
755#define line (G.line )
756#define child_cmd (G.child_cmd )
757
758
Eric Andersen12de6cf2004-08-04 19:19:10 +0000759#ifdef MSHDEBUG
760void print_t(struct op *t)
761{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000762 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
763 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000764
765 if (t->words) {
766 DBGPRINTF(("T: W1: %s", t->words[0]));
767 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000768}
769
770void print_tree(struct op *head)
771{
772 if (head == NULL) {
773 DBGPRINTF(("PRINT_TREE: no tree\n"));
774 return;
775 }
776
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000777 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000778 head->right));
779
780 if (head->left)
781 print_tree(head->left);
782
783 if (head->right)
784 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000785}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000786#endif /* MSHDEBUG */
787
788
789/*
790 * IO functions
791 */
792static void prs(const char *s)
793{
794 if (*s)
795 write(2, s, strlen(s));
796}
797
798static void prn(unsigned u)
799{
800 prs(itoa(u));
801}
802
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000803static void echo(char **wp)
804{
805 int i;
806
807 prs("+");
808 for (i = 0; wp[i]; i++) {
809 if (i)
810 prs(" ");
811 prs(wp[i]);
812 }
813 prs("\n");
814}
815
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000816static void closef(int i)
817{
818 if (i > 2)
819 close(i);
820}
821
822static void closeall(void)
823{
824 int u;
825
826 for (u = NUFILE; u < NOFILE;)
827 close(u++);
828}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000829
Eric Andersenff9eee42001-06-29 04:57:14 +0000830
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000831/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000832static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000833static void fail(void)
834{
835 longjmp(failpt, 1);
836 /* NOTREACHED */
837}
Eric Andersenff9eee42001-06-29 04:57:14 +0000838
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839/* abort shell (or fail in subshell) */
840static void leave(void) ATTRIBUTE_NORETURN;
841static void leave(void)
842{
843 DBGPRINTF(("LEAVE: leave called!\n"));
844
845 if (execflg)
846 fail();
847 scraphere();
848 freehere(1);
849 runtrap(0);
850 _exit(exstat);
851 /* NOTREACHED */
852}
853
854static void warn(const char *s)
855{
856 if (*s) {
857 prs(s);
858 exstat = -1;
859 }
860 prs("\n");
861 if (flag['e'])
862 leave();
863}
864
865static void err(const char *s)
866{
867 warn(s);
868 if (flag['n'])
869 return;
870 if (!interactive)
871 leave();
872 if (e.errpt)
873 longjmp(e.errpt, 1);
874 closeall();
875 e.iop = e.iobase = iostack;
876}
877
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000878
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000879/* -------- area.c -------- */
880
Eric Andersenff9eee42001-06-29 04:57:14 +0000881/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000882 * All memory between (char *)areabot and (char *)(areatop+1) is
883 * exclusively administered by the area management routines.
884 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000885 */
886
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000887#define sbrk(X) ({ \
888 void * __q = (void *)-1; \
889 if (brkaddr + (int)(X) < brktop) { \
890 __q = brkaddr; \
891 brkaddr += (int)(X); \
892 } \
893 __q; \
894})
Eric Andersenff9eee42001-06-29 04:57:14 +0000895
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000896static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000897{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000898 brkaddr = xmalloc(AREASIZE);
899 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000900
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000901 while ((long) sbrk(0) & ALIGN)
902 sbrk(1);
903 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000904
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000905 areabot->next = areabot;
906 areabot->area = BUSY;
907 areatop = areabot;
908 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000909}
910
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000911static char *getcell(unsigned nbytes)
912{
913 int nregio;
914 struct region *p, *q;
915 int i;
916
917 if (nbytes == 0) {
918 puts("getcell(0)");
919 abort();
920 }
921 /* silly and defeats the algorithm */
922 /*
923 * round upwards and add administration area
924 */
925 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
926 p = areanxt;
927 for (;;) {
928 if (p->area > areanum) {
929 /*
930 * merge free cells
931 */
932 while ((q = p->next)->area > areanum && q != areanxt)
933 p->next = q->next;
934 /*
935 * exit loop if cell big enough
936 */
937 if (q >= p + nregio)
938 goto found;
939 }
940 p = p->next;
941 if (p == areanxt)
942 break;
943 }
944 i = nregio >= GROWBY ? nregio : GROWBY;
945 p = (struct region *) sbrk(i * REGSIZE);
946 if (p == (struct region *) -1)
947 return NULL;
948 p--;
949 if (p != areatop) {
950 puts("not contig");
951 abort(); /* allocated areas are contiguous */
952 }
953 q = p + i;
954 p->next = q;
955 p->area = FREE;
956 q->next = areabot;
957 q->area = BUSY;
958 areatop = q;
959 found:
960 /*
961 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
962 */
963 areanxt = p + nregio;
964 if (areanxt < q) {
965 /*
966 * split into requested area and rest
967 */
968 if (areanxt + 1 > q) {
969 puts("OOM");
970 abort(); /* insufficient space left for admin */
971 }
972 areanxt->next = q;
973 areanxt->area = FREE;
974 p->next = areanxt;
975 }
976 p->area = areanum;
977 return (char *) (p + 1);
978}
979
980static void freecell(char *cp)
981{
982 struct region *p;
983
984 p = (struct region *) cp;
985 if (p != NULL) {
986 p--;
987 if (p < areanxt)
988 areanxt = p;
989 p->area = FREE;
990 }
991}
992#define DELETE(obj) freecell((char *)obj)
993
994static void freearea(int a)
995{
996 struct region *p, *top;
997
998 top = areatop;
999 for (p = areabot; p != top; p = p->next)
1000 if (p->area >= a)
1001 p->area = FREE;
1002}
1003
1004static void setarea(char *cp, int a)
1005{
1006 struct region *p;
1007
1008 p = (struct region *) cp;
1009 if (p != NULL)
1010 (p - 1)->area = a;
1011}
1012
1013static int getarea(char *cp)
1014{
1015 return ((struct region *) cp - 1)->area;
1016}
1017
1018static void garbage(void)
1019{
1020 struct region *p, *q, *top;
1021
1022 top = areatop;
1023 for (p = areabot; p != top; p = p->next) {
1024 if (p->area > areanum) {
1025 while ((q = p->next)->area > areanum)
1026 p->next = q->next;
1027 areanxt = p;
1028 }
1029 }
1030#ifdef SHRINKBY
1031 if (areatop >= q + SHRINKBY && q->area > areanum) {
1032 brk((char *) (q + 1));
1033 q->next = areabot;
1034 q->area = BUSY;
1035 areatop = q;
1036 }
1037#endif
1038}
1039
1040static char *space(int n)
1041{
1042 char *cp;
1043
1044 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001045 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001046 err("out of string space");
1047 return cp;
1048}
1049
1050static char *strsave(const char *s, int a)
1051{
1052 char *cp;
1053
1054 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001055 if (cp == NULL) {
1056// FIXME: I highly doubt this is good.
1057 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001058 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001059 setarea(cp, a);
1060 strcpy(cp, s);
1061 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001062}
1063
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001064
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001065/* -------- var.c -------- */
1066
1067static int eqname(const char *n1, const char *n2)
1068{
1069 for (; *n1 != '=' && *n1 != '\0'; n1++)
1070 if (*n2++ != *n1)
1071 return 0;
1072 return *n2 == '\0' || *n2 == '=';
1073}
1074
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001075static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001076{
1077 while (*cp != '\0' && *cp != '=')
1078 cp++;
1079 return cp;
1080}
1081
1082/*
1083 * Find the given name in the dictionary
1084 * and return its value. If the name was
1085 * not previously there, enter it now and
1086 * return a null value.
1087 */
1088static struct var *lookup(const char *n)
1089{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001090// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001091 static struct var dummy;
1092
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001093 struct var *vp;
1094 const char *cp;
1095 char *xp;
1096 int c;
1097
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001098 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001099 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001100 for (c = 0; isdigit(*n) && c < 1000; n++)
1101 c = c * 10 + *n - '0';
1102 dummy.status = RONLY;
1103 dummy.value = (c <= dolc ? dolv[c] : null);
1104 return &dummy;
1105 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001106
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001107 for (vp = vlist; vp; vp = vp->next)
1108 if (eqname(vp->name, n))
1109 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001110
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001111 cp = findeq(n);
1112 vp = (struct var *) space(sizeof(*vp));
1113 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001114 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001115 return &dummy;
1116 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001117
1118 xp = vp->name;
1119 while ((*xp = *n++) != '\0' && *xp != '=')
1120 xp++;
1121 *xp++ = '=';
1122 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001123 setarea((char *) vp, 0);
1124 setarea((char *) vp->name, 0);
1125 vp->value = null;
1126 vp->next = vlist;
1127 vp->status = GETCELL;
1128 vlist = vp;
1129 return vp;
1130}
1131
1132/*
1133 * if name is not NULL, it must be
1134 * a prefix of the space `val',
1135 * and end with `='.
1136 * this is all so that exporting
1137 * values is reasonably painless.
1138 */
1139static void nameval(struct var *vp, const char *val, const char *name)
1140{
1141 const char *cp;
1142 char *xp;
1143 int fl;
1144
1145 if (vp->status & RONLY) {
1146 xp = vp->name;
1147 while (*xp && *xp != '=')
1148 putc(*xp++, stderr);
1149 err(" is read-only");
1150 return;
1151 }
1152 fl = 0;
1153 if (name == NULL) {
1154 xp = space(strlen(vp->name) + strlen(val) + 2);
1155 if (xp == NULL)
1156 return;
1157 /* make string: name=value */
1158 setarea(xp, 0);
1159 name = xp;
1160 cp = vp->name;
1161 while ((*xp = *cp++) != '\0' && *xp != '=')
1162 xp++;
1163 *xp++ = '=';
1164 strcpy(xp, val);
1165 val = xp;
1166 fl = GETCELL;
1167 }
1168 if (vp->status & GETCELL)
1169 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001170 vp->name = (char*)name;
1171 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001172 vp->status |= fl;
1173}
1174
1175/*
1176 * give variable at `vp' the value `val'.
1177 */
1178static void setval(struct var *vp, const char *val)
1179{
1180 nameval(vp, val, NULL);
1181}
1182
1183static void export(struct var *vp)
1184{
1185 vp->status |= EXPORT;
1186}
1187
1188static void ronly(struct var *vp)
1189{
1190 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1191 vp->status |= RONLY;
1192}
1193
1194static int isassign(const char *s)
1195{
1196 unsigned char c;
1197 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1198
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001199 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001200 /* no isalpha() - we shouldn't use locale */
1201 /* c | 0x20 - lowercase (Latin) letters */
1202 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1203 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001204 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001205
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001206 while (1) {
1207 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001208 if (c == '=')
1209 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001210 if (c == '\0')
1211 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001212 if (c != '_'
1213 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001214 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001215 ) {
1216 return 0;
1217 }
1218 }
1219}
1220
1221static int assign(const char *s, int cf)
1222{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001223 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001224 struct var *vp;
1225
1226 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1227
1228 if (!isalpha(*s) && *s != '_')
1229 return 0;
1230 for (cp = s; *cp != '='; cp++)
1231 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1232 return 0;
1233 vp = lookup(s);
1234 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1235 if (cf != COPYV)
1236 vp->status &= ~GETCELL;
1237 return 1;
1238}
1239
1240static int checkname(char *cp)
1241{
1242 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1243
1244 if (!isalpha(*cp++) && *(cp - 1) != '_')
1245 return 0;
1246 while (*cp)
1247 if (!isalnum(*cp++) && *(cp - 1) != '_')
1248 return 0;
1249 return 1;
1250}
1251
1252static void putvlist(int f, int out)
1253{
1254 struct var *vp;
1255
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001256 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001257 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1258 if (vp->status & EXPORT)
1259 write(out, "export ", 7);
1260 if (vp->status & RONLY)
1261 write(out, "readonly ", 9);
1262 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1263 write(out, "\n", 1);
1264 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001265 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001266}
1267
1268
1269/*
1270 * trap handling
1271 */
1272static void sig(int i)
1273{
1274 trapset = i;
1275 signal(i, sig);
1276}
1277
1278static void runtrap(int i)
1279{
1280 char *trapstr;
1281
1282 trapstr = trap[i];
1283 if (trapstr == NULL)
1284 return;
1285
1286 if (i == 0)
1287 trap[i] = NULL;
1288
1289 RUN(aword, trapstr, nlchar);
1290}
1291
1292
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001293static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001294{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001295 char *cp;
1296 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001297 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001298
1299 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001300 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001301 if (flag[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001302 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001303 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001304 setval(lookup("-"), m);
1305}
1306
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001307static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001308{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001309 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001310
1311 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001312
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001313 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001314 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001315 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001316 f = open(s, 0);
1317 if (f < 0) {
1318 prs(s);
1319 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001320 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001321 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001322 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323
Eric Andersenff9eee42001-06-29 04:57:14 +00001324 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001325 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001326}
1327
Eric Andersen12de6cf2004-08-04 19:19:10 +00001328
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001329struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001330{
1331 struct op *dotnode;
1332
1333 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001334 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001335
1336 if (head->left != NULL) {
1337 dotnode = scantree(head->left);
1338 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001339 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001340 }
1341
1342 if (head->right != NULL) {
1343 dotnode = scantree(head->right);
1344 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001345 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001346 }
1347
1348 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001349 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001350
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001351 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001353 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001354 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001355 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001356 }
1357
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001358 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001359}
1360
1361
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001362static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001363{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001364 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 jmp_buf m1;
1366
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001367 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001368
Eric Andersenff9eee42001-06-29 04:57:14 +00001369 while (e.oenv)
1370 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001371
Eric Andersenff9eee42001-06-29 04:57:14 +00001372 areanum = 1;
1373 freehere(areanum);
1374 freearea(areanum);
1375 garbage();
1376 wdlist = 0;
1377 iolist = 0;
1378 e.errpt = 0;
1379 e.linep = line;
1380 yynerrs = 0;
1381 multiline = 0;
1382 inparse = 1;
1383 intr = 0;
1384 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001385
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001386 failpt = m1;
1387 setjmp(failpt); /* Bruce Evans' fix */
1388 failpt = m1;
1389 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001390 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1391
Eric Andersenff9eee42001-06-29 04:57:14 +00001392 while (e.oenv)
1393 quitenv();
1394 scraphere();
1395 if (!interactive && intr)
1396 leave();
1397 inparse = 0;
1398 intr = 0;
1399 return;
1400 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001401
Eric Andersenff9eee42001-06-29 04:57:14 +00001402 inparse = 0;
1403 brklist = 0;
1404 intr = 0;
1405 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001406
1407 if (!flag['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001408 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001409 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001410 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001411 }
1412
Eric Andersenff9eee42001-06-29 04:57:14 +00001413 if (!interactive && intr) {
1414 execflg = 0;
1415 leave();
1416 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001417
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001418 i = trapset;
1419 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001420 trapset = 0;
1421 runtrap(i);
1422 }
1423}
1424
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001425static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001426{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001427 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001428
1429 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001430
1431 if (f) {
1432 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001433 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001434 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001435
Eric Andersenff9eee42001-06-29 04:57:14 +00001436 ep = (struct env *) space(sizeof(*ep));
1437 if (ep == NULL) {
1438 while (e.oenv)
1439 quitenv();
1440 fail();
1441 }
1442 *ep = e;
1443 e.oenv = ep;
1444 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001445
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001446 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001447}
1448
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001449static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001450{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001451 struct env *ep;
1452 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001453
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001454 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001455
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001456 ep = e.oenv;
1457 if (ep != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001458 fd = e.iofd;
1459 e = *ep;
1460 /* should close `'d files */
1461 DELETE(ep);
1462 while (--fd >= e.iofd)
1463 close(fd);
1464 }
1465}
1466
1467/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001468 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001469 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001470static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001471{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001472 while (*s)
1473 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001474 return 1;
1475 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001476}
1477
1478/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001479 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001480 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001481static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001482{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001483 while (*s1)
1484 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001485 return 1;
1486 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001487}
1488
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001489static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001490{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001491 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001492}
1493
Eric Andersen8401eea2004-08-04 19:16:54 +00001494static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001495{
1496 PUSHIO(afile, f, filechar);
1497}
1498
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001499static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001500{
1501 signal(SIGINT, onintr);
1502 intr = 1;
1503 if (interactive) {
1504 if (inparse) {
1505 prs("\n");
1506 fail();
1507 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001508 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001509 execflg = 0;
1510 leave();
1511 }
1512}
1513
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001514
Eric Andersenff9eee42001-06-29 04:57:14 +00001515/* -------- gmatch.c -------- */
1516/*
1517 * int gmatch(string, pattern)
1518 * char *string, *pattern;
1519 *
1520 * Match a pattern as in sh(1).
1521 */
1522
1523#define CMASK 0377
1524#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001525#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001526#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001527
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001528static const char *cclass(const char *p, int sub)
1529{
1530 int c, d, not, found;
1531
1532 not = (*p == NOT);
1533 if (not != 0)
1534 p++;
1535 found = not;
1536 do {
1537 if (*p == '\0')
1538 return NULL;
1539 c = *p & CMASK;
1540 if (p[1] == '-' && p[2] != ']') {
1541 d = p[2] & CMASK;
1542 p++;
1543 } else
1544 d = c;
1545 if (c == sub || (c <= sub && sub <= d))
1546 found = !not;
1547 } while (*++p != ']');
1548 return found ? p + 1 : NULL;
1549}
1550
1551static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001552{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001553 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001554
1555 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001556 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001557
Eric Andersenff9eee42001-06-29 04:57:14 +00001558 while ((pc = *p++ & CMASK) != '\0') {
1559 sc = *s++ & QMASK;
1560 switch (pc) {
1561 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001562 p = cclass(p, sc);
1563 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001564 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001565 break;
1566
1567 case '?':
1568 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001569 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001570 break;
1571
1572 case '*':
1573 s--;
1574 do {
1575 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001576 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001577 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001578 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001579
1580 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001581 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001582 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001583 }
1584 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001585 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001586}
1587
Eric Andersenff9eee42001-06-29 04:57:14 +00001588
Eric Andersenff9eee42001-06-29 04:57:14 +00001589/* -------- csyn.c -------- */
1590/*
1591 * shell: syntax (C version)
1592 */
1593
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001594static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1595static void yyerror(const char *s)
1596{
1597 yynerrs++;
1598 if (interactive && e.iop <= iostack) {
1599 multiline = 0;
1600 while (eofc() == 0 && yylex(0) != '\n');
1601 }
1602 err(s);
1603 fail();
1604}
1605
1606static void zzerr(void) ATTRIBUTE_NORETURN;
1607static void zzerr(void)
1608{
1609 yyerror("syntax error");
1610}
1611
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001612int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001613{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001614 DBGPRINTF7(("YYPARSE: enter...\n"));
1615
Eric Andersen8401eea2004-08-04 19:16:54 +00001616 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001617 peeksym = 0;
1618 yynerrs = 0;
1619 outtree = c_list();
1620 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001621 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001622}
1623
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001624static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001625{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001626 struct op *t, *p;
1627 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001628
1629 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001630
1631 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001633 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634
Eric Andersenff9eee42001-06-29 04:57:14 +00001635 if (t != NULL) {
1636 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001637 p = command(CONTIN);
1638 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001639 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001640 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001641 }
1642
Eric Andersenff9eee42001-06-29 04:57:14 +00001643 if (t->type != TPAREN && t->type != TCOM) {
1644 /* shell statement */
1645 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1646 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647
Eric Andersenff9eee42001-06-29 04:57:14 +00001648 t = block(TPIPE, t, p, NOWORDS);
1649 }
1650 peeksym = c;
1651 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001652
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001653 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001654 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001655}
1656
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001657static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001658{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001659 struct op *t, *p;
1660 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001661
1662 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001663
1664 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001666 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667
Eric Andersenff9eee42001-06-29 04:57:14 +00001668 if (t != NULL) {
1669 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001670 p = pipeline(CONTIN);
1671 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001672 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001673 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001674 }
1675
Eric Andersen8401eea2004-08-04 19:16:54 +00001676 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001677 } /* WHILE */
1678
Eric Andersenff9eee42001-06-29 04:57:14 +00001679 peeksym = c;
1680 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001681
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001682 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001683 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001684}
1685
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001686static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001687{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001688 struct op *t, *p;
1689 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001690
1691 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001692
1693 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001694
Eric Andersenff9eee42001-06-29 04:57:14 +00001695 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001696 peeksym = yylex(0);
1697 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001698 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001699
Eric Andersen8401eea2004-08-04 19:16:54 +00001700 while ((c = yylex(0)) == ';' || c == '&'
1701 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001702
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001703 p = andor();
1704 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001705 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001707 peeksym = yylex(0);
1708 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001709 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001710
Eric Andersenff9eee42001-06-29 04:57:14 +00001711 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001712 } /* WHILE */
1713
Eric Andersenff9eee42001-06-29 04:57:14 +00001714 peeksym = c;
1715 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001716 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001717 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001718 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001719}
1720
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001721static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001722{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001723 struct ioword *iop;
1724 int i;
1725 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001726
1727 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001728
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001729 c = yylex(cf);
1730 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001731 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001732 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001733 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001734
Eric Andersenff9eee42001-06-29 04:57:14 +00001735 i = yylval.i;
1736 musthave(WORD, 0);
1737 iop = io(iounit, i, yylval.cp);
1738 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001739
Eric Andersenff9eee42001-06-29 04:57:14 +00001740 if (i & IOHERE)
1741 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001742
1743 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001744 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001745}
1746
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001747static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001748{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001749 peeksym = yylex(cf);
1750 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001751 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001752 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001753 }
1754
Eric Andersenff9eee42001-06-29 04:57:14 +00001755 peeksym = 0;
1756}
1757
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001758static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001759{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001760 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001761
1762 t = NULL;
1763 for (;;) {
1764 switch (peeksym = yylex(0)) {
1765 case '<':
1766 case '>':
1767 (void) synio(0);
1768 break;
1769
1770 case WORD:
1771 if (t == NULL) {
1772 t = newtp();
1773 t->type = TCOM;
1774 }
1775 peeksym = 0;
1776 word(yylval.cp);
1777 break;
1778
1779 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001780 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001781 }
1782 }
1783}
1784
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001785static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001786{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001787 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001788
1789 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001790
1791 multiline++;
1792 t = c_list();
1793 musthave(mark, 0);
1794 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001795 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001796}
1797
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001798static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001799{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001800 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001801 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001802 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001803
1804 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001805
1806 iosave = iolist;
1807 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001808
Eric Andersenff9eee42001-06-29 04:57:14 +00001809 if (multiline)
1810 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001811
Eric Andersenff9eee42001-06-29 04:57:14 +00001812 while (synio(cf))
1813 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001814
1815 c = yylex(cf);
1816
1817 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001818 default:
1819 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001820 t = simple();
1821 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001822 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001823 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001824 t = newtp();
1825 t->type = TCOM;
1826 }
1827 break;
1828
1829 case '(':
1830 t = nested(TPAREN, ')');
1831 break;
1832
1833 case '{':
1834 t = nested(TBRACE, '}');
1835 break;
1836
1837 case FOR:
1838 t = newtp();
1839 t->type = TFOR;
1840 musthave(WORD, 0);
1841 startl = 1;
1842 t->str = yylval.cp;
1843 multiline++;
1844 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001845 c = yylex(0);
1846 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001847 peeksym = c;
1848 t->left = dogroup(0);
1849 multiline--;
1850 break;
1851
1852 case WHILE:
1853 case UNTIL:
1854 multiline++;
1855 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001856 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001857 t->left = c_list();
1858 t->right = dogroup(1);
1859 t->words = NULL;
1860 multiline--;
1861 break;
1862
1863 case CASE:
1864 t = newtp();
1865 t->type = TCASE;
1866 musthave(WORD, 0);
1867 t->str = yylval.cp;
1868 startl++;
1869 multiline++;
1870 musthave(IN, CONTIN);
1871 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
Eric Andersenff9eee42001-06-29 04:57:14 +00001873 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001874
Eric Andersenff9eee42001-06-29 04:57:14 +00001875 musthave(ESAC, 0);
1876 multiline--;
1877 break;
1878
1879 case IF:
1880 multiline++;
1881 t = newtp();
1882 t->type = TIF;
1883 t->left = c_list();
1884 t->right = thenpart();
1885 musthave(FI, 0);
1886 multiline--;
1887 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001888
1889 case DOT:
1890 t = newtp();
1891 t->type = TDOT;
1892
1893 musthave(WORD, 0); /* gets name of file */
1894 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1895
1896 word(yylval.cp); /* add word to wdlist */
1897 word(NOWORD); /* terminate wdlist */
1898 t->words = copyw(); /* dup wdlist */
1899 break;
1900
Eric Andersenff9eee42001-06-29 04:57:14 +00001901 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001902
Eric Andersen8401eea2004-08-04 19:16:54 +00001903 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001904
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 t = namelist(t);
1906 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001907
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001908 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001909
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001910 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001911}
1912
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001913static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001914{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001915 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001916
1917 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1918
1919 multiline++;
1920 t = c_list();
1921 multiline--;
1922 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001923 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001924 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001925}
1926
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001927static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001928{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001929 int c;
1930 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931
1932 c = yylex(CONTIN);
1933 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001934 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001935 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001936 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001937 mylist = c_list();
1938 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001939 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001940}
1941
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001942static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001943{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001944 int c;
1945 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001946
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001947 c = yylex(0);
1948 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001950 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001951 }
1952 t = newtp();
1953 t->type = 0;
1954 t->left = c_list();
1955 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001956 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001957 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001958 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001959}
1960
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001961static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001962{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001963 int c;
1964 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001965
1966 switch (c = yylex(0)) {
1967 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001968 t = c_list();
1969 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001970 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001971 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001972
1973 case ELIF:
1974 t = newtp();
1975 t->type = TELIF;
1976 t->left = c_list();
1977 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001978 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001979
1980 default:
1981 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001982 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001983 }
1984}
1985
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001986static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001988 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001989
1990 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001991 while ((peeksym = yylex(CONTIN)) != ESAC) {
1992 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001993 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001994 }
1995
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001996 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001997 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001998}
1999
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002000static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002001{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002002 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002003
2004 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002005
2006 t = newtp();
2007 t->type = TPAT;
2008 t->words = pattern();
2009 musthave(')', 0);
2010 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002011 peeksym = yylex(CONTIN);
2012 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00002013 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002014
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002015 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002016
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002017 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002018}
2019
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002020static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002021{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002022 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002023
2024 cf = CONTIN;
2025 do {
2026 musthave(WORD, cf);
2027 word(yylval.cp);
2028 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002029 c = yylex(0);
2030 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002031 peeksym = c;
2032 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002033
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002034 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002035}
2036
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002037static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002038{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002039 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002040
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002041 c = yylex(0);
2042 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002043 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002044 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002045 }
2046 startl = 0;
2047 while ((c = yylex(0)) == WORD)
2048 word(yylval.cp);
2049 word(NOWORD);
2050 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002051 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002052}
2053
2054/*
2055 * supporting functions
2056 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002057static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002058{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002059 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002060
Eric Andersenff9eee42001-06-29 04:57:14 +00002061 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002062 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002063 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002064 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002065
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002066 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002067}
2068
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002069static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002070{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002071 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002072
2073 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002074
2075 t = newtp();
2076 t->type = type;
2077 t->left = t1;
2078 t->right = t2;
2079 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002080
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002081 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002082 t2));
2083
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002084 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002085}
2086
Eric Andersen12de6cf2004-08-04 19:19:10 +00002087/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002088static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002089{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002090 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002091
2092 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002093
2094 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002095 if (strcmp(rp->r_name, n) == 0) {
2096 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002097 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002098 }
2099
2100 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002101 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002102}
2103
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002104static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002105{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002106 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002107
Eric Andersen8401eea2004-08-04 19:16:54 +00002108 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002109 t->type = 0;
2110 t->words = NULL;
2111 t->ioact = NULL;
2112 t->left = NULL;
2113 t->right = NULL;
2114 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002115
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002116 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002118 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002119}
2120
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002121static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002122{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002123
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002124 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002125 T_CMD_NAMES[t->type], iolist));
2126
Eric Andersenff9eee42001-06-29 04:57:14 +00002127 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002128 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002129 t->ioact = copyio();
2130 } else
2131 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002132
Eric Andersenff9eee42001-06-29 04:57:14 +00002133 if (t->type != TCOM) {
2134 if (t->type != TPAREN && t->ioact != NULL) {
2135 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2136 t->ioact = t->left->ioact;
2137 t->left->ioact = NULL;
2138 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002139 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002140 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002141
Eric Andersenff9eee42001-06-29 04:57:14 +00002142 word(NOWORD);
2143 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002144
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002145 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002146}
2147
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002148static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002149{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002150 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002151
2152 wd = getwords(wdlist);
2153 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002154 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002155}
2156
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002157static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002158{
2159 wdlist = addword(cp, wdlist);
2160}
2161
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002162static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002163{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002164 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002165
2166 iop = (struct ioword **) getwords(iolist);
2167 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002168 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002169}
2170
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002171static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002172{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002173 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002174
2175 iop = (struct ioword *) tree(sizeof(*iop));
2176 iop->io_unit = u;
2177 iop->io_flag = f;
2178 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002179 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002180 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002181}
2182
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002183static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002184{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002185 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002186 int atstart;
2187
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002188 c = peeksym;
2189 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002190 peeksym = 0;
2191 if (c == '\n')
2192 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002193 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002194 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002195
Eric Andersenff9eee42001-06-29 04:57:14 +00002196 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002197 atstart = startl;
2198 startl = 0;
2199 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002200 e.linep = line;
2201
2202/* MALAMO */
2203 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002204
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002205 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002206 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2207 ;
2208
Eric Andersenff9eee42001-06-29 04:57:14 +00002209 switch (c) {
2210 default:
2211 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002212 c1 = my_getc(0);
2213 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002214 if (c1 == '<' || c1 == '>') {
2215 iounit = c - '0';
2216 goto loop;
2217 }
2218 *e.linep++ = c;
2219 c = c1;
2220 }
2221 break;
2222
Eric Andersen12de6cf2004-08-04 19:19:10 +00002223 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002224 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002225 unget(c);
2226 goto loop;
2227
2228 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002229 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002230 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002231
2232 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002233 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002234 *e.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002235 c = my_getc(0);
2236 if (c == '{') {
2237 c = collect(c, '}');
2238 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002239 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002240 goto pack;
2241 }
2242 break;
2243
2244 case '`':
2245 case '\'':
2246 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002247 c = collect(c, c);
2248 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002249 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002250 goto pack;
2251
2252 case '|':
2253 case '&':
2254 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002255 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002256 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002257 c1 = dual(c);
2258 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002259 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002260 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002261
Eric Andersenff9eee42001-06-29 04:57:14 +00002262 case '^':
2263 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002264 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002265 case '>':
2266 case '<':
2267 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002268 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002269
2270 case '\n':
2271 nlseen++;
2272 gethere();
2273 startl = 1;
2274 if (multiline || cf & CONTIN) {
2275 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002276#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002277 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002278#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002279 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002280#endif
2281 }
2282 if (cf & CONTIN)
2283 goto loop;
2284 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002285 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002286
2287 case '(':
2288 case ')':
2289 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002290 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 }
2292
2293 unget(c);
2294
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002295 pack:
2296 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002297 if (e.linep >= elinep)
2298 err("word too long");
2299 else
2300 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002301 };
2302
Eric Andersenff9eee42001-06-29 04:57:14 +00002303 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002304
Eric Andersen8401eea2004-08-04 19:16:54 +00002305 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002306 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002307
Eric Andersenff9eee42001-06-29 04:57:14 +00002308 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002309
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002310 if (atstart) {
2311 c = rlookup(line);
2312 if (c != 0) {
2313 startl = 1;
2314 return c;
2315 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002316 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002317
Eric Andersenff9eee42001-06-29 04:57:14 +00002318 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002319 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002320}
2321
Eric Andersen12de6cf2004-08-04 19:19:10 +00002322
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002323static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002324{
2325 char s[2];
2326
Eric Andersen12de6cf2004-08-04 19:19:10 +00002327 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2328
Eric Andersenff9eee42001-06-29 04:57:14 +00002329 *e.linep++ = c;
2330 while ((c = my_getc(c1)) != c1) {
2331 if (c == 0) {
2332 unget(c);
2333 s[0] = c1;
2334 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002335 prs("no closing ");
2336 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002337 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002338 }
2339 if (interactive && c == '\n' && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002340#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002341 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002342#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002343 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002344#endif
2345 }
2346 *e.linep++ = c;
2347 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348
Eric Andersenff9eee42001-06-29 04:57:14 +00002349 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002350
2351 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2352
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002353 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002354}
2355
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356/* "multiline commands" helper func */
2357/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002358static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002359{
2360 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002361 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002362
Eric Andersen12de6cf2004-08-04 19:19:10 +00002363 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2364
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002365 *cp++ = c; /* c is the given "peek" char */
2366 *cp++ = my_getc(0); /* get next char of input */
2367 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002368
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002369 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002370 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002371 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002372
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002373 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002374}
2375
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002376static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002377{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002378 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002379
2380 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002381
2382 c = my_getc(0);
2383 if (c == '>' || c == '<') {
2384 if (c != ec)
2385 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002386 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002387 c = my_getc(0);
2388 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002389 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002390 if (c != '&' || yylval.i == IOHERE)
2391 unget(c);
2392 else
2393 yylval.i |= IODUP;
2394}
2395
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002396static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002397{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002398 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002399
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002400 t = getcell(size);
2401 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002402 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002403 prs("command line too complicated\n");
2404 fail();
2405 /* NOTREACHED */
2406 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002407 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002408}
2409
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002410
Eric Andersenff9eee42001-06-29 04:57:14 +00002411/* VARARGS1 */
2412/* ARGSUSED */
2413
2414/* -------- exec.c -------- */
2415
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002416static struct op **find1case(struct op *t, const char *w)
2417{
2418 struct op *t1;
2419 struct op **tp;
2420 char **wp;
2421 char *cp;
2422
2423 if (t == NULL) {
2424 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2425 return NULL;
2426 }
2427
2428 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2429 T_CMD_NAMES[t->type]));
2430
2431 if (t->type == TLIST) {
2432 tp = find1case(t->left, w);
2433 if (tp != NULL) {
2434 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2435 return tp;
2436 }
2437 t1 = t->right; /* TPAT */
2438 } else
2439 t1 = t;
2440
2441 for (wp = t1->words; *wp;) {
2442 cp = evalstr(*wp++, DOSUB);
2443 if (cp && gmatch(w, cp)) {
2444 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2445 &t1->left));
2446 return &t1->left;
2447 }
2448 }
2449
2450 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2451 return NULL;
2452}
2453
2454static struct op *findcase(struct op *t, const char *w)
2455{
2456 struct op **tp;
2457
2458 tp = find1case(t, w);
2459 return tp != NULL ? *tp : NULL;
2460}
2461
Eric Andersenff9eee42001-06-29 04:57:14 +00002462/*
2463 * execute tree
2464 */
2465
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002466static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002467{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002468 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002469 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002470 const char *cp;
2471 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002472 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002474 struct brkcon bc;
2475
2476#if __GNUC__
2477 /* Avoid longjmp clobbering */
2478 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002479#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002480
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481 if (t == NULL) {
2482 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002483 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002484 }
2485
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002486 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002487 t->type, T_CMD_NAMES[t->type],
2488 ((t->words == NULL) ? "NULL" : t->words[0])));
2489
Eric Andersenff9eee42001-06-29 04:57:14 +00002490 rv = 0;
2491 a = areanum++;
2492 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002493 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2494 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002495
Eric Andersen8401eea2004-08-04 19:16:54 +00002496 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002497 case TDOT:
2498 DBGPRINTF3(("EXECUTE: TDOT\n"));
2499
2500 outtree_save = outtree;
2501
2502 newfile(evalstr(t->words[0], DOALL));
2503
2504 t->left = dowholefile(TLIST, 0);
2505 t->right = NULL;
2506
2507 outtree = outtree_save;
2508
2509 if (t->left)
2510 rv = execute(t->left, pin, pout, 0);
2511 if (t->right)
2512 rv = execute(t->right, pin, pout, 0);
2513 break;
2514
Eric Andersenff9eee42001-06-29 04:57:14 +00002515 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002516 rv = execute(t->left, pin, pout, 0);
2517 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002518
Eric Andersenff9eee42001-06-29 04:57:14 +00002519 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002520 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002521 break;
2522
2523 case TPIPE:
2524 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002525 int pv[2];
2526
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002527 rv = openpipe(pv);
2528 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002529 break;
2530 pv[0] = remap(pv[0]);
2531 pv[1] = remap(pv[1]);
2532 (void) execute(t->left, pin, pv, 0);
2533 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002534 }
2535 break;
2536
2537 case TLIST:
2538 (void) execute(t->left, pin, pout, 0);
2539 rv = execute(t->right, pin, pout, 0);
2540 break;
2541
2542 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002543 {
2544 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002545
Eric Andersen12de6cf2004-08-04 19:19:10 +00002546 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2547
Eric Andersen8401eea2004-08-04 19:16:54 +00002548 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002549 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002550 signal(SIGINT, SIG_IGN);
2551 signal(SIGQUIT, SIG_IGN);
2552 if (interactive)
2553 signal(SIGTERM, SIG_DFL);
2554 interactive = 0;
2555 if (pin == NULL) {
2556 close(0);
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +00002557 open(bb_dev_null, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002558 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002559 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002560 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002561 interactive = hinteractive;
2562 if (i != -1) {
2563 setval(lookup("!"), putn(i));
2564 if (pin != NULL)
2565 closepipe(pin);
2566 if (interactive) {
2567 prs(putn(i));
2568 prs("\n");
2569 }
2570 } else
2571 rv = -1;
2572 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002573 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002574 break;
2575
2576 case TOR:
2577 case TAND:
2578 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002579 t1 = t->right;
2580 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002581 rv = execute(t1, pin, pout, 0);
2582 break;
2583
2584 case TFOR:
2585 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002586 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002587 i = dolc;
2588 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002589 i = 0;
2590 } else {
2591 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002592 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002593 }
2594 vp = lookup(t->str);
2595 while (setjmp(bc.brkpt))
2596 if (isbreak)
2597 goto broken;
2598 brkset(&bc);
2599 for (t1 = t->left; i-- && *wp != NULL;) {
2600 setval(vp, *wp++);
2601 rv = execute(t1, pin, pout, 0);
2602 }
2603 brklist = brklist->nextlev;
2604 break;
2605
2606 case TWHILE:
2607 case TUNTIL:
2608 while (setjmp(bc.brkpt))
2609 if (isbreak)
2610 goto broken;
2611 brkset(&bc);
2612 t1 = t->left;
2613 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2614 rv = execute(t->right, pin, pout, 0);
2615 brklist = brklist->nextlev;
2616 break;
2617
2618 case TIF:
2619 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002620 if (t->right != NULL) {
2621 rv = !execute(t->left, pin, pout, 0) ?
2622 execute(t->right->left, pin, pout, 0) :
2623 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002624 }
2625 break;
2626
2627 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002628 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002629 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002630 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002631
2632 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2633 ((t->str == NULL) ? "NULL" : t->str),
2634 ((cp == NULL) ? "NULL" : cp)));
2635
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002636 t1 = findcase(t->left, cp);
2637 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002638 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002639 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002640 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002641 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002642 break;
2643
2644 case TBRACE:
2645/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002646 iopp = t->ioact;
2647 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002648 while (*iopp)
2649 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2650 rv = -1;
2651 break;
2652 }
2653*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002654 if (rv >= 0) {
2655 t1 = t->left;
2656 if (t1) {
2657 rv = execute(t1, pin, pout, 0);
2658 }
2659 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002660 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002661
2662 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002663
Eric Andersen8401eea2004-08-04 19:16:54 +00002664 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002665 t->words = wp2;
2666 isbreak = 0;
2667 freehere(areanum);
2668 freearea(areanum);
2669 areanum = a;
2670 if (interactive && intr) {
2671 closeall();
2672 fail();
2673 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002674
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002675 i = trapset;
2676 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002677 trapset = 0;
2678 runtrap(i);
2679 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002680
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002681 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002682 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002683}
2684
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002685typedef int (*builtin_func_ptr)(struct op *);
2686
2687static builtin_func_ptr inbuilt(const char *s) {
2688 const struct builtincmd *bp;
2689
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002690 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002691 if (strcmp(bp->name, s) == 0)
2692 return bp->builtinfunc;
2693
2694 return NULL;
2695}
2696
2697static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002698{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002699 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002701 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002702 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002703 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002704 struct ioword **iopp;
2705 int resetsig;
2706 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002707 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002708
2709 int *hpin = pin;
2710 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002711 char *hwp;
2712 int hinteractive;
2713 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002714 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002715 int hexecflg;
2716
2717#if __GNUC__
2718 /* Avoid longjmp clobbering */
2719 (void) &pin;
2720 (void) &pout;
2721 (void) &wp;
2722 (void) &shcom;
2723 (void) &cp;
2724 (void) &resetsig;
2725 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002726#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002727
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002728 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002729 pout, act));
2730 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2731 ((t->words == NULL) ? "NULL" : t->words[0])));
2732
Eric Andersenff9eee42001-06-29 04:57:14 +00002733 owp = wp;
2734 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002735 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002736 if (t->type == TCOM) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002737 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002738 cp = *wp;
2739
2740 /* strip all initial assignments */
2741 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002742 if (flag['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002743 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002744 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002745 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002746 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002747
Eric Andersenff9eee42001-06-29 04:57:14 +00002748 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002749 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2750 /**/;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002751 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002752 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002753 }
2754 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002755 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002756 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002757 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002758
Eric Andersenff9eee42001-06-29 04:57:14 +00002759 t->words = wp;
2760 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002761
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002762 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002763 f & FEXEC, owp));
2764
2765 if (shcom == NULL && (f & FEXEC) == 0) {
2766 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002767 hpin = pin;
2768 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002769 hwp = *wp;
2770 hinteractive = interactive;
2771 hintr = intr;
2772 hbrklist = brklist;
2773 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002774
Eric Andersen12de6cf2004-08-04 19:19:10 +00002775 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2776
2777 newpid = vfork();
2778
2779 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002780 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002781 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002782 }
2783
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002784 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002785 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002786 pin = hpin;
2787 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002788 *wp = hwp;
2789 interactive = hinteractive;
2790 intr = hintr;
2791 brklist = hbrklist;
2792 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002793/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002794 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002795 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002796*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002797 if (pin != NULL)
2798 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799
2800 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002801 }
2802
Eric Andersen12de6cf2004-08-04 19:19:10 +00002803 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002804 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002805
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 if (interactive) {
2807 signal(SIGINT, SIG_IGN);
2808 signal(SIGQUIT, SIG_IGN);
2809 resetsig = 1;
2810 }
2811 interactive = 0;
2812 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002813 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002814 brklist = 0;
2815 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002816 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002817
Eric Andersenff9eee42001-06-29 04:57:14 +00002818 if (owp != NULL)
2819 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2820 if (shcom == NULL)
2821 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002822
Eric Andersenff9eee42001-06-29 04:57:14 +00002823#ifdef COMPIPE
2824 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2825 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002826 if (forked)
2827 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002828 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002829 }
2830#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002831
Eric Andersenff9eee42001-06-29 04:57:14 +00002832 if (pin != NULL) {
2833 dup2(pin[0], 0);
2834 closepipe(pin);
2835 }
2836 if (pout != NULL) {
2837 dup2(pout[1], 1);
2838 closepipe(pout);
2839 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002840
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002841 iopp = t->ioact;
2842 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002843 if (shcom != NULL && shcom != doexec) {
2844 prs(cp);
2845 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002846 if (forked)
2847 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002848 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002849 }
2850 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002851 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2852 if (forked)
2853 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002854 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002855 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002856 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002857
2858 if (shcom) {
2859 i = setstatus((*shcom) (t));
2860 if (forked)
2861 _exit(i);
2862 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002863 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002864 }
2865
Eric Andersenff9eee42001-06-29 04:57:14 +00002866 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002867 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002868 close(i);
2869 if (resetsig) {
2870 signal(SIGINT, SIG_DFL);
2871 signal(SIGQUIT, SIG_DFL);
2872 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002873
Eric Andersen12de6cf2004-08-04 19:19:10 +00002874 if (t->type == TPAREN)
2875 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2876 if (wp[0] == NULL)
2877 _exit(0);
2878
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002879 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002880 prs(wp[0]);
2881 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002882 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002883 if (!execflg)
2884 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002885
2886 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2887
Eric Andersenff9eee42001-06-29 04:57:14 +00002888 leave();
2889 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002890 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002891}
2892
2893/*
2894 * 0< 1> are ignored as required
2895 * within pipelines.
2896 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002897static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002898{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002899 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002900 char *cp = NULL;
2901 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002902
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002903 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002904 pipein, pipeout));
2905
Eric Andersenff9eee42001-06-29 04:57:14 +00002906 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002907 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002908
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002910 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002911
Eric Andersenff9eee42001-06-29 04:57:14 +00002912 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002913 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002914
Eric Andersen8401eea2004-08-04 19:16:54 +00002915 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002917 cp = iop->io_name; /* huh?? */
2918 cp = evalstr(cp, DOSUB | DOTRIM);
2919 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002920 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002921 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002922
Eric Andersenff9eee42001-06-29 04:57:14 +00002923 if (iop->io_flag & IODUP) {
2924 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2925 prs(cp);
2926 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002927 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002928 }
2929 if (*cp == '-')
2930 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002931 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002932 }
2933 switch (iop->io_flag) {
2934 case IOREAD:
2935 u = open(cp, 0);
2936 break;
2937
2938 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002939 case IOHERE | IOXHERE:
2940 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002941 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002942 break;
2943
Eric Andersen8401eea2004-08-04 19:16:54 +00002944 case IOWRITE | IOCAT:
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002945 u = open(cp, 1);
2946 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002947 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002948 break;
2949 }
2950 case IOWRITE:
2951 u = creat(cp, 0666);
2952 break;
2953
2954 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002955 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002956 break;
2957
2958 case IOCLOSE:
2959 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002960 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002961 }
2962 if (u < 0) {
2963 prs(cp);
2964 prs(": cannot ");
2965 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002966 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002967 }
2968 if (u != iop->io_unit) {
2969 dup2(u, iop->io_unit);
2970 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002971 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002972 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002973}
2974
Eric Andersenff9eee42001-06-29 04:57:14 +00002975/*
2976 * Enter a new loop level (marked for break/continue).
2977 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002978static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002979{
2980 bc->nextlev = brklist;
2981 brklist = bc;
2982}
2983
2984/*
2985 * Wait for the last process created.
2986 * Print a message for each process found
2987 * that was killed by a signal.
2988 * Ignore interrupt signals while waiting
2989 * unless `canintr' is true.
2990 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002991static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002992{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002993 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002994 int s;
2995 int oheedint = heedint;
2996
2997 heedint = 0;
2998 rv = 0;
2999 do {
3000 pid = wait(&s);
3001 if (pid == -1) {
3002 if (errno != EINTR || canintr)
3003 break;
3004 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003005 rv = WAITSIG(s);
3006 if (rv != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003007 if (rv < NSIGNAL) {
3008 if (signame[rv] != NULL) {
3009 if (pid != lastpid) {
3010 prn(pid);
3011 prs(": ");
3012 }
3013 prs(signame[rv]);
3014 }
3015 } else {
3016 if (pid != lastpid) {
3017 prn(pid);
3018 prs(": ");
3019 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003020 prs("Signal ");
3021 prn(rv);
3022 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003023 }
3024 if (WAITCORE(s))
3025 prs(" - core dumped");
3026 if (rv >= NSIGNAL || signame[rv])
3027 prs("\n");
3028 rv = -1;
3029 } else
3030 rv = WAITVAL(s);
3031 }
3032 } while (pid != lastpid);
3033 heedint = oheedint;
3034 if (intr) {
3035 if (interactive) {
3036 if (canintr)
3037 intr = 0;
3038 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003039 if (exstat == 0)
3040 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003041 onintr(0);
3042 }
3043 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003044 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003045}
3046
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003047static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003048{
3049 exstat = s;
3050 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003051 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003052}
3053
3054/*
3055 * PATH-searching interface to execve.
3056 * If getenv("PATH") were kept up-to-date,
3057 * execvp might be used.
3058 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003059static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003060{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003061 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003062 const char *sp;
3063 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003064 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003065 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003066
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003067 if (ENABLE_FEATURE_SH_STANDALONE) {
Rob Landleya299efb2006-08-10 21:46:43 +00003068 optind = 1;
3069 if (find_applet_by_name(name)) {
3070 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003071 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003072 * will happen. */
3073 execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3074 }
Eric Andersen1c039232001-07-07 00:05:55 +00003075 }
Eric Andersen1c039232001-07-07 00:05:55 +00003076
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003077 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003078
Eric Andersen8401eea2004-08-04 19:16:54 +00003079 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003080 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003081 while (asis || *sp != '\0') {
3082 asis = 0;
3083 tp = e.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003084 for (; *sp != '\0'; tp++) {
3085 *tp = *sp++;
3086 if (*tp == ':') {
3087 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 break;
3089 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003090 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003091 if (tp != e.linep)
3092 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003093 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003094
Eric Andersen12de6cf2004-08-04 19:19:10 +00003095 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3096
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003098
Eric Andersenff9eee42001-06-29 04:57:14 +00003099 switch (errno) {
3100 case ENOEXEC:
3101 *v = e.linep;
3102 tp = *--v;
3103 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003104 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003105 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003106 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003107
3108 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003109 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003110
3111 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003112 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003113
3114 case EACCES:
3115 eacces++;
3116 break;
3117 }
3118 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003119 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003120}
3121
3122/*
3123 * Run the command produced by generator `f'
3124 * applied to stream `arg'.
3125 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003126static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003127{
3128 struct op *otree;
3129 struct wdblock *swdlist;
3130 struct wdblock *siolist;
3131 jmp_buf ev, rt;
3132 xint *ofail;
3133 int rv;
3134
3135#if __GNUC__
3136 /* Avoid longjmp clobbering */
3137 (void) &rv;
3138#endif
3139
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003140 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003141 areanum, outtree, failpt));
3142
Eric Andersenff9eee42001-06-29 04:57:14 +00003143 areanum++;
3144 swdlist = wdlist;
3145 siolist = iolist;
3146 otree = outtree;
3147 ofail = failpt;
3148 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003149
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003150 errpt = ev;
3151 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003152 wdlist = 0;
3153 iolist = 0;
3154 pushio(argp, f);
3155 e.iobase = e.iop;
3156 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003157 failpt = rt;
3158 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003159 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3160 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003161 } else {
3162 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003163 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003164
Eric Andersenff9eee42001-06-29 04:57:14 +00003165 wdlist = swdlist;
3166 iolist = siolist;
3167 failpt = ofail;
3168 outtree = otree;
3169 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003170
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003171 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003172}
3173
3174/* -------- do.c -------- */
3175
3176/*
3177 * built-in commands: doX
3178 */
3179
Eric Andersen8401eea2004-08-04 19:16:54 +00003180static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003181{
3182 int col;
3183 const struct builtincmd *x;
3184
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003185 puts("\nBuilt-in commands:\n"
3186 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003187
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003188 col = 0;
3189 x = builtincmds;
3190 while (x->name) {
3191 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003192 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003193 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003194 col = 0;
3195 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003196 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003197 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003198#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003199 {
Denis Vlasenko335b63d2007-04-10 21:38:30 +00003200 const struct bb_applet *applet = applets;
Eric Andersen1c039232001-07-07 00:05:55 +00003201
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003202 while (applet->name) {
3203 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003204 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003205 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003206 col = 0;
3207 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003208 applet++;
Eric Andersen1c039232001-07-07 00:05:55 +00003209 }
3210 }
3211#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003212 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003213 return EXIT_SUCCESS;
3214}
3215
Eric Andersen8401eea2004-08-04 19:16:54 +00003216static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003217{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003218 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003219}
3220
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003221static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003222{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003223 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003224
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003225 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003226 if (cp == NULL) {
3227 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003228 if (cp != NULL)
3229 goto do_cd;
3230 er = ": no home directory";
3231 } else {
3232 do_cd:
3233 if (chdir(cp) >= 0)
3234 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003235 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003236 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003237 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003238 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003239 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003240}
3241
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003242static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003243{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003244 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003245
Eric Andersen8401eea2004-08-04 19:16:54 +00003246 n = t->words[1] ? getn(t->words[1]) : 1;
3247 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003248 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250 }
3251 dolv[n] = dolv[0];
3252 dolv += n;
3253 dolc -= n;
3254 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003255 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003256}
3257
3258/*
3259 * execute login and newgrp directly
3260 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003261static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003262{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003263 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003264
3265 if (interactive) {
3266 signal(SIGINT, SIG_DFL);
3267 signal(SIGQUIT, SIG_DFL);
3268 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003269 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003270 prs(t->words[0]);
3271 prs(": ");
3272 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274}
3275
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003276static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003277{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003278 int i, n;
3279 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003280
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003281 cp = t->words[1];
3282 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003283 i = umask(0);
3284 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003285 for (n = 3 * 4; (n -= 3) >= 0;)
3286 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003287 putc('\n', stderr);
3288 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003289/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003290 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3291 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003292 umask(n);
3293 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003294 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003295}
3296
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003297static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003298{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003299 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003300 jmp_buf ex;
3301 xint *ofail;
3302
3303 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003304 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003305 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003306 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003307 execflg = 1;
3308 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003309 failpt = ex;
3310 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003311 execute(t, NOPIPE, NOPIPE, FEXEC);
3312 failpt = ofail;
3313 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003314 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003315}
3316
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003317static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003318{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003319 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003320 const char *sp;
3321 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003322 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003323 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003324
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003325 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003327 cp = t->words[1];
3328 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003329 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003330 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003331 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003332 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333
Eric Andersen8401eea2004-08-04 19:16:54 +00003334 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335
3336 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3337 ((sp == NULL) ? "NULL" : sp),
3338 ((e.linep == NULL) ? "NULL" : e.linep)));
3339
Eric Andersenff9eee42001-06-29 04:57:14 +00003340 while (*sp) {
3341 tp = e.linep;
3342 while (*sp && (*tp = *sp++) != ':')
3343 tp++;
3344 if (tp != e.linep)
3345 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003346
Eric Andersen8401eea2004-08-04 19:16:54 +00003347 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003348
3349 /* Original code */
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003350 i = open(e.linep, 0);
3351 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003352 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003353 maltmp = remap(i);
3354 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3355
3356 next(maltmp); /* Basically a PUSHIO */
3357
3358 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3359
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003360 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003361 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003362 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003363
Eric Andersenff9eee42001-06-29 04:57:14 +00003364 prs(cp);
3365 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003366
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003367 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003368}
3369
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003370static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003371{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003372 int i;
3373 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003374
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003375 cp = t->words[1];
3376 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003377 i = getn(cp);
3378 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003379 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003380 } else
3381 i = -1;
3382 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003383 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003384}
3385
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003386static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003387{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003388 char *cp, **wp;
3389 int nb = 0;
3390 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003391
3392 if (t->words[1] == NULL) {
3393 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003394 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003395 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003396 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003397 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3398 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003399 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003400 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003401 nl = (*cp == '\n');
3402 if (nl || (wp[1] && any(*cp, ifs->value)))
3403 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003404 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003405 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003406 if (nb <= 0)
3407 break;
3408 setval(lookup(*wp), e.linep);
3409 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003410 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003411}
3412
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003413static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003414{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003415 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003416}
3417
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003418static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003419{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003420 int n, i;
3421 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003422
3423 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003424 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003425 if (trap[i]) {
3426 prn(i);
3427 prs(": ");
3428 prs(trap[i]);
3429 prs("\n");
3430 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003431 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003432 }
3433 resetsig = isdigit(*t->words[1]);
3434 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3435 n = getsig(t->words[i]);
3436 freecell(trap[n]);
3437 trap[n] = 0;
3438 if (!resetsig) {
3439 if (*t->words[1] != '\0') {
3440 trap[n] = strsave(t->words[1], 0);
3441 setsig(n, sig);
3442 } else
3443 setsig(n, SIG_IGN);
3444 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003445 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003446 if (n == SIGINT)
3447 setsig(n, onintr);
3448 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003449 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003450 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003451 setsig(n, SIG_DFL);
3452 }
3453 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003454 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003455}
3456
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003457static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003458{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003459 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003460
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003461 n = getn(s);
3462 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003463 err("trap: bad signal number");
3464 n = 0;
3465 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003466 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003467}
3468
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003469static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003470{
3471 if (n == 0)
3472 return;
3473 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3474 ourtrap[n] = 1;
3475 signal(n, f);
3476 }
3477}
3478
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003479static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003480{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003481 char *s;
3482 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003483
3484 s = as;
3485 m = 1;
3486 if (*s == '-') {
3487 m = -1;
3488 s++;
3489 }
3490 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003491 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003492 if (*s) {
3493 prs(as);
3494 err(": bad number");
3495 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003496 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003497}
3498
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003499static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003500{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003501 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003502}
3503
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003504static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003505{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003506 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003507}
3508
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003509static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003510{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003511 struct brkcon *bc;
3512 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003513
Eric Andersen8401eea2004-08-04 19:16:54 +00003514 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003515 if (nl <= 0)
3516 nl = 999;
3517 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003518 bc = brklist;
3519 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003520 break;
3521 brklist = bc->nextlev;
3522 } while (--nl);
3523 if (nl) {
3524 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003525 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003526 }
3527 isbreak = val;
3528 longjmp(bc->brkpt, 1);
3529 /* NOTREACHED */
3530}
3531
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003532static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003533{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003534 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003535
3536 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003537 cp = t->words[1];
3538 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003539 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003540
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003541 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003542
Eric Andersenff9eee42001-06-29 04:57:14 +00003543 leave();
3544 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003545 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003546}
3547
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003548static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003549{
Eric Andersen8401eea2004-08-04 19:16:54 +00003550 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003551 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003552}
3553
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003554static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003555{
Eric Andersen8401eea2004-08-04 19:16:54 +00003556 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003557 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003558}
3559
Eric Andersen8401eea2004-08-04 19:16:54 +00003560static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003561{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003562 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003563 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3564
Eric Andersenff9eee42001-06-29 04:57:14 +00003565 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003566 for (; *wp != NULL; wp++) {
3567 if (isassign(*wp)) {
3568 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003569
Matt Kraaif69bfc72001-07-12 19:39:59 +00003570 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003571 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003572 *cp = '\0';
3573 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003574 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003575 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003576 else
3577 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003578 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003579 } else
3580 putvlist(key, 1);
3581}
3582
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003583static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003584{
3585 prs(s);
3586 err(": bad identifier");
3587}
3588
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003589static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003590{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003591 struct var *vp;
3592 char *cp;
3593 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003594
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003595 cp = t->words[1];
3596 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003597 for (vp = vlist; vp; vp = vp->next)
3598 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003599 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 }
3601 if (*cp == '-') {
3602 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003603 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 if (*++cp == 0)
3605 flag['x'] = flag['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003606 else {
3607 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 switch (*cp) {
3609 case 'e':
3610 if (!interactive)
3611 flag['e']++;
3612 break;
3613
3614 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003615 if (*cp >= 'a' && *cp <= 'z')
3616 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003617 break;
3618 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003619 }
3620 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 setdash();
3622 }
3623 if (t->words[1]) {
3624 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003625 for (n = 1; t->words[n]; n++)
3626 setarea((char *) t->words[n], 0);
3627 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003628 dolv = t->words;
3629 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003630 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003631 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003632 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003633}
3634
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003635static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003636{
Matt Kraai69edfec2001-08-06 14:14:18 +00003637 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003638 write(out, s, strlen(s));
3639 write(out, "\n", 1);
3640 }
3641}
3642
3643
3644/*
3645 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3646 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003647 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003648static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003649{
3650 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003651 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003652
3653 times(&buf);
3654 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003655 (int) (buf.tms_utime / clk_tck / 60),
3656 ((double) buf.tms_utime) / clk_tck,
3657 (int) (buf.tms_stime / clk_tck / 60),
3658 ((double) buf.tms_stime) / clk_tck,
3659 (int) (buf.tms_cutime / clk_tck / 60),
3660 ((double) buf.tms_cutime) / clk_tck,
3661 (int) (buf.tms_cstime / clk_tck / 60),
3662 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003663 return 0;
3664}
3665
3666
Eric Andersenff9eee42001-06-29 04:57:14 +00003667/* -------- eval.c -------- */
3668
3669/*
3670 * ${}
3671 * `command`
3672 * blank interpretation
3673 * quoting
3674 * glob
3675 */
3676
Eric Andersen8401eea2004-08-04 19:16:54 +00003677static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003678{
3679 struct wdblock *wb;
3680 char **wp;
3681 char **wf;
3682 jmp_buf ev;
3683
3684#if __GNUC__
3685 /* Avoid longjmp clobbering */
3686 (void) &wp;
3687 (void) &ap;
3688#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003689
3690 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3691
Eric Andersenff9eee42001-06-29 04:57:14 +00003692 wp = NULL;
3693 wb = NULL;
3694 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003695 errpt = ev;
3696 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003697 while (*ap && isassign(*ap))
3698 expand(*ap++, &wb, f & ~DOGLOB);
3699 if (flag['k']) {
3700 for (wf = ap; *wf; wf++) {
3701 if (isassign(*wf))
3702 expand(*wf, &wb, f & ~DOGLOB);
3703 }
3704 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003705 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003706 if (!flag['k'] || !isassign(*ap))
3707 expand(*ap, &wb, f & ~DOKEY);
3708 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003709 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003710 wp = getwords(wb);
3711 quitenv();
3712 } else
3713 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003714
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003715 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003716}
3717
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003718
Eric Andersenff9eee42001-06-29 04:57:14 +00003719/*
3720 * Make the exported environment from the exported
3721 * names in the dictionary. Keyword assignments
3722 * will already have been done.
3723 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003724static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003725{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003726 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003727
3728 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003729
Eric Andersenff9eee42001-06-29 04:57:14 +00003730 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003731 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003732 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003733 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003734 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003735}
3736
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003737static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003738{
3739 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003740 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003741
3742#if __GNUC__
3743 /* Avoid longjmp clobbering */
3744 (void) &cp;
3745#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003746
3747 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3748
Eric Andersenff9eee42001-06-29 04:57:14 +00003749 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003750
Eric Andersenff9eee42001-06-29 04:57:14 +00003751 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003752 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003753
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003754 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3755 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3756 ) {
3757 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003758 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003759 unquote(xp);
3760 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003761 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003762 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003763 errpt = ev;
3764 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003765 PUSHIO(aword, cp, strchar);
3766 e.iobase = e.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003767 while ((xp = blank(f)) && gflg == 0) {
3768 e.linep = xp;
3769 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003770 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003771 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003772 unquote(xp);
3773 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003774 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003775 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003776 }
3777 quitenv();
3778 } else
3779 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003780 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003781}
3782
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003783static char *evalstr(char *cp, int f)
3784{
3785 struct wdblock *wb;
3786
3787 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3788
3789 wb = NULL;
3790 if (expand(cp, &wb, f)) {
3791 if (wb == NULL || wb->w_nword == 0
3792 || (cp = wb->w_words[0]) == NULL
3793 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003794// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003795// char *evalstr(char *cp, int f) is actually
3796// const char *evalstr(const char *cp, int f)!
3797 cp = (char*)"";
3798 }
3799 DELETE(wb);
3800 } else
3801 cp = NULL;
3802 return cp;
3803}
3804
3805
Eric Andersenff9eee42001-06-29 04:57:14 +00003806/*
3807 * Blank interpretation and quoting
3808 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003809static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003810{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003811 int c, c1;
3812 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003813 int scanequals, foundequals;
3814
Eric Andersen12de6cf2004-08-04 19:19:10 +00003815 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3816
Eric Andersenff9eee42001-06-29 04:57:14 +00003817 sp = e.linep;
3818 scanequals = f & DOKEY;
3819 foundequals = 0;
3820
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003821 loop:
3822 c = subgetc('"', foundequals);
3823 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003824 case 0:
3825 if (sp == e.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003826 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003827 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003828 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003829
3830 default:
3831 if (f & DOBLANK && any(c, ifs->value))
3832 goto loop;
3833 break;
3834
3835 case '"':
3836 case '\'':
3837 scanequals = 0;
3838 if (INSUB())
3839 break;
3840 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3841 if (c == 0)
3842 break;
3843 if (c == '\'' || !any(c, "$`\""))
3844 c |= QUOTE;
3845 *e.linep++ = c;
3846 }
3847 c = 0;
3848 }
3849 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003850 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003851 scanequals = 0;
3852 for (;;) {
3853 c = subgetc('"', foundequals);
3854 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003855 f & (DOBLANK && any(c, ifs->value)) ||
3856 (!INSUB() && any(c, "\"'"))) {
3857 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003858 unget(c);
3859 if (any(c, "\"'"))
3860 goto loop;
3861 break;
3862 }
3863 if (scanequals) {
3864 if (c == '=') {
3865 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003866 scanequals = 0;
3867 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003868 scanequals = 0;
3869 }
3870 *e.linep++ = c;
3871 }
3872 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003873 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003874}
3875
3876/*
3877 * Get characters, substituting for ` and $
3878 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003879static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003880{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003881 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003882
3883 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003884
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003885 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003886 c = my_getc(ec);
3887 if (!INSUB() && ec != '\'') {
3888 if (c == '`') {
3889 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003890 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003891 e.iop->task = XGRAVE;
3892 goto again;
3893 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003894 if (c == '$') {
3895 c = dollar(quoted);
3896 if (c == 0) {
3897 e.iop->task = XDOLL;
3898 goto again;
3899 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003900 }
3901 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003902 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003903}
3904
3905/*
3906 * Prepare to generate the string returned by ${} substitution.
3907 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003908static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003909{
3910 int otask;
3911 struct io *oiop;
3912 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003913 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003914 struct var *vp;
3915
Eric Andersen12de6cf2004-08-04 19:19:10 +00003916 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3917
Eric Andersenff9eee42001-06-29 04:57:14 +00003918 c = readc();
3919 s = e.linep;
3920 if (c != '{') {
3921 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003922 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003923 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00003924 if (e.linep < elinep)
3925 *e.linep++ = c;
3926 unget(c);
3927 }
3928 c = 0;
3929 } else {
3930 oiop = e.iop;
3931 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003932
Eric Andersenff9eee42001-06-29 04:57:14 +00003933 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003934 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00003935 if (e.linep < elinep)
3936 *e.linep++ = c;
3937 if (oiop == e.iop)
3938 e.iop->task = otask;
3939 if (c != '}') {
3940 err("unclosed ${");
3941 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003942 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003943 }
3944 }
3945 if (e.linep >= elinep) {
3946 err("string in ${} too long");
3947 gflg++;
3948 e.linep -= 10;
3949 }
3950 *e.linep = 0;
3951 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003952 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003953 if (any(*cp, "=-+?")) {
3954 c = *cp;
3955 *cp++ = 0;
3956 break;
3957 }
3958 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3959 if (dolc > 1) {
3960 /* currently this does not distinguish $* and $@ */
3961 /* should check dollar */
3962 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003963 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003964 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003965 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003966 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003967 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003968 }
3969 }
3970 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003971 dolp = vp->value;
3972 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003973 switch (c) {
3974 case '=':
3975 if (isdigit(*s)) {
3976 err("cannot use ${...=...} with $n");
3977 gflg++;
3978 break;
3979 }
3980 setval(vp, cp);
3981 dolp = vp->value;
3982 break;
3983
3984 case '-':
3985 dolp = strsave(cp, areanum);
3986 break;
3987
3988 case '?':
3989 if (*cp == 0) {
3990 prs("missing value for ");
3991 err(s);
3992 } else
3993 err(cp);
3994 gflg++;
3995 break;
3996 }
3997 } else if (c == '+')
3998 dolp = strsave(cp, areanum);
3999 if (flag['u'] && dolp == null) {
4000 prs("unset variable: ");
4001 err(s);
4002 gflg++;
4003 }
4004 e.linep = s;
4005 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004006 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004007}
4008
4009/*
4010 * Run the command in `...` and read its output.
4011 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004012
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004013static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004014{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004015 /* moved to G: static char child_cmd[LINELIM]; */
4016
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004017 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004018 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004019 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004020 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004021 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004022 char *dest;
4023 int count;
4024 int ignore;
4025 int ignore_once;
4026 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004027 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004028
4029#if __GNUC__
4030 /* Avoid longjmp clobbering */
4031 (void) &cp;
4032#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004033
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004034 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004035 if (*cp == 0) {
4036 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004037 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004038 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004039 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004040
4041 /* string copy with dollar expansion */
4042 src = e.iop->argp->aword;
4043 dest = child_cmd;
4044 count = 0;
4045 ignore = 0;
4046 ignore_once = 0;
4047 while ((*src != '`') && (count < LINELIM)) {
4048 if (*src == '\'')
4049 ignore = !ignore;
4050 if (*src == '\\')
4051 ignore_once = 1;
4052 if (*src == '$' && !ignore && !ignore_once) {
4053 struct var *vp;
4054 char var_name[LINELIM];
4055 char alt_value[LINELIM];
4056 int var_index = 0;
4057 int alt_index = 0;
4058 char operator = 0;
4059 int braces = 0;
4060 char *value;
4061
4062 src++;
4063 if (*src == '{') {
4064 braces = 1;
4065 src++;
4066 }
4067
4068 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004069 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004070 var_name[var_index++] = *src++;
4071 var_name[var_index] = 0;
4072
4073 if (braces) {
4074 switch (*src) {
4075 case '}':
4076 break;
4077 case '-':
4078 case '=':
4079 case '+':
4080 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004081 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004082 break;
4083 default:
4084 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004085 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004086 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004087 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004088 src++;
4089 while (*src && (*src != '}')) {
4090 alt_value[alt_index++] = *src++;
4091 }
4092 alt_value[alt_index] = 0;
4093 if (*src != '}') {
4094 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004095 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004096 }
4097 }
4098 src++;
4099 }
4100
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004101 if (isalpha(*var_name)) {
4102 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004103
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004104 char *namep = var_name;
4105
4106 *dest++ = '$';
4107 if (braces)
4108 *dest++ = '{';
4109 while (*namep)
4110 *dest++ = *namep++;
4111 if (operator) {
4112 char *altp = alt_value;
4113 *dest++ = operator;
4114 while (*altp)
4115 *dest++ = *altp++;
4116 }
4117 if (braces)
4118 *dest++ = '}';
4119
4120 wb = addword(lookup(var_name)->name, wb);
4121 } else {
4122 /* expand */
4123
4124 vp = lookup(var_name);
4125 if (vp->value != null)
4126 value = (operator == '+') ?
4127 alt_value : vp->value;
4128 else if (operator == '?') {
4129 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004130 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004131 } else if (alt_index && (operator != '+')) {
4132 value = alt_value;
4133 if (operator == '=')
4134 setval(vp, value);
4135 } else
4136 continue;
4137
4138 while (*value && (count < LINELIM)) {
4139 *dest++ = *value++;
4140 count++;
4141 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004142 }
4143 } else {
4144 *dest++ = *src++;
4145 count++;
4146 ignore_once = 0;
4147 }
4148 }
4149 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004150
Eric Andersenff9eee42001-06-29 04:57:14 +00004151 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004152 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004153
Eric Andersen8401eea2004-08-04 19:16:54 +00004154 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004155
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004156 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004157
Eric Andersen737f5fb2003-03-14 16:05:59 +00004158 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004159 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004160 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004161 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004162 }
4163 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004164 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004165 e.iop->argp->aword = ++cp;
4166 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004167 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004168 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004169 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004170 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004171 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004172 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004173 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004174 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4175 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004176
Eric Andersenff9eee42001-06-29 04:57:14 +00004177 dup2(pf[1], 1);
4178 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004179
Eric Andersen8401eea2004-08-04 19:16:54 +00004180 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004181 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004182 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004183 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004184
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004185 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004186 prs(argument_list[0]);
4187 prs(": ");
4188 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004189 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004190}
4191
Eric Andersen737f5fb2003-03-14 16:05:59 +00004192
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004193static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004194{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004195 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004196
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004197 s = as;
4198 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004199 while (*s)
4200 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004201 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004202}
4203
4204/* -------- glob.c -------- */
4205
4206/*
4207 * glob
4208 */
4209
4210#define scopy(x) strsave((x), areanum)
4211#define BLKSIZ 512
4212#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4213
Eric Andersen8401eea2004-08-04 19:16:54 +00004214static struct wdblock *cl, *nl;
4215static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004216
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004217static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004218{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004219 int i;
4220 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004221
4222 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004223 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004224 i = 0;
4225 for (pp = cp; *pp; pp++)
4226 if (any(*pp, spcl))
4227 i++;
4228 else if (!any(*pp & ~QUOTE, spcl))
4229 *pp &= ~QUOTE;
4230 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004231 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004232 nl = newword(cl->w_nword * 2);
4233 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004234 for (pp = cl->w_words[i]; *pp; pp++)
4235 if (any(*pp, spcl)) {
4236 globname(cl->w_words[i], pp);
4237 break;
4238 }
4239 if (*pp == '\0')
4240 nl = addword(scopy(cl->w_words[i]), nl);
4241 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004242 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004243 DELETE(cl->w_words[i]);
4244 DELETE(cl);
4245 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004246 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004247 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004248 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004249 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004250 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004251 wb = addword(cl->w_words[i], wb);
4252 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004253 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004254 }
4255 }
4256 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004257 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004258}
4259
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004260static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004261{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004262 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004263 char *name, *gp, *dp;
4264 int k;
4265 DIR *dirp;
4266 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004267 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004268 struct stat dbuf;
4269
4270 for (np = we; np != pp; pp--)
4271 if (pp[-1] == '/')
4272 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004273 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004274 *cp++ = *np++;
4275 *cp++ = '.';
4276 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004277 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004278 *cp++ = *np++;
4279 *cp = '\0';
4280 dirp = opendir(dp);
4281 if (dirp == 0) {
4282 DELETE(dp);
4283 DELETE(gp);
4284 return;
4285 }
4286 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004288 /* XXX Hmmm... What this could be? (abial) */
4289 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004290 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004291 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004292 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004293 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004294 if (dname[0] == '.')
4295 if (*gp != '.')
4296 continue;
4297 for (k = 0; k < NAME_MAX; k++)
4298 if (any(dname[k], spcl))
4299 dname[k] |= QUOTE;
4300 if (gmatch(dname, gp)) {
4301 name = generate(we, pp, dname, np);
4302 if (*np && !anys(np, spcl)) {
4303 if (stat(name, &dbuf)) {
4304 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004305 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004306 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004307 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004308 nl = addword(name, nl);
4309 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004310 }
4311 closedir(dirp);
4312 DELETE(dp);
4313 DELETE(gp);
4314}
4315
4316/*
4317 * generate a pathname as below.
4318 * start..end1 / middle end
4319 * the slashes come for free
4320 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004321static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004322{
4323 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004324 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004325
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004326 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004327 for (xp = start1; xp != end1;)
4328 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004329 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004330 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004331 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004332 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004333}
4334
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004335static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004336{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004337 int i;
4338 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004339
4340 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004341 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004342 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004343 return 1;
4344 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004345}
4346
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004347static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004348{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004349 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004350}
4351
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004352
Eric Andersenff9eee42001-06-29 04:57:14 +00004353/* -------- word.c -------- */
4354
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004355static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004356{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004357 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004358
Eric Andersen8401eea2004-08-04 19:16:54 +00004359 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004360 wb->w_bsize = nw;
4361 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004362 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004363}
4364
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004365static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004366{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004367 struct wdblock *wb2;
4368 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004369
4370 if (wb == NULL)
4371 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004372 nw = wb->w_nword;
4373 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004374 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004375 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4376 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004377 wb2->w_nword = nw;
4378 DELETE(wb);
4379 wb = wb2;
4380 }
4381 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004382 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383}
Eric Andersen8401eea2004-08-04 19:16:54 +00004384
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004385static
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004386char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004387{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004388 char **wd;
4389 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004390
4391 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004392 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004393 if (wb->w_nword == 0) {
4394 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004395 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004396 }
4397 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004398 memcpy((char *) wd, (char *) wb->w_words, nb);
4399 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004400 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004401}
4402
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004403static int (*func) (char *, char *);
4404static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004405
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004406static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004407{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004408 char *index1, *index2, *index3;
4409 int c;
4410 int m;
4411
4412 m = globv;
4413 index1 = i;
4414 index2 = j;
4415 index3 = k;
4416 do {
4417 c = *index1;
4418 *index1++ = *index3;
4419 *index3++ = *index2;
4420 *index2++ = c;
4421 } while (--m);
4422}
4423
4424static void glob2(char *i, char *j)
4425{
4426 char *index1, *index2, c;
4427 int m;
4428
4429 m = globv;
4430 index1 = i;
4431 index2 = j;
4432 do {
4433 c = *index1;
4434 *index1++ = *index2;
4435 *index2++ = c;
4436 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004437}
4438
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004439static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004440{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004441 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004442 int v2;
4443 char *lptr, *hptr;
4444 int c;
4445 unsigned n;
4446
Eric Andersenff9eee42001-06-29 04:57:14 +00004447 v2 = globv;
4448
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004449 top:
4450 n = (int) (lim - base);
4451 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004453 n = v2 * (n / (2 * v2));
4454 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004455 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004456 j = lim - v2;
4457 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004458 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004459 c = (*func) (i, lptr);
4460 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004461 lptr -= v2;
4462 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004463 continue;
4464 }
4465 if (c < 0) {
4466 i += v2;
4467 continue;
4468 }
4469 }
4470
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004471 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004472 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004473 c = (*func) (hptr, j);
4474 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004475 hptr += v2;
4476 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004477 goto begin;
4478 }
4479 if (c > 0) {
4480 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004481 hptr += v2;
4482 glob3(i, hptr, j);
4483 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004484 goto begin;
4485 }
4486 glob2(i, j);
4487 j -= v2;
4488 i += v2;
4489 continue;
4490 }
4491 j -= v2;
4492 goto begin;
4493 }
4494
4495
4496 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004497 if (lptr - base >= lim - hptr) {
4498 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004499 lim = lptr;
4500 } else {
4501 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004502 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004503 }
4504 goto top;
4505 }
4506
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004507 lptr -= v2;
4508 glob3(j, lptr, i);
4509 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004510 }
4511}
4512
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004513static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004514{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004515 func = a3;
4516 globv = a2;
4517 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004518}
4519
Eric Andersenff9eee42001-06-29 04:57:14 +00004520
4521/* -------- io.c -------- */
4522
4523/*
4524 * shell IO
4525 */
4526
Eric Andersen8401eea2004-08-04 19:16:54 +00004527static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004528{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004529 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004530
Eric Andersen8401eea2004-08-04 19:16:54 +00004531 if (e.linep > elinep) {
4532 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004533 err("input line too long");
4534 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004535 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 }
4537 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004538 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004539 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004540 c = readc();
4541 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004542 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004543 c |= QUOTE;
4544 }
4545 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004546 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004547}
4548
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004549static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004550{
4551 if (e.iop >= e.iobase)
4552 e.iop->peekc = c;
4553}
4554
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004555static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004556{
Eric Andersen8401eea2004-08-04 19:16:54 +00004557 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004558}
4559
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004560static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004561{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004562 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004563
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004564 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004565
4566 for (; e.iop >= e.iobase; e.iop--) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004567 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004568 c = e.iop->peekc;
4569 if (c != '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004570 e.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004571 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004572 }
4573 if (e.iop->prev != 0) {
4574 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4575 if (c != '\0') {
4576 if (c == -1) {
4577 e.iop++;
4578 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004579 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004580 if (e.iop == iostack)
4581 ioecho(c);
4582 e.iop->prev = c;
4583 return e.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004584 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004585 if (e.iop->task == XIO && e.iop->prev != '\n') {
4586 e.iop->prev = 0;
4587 if (e.iop == iostack)
4588 ioecho('\n');
4589 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004590 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004591 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004592 if (e.iop->task == XIO) {
4593 if (multiline) {
4594 e.iop->prev = 0;
4595 return e.iop->prev;
4596 }
4597 if (interactive && e.iop == iostack + 1) {
4598#if ENABLE_FEATURE_EDITING
4599 current_prompt = prompt->value;
4600#else
4601 prs(prompt->value);
4602#endif
4603 }
4604 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004605 } /* FOR */
4606
4607 if (e.iop >= iostack) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004608 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004609 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004610 }
4611
4612 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004613 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004614
Eric Andersenff9eee42001-06-29 04:57:14 +00004615 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004616 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004617}
4618
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004619static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004620{
4621 if (flag['v'])
4622 write(2, &c, sizeof c);
4623}
4624
Eric Andersen12de6cf2004-08-04 19:19:10 +00004625
Eric Andersen8401eea2004-08-04 19:16:54 +00004626static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004627{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004628 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
Eric Andersen12de6cf2004-08-04 19:19:10 +00004629 argp->afid, e.iop));
4630
4631 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004632 if (++e.iop >= &iostack[NPUSH]) {
4633 e.iop--;
4634 err("Shell input nested too deeply");
4635 gflg++;
4636 return;
4637 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004638
4639 /* We did not overflow the NPUSH array spots so setup data structs */
4640
4641 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004642
4643 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004644 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004645 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004646
4647 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4648 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4649
4650 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4651
4652 if (e.iop == &iostack[0])
4653 e.iop->argp->afbuf = &mainbuf;
4654 else
4655 e.iop->argp->afbuf = &sharedbuf;
4656
4657 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4658 /* This line appears to be active when running scripts from command line */
4659 if ((isatty(e.iop->argp->afile) == 0)
4660 && (e.iop == &iostack[0]
Denis Vlasenkoea620772006-10-14 02:23:43 +00004661 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004662 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4663 bufid = AFID_ID; /* AFID_ID = 0 */
4664
4665 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004666 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004667
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004668 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004669 iostack, e.iop, e.iop->argp->afbuf));
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004670 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004671 &mainbuf, &sharedbuf, bufid, e.iop));
4672
Eric Andersenff9eee42001-06-29 04:57:14 +00004673 }
4674
Eric Andersen8401eea2004-08-04 19:16:54 +00004675 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004676 e.iop->peekc = 0;
4677 e.iop->xchar = 0;
4678 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004679
Eric Andersenff9eee42001-06-29 04:57:14 +00004680 if (fn == filechar || fn == linechar)
4681 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004682 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004683 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004684 e.iop->task = XGRAVE;
4685 else
4686 e.iop->task = XOTHER;
4687}
4688
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004689static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004690{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004691 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004692
4693 xp = e.iobase;
4694 e.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004695 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004696}
4697
4698/*
4699 * Input generating functions
4700 */
4701
4702/*
4703 * Produce the characters of a string, then a newline, then EOF.
4704 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004705static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004706{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004707 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004708
4709 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004710 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004711 c = *ap->aword++;
4712 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004713 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004714 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004715 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004716 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004717}
4718
4719/*
4720 * Given a list of words, produce the characters
4721 * in them, with a space after each word.
4722 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004723static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004724{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004725 char c;
4726 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004727
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004728 wl = ap->awordlist;
4729 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004730 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004731 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004732 c = *(*wl)++;
4733 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004734 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004735 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004736 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004737 }
4738 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004739 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004740}
4741
4742/*
4743 * Return the characters of a list of words,
4744 * producing a space between them.
4745 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004746static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004747{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004748 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004749
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004750 wp = *ap->awordlist++;
4751 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004752 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004753 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004754 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004755 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756}
4757
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004758static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004759{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004760 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761
4762 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004763 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004764 c = *ap->aword++;
4765 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004766 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004767 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004768 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004769 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004770}
4771
4772/*
4773 * Produce the characters from a single word (string).
4774 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004775static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004776{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004777 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004778 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004779 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004780}
4781
4782/*
4783 * Produce quoted characters from a single word (string).
4784 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004785static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004786{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004787 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004788
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004789 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004790 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004791 c = *ap->aword++;
4792 if (c)
4793 c |= QUOTE;
4794 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004795}
4796
4797/*
4798 * Return the characters from a file.
4799 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004800static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004801{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004802 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004803 char c;
4804 struct iobuf *bp = ap->afbuf;
4805
4806 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004807 i = (ap->afid != bp->id);
4808 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004809 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004810 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004811
Eric Andersen8401eea2004-08-04 19:16:54 +00004812 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4813 if (i <= 0) {
4814 closef(ap->afile);
4815 return 0;
4816 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004817
Eric Andersen8401eea2004-08-04 19:16:54 +00004818 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004819 bp->bufp = bp->buf;
4820 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004821 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004822
Eric Andersen8401eea2004-08-04 19:16:54 +00004823 ap->afpos++;
4824 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004825 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004826#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004827 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004828 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004829 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004830
Eric Andersen8401eea2004-08-04 19:16:54 +00004831 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004832 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4833 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004834 position = 0;
4835 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004836 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004837 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004838 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004839 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004840#endif
4841 i = safe_read(ap->afile, &c, sizeof(c));
4842 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004843}
4844
4845/*
4846 * Return the characters from a here temp file.
4847 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004848static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004849{
4850 char c;
4851
Eric Andersenff9eee42001-06-29 04:57:14 +00004852 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4853 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004854 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004855 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004856 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004857}
4858
4859/*
4860 * Return the characters produced by a process (`...`).
4861 * Quote them if required, and remove any trailing newline characters.
4862 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004863static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004864{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004865 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004866
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004867 c = qgravechar(ap, iop) & ~QUOTE;
4868 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004869 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004870 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004871}
4872
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004873static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004874{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004875 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004876
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004877 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004878
4879 if (iop->xchar) {
4880 if (iop->nlcount) {
4881 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004882 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004883 }
4884 c = iop->xchar;
4885 iop->xchar = 0;
4886 } else if ((c = filechar(ap)) == '\n') {
4887 iop->nlcount = 1;
4888 while ((c = filechar(ap)) == '\n')
4889 iop->nlcount++;
4890 iop->xchar = c;
4891 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004892 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004893 iop->nlcount--;
4894 c = '\n';
4895 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004896 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004897}
4898
4899/*
4900 * Return a single command (usually the first line) from a file.
4901 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004902static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004903{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004904 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004905
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004906 c = filechar(ap);
4907 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004908 if (!multiline) {
4909 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004910 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004911 }
4912 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004913 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004914}
4915
Eric Andersenff9eee42001-06-29 04:57:14 +00004916/*
4917 * remap fd into Shell's fd space
4918 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004919static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004920{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004921 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004922 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004923 int newfd;
4924
Eric Andersen12de6cf2004-08-04 19:19:10 +00004925 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004926
4927 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004928 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004929 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004930
Eric Andersenff9eee42001-06-29 04:57:14 +00004931 do {
4932 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004933 newfd = dup(fd);
4934 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004935 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004936
Eric Andersen8401eea2004-08-04 19:16:54 +00004937 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004938 if (map[i])
4939 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004940
Eric Andersenff9eee42001-06-29 04:57:14 +00004941 if (fd < 0)
4942 err("too many files open in shell");
4943 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004944
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004945 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004946}
4947
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004948static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004949{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004950 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004951
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004952 i = pipe(pv);
4953 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004954 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004955 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004956}
4957
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004958static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004959{
4960 if (pv != NULL) {
4961 close(*pv++);
4962 close(*pv);
4963 }
4964}
4965
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004966
Eric Andersenff9eee42001-06-29 04:57:14 +00004967/* -------- here.c -------- */
4968
4969/*
4970 * here documents
4971 */
4972
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004973static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004974{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004975 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004976
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004977 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004978
4979 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004980 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004981 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004982
Eric Andersenff9eee42001-06-29 04:57:14 +00004983 h->h_tag = evalstr(s, DOSUB);
4984 if (h->h_tag == 0)
4985 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004986
Eric Andersenff9eee42001-06-29 04:57:14 +00004987 h->h_iop = iop;
4988 iop->io_name = 0;
4989 h->h_next = NULL;
4990 if (inhere == 0)
4991 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004992 else {
4993 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004994 if (lh->h_next == 0) {
4995 lh->h_next = h;
4996 break;
4997 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004998 }
4999 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005000 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005001 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005002 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005003 iop->io_flag &= ~IOXHERE;
5004 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005005 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005006 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005007 h->h_dosub = iop->io_flag & IOXHERE;
5008}
5009
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005010static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005011{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005012 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005013
5014 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005015
5016 /* Scan here files first leaving inhere list in place */
5017 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005018 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005019
5020 /* Make inhere list active - keep list intact for scraphere */
5021 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005022 hp->h_next = acthere;
5023 acthere = inhere;
5024 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005025 }
5026}
5027
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005028static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005029{
5030 int tf;
5031 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005032 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005033 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005034 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005035 char *thenext;
5036
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005037 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005038
Eric Andersenff9eee42001-06-29 04:57:14 +00005039 tf = mkstemp(tname);
5040 if (tf < 0)
5041 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005042
Eric Andersenff9eee42001-06-29 04:57:14 +00005043 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005044 errpt = ev;
5045 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005046 unlink(tname);
5047 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005048 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005049 e.iobase = e.iop;
5050 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005051 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005052#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005053 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005054#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005055 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005056#endif
5057 }
5058 thenext = myline;
5059 while ((c = my_getc(ec)) != '\n' && c) {
5060 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005061 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005062 if (thenext >= &myline[LINELIM]) {
5063 c = 0;
5064 break;
5065 }
5066 *thenext++ = c;
5067 }
5068 *thenext = 0;
5069 if (strcmp(s, myline) == 0 || c == 0)
5070 break;
5071 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005072 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005073 }
5074 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005075 prs("here document `");
5076 prs(s);
5077 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005078 }
5079 quitenv();
5080 }
5081 close(tf);
5082}
5083
5084/*
5085 * open here temp file.
5086 * if unquoted here, expand here temp file into second temp file.
5087 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005088static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005089{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005090 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005091 int tf;
5092
5093#if __GNUC__
5094 /* Avoid longjmp clobbering */
5095 (void) &tf;
5096#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005097 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005098 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005099
5100 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5101
Eric Andersenff9eee42001-06-29 04:57:14 +00005102 hf = open(hname, 0);
5103 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005104 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005105
Eric Andersenff9eee42001-06-29 04:57:14 +00005106 if (xdoll) {
5107 char c;
5108 char tname[30] = ".msh_XXXXXX";
5109 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005110
Eric Andersenff9eee42001-06-29 04:57:14 +00005111 tf = mkstemp(tname);
5112 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005113 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005114 errpt = ev;
5115 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005116 PUSHIO(afile, hf, herechar);
5117 setbase(e.iop);
5118 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005119 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005120 write(tf, &c, sizeof c);
5121 }
5122 quitenv();
5123 } else
5124 unlink(tname);
5125 close(tf);
5126 tf = open(tname, 0);
5127 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005128 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005129 }
5130 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005131}
5132
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005133static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005134{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005135 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005136
5137 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005138
5139 for (h = inhere; h != NULL; h = h->h_next) {
5140 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005141 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005142 }
5143 inhere = NULL;
5144}
5145
5146/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005147static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005148{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005149 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005150
5151 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005152
5153 hl = NULL;
5154 for (h = acthere; h != NULL; h = h->h_next)
5155 if (getarea((char *) h) >= area) {
5156 if (h->h_iop->io_name != NULL)
5157 unlink(h->h_iop->io_name);
5158 if (hl == NULL)
5159 acthere = h->h_next;
5160 else
5161 hl->h_next = h->h_next;
5162 } else
5163 hl = h;
5164}
5165
5166
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005167/* -------- sh.c -------- */
5168/*
5169 * shell
5170 */
5171
Denis Vlasenko06af2162007-02-03 17:28:39 +00005172int msh_main(int argc, char **argv);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005173int msh_main(int argc, char **argv)
5174{
5175 int f;
5176 char *s;
5177 int cflag;
5178 char *name, **ap;
5179 int (*iof) (struct ioarg *);
5180
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005181 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5182 sharedbuf.id = AFID_NOBUF;
5183 mainbuf.id = AFID_NOBUF;
5184 e.linep = line;
5185 elinep = line + sizeof(line) - 5;
5186
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005187#if ENABLE_FEATURE_EDITING
5188 line_input_state = new_line_input_t(FOR_SHELL);
5189#endif
5190
5191 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5192
5193 initarea();
5194 ap = environ;
5195 if (ap != NULL) {
5196 while (*ap)
5197 assign(*ap++, !COPYV);
5198 for (ap = environ; *ap;)
5199 export(lookup(*ap++));
5200 }
5201 closeall();
5202 areanum = 1;
5203
5204 shell = lookup("SHELL");
5205 if (shell->value == null)
5206 setval(shell, (char *)DEFAULT_SHELL);
5207 export(shell);
5208
5209 homedir = lookup("HOME");
5210 if (homedir->value == null)
5211 setval(homedir, "/");
5212 export(homedir);
5213
5214 setval(lookup("$"), putn(getpid()));
5215
5216 path = lookup("PATH");
5217 if (path->value == null) {
5218 if (geteuid() == 0)
5219 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
5220 else
5221 setval(path, "/bin:/usr/bin");
5222 }
5223 export(path);
5224
5225 ifs = lookup("IFS");
5226 if (ifs->value == null)
5227 setval(ifs, " \t\n");
5228
5229#ifdef MSHDEBUG
5230 mshdbg_var = lookup("MSHDEBUG");
5231 if (mshdbg_var->value == null)
5232 setval(mshdbg_var, "0");
5233#endif
5234
5235 prompt = lookup("PS1");
5236#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5237 if (prompt->value == null)
5238#endif
5239 setval(prompt, DEFAULT_USER_PROMPT);
5240 if (geteuid() == 0) {
5241 setval(prompt, DEFAULT_ROOT_PROMPT);
5242 prompt->status &= ~EXPORT;
5243 }
5244 cprompt = lookup("PS2");
5245#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5246 if (cprompt->value == null)
5247#endif
5248 setval(cprompt, "> ");
5249
5250 iof = filechar;
5251 cflag = 0;
5252 name = *argv++;
5253 if (--argc >= 1) {
5254 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5255 for (s = argv[0] + 1; *s; s++)
5256 switch (*s) {
5257 case 'c':
5258 prompt->status &= ~EXPORT;
5259 cprompt->status &= ~EXPORT;
5260 setval(prompt, "");
5261 setval(cprompt, "");
5262 cflag = 1;
5263 if (--argc > 0)
5264 PUSHIO(aword, *++argv, iof = nlchar);
5265 break;
5266
5267 case 'q':
5268 qflag = SIG_DFL;
5269 break;
5270
5271 case 's':
5272 /* standard input */
5273 break;
5274
5275 case 't':
5276 prompt->status &= ~EXPORT;
5277 setval(prompt, "");
5278 iof = linechar;
5279 break;
5280
5281 case 'i':
5282 interactive++;
5283 default:
5284 if (*s >= 'a' && *s <= 'z')
5285 flag[(int) *s]++;
5286 }
5287 } else {
5288 argv--;
5289 argc++;
5290 }
5291
5292 if (iof == filechar && --argc > 0) {
5293 setval(prompt, "");
5294 setval(cprompt, "");
5295 prompt->status &= ~EXPORT;
5296 cprompt->status &= ~EXPORT;
5297
5298/* Shell is non-interactive, activate printf-based debug */
5299#ifdef MSHDEBUG
5300 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5301 if (mshdbg < 0)
5302 mshdbg = 0;
5303#endif
5304 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5305
5306 name = *++argv;
5307 if (newfile(name))
5308 exit(1); /* Exit on error */
5309 }
5310 }
5311
5312 setdash();
5313
5314 /* This won't be true if PUSHIO has been called, say from newfile() above */
5315 if (e.iop < iostack) {
5316 PUSHIO(afile, 0, iof);
5317 if (isatty(0) && isatty(1) && !cflag) {
5318 interactive++;
5319#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5320#ifdef MSHDEBUG
5321 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
5322#else
5323 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
5324#endif
5325 printf("Enter 'help' for a list of built-in commands.\n\n");
5326#endif
5327 }
5328 }
5329
5330 signal(SIGQUIT, qflag);
5331 if (name && name[0] == '-') {
5332 interactive++;
5333 f = open(".profile", 0);
5334 if (f >= 0)
5335 next(remap(f));
5336 f = open("/etc/profile", 0);
5337 if (f >= 0)
5338 next(remap(f));
5339 }
5340 if (interactive)
5341 signal(SIGTERM, sig);
5342
5343 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5344 signal(SIGINT, onintr);
5345 dolv = argv;
5346 dolc = argc;
5347 dolv[0] = name;
5348 if (dolc > 1) {
5349 for (ap = ++argv; --argc > 0;) {
5350 *ap = *argv++;
5351 if (assign(*ap, !COPYV)) {
5352 dolc--; /* keyword */
5353 } else {
5354 ap++;
5355 }
5356 }
5357 }
5358 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5359
5360 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5361
5362 for (;;) {
5363 if (interactive && e.iop <= iostack) {
5364#if ENABLE_FEATURE_EDITING
5365 current_prompt = prompt->value;
5366#else
5367 prs(prompt->value);
5368#endif
5369 }
5370 onecommand();
5371 /* Ensure that getenv("PATH") stays current */
5372 setenv("PATH", path->value, 1);
5373 }
5374
5375 DBGPRINTF(("MSH_MAIN: returning.\n"));
5376}
5377
5378
Eric Andersenff9eee42001-06-29 04:57:14 +00005379/*
5380 * Copyright (c) 1987,1997, Prentice Hall
5381 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005382 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005383 * Redistribution and use of the MINIX operating system in source and
5384 * binary forms, with or without modification, are permitted provided
5385 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005386 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005387 * Redistributions of source code must retain the above copyright
5388 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005389 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005390 * Redistributions in binary form must reproduce the above
5391 * copyright notice, this list of conditions and the following
5392 * disclaimer in the documentation and/or other materials provided
5393 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005394 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005395 * Neither the name of Prentice Hall nor the names of the software
5396 * authors or contributors may be used to endorse or promote
5397 * products derived from this software without specific prior
5398 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005399 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005400 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5401 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5402 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5403 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5404 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5405 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5406 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5407 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5408 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5409 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5410 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5411 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5412 *
5413 */