summaryrefslogtreecommitdiff
path: root/release/src/router/busybox/shell/msh.c
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/busybox/shell/msh.c')
-rw-r--r--release/src/router/busybox/shell/msh.c5904
1 files changed, 3143 insertions, 2761 deletions
diff --git a/release/src/router/busybox/shell/msh.c b/release/src/router/busybox/shell/msh.c
index a142c451..dffacf02 100644
--- a/release/src/router/busybox/shell/msh.c
+++ b/release/src/router/busybox/shell/msh.c
@@ -10,43 +10,128 @@
* Robert Schwebel <r.schwebel@pengutronix.de>
* Erik Andersen <andersen@codepoet.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Original copyright notice is retained at the end of this file.
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/stat.h>
#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/wait.h>
+#include <setjmp.h>
+
+#ifdef STANDALONE
+# ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+# endif
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/wait.h>
+# include <signal.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <string.h>
+# include <errno.h>
+# include <dirent.h>
+# include <fcntl.h>
+# include <ctype.h>
+# include <assert.h>
+# define bb_dev_null "/dev/null"
+# define DEFAULT_SHELL "/proc/self/exe"
+# define bb_banner "busybox standalone"
+# define ENABLE_FEATURE_SH_STANDALONE 0
+# define bb_msg_memory_exhausted "memory exhausted"
+# define xmalloc(size) malloc(size)
+# define msh_main(argc,argv) main(argc,argv)
+# define safe_read(fd,buf,count) read(fd,buf,count)
+# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
+# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
+# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
+# define NORETURN __attribute__ ((__noreturn__))
+static int find_applet_by_name(const char *applet)
+{
+ return -1;
+}
+static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
+{
+ unsigned i, out, res;
+ assert(sizeof(unsigned) == 4);
+ if (buflen) {
+ out = 0;
+ for (i = 1000000000; i; i /= 10) {
+ res = n / i;
+ if (res || out || i == 1) {
+ if (!--buflen) break;
+ out++;
+ n -= res*i;
+ *buf++ = '0' + res;
+ }
+ }
+ }
+ return buf;
+}
+static char *itoa_to_buf(int n, char *buf, unsigned buflen)
+{
+ if (buflen && n < 0) {
+ n = -n;
+ *buf++ = '-';
+ buflen--;
+ }
+ return utoa_to_buf((unsigned)n, buf, buflen);
+}
+static char local_buf[12];
+static char *itoa(int n)
+{
+ *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
+ return local_buf;
+}
+#else
+# include "busybox.h" /* for applet_names */
+#endif
+
+//#define MSHDEBUG 4
+
+#ifdef MSHDEBUG
+static int mshdbg = MSHDEBUG;
+
+#define DBGPRINTF(x) if (mshdbg > 0) printf x
+#define DBGPRINTF0(x) if (mshdbg > 0) printf x
+#define DBGPRINTF1(x) if (mshdbg > 1) printf x
+#define DBGPRINTF2(x) if (mshdbg > 2) printf x
+#define DBGPRINTF3(x) if (mshdbg > 3) printf x
+#define DBGPRINTF4(x) if (mshdbg > 4) printf x
+#define DBGPRINTF5(x) if (mshdbg > 5) printf x
+#define DBGPRINTF6(x) if (mshdbg > 6) printf x
+#define DBGPRINTF7(x) if (mshdbg > 7) printf x
+#define DBGPRINTF8(x) if (mshdbg > 8) printf x
+#define DBGPRINTF9(x) if (mshdbg > 9) printf x
+
+static int mshdbg_rc = 0;
+
+#define RCPRINTF(x) if (mshdbg_rc) printf x
+
+#else
+
+#define DBGPRINTF(x)
+#define DBGPRINTF0(x) ((void)0)
+#define DBGPRINTF1(x) ((void)0)
+#define DBGPRINTF2(x) ((void)0)
+#define DBGPRINTF3(x) ((void)0)
+#define DBGPRINTF4(x) ((void)0)
+#define DBGPRINTF5(x) ((void)0)
+#define DBGPRINTF6(x) ((void)0)
+#define DBGPRINTF7(x) ((void)0)
+#define DBGPRINTF8(x) ((void)0)
+#define DBGPRINTF9(x) ((void)0)
+
+#define RCPRINTF(x) ((void)0)
-#include "cmdedit.h"
-#include "busybox.h"
+#endif /* MSHDEBUG */
+
+
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
+# define DEFAULT_USER_PROMPT "\\u:\\w$ "
+#else
+# define DEFAULT_ROOT_PROMPT "# "
+# define DEFAULT_USER_PROMPT "$ "
+#endif
/* -------- sh.h -------- */
@@ -54,508 +139,406 @@
* shell
*/
-#define LINELIM 2100
-#define NPUSH 8 /* limit to input nesting */
+#define LINELIM 2100
+#define NPUSH 8 /* limit to input nesting */
#undef NOFILE
-#define NOFILE 20 /* Number of open files */
-#define NUFILE 10 /* Number of user-accessible files */
-#define FDBASE 10 /* First file usable by Shell */
+#define NOFILE 20 /* Number of open files */
+#define NUFILE 10 /* Number of user-accessible files */
+#define FDBASE 10 /* First file usable by Shell */
/*
* values returned by wait
*/
-#define WAITSIG(s) ((s)&0177)
-#define WAITVAL(s) (((s)>>8)&0377)
-#define WAITCORE(s) (((s)&0200)!=0)
+#define WAITSIG(s) ((s) & 0177)
+#define WAITVAL(s) (((s) >> 8) & 0377)
+#define WAITCORE(s) (((s) & 0200) != 0)
/*
- * library and system defintions
+ * library and system definitions
*/
-typedef void xint; /* base type of jmp_buf, for not broken compilers */
+typedef void xint; /* base type of jmp_buf, for not broken compilers */
/*
* shell components
*/
-
-#define QUOTE 0200
-
#define NOBLOCK ((struct op *)NULL)
#define NOWORD ((char *)NULL)
#define NOWORDS ((char **)NULL)
#define NOPIPE ((int *)NULL)
/*
+ * redirection
+ */
+struct ioword {
+ smallint io_flag; /* action (below) */
+ int io_fd; /* fd affected */
+ char *io_name; /* file name */
+};
+
+#define IOREAD 1 /* < */
+#define IOHERE 2 /* << (here file) */
+#define IOWRITE 4 /* > */
+#define IOCAT 8 /* >> */
+#define IOXHERE 16 /* ${}, ` in << */
+#define IODUP 32 /* >&digit */
+#define IOCLOSE 64 /* >&- */
+
+#define IODEFAULT (-1) /* "default" IO fd */
+
+
+/*
* Description of a command or an operation on commands.
* Might eventually use a union.
*/
struct op {
- int type; /* operation type, see below */
- char **words; /* arguments to a command */
- struct ioword **ioact; /* IO actions (eg, < > >>) */
+ smallint op_type; /* operation type, see Txxxx below */
+ char **op_words; /* arguments to a command */
+ struct ioword **ioact; /* IO actions (eg, < > >>) */
struct op *left;
struct op *right;
- char *str; /* identifier for case and for */
+ char *str; /* identifier for case and for */
};
-#define TCOM 1 /* command */
-#define TPAREN 2 /* (c-list) */
-#define TPIPE 3 /* a | b */
-#define TLIST 4 /* a [&;] b */
-#define TOR 5 /* || */
-#define TAND 6 /* && */
-#define TFOR 7
-#define TDO 8
-#define TCASE 9
-#define TIF 10
-#define TWHILE 11
-#define TUNTIL 12
-#define TELIF 13
-#define TPAT 14 /* pattern in case */
-#define TBRACE 15 /* {c-list} */
-#define TASYNC 16 /* c & */
+#define TCOM 1 /* command */
+#define TPAREN 2 /* (c-list) */
+#define TPIPE 3 /* a | b */
+#define TLIST 4 /* a [&;] b */
+#define TOR 5 /* || */
+#define TAND 6 /* && */
+#define TFOR 7
+#define TDO 8
+#define TCASE 9
+#define TIF 10
+#define TWHILE 11
+#define TUNTIL 12
+#define TELIF 13
+#define TPAT 14 /* pattern in case */
+#define TBRACE 15 /* {c-list} */
+#define TASYNC 16 /* c & */
+/* Added to support "." file expansion */
+#define TDOT 17
+
+/* Strings for names to make debug easier */
+#ifdef MSHDEBUG
+static const char *const T_CMD_NAMES[] = {
+ "PLACEHOLDER",
+ "TCOM",
+ "TPAREN",
+ "TPIPE",
+ "TLIST",
+ "TOR",
+ "TAND",
+ "TFOR",
+ "TDO",
+ "TCASE",
+ "TIF",
+ "TWHILE",
+ "TUNTIL",
+ "TELIF",
+ "TPAT",
+ "TBRACE",
+ "TASYNC",
+ "TDOT",
+};
+#endif
-/*
- * actions determining the environment of a process
- */
-#define BIT(i) (1<<(i))
-#define FEXEC BIT(0) /* execute without forking */
+#define AREASIZE (90000)
/*
* flags to control evaluation of words
*/
-#define DOSUB 1 /* interpret $, `, and quotes */
-#define DOBLANK 2 /* perform blank interpretation */
-#define DOGLOB 4 /* interpret [?* */
-#define DOKEY 8 /* move words with `=' to 2nd arg. list */
-#define DOTRIM 16 /* trim resulting string */
-
-#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
-
-static char **dolv;
-static int dolc;
-static int exstat;
-static char gflg;
-static int interactive; /* Is this an interactive shell */
-static int execflg;
-static int multiline; /* \n changed to ; */
-static struct op *outtree; /* result from parser */
-
-static xint *failpt;
-static xint *errpt;
-static struct brkcon *brklist;
-static int isbreak;
-static int newfile(char *s);
-static char *findeq(char *cp);
-static char *cclass(char *p, int sub);
-static void initarea(void);
-extern int msh_main(int argc, char **argv);
-
-
-struct brkcon {
- jmp_buf brkpt;
- struct brkcon *nextlev;
-} ;
+#define DOSUB 1 /* interpret $, `, and quotes */
+#define DOBLANK 2 /* perform blank interpretation */
+#define DOGLOB 4 /* interpret [?* */
+#define DOKEY 8 /* move words with `=' to 2nd arg. list */
+#define DOTRIM 16 /* trim resulting string */
-/*
- * redirection
- */
-struct ioword {
- short io_unit; /* unit affected */
- short io_flag; /* action (below) */
- char *io_name; /* file name */
-};
-#define IOREAD 1 /* < */
-#define IOHERE 2 /* << (here file) */
-#define IOWRITE 4 /* > */
-#define IOCAT 8 /* >> */
-#define IOXHERE 16 /* ${}, ` in << */
-#define IODUP 32 /* >&digit */
-#define IOCLOSE 64 /* >&- */
-
-#define IODEFAULT (-1) /* token for default IO unit */
+#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
-static struct wdblock *wdlist;
-static struct wdblock *iolist;
-/*
- * parsing & execution environment
- */
-static struct env {
- char *linep;
- struct io *iobase;
- struct io *iop;
- xint *errpt;
- int iofd;
- struct env *oenv;
-} e;
+struct brkcon {
+ jmp_buf brkpt;
+ struct brkcon *nextlev;
+};
-/*
- * flags:
- * -e: quit on error
- * -k: look for name=value everywhere on command line
- * -n: no execution
- * -t: exit after reading and executing one command
- * -v: echo as read
- * -x: trace
- * -u: unset variables net diagnostic
- */
-static char *flag;
-static char *null; /* null value for variable */
-static int intr; /* interrupt pending */
+static smallint trapset; /* trap pending (signal number) */
-static char *trap[_NSIG+1];
-static char ourtrap[_NSIG+1];
-static int trapset; /* trap pending */
+static smallint yynerrs; /* yacc (flag) */
-static int heedint; /* heed interrupt signals */
+/* moved to G: static char line[LINELIM]; */
-static int yynerrs; /* yacc */
+#if ENABLE_FEATURE_EDITING
+static char *current_prompt;
+static line_input_t *line_input_state;
+#endif
-static char line[LINELIM];
-static char *elinep;
/*
* other functions
*/
-static int(*inbuilt(char *s))(struct op *);
-
-
-static char *rexecve (char *c , char **v, char **envp );
-static char *space (int n );
-static char *strsave (char *s, int a );
-static char *evalstr (char *cp, int f );
-static char *putn (int n );
-static char *itoa (int n );
-static char *unquote (char *as );
-static struct var *lookup (char *n );
-static int rlookup (char *n );
-static struct wdblock *glob (char *cp, struct wdblock *wb );
-static int my_getc( int ec);
-static int subgetc (int ec, int quoted );
-static char **makenv (void);
-static char **eval (char **ap, int f );
-static int setstatus (int s );
-static int waitfor (int lastpid, int canintr );
-
-static void onintr (int s ); /* SIGINT handler */
-
-static int newenv (int f );
-static void quitenv (void);
-static void err (char *s );
-static int anys (char *s1, char *s2 );
-static int any (int c, char *s );
-static void next (int f );
-static void setdash (void);
-static void onecommand (void);
-static void runtrap (int i );
-static int gmatch (char *s, char *p );
-
-/*
- * error handling
- */
-static void leave (void); /* abort shell (or fail in subshell) */
-static void fail (void); /* fail but return to process next command */
-static void warn (char *s );
-static void sig (int i ); /* default signal handler */
-
+static const char *rexecve(char *c, char **v, char **envp);
+static char *evalstr(char *cp, int f);
+static char *putn(int n);
+static char *unquote(char *as);
+static int rlookup(char *n);
+static struct wdblock *glob(char *cp, struct wdblock *wb);
+static int my_getc(int ec);
+static int subgetc(char ec, int quoted);
+static char **makenv(int all, struct wdblock *wb);
+static char **eval(char **ap, int f);
+static int setstatus(int s);
+static int waitfor(int lastpid, int canintr);
+
+static void onintr(int s); /* SIGINT handler */
+
+static int newenv(int f);
+static void quitenv(void);
+static void next(int f);
+static void setdash(void);
+static void onecommand(void);
+static void runtrap(int i);
/* -------- area stuff -------- */
-#define REGSIZE sizeof(struct region)
-#define GROWBY 256
-//#define SHRINKBY 64
-#undef SHRINKBY
-#define FREE 32767
-#define BUSY 0
-#define ALIGN (sizeof(int)-1)
+#define REGSIZE sizeof(struct region)
+#define GROWBY (256)
+/* #define SHRINKBY (64) */
+#undef SHRINKBY
+#define FREE (32767)
+#define BUSY (0)
+#define ALIGN (sizeof(int)-1)
struct region {
- struct region *next;
- int area;
+ struct region *next;
+ int area;
};
-
/* -------- grammar stuff -------- */
typedef union {
- char *cp;
- char **wp;
- int i;
- struct op *o;
+ char *cp;
+ char **wp;
+ int i;
+ struct op *o;
} YYSTYPE;
-#define WORD 256
-#define LOGAND 257
-#define LOGOR 258
-#define BREAK 259
-#define IF 260
-#define THEN 261
-#define ELSE 262
-#define ELIF 263
-#define FI 264
-#define CASE 265
-#define ESAC 266
-#define FOR 267
-#define WHILE 268
-#define UNTIL 269
-#define DO 270
-#define DONE 271
-#define IN 272
+
+#define WORD 256
+#define LOGAND 257
+#define LOGOR 258
+#define BREAK 259
+#define IF 260
+#define THEN 261
+#define ELSE 262
+#define ELIF 263
+#define FI 264
+#define CASE 265
+#define ESAC 266
+#define FOR 267
+#define WHILE 268
+#define UNTIL 269
+#define DO 270
+#define DONE 271
+#define IN 272
+/* Added for "." file expansion */
+#define DOT 273
+
#define YYERRCODE 300
/* flags to yylex */
-#define CONTIN 01 /* skip new lines to complete command */
+#define CONTIN 01 /* skip new lines to complete command */
-#define SYNTAXERR zzerr()
-static struct op *pipeline(int cf );
+static struct op *pipeline(int cf);
static struct op *andor(void);
static struct op *c_list(void);
-static int synio(int cf );
-static void musthave (int c, int cf );
+static int synio(int cf);
+static void musthave(int c, int cf);
static struct op *simple(void);
-static struct op *nested(int type, int mark );
-static struct op *command(int cf );
-static struct op *dogroup(int onlydone );
+static struct op *nested(int type, int mark);
+static struct op *command(int cf);
+static struct op *dogroup(int onlydone);
static struct op *thenpart(void);
static struct op *elsepart(void);
static struct op *caselist(void);
static struct op *casepart(void);
static char **pattern(void);
static char **wordlist(void);
-static struct op *list(struct op *t1, struct op *t2 );
-static struct op *block(int type, struct op *t1, struct op *t2, char **wp );
+static struct op *list(struct op *t1, struct op *t2);
+static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
static struct op *newtp(void);
-static struct op *namelist(struct op *t );
+static struct op *namelist(struct op *t);
static char **copyw(void);
-static void word(char *cp );
+static void word(char *cp);
static struct ioword **copyio(void);
-static struct ioword *io (int u, int f, char *cp );
-static void zzerr(void);
-static void yyerror(char *s );
-static int yylex(int cf );
-static int collect(int c, int c1 );
-static int dual(int c );
-static void diag(int ec );
-static char *tree(unsigned size );
+static struct ioword *io(int u, int f, char *cp);
+static int yylex(int cf);
+static int collect(int c, int c1);
+static int dual(int c);
+static void diag(int ec);
+static char *tree(unsigned size);
/* -------- var.h -------- */
-struct var {
- char *value;
- char *name;
- struct var *next;
- char status;
+struct var {
+ char *value;
+ char *name;
+ struct var *next;
+ char status;
};
-#define COPYV 1 /* flag to setval, suggesting copy */
-#define RONLY 01 /* variable is read-only */
-#define EXPORT 02 /* variable is to be exported */
-#define GETCELL 04 /* name & value space was got with getcell */
-
-static struct var *vlist; /* dictionary */
-
-static struct var *homedir; /* home directory */
-static struct var *prompt; /* main prompt */
-static struct var *cprompt; /* continuation prompt */
-static struct var *path; /* search path for commands */
-static struct var *shell; /* shell to interpret command files */
-static struct var *ifs; /* field separators */
-
-static int yyparse (void);
-static struct var *lookup (char *n );
-static void setval (struct var *vp, char *val );
-static void nameval (struct var *vp, char *val, char *name );
-static void export (struct var *vp );
-static void ronly (struct var *vp );
-static int isassign (char *s );
-static int checkname (char *cp );
-static int assign (char *s, int cf );
-static void putvlist (int f, int out );
-static int eqname (char *n1, char *n2 );
-
-static int execute (struct op *t, int *pin, int *pout, int act );
+
+#define COPYV 1 /* flag to setval, suggesting copy */
+#define RONLY 01 /* variable is read-only */
+#define EXPORT 02 /* variable is to be exported */
+#define GETCELL 04 /* name & value space was got with getcell */
+
+static int yyparse(void);
+
/* -------- io.h -------- */
/* io buffer */
struct iobuf {
- unsigned id; /* buffer id */
- char buf[512]; /* buffer */
- char *bufp; /* pointer into buffer */
- char *ebufp; /* pointer to end of buffer */
+ unsigned id; /* buffer id */
+ char buf[512]; /* buffer */
+ char *bufp; /* pointer into buffer */
+ char *ebufp; /* pointer to end of buffer */
};
/* possible arguments to an IO function */
struct ioarg {
- char *aword;
- char **awordlist;
- int afile; /* file descriptor */
- unsigned afid; /* buffer id */
- long afpos; /* file position */
- struct iobuf *afbuf; /* buffer for this file */
+ const char *aword;
+ char **awordlist;
+ int afile; /* file descriptor */
+ unsigned afid; /* buffer id */
+ off_t afpos; /* file position */
+ struct iobuf *afbuf; /* buffer for this file */
};
-//static struct ioarg ioargstack[NPUSH];
-#define AFID_NOBUF (~0)
-#define AFID_ID 0
/* an input generator's state */
-struct io {
- int (*iofn)(struct ioarg *, struct io *);
- struct ioarg *argp;
- int peekc;
- char prev; /* previous character read by readc() */
- char nlcount; /* for `'s */
- char xchar; /* for `'s */
- char task; /* reason for pushed IO */
+struct io {
+ int (*iofn) (struct ioarg *, struct io *);
+ struct ioarg *argp;
+ int peekc;
+ char prev; /* previous character read by readc() */
+ char nlcount; /* for `'s */
+ char xchar; /* for `'s */
+ char task; /* reason for pushed IO */
};
-//static struct io iostack[NPUSH];
+/* ->task: */
#define XOTHER 0 /* none of the below */
#define XDOLL 1 /* expanding ${} */
#define XGRAVE 2 /* expanding `'s */
#define XIO 3 /* file IO */
-/* in substitution */
-#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
/*
* input generators for IO structure
*/
-static int nlchar (struct ioarg *ap );
-static int strchar (struct ioarg *ap );
-static int qstrchar (struct ioarg *ap );
-static int filechar (struct ioarg *ap );
-static int herechar (struct ioarg *ap );
-static int linechar (struct ioarg *ap );
-static int gravechar (struct ioarg *ap, struct io *iop );
-static int qgravechar (struct ioarg *ap, struct io *iop );
-static int dolchar (struct ioarg *ap );
-static int wdchar (struct ioarg *ap );
-static void scraphere (void);
-static void freehere (int area );
-static void gethere (void);
-static void markhere (char *s, struct ioword *iop );
-static int herein (char *hname, int xdoll );
-static int run (struct ioarg *argp, int (*f)(struct ioarg *));
+static int nlchar(struct ioarg *ap);
+static int strchar(struct ioarg *ap);
+static int qstrchar(struct ioarg *ap);
+static int filechar(struct ioarg *ap);
+static int herechar(struct ioarg *ap);
+static int linechar(struct ioarg *ap);
+static int gravechar(struct ioarg *ap, struct io *iop);
+static int qgravechar(struct ioarg *ap, struct io *iop);
+static int dolchar(struct ioarg *ap);
+static int wdchar(struct ioarg *ap);
+static void scraphere(void);
+static void freehere(int area);
+static void gethere(void);
+static void markhere(char *s, struct ioword *iop);
+static int herein(char *hname, int xdoll);
+static int run(struct ioarg *argp, int (*f) (struct ioarg *));
+
+
+static int eofc(void);
+static int readc(void);
+static void unget(int c);
+static void ioecho(char c);
-/*
- * IO functions
- */
-static int eofc (void);
-static int readc (void);
-static void unget (int c );
-static void ioecho (int c );
-static void prs (char *s );
-static void prn (unsigned u );
-static void closef (int i );
-static void closeall (void);
/*
* IO control
*/
-static void pushio (struct ioarg *argp, int (*f)(struct ioarg *));
-static int remap (int fd );
-static int openpipe (int *pv );
-static void closepipe (int *pv );
-static struct io *setbase (struct io *ip );
-
-static struct ioarg temparg; /* temporary for PUSHIO */
-#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
-#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
+static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
+#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
+static int remap(int fd);
+static int openpipe(int *pv);
+static void closepipe(int *pv);
+static struct io *setbase(struct io *ip);
/* -------- word.h -------- */
-#define NSTART 16 /* default number of words to allow for initially */
+#define NSTART 16 /* default number of words to allow for initially */
-struct wdblock {
- short w_bsize;
- short w_nword;
+struct wdblock {
+ short w_bsize;
+ short w_nword;
/* bounds are arbitrary */
- char *w_words[1];
+ char *w_words[1];
};
-static struct wdblock *addword (char *wd, struct wdblock *wb );
-static struct wdblock *newword (int nw );
-static char **getwords (struct wdblock *wb );
-
-/* -------- area.h -------- */
-
-/*
- * storage allocation
- */
-static char *getcell (unsigned nbytes );
-static void garbage (void);
-static void setarea (char *cp, int a );
-static int getarea (char *cp );
-static void freearea (int a );
-static void freecell (char *cp );
-static int areanum; /* current allocation area */
-
-#define NEW(type) (type *)getcell(sizeof(type))
-#define DELETE(obj) freecell((char *)obj)
-
+static struct wdblock *addword(char *wd, struct wdblock *wb);
+static struct wdblock *newword(int nw);
+static char **getwords(struct wdblock *wb);
/* -------- misc stuff -------- */
-static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked );
-static int iosetup (struct ioword *iop, int pipein, int pipeout );
-static void echo(char **wp );
-static struct op **find1case (struct op *t, char *w );
-static struct op *findcase (struct op *t, char *w );
-static void brkset(struct brkcon *bc );
-static int dolabel(struct op *t );
-static int dohelp(struct op *t );
-static int dochdir(struct op *t );
-static int doshift(struct op *t );
-static int dologin(struct op *t );
-static int doumask(struct op *t );
-static int doexec(struct op *t );
-static int dodot(struct op *t );
-static int dowait(struct op *t );
-static int doread(struct op *t );
-static int doeval(struct op *t );
-static int dotrap(struct op *t );
-static int getsig(char *s );
-static void setsig (int n, sighandler_t f);
-static int getn(char *as );
-static int dobreak(struct op *t );
-static int docontinue(struct op *t );
-static int brkcontin (char *cp, int val );
-static int doexit(struct op *t );
-static int doexport(struct op *t );
-static int doreadonly(struct op *t );
-static void rdexp (char **wp, void (*f)(struct var *), int key);
-static void badid(char *s );
-static int doset(struct op *t );
-static void varput (char *s, int out );
-static int dotimes(struct op *t );
-static int expand (char *cp, struct wdblock **wbp, int f );
-static char *blank(int f );
-static int dollar(int quoted );
-static int grave(int quoted );
-static void globname (char *we, char *pp );
-static char *generate (char *start1, char *end1, char *middle, char *end );
-static int anyspcl(struct wdblock *wb );
-static int xstrcmp (char *p1, char *p2 );
-static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *));
-static void glob1 (char *base, char *lim );
-static void glob2 (char *i, char *j );
-static void glob3 (char *i, char *j, char *k );
-static void readhere (char **name, char *s, int ec );
-static void pushio (struct ioarg *argp, int (*f)(struct ioarg *));
-static int xxchar(struct ioarg *ap );
-
-struct here {
- char *h_tag;
- int h_dosub;
- struct ioword *h_iop;
- struct here *h_next;
+static int dolabel(struct op *t, char **args);
+static int dohelp(struct op *t, char **args);
+static int dochdir(struct op *t, char **args);
+static int doshift(struct op *t, char **args);
+static int dologin(struct op *t, char **args);
+static int doumask(struct op *t, char **args);
+static int doexec(struct op *t, char **args);
+static int dodot(struct op *t, char **args);
+static int dowait(struct op *t, char **args);
+static int doread(struct op *t, char **args);
+static int doeval(struct op *t, char **args);
+static int dotrap(struct op *t, char **args);
+static int dobreak(struct op *t, char **args);
+static int doexit(struct op *t, char **args);
+static int doexport(struct op *t, char **args);
+static int doreadonly(struct op *t, char **args);
+static int doset(struct op *t, char **args);
+static int dotimes(struct op *t, char **args);
+static int docontinue(struct op *t, char **args);
+
+static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
+static int execute(struct op *t, int *pin, int *pout, int no_fork);
+static int iosetup(struct ioword *iop, int pipein, int pipeout);
+static void brkset(struct brkcon *bc);
+static int getsig(char *s);
+static void setsig(int n, sighandler_t f);
+static int getn(char *as);
+static int brkcontin(char *cp, int val);
+static void rdexp(char **wp, void (*f) (struct var *), int key);
+static void badid(char *s);
+static void varput(char *s, int out);
+static int expand(const char *cp, struct wdblock **wbp, int f);
+static char *blank(int f);
+static int dollar(int quoted);
+static int grave(int quoted);
+static void globname(char *we, char *pp);
+static char *generate(char *start1, char *end1, char *middle, char *end);
+static int anyspcl(struct wdblock *wb);
+static void readhere(char **name, char *s, int ec);
+static int xxchar(struct ioarg *ap);
+
+struct here {
+ char *h_tag;
+ char h_dosub;
+ struct ioword *h_iop;
+ struct here *h_next;
};
-static char *signame[] = {
+static const char *const signame[] = {
"Signal 0",
"Hangup",
- (char *)NULL, /* interrupt */
+ NULL, /* interrupt */
"Quit",
"Illegal instruction",
"Trace/BPT trap",
@@ -566,637 +549,534 @@ static char *signame[] = {
"SIGUSR1",
"SIGSEGV",
"SIGUSR2",
- (char *)NULL, /* broken pipe */
+ NULL, /* broken pipe */
"Alarm clock",
- "Terminated",
+ "Terminated"
};
-#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
-struct res {
- char *r_name;
- int r_val;
-};
-static struct res restab[] = {
- {"for", FOR},
- {"case", CASE},
- {"esac", ESAC},
- {"while", WHILE},
- {"do", DO},
- {"done", DONE},
- {"if", IF},
- {"in", IN},
- {"then", THEN},
- {"else", ELSE},
- {"elif", ELIF},
- {"until", UNTIL},
- {"fi", FI},
-
- {";;", BREAK},
- {"||", LOGOR},
- {"&&", LOGAND},
- {"{", '{'},
- {"}", '}'},
- {0, 0},
-};
+typedef int (*builtin_func_ptr)(struct op *, char **);
struct builtincmd {
const char *name;
- int (*builtinfunc)(struct op *t);
+ builtin_func_ptr builtinfunc;
};
-static const struct builtincmd builtincmds[] = {
- {".", dodot},
- {":", dolabel},
- {"break", dobreak},
- {"cd", dochdir},
- {"continue",docontinue},
- {"eval", doeval},
- {"exec", doexec},
- {"exit", doexit},
- {"export", doexport},
- {"help", dohelp},
- {"login", dologin},
- {"newgrp", dologin},
- {"read", doread},
- {"readonly",doreadonly},
- {"set", doset},
- {"shift", doshift},
- {"times", dotimes},
- {"trap", dotrap},
- {"umask", doumask},
- {"wait", dowait},
- {0,0}
+
+static const struct builtincmd builtincmds[] = {
+ { "." , dodot },
+ { ":" , dolabel },
+ { "break" , dobreak },
+ { "cd" , dochdir },
+ { "continue", docontinue },
+ { "eval" , doeval },
+ { "exec" , doexec },
+ { "exit" , doexit },
+ { "export" , doexport },
+ { "help" , dohelp },
+ { "login" , dologin },
+ { "newgrp" , dologin },
+ { "read" , doread },
+ { "readonly", doreadonly },
+ { "set" , doset },
+ { "shift" , doshift },
+ { "times" , dotimes },
+ { "trap" , dotrap },
+ { "umask" , doumask },
+ { "wait" , dowait },
+ { NULL , NULL },
};
+static struct op *dowholefile(int /*, int*/);
+
+
/* Globals */
-extern char **environ; /* environment pointer */
-static char **dolv;
-static int dolc;
-static int exstat;
-static char gflg;
-static int interactive; /* Is this an interactive shell */
-static int execflg;
-static int multiline; /* \n changed to ; */
-static struct op *outtree; /* result from parser */
-static xint *failpt;
-static xint *errpt;
-static struct brkcon *brklist;
-static int isbreak;
-static struct wdblock *wdlist;
-static struct wdblock *iolist;
-static char *trap[_NSIG+1];
-static char ourtrap[_NSIG+1];
-static int trapset; /* trap pending */
-static int yynerrs; /* yacc */
-static char line[LINELIM];
-static struct var *vlist; /* dictionary */
-static struct var *homedir; /* home directory */
-static struct var *prompt; /* main prompt */
-static struct var *cprompt; /* continuation prompt */
-static struct var *path; /* search path for commands */
-static struct var *shell; /* shell to interpret command files */
-static struct var *ifs; /* field separators */
-static struct ioarg ioargstack[NPUSH];
-static struct io iostack[NPUSH];
-static int areanum; /* current allocation area */
-static int intr;
-static int inparse;
-static char flags['z'-'a'+1];
-static char *flag = flags-'a';
-static char *elinep = line+sizeof(line)-5;
-static char *null = "";
-static int heedint =1;
-static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL};
-static void (*qflag)(int) = SIG_IGN;
-static char shellname[] = "/bin/sh";
-static int startl;
-static int peeksym;
-static int nlseen;
-static int iounit = IODEFAULT;
-static YYSTYPE yylval;
-static struct iobuf sharedbuf = {AFID_NOBUF};
-static struct iobuf mainbuf = {AFID_NOBUF};
-static unsigned bufid = AFID_ID; /* buffer id counter */
-static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
-static struct here *inhere; /* list of hear docs while parsing */
-static struct here *acthere; /* list of active here documents */
-static struct region *areabot; /* bottom of area */
-static struct region *areatop; /* top of area */
-static struct region *areanxt; /* starting point of scan */
-static void * brktop;
-static void * brkaddr;
-
-
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
-static char * current_prompt;
+static char **dolv;
+static int dolc;
+static uint8_t exstat;
+static smallint gflg; /* (seems to be a parse error indicator) */
+static smallint interactive; /* Is this an interactive shell */
+static smallint execflg;
+static smallint isbreak; /* "break" statement was seen */
+static int multiline; /* '\n' changed to ';' (counter) */
+static struct op *outtree; /* result from parser */
+static xint *failpt;
+static xint *errpt;
+static struct brkcon *brklist;
+static struct wdblock *wdlist;
+static struct wdblock *iolist;
+
+#ifdef MSHDEBUG
+static struct var *mshdbg_var;
#endif
+static struct var *vlist; /* dictionary */
+static struct var *homedir; /* home directory */
+static struct var *prompt; /* main prompt */
+static struct var *cprompt; /* continuation prompt */
+static struct var *path; /* search path for commands */
+static struct var *shell; /* shell to interpret command files */
+static struct var *ifs; /* field separators */
+
+static int areanum; /* current allocation area */
+static smallint intr; /* interrupt pending (bool) */
+static smallint heedint = 1; /* heed interrupt signals (bool) */
+static int inparse;
+static char *null = (char*)""; /* null value for variable */
+static void (*qflag)(int) = SIG_IGN;
+static int startl;
+static int peeksym;
+static int nlseen;
+static int iounit = IODEFAULT;
+static YYSTYPE yylval;
+static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
+
+static struct here *inhere; /* list of hear docs while parsing */
+static struct here *acthere; /* list of active here documents */
+static struct region *areabot; /* bottom of area */
+static struct region *areatop; /* top of area */
+static struct region *areanxt; /* starting point of scan */
+static void *brktop;
+static void *brkaddr;
+
+#define AFID_NOBUF (~0)
+#define AFID_ID 0
+
-/* -------- sh.c -------- */
/*
- * shell
+ * parsing & execution environment
*/
+struct env {
+ char *linep;
+ struct io *iobase;
+ struct io *iop;
+ xint *errpt; /* void * */
+ int iofd;
+ struct env *oenv;
+};
-extern int msh_main(int argc, char **argv)
-{
- register int f;
- register char *s;
- int cflag;
- char *name, **ap;
- int (*iof)(struct ioarg *);
+struct globals {
+ struct env global_env;
+ struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
+ unsigned bufid; // = AFID_ID; /* buffer id counter */
+ char ourtrap[_NSIG + 1];
+ char *trap[_NSIG + 1];
+ struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
+ struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
+ struct ioarg ioargstack[NPUSH];
+ /*
+ * flags:
+ * -e: quit on error
+ * -k: look for name=value everywhere on command line
+ * -n: no execution
+ * -t: exit after reading and executing one command
+ * -v: echo as read
+ * -x: trace
+ * -u: unset variables net diagnostic
+ */
+ char flags['z' - 'a' + 1];
+ char filechar_cmdbuf[BUFSIZ];
+ char line[LINELIM];
+ char child_cmd[LINELIM];
- initarea();
- if ((ap = environ) != NULL) {
- while (*ap)
- assign(*ap++, !COPYV);
- for (ap = environ; *ap;)
- export(lookup(*ap++));
- }
- closeall();
- areanum = 1;
+ struct io iostack[NPUSH];
- shell = lookup("SHELL");
- if (shell->value == null)
- setval(shell, shellname);
- export(shell);
+ char grave__var_name[LINELIM];
+ char grave__alt_value[LINELIM];
+};
- homedir = lookup("HOME");
- if (homedir->value == null)
- setval(homedir, "/");
- export(homedir);
+#define G (*ptr_to_globals)
+#define global_env (G.global_env )
+#define temparg (G.temparg )
+#define bufid (G.bufid )
+#define ourtrap (G.ourtrap )
+#define trap (G.trap )
+#define sharedbuf (G.sharedbuf )
+#define mainbuf (G.mainbuf )
+#define ioargstack (G.ioargstack )
+/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
+#define FLAG (G.flags - 'a' )
+#define filechar_cmdbuf (G.filechar_cmdbuf)
+#define line (G.line )
+#define child_cmd (G.child_cmd )
+#define iostack (G.iostack )
+#define INIT_G() do { \
+ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+ global_env.linep = line; \
+ global_env.iobase = iostack; \
+ global_env.iop = iostack - 1; \
+ global_env.iofd = FDBASE; \
+ temparg.afid = AFID_NOBUF; \
+ bufid = AFID_ID; \
+} while (0)
- setval(lookup("$"), putn(getpid()));
- path = lookup("PATH");
- if (path->value == null) {
- if (geteuid() == 0)
- setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
- else
- setval(path, "/bin:/usr/bin");
- }
- export(path);
+/* in substitution */
+#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
- ifs = lookup("IFS");
- if (ifs->value == null)
- setval(ifs, " \t\n");
+#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
- prompt = lookup("PS1");
-#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
- if (prompt->value == null)
-#endif
- setval(prompt, "$ ");
- if (geteuid() == 0) {
- setval(prompt, "# ");
- prompt->status &= ~EXPORT;
+#ifdef MSHDEBUG
+static void print_tree(struct op *head)
+{
+ if (head == NULL) {
+ DBGPRINTF(("PRINT_TREE: no tree\n"));
+ return;
}
- cprompt = lookup("PS2");
-#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
- if (cprompt->value == null)
-#endif
- setval(cprompt, "> ");
- iof = filechar;
- cflag = 0;
- name = *argv++;
- if (--argc >= 1) {
- if(argv[0][0] == '-' && argv[0][1] != '\0') {
- for (s = argv[0]+1; *s; s++)
- switch (*s) {
- case 'c':
- prompt->status &= ~EXPORT;
- cprompt->status &= ~EXPORT;
- setval(prompt, "");
- setval(cprompt, "");
- cflag = 1;
- if (--argc > 0)
- PUSHIO(aword, *++argv, iof = nlchar);
- break;
-
- case 'q':
- qflag = SIG_DFL;
- break;
+ DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
+ head->right));
- case 's':
- /* standard input */
- break;
-
- case 't':
- prompt->status &= ~EXPORT;
- setval(prompt, "");
- iof = linechar;
- break;
-
- case 'i':
- interactive++;
- default:
- if (*s>='a' && *s<='z')
- flag[(int)*s]++;
- }
- } else {
- argv--;
- argc++;
- }
- if (iof == filechar && --argc > 0) {
- setval(prompt, "");
- setval(cprompt, "");
- prompt->status &= ~EXPORT;
- cprompt->status &= ~EXPORT;
- if (newfile(name = *++argv))
- exit(1);
- }
- }
- setdash();
- if (e.iop < iostack) {
- PUSHIO(afile, 0, iof);
- if (isatty(0) && isatty(1) && !cflag) {
- interactive++;
-#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
- printf( "\n\n" BB_BANNER " Built-in shell (msh)\n");
- printf( "Enter 'help' for a list of built-in commands.\n\n");
-#endif
- }
- }
- signal(SIGQUIT, qflag);
- if (name && name[0] == '-') {
- interactive++;
- if ((f = open(".profile", 0)) >= 0)
- next(remap(f));
- if ((f = open("/etc/profile", 0)) >= 0)
- next(remap(f));
- }
- if (interactive)
- signal(SIGTERM, sig);
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, onintr);
- dolv = argv;
- dolc = argc;
- dolv[0] = name;
- if (dolc > 1) {
- for (ap = ++argv; --argc > 0;) {
- if (assign(*ap = *argv++, !COPYV)) {
- dolc--; /* keyword */
- } else {
- ap++;
- }
- }
- }
- setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
+ if (head->left)
+ print_tree(head->left);
- for (;;) {
- if (interactive && e.iop <= iostack) {
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
- current_prompt=prompt->value;
-#else
- prs(prompt->value);
-#endif
- }
- onecommand();
- /* Ensure that getenv("PATH") stays current */
- setenv("PATH", path->value, 1);
- }
+ if (head->right)
+ print_tree(head->right);
}
+#endif /* MSHDEBUG */
+
-static void
-setdash()
+/*
+ * IO functions
+ */
+static void prs(const char *s)
{
- register char *cp;
- register int c;
- char m['z'-'a'+1];
+ if (*s)
+ xwrite_str(STDERR_FILENO, s);
+}
- cp = m;
- for (c='a'; c<='z'; c++)
- if (flag[(int)c])
- *cp++ = c;
- *cp = 0;
- setval(lookup("-"), m);
+static void prn(unsigned u)
+{
+ prs(itoa(u));
}
-static int
-newfile(s)
-register char *s;
+static void echo(char **wp)
{
- register int f;
+ int i;
- if (strcmp(s, "-") != 0) {
- f = open(s, 0);
- if (f < 0) {
- prs(s);
- err(": cannot open");
- return(1);
- }
- } else
- f = 0;
- next(remap(f));
- return(0);
+ prs("+");
+ for (i = 0; wp[i]; i++) {
+ if (i)
+ prs(" ");
+ prs(wp[i]);
+ }
+ prs("\n");
}
-static void
-onecommand()
+static void closef(int i)
{
- register int i;
- jmp_buf m1;
+ if (i > 2)
+ close(i);
+}
- while (e.oenv)
- quitenv();
- areanum = 1;
- freehere(areanum);
- freearea(areanum);
- garbage();
- wdlist = 0;
- iolist = 0;
- e.errpt = 0;
- e.linep = line;
- yynerrs = 0;
- multiline = 0;
- inparse = 1;
- intr = 0;
- execflg = 0;
- setjmp(failpt = m1); /* Bruce Evans' fix */
- if (setjmp(failpt = m1) || yyparse() || intr) {
- while (e.oenv)
- quitenv();
- scraphere();
- if (!interactive && intr)
- leave();
- inparse = 0;
- intr = 0;
- return;
- }
- inparse = 0;
- brklist = 0;
- intr = 0;
- execflg = 0;
- if (!flag['n'])
- execute(outtree, NOPIPE, NOPIPE, 0);
- if (!interactive && intr) {
- execflg = 0;
- leave();
- }
- if ((i = trapset) != 0) {
- trapset = 0;
- runtrap(i);
- }
+static void closeall(void)
+{
+ int u;
+
+ for (u = NUFILE; u < NOFILE;)
+ close(u++);
}
-static void
-fail()
+
+/* fail but return to process next command */
+static void fail(void) NORETURN;
+static void fail(void)
{
longjmp(failpt, 1);
/* NOTREACHED */
}
-static void
-leave()
+/* abort shell (or fail in subshell) */
+static void leave(void) NORETURN;
+static void leave(void)
{
+ DBGPRINTF(("LEAVE: leave called!\n"));
+
if (execflg)
fail();
scraphere();
freehere(1);
runtrap(0);
- exit(exstat);
+ _exit(exstat);
/* NOTREACHED */
}
-static void
-warn(s)
-register char *s;
+static void warn(const char *s)
{
- if(*s) {
+ if (*s) {
prs(s);
- exstat = -1;
+ if (!exstat)
+ exstat = 255;
}
prs("\n");
- if (flag['e'])
+ if (FLAG['e'])
leave();
}
-static void
-err(s)
-char *s;
+static void err(const char *s)
{
warn(s);
- if (flag['n'])
+ if (FLAG['n'])
return;
if (!interactive)
leave();
- if (e.errpt)
- longjmp(e.errpt, 1);
+ if (global_env.errpt)
+ longjmp(global_env.errpt, 1);
closeall();
- e.iop = e.iobase = iostack;
+ global_env.iop = global_env.iobase = iostack;
}
-static int
-newenv(f)
-int f;
+
+/* -------- area.c -------- */
+
+/*
+ * All memory between (char *)areabot and (char *)(areatop+1) is
+ * exclusively administered by the area management routines.
+ * It is assumed that sbrk() and brk() manipulate the high end.
+ */
+
+#define sbrk(X) ({ \
+ void * __q = (void *)-1; \
+ if (brkaddr + (int)(X) < brktop) { \
+ __q = brkaddr; \
+ brkaddr += (int)(X); \
+ } \
+ __q; \
+})
+
+static void initarea(void)
{
- register struct env *ep;
+ brkaddr = xmalloc(AREASIZE);
+ brktop = brkaddr + AREASIZE;
- if (f) {
- quitenv();
- return(1);
- }
- ep = (struct env *) space(sizeof(*ep));
- if (ep == NULL) {
- while (e.oenv)
- quitenv();
- fail();
- }
- *ep = e;
- e.oenv = ep;
- e.errpt = errpt;
- return(0);
+ while ((long) sbrk(0) & ALIGN)
+ sbrk(1);
+ areabot = (struct region *) sbrk(REGSIZE);
+
+ areabot->next = areabot;
+ areabot->area = BUSY;
+ areatop = areabot;
+ areanxt = areabot;
}
-static void
-quitenv()
+static char *getcell(unsigned nbytes)
{
- register struct env *ep;
- register int fd;
+ int nregio;
+ struct region *p, *q;
+ int i;
- if ((ep = e.oenv) != NULL) {
- fd = e.iofd;
- e = *ep;
- /* should close `'d files */
- DELETE(ep);
- while (--fd >= e.iofd)
- close(fd);
+ if (nbytes == 0) {
+ puts("getcell(0)");
+ abort();
}
+ /* silly and defeats the algorithm */
+ /*
+ * round upwards and add administration area
+ */
+ nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
+ p = areanxt;
+ for (;;) {
+ if (p->area > areanum) {
+ /*
+ * merge free cells
+ */
+ while ((q = p->next)->area > areanum && q != areanxt)
+ p->next = q->next;
+ /*
+ * exit loop if cell big enough
+ */
+ if (q >= p + nregio)
+ goto found;
+ }
+ p = p->next;
+ if (p == areanxt)
+ break;
+ }
+ i = nregio >= GROWBY ? nregio : GROWBY;
+ p = (struct region *) sbrk(i * REGSIZE);
+ if (p == (struct region *) -1)
+ return NULL;
+ p--;
+ if (p != areatop) {
+ puts("not contig");
+ abort(); /* allocated areas are contiguous */
+ }
+ q = p + i;
+ p->next = q;
+ p->area = FREE;
+ q->next = areabot;
+ q->area = BUSY;
+ areatop = q;
+ found:
+ /*
+ * we found a FREE area big enough, pointed to by 'p', and up to 'q'
+ */
+ areanxt = p + nregio;
+ if (areanxt < q) {
+ /*
+ * split into requested area and rest
+ */
+ if (areanxt + 1 > q) {
+ puts("OOM");
+ abort(); /* insufficient space left for admin */
+ }
+ areanxt->next = q;
+ areanxt->area = FREE;
+ p->next = areanxt;
+ }
+ p->area = areanum;
+ return (char *) (p + 1);
}
-/*
- * Is any character from s1 in s2?
- */
-static int
-anys(s1, s2)
-register char *s1, *s2;
+static void freecell(char *cp)
{
- while (*s1)
- if (any(*s1++, s2))
- return(1);
- return(0);
-}
+ struct region *p;
-/*
- * Is character c in s?
- */
-static int
-any(c, s)
-register int c;
-register char *s;
-{
- while (*s)
- if (*s++ == c)
- return(1);
- return(0);
+ p = (struct region *) cp;
+ if (p != NULL) {
+ p--;
+ if (p < areanxt)
+ areanxt = p;
+ p->area = FREE;
+ }
}
+#define DELETE(obj) freecell((char *)obj)
-static char *
-putn(n)
-register int n;
+static void freearea(int a)
{
- return(itoa(n));
+ struct region *p, *top;
+
+ top = areatop;
+ for (p = areabot; p != top; p = p->next)
+ if (p->area >= a)
+ p->area = FREE;
}
-static char *
-itoa(n)
-register int n;
+static void setarea(char *cp, int a)
{
- static char s[20];
- snprintf(s, sizeof(s), "%u", n);
- return(s);
+ struct region *p;
+
+ p = (struct region *) cp;
+ if (p != NULL)
+ (p - 1)->area = a;
}
-static void
-next(int f)
+static int getarea(char *cp)
{
- PUSHIO(afile, f, filechar);
+ return ((struct region *) cp - 1)->area;
}
-static void
-onintr(s)
-int s; /* ANSI C requires a parameter */
+static void garbage(void)
{
- signal(SIGINT, onintr);
- intr = 1;
- if (interactive) {
- if (inparse) {
- prs("\n");
- fail();
+ struct region *p, *q, *top;
+
+ top = areatop;
+ for (p = areabot; p != top; p = p->next) {
+ if (p->area > areanum) {
+ while ((q = p->next)->area > areanum)
+ p->next = q->next;
+ areanxt = p;
}
}
- else if (heedint) {
- execflg = 0;
- leave();
+#ifdef SHRINKBY
+ if (areatop >= q + SHRINKBY && q->area > areanum) {
+ brk((char *) (q + 1));
+ q->next = areabot;
+ q->area = BUSY;
+ areatop = q;
}
+#endif
}
-static char *
-space(n)
-int n;
+static void *get_space(int n)
{
- register char *cp;
+ char *cp;
- if ((cp = getcell(n)) == 0)
+ cp = getcell(n);
+ if (cp == NULL)
err("out of string space");
- return(cp);
+ return cp;
}
-static char *
-strsave(s, a)
-register char *s;
-int a;
+static char *strsave(const char *s, int a)
{
- register char *cp, *xp;
+ char *cp;
- if ((cp = space(strlen(s)+1)) != NULL) {
- setarea((char *)cp, a);
- for (xp = cp; (*xp++ = *s++) != '\0';)
- ;
- return(cp);
+ cp = get_space(strlen(s) + 1);
+ if (cp == NULL) {
+// FIXME: I highly doubt this is good.
+ return (char*)"";
}
- return("");
+ setarea(cp, a);
+ strcpy(cp, s);
+ return cp;
}
-/*
- * trap handling
- */
-static void
-sig(i)
-register int i;
+
+/* -------- var.c -------- */
+
+static int eqname(const char *n1, const char *n2)
{
- trapset = i;
- signal(i, sig);
+ for (; *n1 != '=' && *n1 != '\0'; n1++)
+ if (*n2++ != *n1)
+ return 0;
+ return *n2 == '\0' || *n2 == '=';
}
-static void runtrap(i)
-int i;
+static const char *findeq(const char *cp)
{
- char *trapstr;
-
- if ((trapstr = trap[i]) == NULL)
- return;
- if (i == 0)
- trap[i] = 0;
- RUN(aword, trapstr, nlchar);
+ while (*cp != '\0' && *cp != '=')
+ cp++;
+ return cp;
}
-/* -------- var.c -------- */
-
/*
* Find the given name in the dictionary
* and return its value. If the name was
* not previously there, enter it now and
* return a null value.
*/
-static struct var *
-lookup(n)
-register char *n;
+static struct var *lookup(const char *n)
{
- register struct var *vp;
- register char *cp;
- register int c;
+// FIXME: dirty hack
static struct var dummy;
+ struct var *vp;
+ const char *cp;
+ char *xp;
+ int c;
+
if (isdigit(*n)) {
- dummy.name = n;
+ dummy.name = (char*)n;
for (c = 0; isdigit(*n) && c < 1000; n++)
- c = c*10 + *n-'0';
+ c = c * 10 + *n - '0';
dummy.status = RONLY;
- dummy.value = c <= dolc? dolv[c]: null;
- return(&dummy);
+ dummy.value = (c <= dolc ? dolv[c] : null);
+ return &dummy;
}
+
for (vp = vlist; vp; vp = vp->next)
if (eqname(vp->name, n))
- return(vp);
+ return vp;
+
cp = findeq(n);
- vp = (struct var *)space(sizeof(*vp));
- if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
- dummy.name = dummy.value = "";
- return(&dummy);
- }
- for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
- ;
- if (*cp == 0)
- *cp = '=';
- *++cp = 0;
- setarea((char *)vp, 0);
- setarea((char *)vp->name, 0);
+ vp = get_space(sizeof(*vp));
+ if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
+ dummy.name = dummy.value = (char*)"";
+ return &dummy;
+ }
+
+ xp = vp->name;
+ while ((*xp = *n++) != '\0' && *xp != '=')
+ xp++;
+ *xp++ = '=';
+ *xp = '\0';
+ setarea((char *) vp, 0);
+ setarea((char *) vp->name, 0);
vp->value = null;
vp->next = vlist;
vp->status = GETCELL;
vlist = vp;
- return(vp);
-}
-
-/*
- * give variable at `vp' the value `val'.
- */
-static void
-setval(vp, val)
-struct var *vp;
-char *val;
-{
- nameval(vp, val, (char *)NULL);
+ return vp;
}
/*
@@ -1206,494 +1086,631 @@ char *val;
* this is all so that exporting
* values is reasonably painless.
*/
-static void
-nameval(vp, val, name)
-register struct var *vp;
-char *val, *name;
+static void nameval(struct var *vp, const char *val, const char *name)
{
- register char *cp, *xp;
- char *nv;
+ const char *cp;
+ char *xp;
int fl;
if (vp->status & RONLY) {
- for (xp = vp->name; *xp && *xp != '=';)
- putc(*xp++, stderr);
+ xp = vp->name;
+ while (*xp && *xp != '=')
+ fputc(*xp++, stderr);
err(" is read-only");
return;
}
fl = 0;
if (name == NULL) {
- xp = space(strlen(vp->name)+strlen(val)+2);
- if (xp == 0)
+ xp = get_space(strlen(vp->name) + strlen(val) + 2);
+ if (xp == NULL)
return;
- /* make string: name=value */
- setarea((char *)xp, 0);
+ /* make string: name=value */
+ setarea(xp, 0);
name = xp;
- for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
- ;
- if (*xp++ == 0)
- xp[-1] = '=';
- nv = xp;
- for (cp = val; (*xp++ = *cp++) != '\0';)
- ;
- val = nv;
+ cp = vp->name;
+ while ((*xp = *cp++) != '\0' && *xp != '=')
+ xp++;
+ *xp++ = '=';
+ strcpy(xp, val);
+ val = xp;
fl = GETCELL;
}
if (vp->status & GETCELL)
- freecell(vp->name); /* form new string `name=value' */
- vp->name = name;
- vp->value = val;
+ freecell(vp->name); /* form new string `name=value' */
+ vp->name = (char*)name;
+ vp->value = (char*)val;
vp->status |= fl;
}
-static void
-export(vp)
-struct var *vp;
+/*
+ * give variable at `vp' the value `val'.
+ */
+static void setval(struct var *vp, const char *val)
+{
+ nameval(vp, val, NULL);
+}
+
+static void export(struct var *vp)
{
vp->status |= EXPORT;
}
-static void
-ronly(vp)
-struct var *vp;
+static void ronly(struct var *vp)
{
if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
vp->status |= RONLY;
}
-static int
-isassign(s)
-register char *s;
-{
- if (!isalpha((int)*s) && *s != '_')
- return(0);
- for (; *s != '='; s++)
- if (*s == 0 || (!isalnum(*s) && *s != '_'))
- return(0);
- return(1);
+static int isassign(const char *s)
+{
+ unsigned char c;
+ DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
+
+ c = *s;
+ /* no isalpha() - we shouldn't use locale */
+ /* c | 0x20 - lowercase (Latin) letters */
+ if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
+ /* not letter */
+ return 0;
+
+ while (1) {
+ c = *++s;
+ if (c == '=')
+ return 1;
+ if (c == '\0')
+ return 0;
+ if (c != '_'
+ && (unsigned)(c - '0') > 9 /* not number */
+ && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
+ ) {
+ return 0;
+ }
+ }
}
-static int
-assign(s, cf)
-register char *s;
-int cf;
+static int assign(const char *s, int cf)
{
- register char *cp;
+ const char *cp;
struct var *vp;
+ DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
+
if (!isalpha(*s) && *s != '_')
- return(0);
+ return 0;
for (cp = s; *cp != '='; cp++)
- if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
- return(0);
+ if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
+ return 0;
vp = lookup(s);
- nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
+ nameval(vp, ++cp, cf == COPYV ? NULL : s);
if (cf != COPYV)
vp->status &= ~GETCELL;
- return(1);
+ return 1;
}
-static int
-checkname(cp)
-register char *cp;
+static int checkname(char *cp)
{
- if (!isalpha(*cp++) && *(cp-1) != '_')
- return(0);
+ DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
+
+ if (!isalpha(*cp++) && *(cp - 1) != '_')
+ return 0;
while (*cp)
- if (!isalnum(*cp++) && *(cp-1) != '_')
- return(0);
- return(1);
+ if (!isalnum(*cp++) && *(cp - 1) != '_')
+ return 0;
+ return 1;
}
-static void
-putvlist(f, out)
-register int f, out;
+static void putvlist(int f, int out)
{
- register struct var *vp;
+ struct var *vp;
- for (vp = vlist; vp; vp = vp->next)
+ for (vp = vlist; vp; vp = vp->next) {
if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
if (vp->status & EXPORT)
write(out, "export ", 7);
if (vp->status & RONLY)
write(out, "readonly ", 9);
- write(out, vp->name, (int)(findeq(vp->name) - vp->name));
+ write(out, vp->name, (int) (findeq(vp->name) - vp->name));
write(out, "\n", 1);
}
+ }
}
-static int
-eqname(n1, n2)
-register char *n1, *n2;
+
+/*
+ * trap handling
+ */
+static void sig(int i)
{
- for (; *n1 != '=' && *n1 != 0; n1++)
- if (*n2++ != *n1)
- return(0);
- return(*n2 == 0 || *n2 == '=');
+ trapset = i;
+ signal(i, sig);
}
-static char *
-findeq(cp)
-register char *cp;
+static void runtrap(int i)
{
- while (*cp != '\0' && *cp != '=')
- cp++;
- return(cp);
-}
+ char *trapstr;
-/* -------- gmatch.c -------- */
-/*
- * int gmatch(string, pattern)
- * char *string, *pattern;
- *
- * Match a pattern as in sh(1).
- */
+ trapstr = trap[i];
+ if (trapstr == NULL)
+ return;
-#define CMASK 0377
-#define QUOTE 0200
-#define QMASK (CMASK&~QUOTE)
-#define NOT '!' /* might use ^ */
+ if (i == 0)
+ trap[i] = NULL;
-static int
-gmatch(s, p)
-register char *s, *p;
+ RUN(aword, trapstr, nlchar);
+}
+
+
+static void setdash(void)
{
- register int sc, pc;
+ char *cp;
+ int c;
+ char m['z' - 'a' + 1];
- if (s == NULL || p == NULL)
- return(0);
- while ((pc = *p++ & CMASK) != '\0') {
- sc = *s++ & QMASK;
- switch (pc) {
- case '[':
- if ((p = cclass(p, sc)) == NULL)
- return(0);
- break;
+ cp = m;
+ for (c = 'a'; c <= 'z'; c++)
+ if (FLAG[c])
+ *cp++ = c;
+ *cp = '\0';
+ setval(lookup("-"), m);
+}
- case '?':
- if (sc == 0)
- return(0);
- break;
+static int newfile(char *s)
+{
+ int f;
- case '*':
- s--;
- do {
- if (*p == '\0' || gmatch(s, p))
- return(1);
- } while (*s++ != '\0');
- return(0);
+ DBGPRINTF7(("NEWFILE: opening %s\n", s));
- default:
- if (sc != (pc&~QUOTE))
- return(0);
+ f = 0;
+ if (NOT_LONE_DASH(s)) {
+ DBGPRINTF(("NEWFILE: s is %s\n", s));
+ f = open(s, O_RDONLY);
+ if (f < 0) {
+ prs(s);
+ err(": can't open");
+ return 1;
}
}
- return(*s == 0);
+
+ next(remap(f));
+ return 0;
}
-static char *
-cclass(p, sub)
-register char *p;
-register int sub;
-{
- register int c, d, not, found;
- if ((not = *p == NOT) != 0)
- p++;
- found = not;
- do {
- if (*p == '\0')
- return((char *)NULL);
- c = *p & CMASK;
- if (p[1] == '-' && p[2] != ']') {
- d = p[2] & CMASK;
- p++;
- } else
- d = c;
- if (c == sub || (c <= sub && sub <= d))
- found = !not;
- } while (*++p != ']');
- return(found? p+1: (char *)NULL);
-}
+#ifdef UNUSED
+struct op *scantree(struct op *head)
+{
+ struct op *dotnode;
+ if (head == NULL)
+ return NULL;
-/* -------- area.c -------- */
+ if (head->left != NULL) {
+ dotnode = scantree(head->left);
+ if (dotnode)
+ return dotnode;
+ }
-/*
- * All memory between (char *)areabot and (char *)(areatop+1) is
- * exclusively administered by the area management routines.
- * It is assumed that sbrk() and brk() manipulate the high end.
- */
+ if (head->right != NULL) {
+ dotnode = scantree(head->right);
+ if (dotnode)
+ return dotnode;
+ }
-#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
+ if (head->op_words == NULL)
+ return NULL;
-static void
-initarea()
-{
- brkaddr = malloc(65000);
- brktop = brkaddr + 65000;
+ DBGPRINTF5(("SCANTREE: checking node %p\n", head));
- while ((int)sbrk(0) & ALIGN)
- sbrk(1);
- areabot = (struct region *)sbrk(REGSIZE);
+ if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
+ DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
+ return head;
+ }
- areabot->next = areabot;
- areabot->area = BUSY;
- areatop = areabot;
- areanxt = areabot;
+ return NULL;
}
+#endif
+
-char *
-getcell(nbytes)
-unsigned nbytes;
+static void onecommand(void)
{
- register int nregio;
- register struct region *p, *q;
- register int i;
+ int i;
+ jmp_buf m1;
- if (nbytes == 0) {
- puts("getcell(0)");
- abort();
- } /* silly and defeats the algorithm */
- /*
- * round upwards and add administration area
- */
- nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
- for (p = areanxt;;) {
- if (p->area > areanum) {
- /*
- * merge free cells
- */
- while ((q = p->next)->area > areanum && q != areanxt)
- p->next = q->next;
- /*
- * exit loop if cell big enough
- */
- if (q >= p + nregio)
- goto found;
- }
- p = p->next;
- if (p == areanxt)
- break;
+ DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
+
+ while (global_env.oenv)
+ quitenv();
+
+ areanum = 1;
+ freehere(areanum);
+ freearea(areanum);
+ garbage();
+ wdlist = NULL;
+ iolist = NULL;
+ global_env.errpt = NULL;
+ global_env.linep = line;
+ yynerrs = 0;
+ multiline = 0;
+ inparse = 1;
+ intr = 0;
+ execflg = 0;
+
+ failpt = m1;
+ setjmp(failpt); /* Bruce Evans' fix */
+ failpt = m1;
+ if (setjmp(failpt) || yyparse() || intr) {
+ DBGPRINTF(("ONECOMMAND: this is not good.\n"));
+
+ while (global_env.oenv)
+ quitenv();
+ scraphere();
+ if (!interactive && intr)
+ leave();
+ inparse = 0;
+ intr = 0;
+ return;
}
- i = nregio >= GROWBY ? nregio : GROWBY;
- p = (struct region *)sbrk(i * REGSIZE);
- if (p == (struct region *)-1)
- return((char *)NULL);
- p--;
- if (p != areatop) {
- puts("not contig");
- abort(); /* allocated areas are contiguous */
+
+ inparse = 0;
+ brklist = 0;
+ intr = 0;
+ execflg = 0;
+
+ if (!FLAG['n']) {
+ DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
+ outtree));
+ execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
}
- q = p + i;
- p->next = q;
- p->area = FREE;
- q->next = areabot;
- q->area = BUSY;
- areatop = q;
-found:
- /*
- * we found a FREE area big enough, pointed to by 'p', and up to 'q'
- */
- areanxt = p + nregio;
- if (areanxt < q) {
- /*
- * split into requested area and rest
- */
- if (areanxt+1 > q) {
- puts("OOM");
- abort(); /* insufficient space left for admin */
- }
- areanxt->next = q;
- areanxt->area = FREE;
- p->next = areanxt;
+
+ if (!interactive && intr) {
+ execflg = 0;
+ leave();
+ }
+
+ i = trapset;
+ if (i != 0) {
+ trapset = 0;
+ runtrap(i);
}
- p->area = areanum;
- return((char *)(p+1));
}
-static void
-freecell(cp)
-char *cp;
+static int newenv(int f)
{
- register struct region *p;
+ struct env *ep;
- if ((p = (struct region *)cp) != NULL) {
- p--;
- if (p < areanxt)
- areanxt = p;
- p->area = FREE;
+ DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
+
+ if (f) {
+ quitenv();
+ return 1;
+ }
+
+ ep = get_space(sizeof(*ep));
+ if (ep == NULL) {
+ while (global_env.oenv)
+ quitenv();
+ fail();
}
+ *ep = global_env;
+ global_env.oenv = ep;
+ global_env.errpt = errpt;
+
+ return 0;
}
-static void
-freearea(a)
-register int a;
+static void quitenv(void)
{
- register struct region *p, *top;
+ struct env *ep;
+ int fd;
- top = areatop;
- for (p = areabot; p != top; p = p->next)
- if (p->area >= a)
- p->area = FREE;
+ DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
+
+ ep = global_env.oenv;
+ if (ep != NULL) {
+ fd = global_env.iofd;
+ global_env = *ep;
+ /* should close `'d files */
+ DELETE(ep);
+ while (--fd >= global_env.iofd)
+ close(fd);
+ }
}
-static void
-setarea(cp,a)
-char *cp;
-int a;
+/*
+ * Is character c in s?
+ */
+static int any(int c, const char *s)
{
- register struct region *p;
+ while (*s)
+ if (*s++ == c)
+ return 1;
+ return 0;
+}
- if ((p = (struct region *)cp) != NULL)
- (p-1)->area = a;
+/*
+ * Is any character from s1 in s2?
+ */
+static int anys(const char *s1, const char *s2)
+{
+ while (*s1)
+ if (any(*s1++, s2))
+ return 1;
+ return 0;
}
-int
-getarea(cp)
-char *cp;
+static char *putn(int n)
{
- return ((struct region*)cp-1)->area;
+ return itoa(n);
}
-static void
-garbage()
+static void next(int f)
{
- register struct region *p, *q, *top;
+ PUSHIO(afile, f, filechar);
+}
- top = areatop;
- for (p = areabot; p != top; p = p->next) {
- if (p->area > areanum) {
- while ((q = p->next)->area > areanum)
- p->next = q->next;
- areanxt = p;
+static void onintr(int s UNUSED_PARAM) /* ANSI C requires a parameter */
+{
+ signal(SIGINT, onintr);
+ intr = 1;
+ if (interactive) {
+ if (inparse) {
+ prs("\n");
+ fail();
}
+ } else if (heedint) {
+ execflg = 0;
+ leave();
}
-#ifdef SHRINKBY
- if (areatop >= q + SHRINKBY && q->area > areanum) {
- brk((char *)(q+1));
- q->next = areabot;
- q->area = BUSY;
- areatop = q;
+}
+
+
+/* -------- gmatch.c -------- */
+/*
+ * int gmatch(string, pattern)
+ * char *string, *pattern;
+ *
+ * Match a pattern as in sh(1).
+ */
+
+#define CMASK 0377
+#define QUOTE 0200
+#define QMASK (CMASK & ~QUOTE)
+#define NOT '!' /* might use ^ */
+
+static const char *cclass(const char *p, int sub)
+{
+ int c, d, not, found;
+
+ not = (*p == NOT);
+ if (not != 0)
+ p++;
+ found = not;
+ do {
+ if (*p == '\0')
+ return NULL;
+ c = *p & CMASK;
+ if (p[1] == '-' && p[2] != ']') {
+ d = p[2] & CMASK;
+ p++;
+ } else
+ d = c;
+ if (c == sub || (c <= sub && sub <= d))
+ found = !not;
+ } while (*++p != ']');
+ return found ? p + 1 : NULL;
+}
+
+static int gmatch(const char *s, const char *p)
+{
+ int sc, pc;
+
+ if (s == NULL || p == NULL)
+ return 0;
+
+ while ((pc = *p++ & CMASK) != '\0') {
+ sc = *s++ & QMASK;
+ switch (pc) {
+ case '[':
+ p = cclass(p, sc);
+ if (p == NULL)
+ return 0;
+ break;
+
+ case '?':
+ if (sc == 0)
+ return 0;
+ break;
+
+ case '*':
+ s--;
+ do {
+ if (*p == '\0' || gmatch(s, p))
+ return 1;
+ } while (*s++ != '\0');
+ return 0;
+
+ default:
+ if (sc != (pc & ~QUOTE))
+ return 0;
+ }
}
-#endif
+ return *s == '\0';
}
+
/* -------- csyn.c -------- */
/*
* shell: syntax (C version)
*/
+static void yyerror(const char *s) NORETURN;
+static void yyerror(const char *s)
+{
+ yynerrs = 1;
+ if (interactive && global_env.iop <= iostack) {
+ multiline = 0;
+ while (eofc() == 0 && yylex(0) != '\n')
+ continue;
+ }
+ err(s);
+ fail();
+}
+
+static void zzerr(void) NORETURN;
+static void zzerr(void)
+{
+ yyerror("syntax error");
+}
-int
-yyparse()
+int yyparse(void)
{
- startl = 1;
+ DBGPRINTF7(("YYPARSE: enter...\n"));
+
+ startl = 1;
peeksym = 0;
yynerrs = 0;
outtree = c_list();
musthave('\n', 0);
- return(yynerrs!=0);
+ return yynerrs; /* 0/1 */
}
-static struct op *
-pipeline(cf)
-int cf;
+static struct op *pipeline(int cf)
{
- register struct op *t, *p;
- register int c;
+ struct op *t, *p;
+ int c;
+
+ DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
t = command(cf);
+
+ DBGPRINTF9(("PIPELINE: t=%p\n", t));
+
if (t != NULL) {
while ((c = yylex(0)) == '|') {
- if ((p = command(CONTIN)) == NULL)
- SYNTAXERR;
- if (t->type != TPAREN && t->type != TCOM) {
+ p = command(CONTIN);
+ if (p == NULL) {
+ DBGPRINTF8(("PIPELINE: error!\n"));
+ zzerr();
+ }
+
+ if (t->op_type != TPAREN && t->op_type != TCOM) {
/* shell statement */
t = block(TPAREN, t, NOBLOCK, NOWORDS);
}
+
t = block(TPIPE, t, p, NOWORDS);
}
peeksym = c;
}
- return(t);
+
+ DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
+ return t;
}
-static struct op *
-andor()
+static struct op *andor(void)
{
- register struct op *t, *p;
- register int c;
+ struct op *t, *p;
+ int c;
+
+ DBGPRINTF7(("ANDOR: enter...\n"));
t = pipeline(0);
+
+ DBGPRINTF9(("ANDOR: t=%p\n", t));
+
if (t != NULL) {
while ((c = yylex(0)) == LOGAND || c == LOGOR) {
- if ((p = pipeline(CONTIN)) == NULL)
- SYNTAXERR;
- t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
+ p = pipeline(CONTIN);
+ if (p == NULL) {
+ DBGPRINTF8(("ANDOR: error!\n"));
+ zzerr();
+ }
+
+ t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
}
+
peeksym = c;
}
- return(t);
+
+ DBGPRINTF7(("ANDOR: returning t=%p\n", t));
+ return t;
}
-static struct op *
-c_list()
+static struct op *c_list(void)
{
- register struct op *t, *p;
- register int c;
+ struct op *t, *p;
+ int c;
+
+ DBGPRINTF7(("C_LIST: enter...\n"));
t = andor();
+
if (t != NULL) {
- if((peeksym = yylex(0)) == '&')
+ peeksym = yylex(0);
+ if (peeksym == '&')
t = block(TASYNC, t, NOBLOCK, NOWORDS);
- while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) {
- if ((p = andor()) == NULL)
- return(t);
- if((peeksym = yylex(0)) == '&')
+
+ while ((c = yylex(0)) == ';' || c == '&'
+ || (multiline && c == '\n')
+ ) {
+ p = andor();
+ if (p== NULL)
+ return t;
+
+ peeksym = yylex(0);
+ if (peeksym == '&')
p = block(TASYNC, p, NOBLOCK, NOWORDS);
+
t = list(t, p);
- }
+ } /* WHILE */
+
peeksym = c;
}
- return(t);
+ /* IF */
+ DBGPRINTF7(("C_LIST: returning t=%p\n", t));
+ return t;
}
-
-static int
-synio(cf)
-int cf;
+static int synio(int cf)
{
- register struct ioword *iop;
- register int i;
- register int c;
+ struct ioword *iop;
+ int i;
+ int c;
+
+ DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
- if ((c = yylex(cf)) != '<' && c != '>') {
+ c = yylex(cf);
+ if (c != '<' && c != '>') {
peeksym = c;
- return(0);
+ return 0;
}
+
i = yylval.i;
musthave(WORD, 0);
iop = io(iounit, i, yylval.cp);
iounit = IODEFAULT;
+
if (i & IOHERE)
markhere(yylval.cp, iop);
- return(1);
+
+ DBGPRINTF7(("SYNIO: returning 1\n"));
+ return 1;
}
-static void
-musthave(c, cf)
-int c, cf;
+static void musthave(int c, int cf)
{
- if ((peeksym = yylex(cf)) != c)
- SYNTAXERR;
+ peeksym = yylex(cf);
+ if (peeksym != c) {
+ DBGPRINTF7(("MUSTHAVE: error!\n"));
+ zzerr();
+ }
+
peeksym = 0;
}
-static struct op *
-simple()
+static struct op *simple(void)
{
- register struct op *t;
+ struct op *t;
t = NULL;
for (;;) {
@@ -1706,53 +1723,59 @@ simple()
case WORD:
if (t == NULL) {
t = newtp();
- t->type = TCOM;
+ t->op_type = TCOM;
}
peeksym = 0;
word(yylval.cp);
break;
default:
- return(t);
+ return t;
}
}
}
-static struct op *
-nested(type, mark)
-int type, mark;
+static struct op *nested(int type, int mark)
{
- register struct op *t;
+ struct op *t;
+
+ DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
multiline++;
t = c_list();
musthave(mark, 0);
multiline--;
- return(block(type, t, NOBLOCK, NOWORDS));
+ return block(type, t, NOBLOCK, NOWORDS);
}
-static struct op *
-command(cf)
-int cf;
+static struct op *command(int cf)
{
- register struct op *t;
+ struct op *t;
struct wdblock *iosave;
- register int c;
+ int c;
+
+ DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
iosave = iolist;
iolist = NULL;
+
if (multiline)
cf |= CONTIN;
+
while (synio(cf))
cf = 0;
- switch (c = yylex(cf)) {
+
+ c = yylex(cf);
+
+ switch (c) {
default:
peeksym = c;
- if ((t = simple()) == NULL) {
+ t = simple();
+ if (t == NULL) {
if (iolist == NULL)
- return((struct op *)NULL);
+ return NULL;
t = newtp();
- t->type = TCOM;
+ t->op_type = TCOM;
}
break;
@@ -1766,13 +1789,14 @@ int cf;
case FOR:
t = newtp();
- t->type = TFOR;
+ t->op_type = TFOR;
musthave(WORD, 0);
startl = 1;
t->str = yylval.cp;
multiline++;
- t->words = wordlist();
- if ((c = yylex(0)) != '\n' && c != ';')
+ t->op_words = wordlist();
+ c = yylex(0);
+ if (c != '\n' && c != ';')
peeksym = c;
t->left = dogroup(0);
multiline--;
@@ -1782,23 +1806,25 @@ int cf;
case UNTIL:
multiline++;
t = newtp();
- t->type = c == WHILE? TWHILE: TUNTIL;
+ t->op_type = (c == WHILE ? TWHILE : TUNTIL);
t->left = c_list();
t->right = dogroup(1);
- t->words = NULL;
+ /* t->op_words = NULL; - newtp() did this */
multiline--;
break;
case CASE:
t = newtp();
- t->type = TCASE;
+ t->op_type = TCASE;
musthave(WORD, 0);
t->str = yylval.cp;
startl++;
multiline++;
musthave(IN, CONTIN);
startl++;
+
t->left = caselist();
+
musthave(ESAC, 0);
multiline--;
break;
@@ -1806,331 +1832,386 @@ int cf;
case IF:
multiline++;
t = newtp();
- t->type = TIF;
+ t->op_type = TIF;
t->left = c_list();
t->right = thenpart();
musthave(FI, 0);
multiline--;
break;
+
+ case DOT:
+ t = newtp();
+ t->op_type = TDOT;
+
+ musthave(WORD, 0); /* gets name of file */
+ DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
+
+ word(yylval.cp); /* add word to wdlist */
+ word(NOWORD); /* terminate wdlist */
+ t->op_words = copyw(); /* dup wdlist */
+ break;
+
}
+
while (synio(0))
- ;
+ continue;
+
t = namelist(t);
iolist = iosave;
- return(t);
+
+ DBGPRINTF(("COMMAND: returning %p\n", t));
+
+ return t;
}
-static struct op *
-dogroup(onlydone)
-int onlydone;
+static struct op *dowholefile(int type /*, int mark*/)
{
- register int c;
- register struct op *mylist;
+ struct op *t;
+
+ DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
+
+ multiline++;
+ t = c_list();
+ multiline--;
+ t = block(type, t, NOBLOCK, NOWORDS);
+ DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
+ return t;
+}
+
+static struct op *dogroup(int onlydone)
+{
+ int c;
+ struct op *mylist;
c = yylex(CONTIN);
if (c == DONE && onlydone)
- return((struct op *)NULL);
+ return NULL;
if (c != DO)
- SYNTAXERR;
+ zzerr();
mylist = c_list();
musthave(DONE, 0);
- return(mylist);
+ return mylist;
}
-static struct op *
-thenpart()
+static struct op *thenpart(void)
{
- register int c;
- register struct op *t;
+ int c;
+ struct op *t;
- if ((c = yylex(0)) != THEN) {
+ c = yylex(0);
+ if (c != THEN) {
peeksym = c;
- return((struct op *)NULL);
+ return NULL;
}
t = newtp();
- t->type = 0;
+ /*t->op_type = 0; - newtp() did this */
t->left = c_list();
if (t->left == NULL)
- SYNTAXERR;
+ zzerr();
t->right = elsepart();
- return(t);
+ return t;
}
-static struct op *
-elsepart()
+static struct op *elsepart(void)
{
- register int c;
- register struct op *t;
+ int c;
+ struct op *t;
switch (c = yylex(0)) {
case ELSE:
- if ((t = c_list()) == NULL)
- SYNTAXERR;
- return(t);
+ t = c_list();
+ if (t == NULL)
+ zzerr();
+ return t;
case ELIF:
t = newtp();
- t->type = TELIF;
+ t->op_type = TELIF;
t->left = c_list();
t->right = thenpart();
- return(t);
+ return t;
default:
peeksym = c;
- return((struct op *)NULL);
+ return NULL;
}
}
-static struct op *
-caselist()
+static struct op *caselist(void)
{
- register struct op *t;
+ struct op *t;
t = NULL;
- while ((peeksym = yylex(CONTIN)) != ESAC)
+ while ((peeksym = yylex(CONTIN)) != ESAC) {
+ DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
t = list(t, casepart());
- return(t);
+ }
+
+ DBGPRINTF(("CASELIST, returning t=%p\n", t));
+ return t;
}
-static struct op *
-casepart()
+static struct op *casepart(void)
{
- register struct op *t;
+ struct op *t;
+
+ DBGPRINTF7(("CASEPART: enter...\n"));
t = newtp();
- t->type = TPAT;
- t->words = pattern();
+ t->op_type = TPAT;
+ t->op_words = pattern();
musthave(')', 0);
t->left = c_list();
- if ((peeksym = yylex(CONTIN)) != ESAC)
+ peeksym = yylex(CONTIN);
+ if (peeksym != ESAC)
musthave(BREAK, CONTIN);
- return(t);
+
+ DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
+
+ return t;
}
-static char **
-pattern()
+static char **pattern(void)
{
- register int c, cf;
+ int c, cf;
cf = CONTIN;
do {
musthave(WORD, cf);
word(yylval.cp);
cf = 0;
- } while ((c = yylex(0)) == '|');
+ c = yylex(0);
+ } while (c == '|');
peeksym = c;
word(NOWORD);
- return(copyw());
+
+ return copyw();
}
-static char **
-wordlist()
+static char **wordlist(void)
{
- register int c;
+ int c;
- if ((c = yylex(0)) != IN) {
+ c = yylex(0);
+ if (c != IN) {
peeksym = c;
- return((char **)NULL);
+ return NULL;
}
startl = 0;
while ((c = yylex(0)) == WORD)
word(yylval.cp);
word(NOWORD);
peeksym = c;
- return(copyw());
+ return copyw();
}
/*
* supporting functions
*/
-static struct op *
-list(t1, t2)
-register struct op *t1, *t2;
+static struct op *list(struct op *t1, struct op *t2)
{
+ DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
+
if (t1 == NULL)
- return(t2);
+ return t2;
if (t2 == NULL)
- return(t1);
- return(block(TLIST, t1, t2, NOWORDS));
+ return t1;
+
+ return block(TLIST, t1, t2, NOWORDS);
}
-static struct op *
-block(type, t1, t2, wp)
-int type;
-struct op *t1, *t2;
-char **wp;
+static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
{
- register struct op *t;
+ struct op *t;
+
+ DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
t = newtp();
- t->type = type;
+ t->op_type = type;
t->left = t1;
t->right = t2;
- t->words = wp;
- return(t);
+ t->op_words = wp;
+
+ DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
+
+ return t;
+}
+
+/* See if given string is a shell multiline (FOR, IF, etc) */
+static int rlookup(char *n)
+{
+ struct res {
+ char r_name[6];
+ int16_t r_val;
+ };
+ static const struct res restab[] = {
+ { "for" , FOR },
+ { "case" , CASE },
+ { "esac" , ESAC },
+ { "while", WHILE },
+ { "do" , DO },
+ { "done" , DONE },
+ { "if" , IF },
+ { "in" , IN },
+ { "then" , THEN },
+ { "else" , ELSE },
+ { "elif" , ELIF },
+ { "until", UNTIL },
+ { "fi" , FI },
+ { ";;" , BREAK },
+ { "||" , LOGOR },
+ { "&&" , LOGAND },
+ { "{" , '{' },
+ { "}" , '}' },
+ { "." , DOT },
+ { },
+ };
+
+ const struct res *rp;
+
+ DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
+
+ for (rp = restab; rp->r_name[0]; rp++)
+ if (strcmp(rp->r_name, n) == 0) {
+ DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
+ return rp->r_val; /* Return numeric code for shell multiline */
+ }
+
+ DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
+ return 0; /* Not a shell multiline */
}
-static int
-rlookup(n)
-register char *n;
+static struct op *newtp(void)
{
- register struct res *rp;
+ struct op *t;
- for (rp = restab; rp->r_name; rp++)
- if (strcmp(rp->r_name, n) == 0)
- return(rp->r_val);
- return(0);
-}
+ t = (struct op *) tree(sizeof(*t));
+ memset(t, 0, sizeof(*t));
-static struct op *
-newtp()
-{
- register struct op *t;
+ DBGPRINTF3(("NEWTP: allocated %p\n", t));
- t = (struct op *)tree(sizeof(*t));
- t->type = 0;
- t->words = NULL;
- t->ioact = NULL;
- t->left = NULL;
- t->right = NULL;
- t->str = NULL;
- return(t);
+ return t;
}
-static struct op *
-namelist(t)
-register struct op *t;
+static struct op *namelist(struct op *t)
{
+ DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
+ T_CMD_NAMES[t->op_type], iolist));
+
if (iolist) {
- iolist = addword((char *)NULL, iolist);
+ iolist = addword((char *) NULL, iolist);
t->ioact = copyio();
} else
t->ioact = NULL;
- if (t->type != TCOM) {
- if (t->type != TPAREN && t->ioact != NULL) {
+
+ if (t->op_type != TCOM) {
+ if (t->op_type != TPAREN && t->ioact != NULL) {
t = block(TPAREN, t, NOBLOCK, NOWORDS);
t->ioact = t->left->ioact;
t->left->ioact = NULL;
}
- return(t);
+ return t;
}
+
word(NOWORD);
- t->words = copyw();
- return(t);
+ t->op_words = copyw();
+
+ return t;
}
-static char **
-copyw()
+static char **copyw(void)
{
- register char **wd;
+ char **wd;
wd = getwords(wdlist);
- wdlist = 0;
- return(wd);
+ wdlist = NULL;
+ return wd;
}
-static void
-word(cp)
-char *cp;
+static void word(char *cp)
{
wdlist = addword(cp, wdlist);
}
-static struct ioword **
-copyio()
+static struct ioword **copyio(void)
{
- register struct ioword **iop;
+ struct ioword **iop;
iop = (struct ioword **) getwords(iolist);
- iolist = 0;
- return(iop);
+ iolist = NULL;
+ return iop;
}
-static struct ioword *
-io(u, f, cp)
-int u;
-int f;
-char *cp;
+static struct ioword *io(int u, int f, char *cp)
{
- register struct ioword *iop;
+ struct ioword *iop;
iop = (struct ioword *) tree(sizeof(*iop));
- iop->io_unit = u;
+ iop->io_fd = u;
iop->io_flag = f;
iop->io_name = cp;
- iolist = addword((char *)iop, iolist);
- return(iop);
+ iolist = addword((char *) iop, iolist);
+ return iop;
}
-static void
-zzerr()
+static int yylex(int cf)
{
- yyerror("syntax error");
-}
-
-static void
-yyerror(s)
-char *s;
-{
- yynerrs++;
- if (interactive && e.iop <= iostack) {
- multiline = 0;
- while (eofc() == 0 && yylex(0) != '\n')
- ;
- }
- err(s);
- fail();
-}
-
-static int
-yylex(cf)
-int cf;
-{
- register int c, c1;
+ int c, c1;
int atstart;
- if ((c = peeksym) > 0) {
+ c = peeksym;
+ if (c > 0) {
peeksym = 0;
if (c == '\n')
startl = 1;
- return(c);
+ return c;
}
+
nlseen = 0;
- e.linep = line;
atstart = startl;
startl = 0;
yylval.i = 0;
+ global_env.linep = line;
+
+/* MALAMO */
+ line[LINELIM - 1] = '\0';
+
+ loop:
+ while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
+ continue;
-loop:
- while ((c = my_getc(0)) == ' ' || c == '\t')
- ;
switch (c) {
default:
if (any(c, "0123456789")) {
- unget(c1 = my_getc(0));
+ c1 = my_getc(0);
+ unget(c1);
if (c1 == '<' || c1 == '>') {
iounit = c - '0';
goto loop;
}
- *e.linep++ = c;
+ *global_env.linep++ = c;
c = c1;
}
break;
- case '#':
- while ((c = my_getc(0)) != 0 && c != '\n')
- ;
+ case '#': /* Comment, skip to next newline or End-of-string */
+ while ((c = my_getc(0)) != '\0' && c != '\n')
+ continue;
unget(c);
goto loop;
case 0:
- return(c);
+ DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
+ return c;
case '$':
- *e.linep++ = c;
- if ((c = my_getc(0)) == '{') {
- if ((c = collect(c, '}')) != '\0')
- return(c);
+ DBGPRINTF9(("YYLEX: found $\n"));
+ *global_env.linep++ = c;
+ c = my_getc(0);
+ if (c == '{') {
+ c = collect(c, '}');
+ if (c != '\0')
+ return c;
goto pack;
}
break;
@@ -2138,227 +2219,325 @@ loop:
case '`':
case '\'':
case '"':
- if ((c = collect(c, c)) != '\0')
- return(c);
+ c = collect(c, c);
+ if (c != '\0')
+ return c;
goto pack;
case '|':
case '&':
case ';':
- if ((c1 = dual(c)) != '\0') {
- startl = 1;
- return(c1);
- }
startl = 1;
- return(c);
+ /* If more chars process them, else return NULL char */
+ c1 = dual(c);
+ if (c1 != '\0')
+ return c1;
+ return c;
+
case '^':
startl = 1;
- return('|');
+ return '|';
case '>':
case '<':
diag(c);
- return(c);
+ return c;
case '\n':
nlseen++;
gethere();
startl = 1;
if (multiline || cf & CONTIN) {
- if (interactive && e.iop <= iostack) {
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
- current_prompt=cprompt->value;
+ if (interactive && global_env.iop <= iostack) {
+#if ENABLE_FEATURE_EDITING
+ current_prompt = cprompt->value;
#else
- prs(cprompt->value);
+ prs(cprompt->value);
#endif
}
if (cf & CONTIN)
goto loop;
}
- return(c);
+ return c;
case '(':
case ')':
startl = 1;
- return(c);
+ return c;
}
unget(c);
-pack:
- while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n"))
- if (e.linep >= elinep)
+ pack:
+ while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
+ if (global_env.linep >= elinep)
err("word too long");
else
- *e.linep++ = c;
+ *global_env.linep++ = c;
+ };
+
unget(c);
- if(any(c, "\"'`$"))
+
+ if (any(c, "\"'`$"))
goto loop;
- *e.linep++ = '\0';
- if (atstart && (c = rlookup(line))!=0) {
- startl = 1;
- return(c);
+
+ *global_env.linep++ = '\0';
+
+ if (atstart) {
+ c = rlookup(line);
+ if (c != 0) {
+ startl = 1;
+ return c;
+ }
}
+
yylval.cp = strsave(line, areanum);
- return(WORD);
+ return WORD;
}
-static int
-collect(c, c1)
-register int c, c1;
+
+static int collect(int c, int c1)
{
char s[2];
- *e.linep++ = c;
+ DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
+
+ *global_env.linep++ = c;
while ((c = my_getc(c1)) != c1) {
if (c == 0) {
unget(c);
s[0] = c1;
s[1] = 0;
- prs("no closing "); yyerror(s);
- return(YYERRCODE);
+ prs("no closing ");
+ yyerror(s);
+ return YYERRCODE;
}
- if (interactive && c == '\n' && e.iop <= iostack) {
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
- current_prompt=cprompt->value;
+ if (interactive && c == '\n' && global_env.iop <= iostack) {
+#if ENABLE_FEATURE_EDITING
+ current_prompt = cprompt->value;
#else
- prs(cprompt->value);
+ prs(cprompt->value);
#endif
}
- *e.linep++ = c;
+ *global_env.linep++ = c;
}
- *e.linep++ = c;
- return(0);
+
+ *global_env.linep++ = c;
+
+ DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
+
+ return 0;
}
-static int
-dual(c)
-register int c;
+/* "multiline commands" helper func */
+/* see if next 2 chars form a shell multiline */
+static int dual(int c)
{
char s[3];
- register char *cp = s;
+ char *cp = s;
- *cp++ = c;
- *cp++ = my_getc(0);
- *cp = 0;
- if ((c = rlookup(s)) == 0)
- unget(*--cp);
- return(c);
+ DBGPRINTF8(("DUAL: enter, c=%d\n", c));
+
+ *cp++ = c; /* c is the given "peek" char */
+ *cp++ = my_getc(0); /* get next char of input */
+ *cp = '\0'; /* add EOS marker */
+
+ c = rlookup(s); /* see if 2 chars form a shell multiline */
+ if (c == 0)
+ unget(*--cp); /* String is not a shell multiline, put peek char back */
+
+ return c; /* String is multiline, return numeric multiline (restab) code */
}
-static void
-diag(ec)
-register int ec;
+static void diag(int ec)
{
- register int c;
+ int c;
+
+ DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
c = my_getc(0);
if (c == '>' || c == '<') {
if (c != ec)
zzerr();
- yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE;
+ yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
c = my_getc(0);
} else
- yylval.i = ec == '>'? IOWRITE: IOREAD;
+ yylval.i = (ec == '>' ? IOWRITE : IOREAD);
if (c != '&' || yylval.i == IOHERE)
unget(c);
else
yylval.i |= IODUP;
}
-static char *
-tree(size)
-unsigned size;
+static char *tree(unsigned size)
{
- register char *t;
+ char *t;
- if ((t = getcell(size)) == NULL) {
+ t = getcell(size);
+ if (t == NULL) {
+ DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
prs("command line too complicated\n");
fail();
/* NOTREACHED */
}
- return(t);
+ return t;
}
+
/* VARARGS1 */
/* ARGSUSED */
/* -------- exec.c -------- */
+static struct op **find1case(struct op *t, const char *w)
+{
+ struct op *t1;
+ struct op **tp;
+ char **wp;
+ char *cp;
+
+ if (t == NULL) {
+ DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
+ return NULL;
+ }
+
+ DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
+ T_CMD_NAMES[t->op_type]));
+
+ if (t->op_type == TLIST) {
+ tp = find1case(t->left, w);
+ if (tp != NULL) {
+ DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
+ return tp;
+ }
+ t1 = t->right; /* TPAT */
+ } else
+ t1 = t;
+
+ for (wp = t1->op_words; *wp;) {
+ cp = evalstr(*wp++, DOSUB);
+ if (cp && gmatch(w, cp)) {
+ DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
+ &t1->left));
+ return &t1->left;
+ }
+ }
+
+ DBGPRINTF(("FIND1CASE: returning NULL\n"));
+ return NULL;
+}
+
+static struct op *findcase(struct op *t, const char *w)
+{
+ struct op **tp;
+
+ tp = find1case(t, w);
+ return tp != NULL ? *tp : NULL;
+}
+
/*
* execute tree
*/
-
-static int
-execute(t, pin, pout, act)
-register struct op *t;
-int *pin, *pout;
-int act;
+static int execute(struct op *t, int *pin, int *pout, int no_fork)
{
- register struct op *t1;
+ struct op *t1;
volatile int i, rv, a;
- char *cp, **wp, **wp2;
+ const char *cp;
+ char **wp, **wp2;
struct var *vp;
+ struct op *outtree_save;
struct brkcon bc;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &wp;
-#endif
+#endif
+
+ if (t == NULL) {
+ DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
+ return 0;
+ }
+ DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
+ t->op_type, T_CMD_NAMES[t->op_type],
+ ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
- if (t == NULL)
- return(0);
rv = 0;
a = areanum++;
- wp = (wp2 = t->words) != NULL
- ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
- : NULL;
+ wp2 = t->op_words;
+ wp = (wp2 != NULL)
+ ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
+ : NULL;
+
+ switch (t->op_type) {
+ case TDOT:
+ DBGPRINTF3(("EXECUTE: TDOT\n"));
+
+ outtree_save = outtree;
+
+ newfile(evalstr(t->op_words[0], DOALL));
+
+ t->left = dowholefile(TLIST /*, 0*/);
+ t->right = NULL;
+
+ outtree = outtree_save;
+
+ if (t->left)
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
+ if (t->right)
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
+ break;
- switch(t->type) {
case TPAREN:
- rv = execute(t->left, pin, pout, 0);
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
break;
-
+
case TCOM:
- {
- int child;
- rv = forkexec(t, pin, pout, act, wp, &child);
- if (child) {
- exstat = rv;
- leave();
- }
- }
+ rv = forkexec(t, pin, pout, no_fork, wp);
break;
case TPIPE:
{
- int pv[2];
- if ((rv = openpipe(pv)) < 0)
- break;
- pv[0] = remap(pv[0]);
- pv[1] = remap(pv[1]);
- (void) execute(t->left, pin, pv, 0);
- rv = execute(t->right, pv, pout, 0);
+ int pv[2];
+
+ rv = openpipe(pv);
+ if (rv < 0)
+ break;
+ pv[0] = remap(pv[0]);
+ pv[1] = remap(pv[1]);
+ (void) execute(t->left, pin, pv, /* no_fork: */ 0);
+ rv = execute(t->right, pv, pout, /* no_fork: */ 0);
}
break;
case TLIST:
- (void) execute(t->left, pin, pout, 0);
- rv = execute(t->right, pin, pout, 0);
+ (void) execute(t->left, pin, pout, /* no_fork: */ 0);
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
break;
case TASYNC:
- {
- int hinteractive = interactive;
-
- i = vfork();
- if (i != 0) {
+ {
+ smallint hinteractive = interactive;
+
+ DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
+
+ i = vfork();
+ if (i == 0) { /* child */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if (interactive)
+ signal(SIGTERM, SIG_DFL);
+ interactive = 0;
+ if (pin == NULL) {
+ close(0);
+ xopen(bb_dev_null, O_RDONLY);
+ }
+ _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
+ }
interactive = hinteractive;
if (i != -1) {
setval(lookup("!"), putn(i));
- if (pin != NULL)
- closepipe(pin);
+ closepipe(pin);
if (interactive) {
prs(putn(i));
prs("\n");
@@ -2366,46 +2545,40 @@ int act;
} else
rv = -1;
setstatus(rv);
- } else {
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- if (interactive)
- signal(SIGTERM, SIG_DFL);
- interactive = 0;
- if (pin == NULL) {
- close(0);
- open("/dev/null", 0);
- }
- exit(execute(t->left, pin, pout, FEXEC));
}
- }
break;
case TOR:
case TAND:
- rv = execute(t->left, pin, pout, 0);
- if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND))
- rv = execute(t1, pin, pout, 0);
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
+ t1 = t->right;
+ if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
break;
case TFOR:
if (wp == NULL) {
- wp = dolv+1;
- if ((i = dolc) < 0)
+ wp = dolv + 1;
+ i = dolc;
+ if (i < 0)
i = 0;
} else {
i = -1;
while (*wp++ != NULL)
- ;
+ continue;
}
vp = lookup(t->str);
while (setjmp(bc.brkpt))
if (isbreak)
goto broken;
+ /* Restore areanum value. It may be incremented by execute()
+ * below, and then "continue" may jump back to setjmp above */
+ areanum = a + 1;
+ freearea(areanum + 1);
brkset(&bc);
for (t1 = t->left; i-- && *wp != NULL;) {
setval(vp, *wp++);
- rv = execute(t1, pin, pout, 0);
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
}
brklist = brklist->nextlev;
break;
@@ -2415,45 +2588,67 @@ int act;
while (setjmp(bc.brkpt))
if (isbreak)
goto broken;
+ /* Restore areanum value. It may be incremented by execute()
+ * below, and then "continue" may jump back to setjmp above */
+ areanum = a + 1;
+ freearea(areanum + 1);
brkset(&bc);
t1 = t->left;
- while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
- rv = execute(t->right, pin, pout, 0);
+ while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
brklist = brklist->nextlev;
break;
case TIF:
case TELIF:
- if (t->right != NULL) {
- rv = !execute(t->left, pin, pout, 0) ?
- execute(t->right->left, pin, pout, 0):
- execute(t->right->right, pin, pout, 0);
+ if (t->right != NULL) {
+ rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
+ execute(t->right->left, pin, pout, /* no_fork: */ 0) :
+ execute(t->right->right, pin, pout, /* no_fork: */ 0);
}
break;
case TCASE:
- if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0)
+ cp = evalstr(t->str, DOSUB | DOTRIM);
+ if (cp == NULL)
cp = "";
- if ((t1 = findcase(t->left, cp)) != NULL)
- rv = execute(t1, pin, pout, 0);
+
+ DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
+ ((t->str == NULL) ? "NULL" : t->str),
+ ((cp == NULL) ? "NULL" : cp)));
+
+ t1 = findcase(t->left, cp);
+ if (t1 != NULL) {
+ DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
+ DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
+ }
break;
case TBRACE:
/*
- if (iopp = t->ioact)
+ iopp = t->ioact;
+ if (i)
while (*iopp)
if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
rv = -1;
break;
}
*/
- if (rv >= 0 && (t1 = t->left))
- rv = execute(t1, pin, pout, 0);
+ if (rv >= 0) {
+ t1 = t->left;
+ if (t1) {
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
+ }
+ }
break;
- }
-broken:
- t->words = wp2;
+ };
+
+ broken:
+// Restoring op_words is most likely not needed now: see comment in forkexec()
+// (also take a look at exec builtin (doexec) - it touches t->op_words)
+ t->op_words = wp2;
isbreak = 0;
freehere(areanum);
freearea(areanum);
@@ -2462,98 +2657,137 @@ broken:
closeall();
fail();
}
- if ((i = trapset) != 0) {
+
+ i = trapset;
+ if (i != 0) {
trapset = 0;
runtrap(i);
}
- return(rv);
+
+ DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
+ return rv;
}
-static int
-forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked)
+static builtin_func_ptr inbuilt(const char *s)
{
- int i, rv;
- int (*shcom)(struct op *) = NULL;
- register int f;
- char *cp = NULL;
+ const struct builtincmd *bp;
+
+ for (bp = builtincmds; bp->name; bp++)
+ if (strcmp(bp->name, s) == 0)
+ return bp->builtinfunc;
+ return NULL;
+}
+
+static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
+{
+ pid_t newpid;
+ int i;
+ builtin_func_ptr bltin = NULL;
+ const char *bltin_name = NULL;
+ const char *cp;
struct ioword **iopp;
int resetsig;
char **owp;
+ int forked;
int *hpin = pin;
int *hpout = pout;
- int hforked;
char *hwp;
- int hinteractive;
- int hintr;
- struct brkcon * hbrklist;
- int hexecflg;
+ smallint hinteractive;
+ smallint hintr;
+ smallint hexecflg;
+ struct brkcon *hbrklist;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &pin;
(void) &pout;
(void) &wp;
- (void) &shcom;
+ (void) &bltin;
(void) &cp;
(void) &resetsig;
(void) &owp;
-#endif
+#endif
+ DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
+ pout, no_fork));
+ DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
+ ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
owp = wp;
resetsig = 0;
- *pforked = 0;
- rv = -1; /* system-detected error */
- if (t->type == TCOM) {
- while ((cp = *wp++) != NULL)
- ;
+ if (t->op_type == TCOM) {
+ while (*wp++ != NULL)
+ continue;
cp = *wp;
/* strip all initial assignments */
- /* not correct wrt PATH=yyy command etc */
- if (flag['x'])
- echo (cp ? wp: owp);
- if (cp == NULL && t->ioact == NULL) {
- while ((cp = *owp++) != NULL && assign(cp, COPYV))
- ;
- return(setstatus(0));
+ /* FIXME: not correct wrt PATH=yyy command etc */
+ if (FLAG['x']) {
+ DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
+ cp, wp, owp));
+ echo(cp ? wp : owp);
+ }
+
+ if (cp == NULL) {
+ if (t->ioact == NULL) {
+ while ((cp = *owp++) != NULL && assign(cp, COPYV))
+ continue;
+ DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
+ return setstatus(0);
+ }
+ } else { /* cp != NULL */
+ bltin_name = cp;
+ bltin = inbuilt(cp);
}
- else if (cp != NULL)
- shcom = inbuilt(cp);
}
- t->words = wp;
- f = act;
- if (shcom == NULL && (f & FEXEC) == 0) {
+ forked = 0;
+ // We were pointing t->op_words to temporary (expanded) arg list:
+ // t->op_words = wp;
+ // and restored it later (in execute()), but "break"
+ // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
+ // See http://bugs.busybox.net/view.php?id=846.
+ // Now we do not touch t->op_words, but separately pass wp as param list
+ // to builtins
+ DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
+ no_fork, owp));
+ /* Don't fork if it is a lone builtin (not in pipe)
+ * OR we are told to _not_ fork */
+ if ((!bltin || pin || pout) /* not lone bltin AND */
+ && !no_fork /* not told to avoid fork */
+ ) {
+ /* Save values in case child alters them after vfork */
hpin = pin;
hpout = pout;
- hforked = *pforked;
hwp = *wp;
hinteractive = interactive;
hintr = intr;
hbrklist = brklist;
hexecflg = execflg;
-
- i = vfork();
- if (i != 0) {
- /* who wrote this crappy non vfork safe shit? */
+
+ DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
+ newpid = vfork();
+ if (newpid == -1) {
+ DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
+ return -1;
+ }
+
+ if (newpid > 0) { /* Parent */
+ /* Restore values */
pin = hpin;
pout = hpout;
- *pforked = hforked;
*wp = hwp;
interactive = hinteractive;
intr = hintr;
brklist = hbrklist;
execflg = hexecflg;
- *pforked = 0;
- if (i == -1)
- return(rv);
- if (pin != NULL)
- closepipe(pin);
- return(pout==NULL? setstatus(waitfor(i,0)): 0);
+ closepipe(pin);
+ return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
}
+ /* Child */
+ DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
if (interactive) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
@@ -2561,191 +2795,176 @@ forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *p
}
interactive = 0;
intr = 0;
- (*pforked)++;
+ forked = 1;
brklist = 0;
execflg = 0;
- }
- if (owp != NULL)
+ }
+
+ if (owp)
while ((cp = *owp++) != NULL && assign(cp, COPYV))
- if (shcom == NULL)
+ if (!bltin)
export(lookup(cp));
-#ifdef COMPIPE
- if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
- err("piping to/from shell builtins not yet done");
- return(-1);
+
+ if (pin) { /* NB: close _first_, then move fds! */
+ close(pin[1]);
+ xmove_fd(pin[0], 0);
}
-#endif
- if (pin != NULL) {
- dup2(pin[0], 0);
- closepipe(pin);
+ if (pout) {
+ close(pout[0]);
+ xmove_fd(pout[1], 1);
}
- if (pout != NULL) {
- dup2(pout[1], 1);
- closepipe(pout);
+
+ iopp = t->ioact;
+ if (iopp) {
+ if (bltin && bltin != doexec) {
+ prs(bltin_name);
+ err(": can't redirect shell command");
+ if (forked)
+ _exit(-1);
+ return -1;
+ }
+ while (*iopp) {
+ if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
+ /* system-detected error */
+ if (forked)
+ _exit(-1);
+ return -1;
+ }
+ }
}
- if ((iopp = t->ioact) != NULL) {
- if (shcom != NULL && shcom != doexec) {
- prs(cp);
- err(": cannot redirect shell command");
- return(-1);
+
+ if (bltin) {
+ if (forked || pin || pout) {
+ /* Builtin in pipe: disallowed */
+ /* TODO: allow "exec"? */
+ prs(bltin_name);
+ err(": can't run builtin as part of pipe");
+ if (forked)
+ _exit(-1);
+ return -1;
}
- while (*iopp)
- if (iosetup(*iopp++, pin!=NULL, pout!=NULL))
- return(rv);
+ /* Run builtin */
+ i = setstatus(bltin(t, wp));
+ if (forked)
+ _exit(i);
+ DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
+ return i;
}
- if (shcom)
- return(setstatus((*shcom)(t)));
+
/* should use FIOCEXCL */
- for (i=FDBASE; i<NOFILE; i++)
+ for (i = FDBASE; i < NOFILE; i++)
close(i);
if (resetsig) {
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
}
- if (t->type == TPAREN)
- exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
+
+ if (t->op_type == TPAREN)
+ _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
if (wp[0] == NULL)
- exit(0);
+ _exit(EXIT_SUCCESS);
- cp = rexecve(wp[0], wp, makenv());
- prs(wp[0]); prs(": "); warn(cp);
+ cp = rexecve(wp[0], wp, makenv(0, NULL));
+ prs(wp[0]);
+ prs(": ");
+ err(cp);
if (!execflg)
trap[0] = NULL;
+
+ DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
+
leave();
/* NOTREACHED */
- exit(1);
+ return 0;
}
/*
* 0< 1> are ignored as required
* within pipelines.
*/
-static int
-iosetup(iop, pipein, pipeout)
-register struct ioword *iop;
-int pipein, pipeout;
-{
- register int u = -1;
- char *cp=NULL, *msg;
-
- if (iop->io_unit == IODEFAULT) /* take default */
- iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1;
- if (pipein && iop->io_unit == 0)
- return(0);
- if (pipeout && iop->io_unit == 1)
- return(0);
- msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create";
+static int iosetup(struct ioword *iop, int pipein, int pipeout)
+{
+ int u = -1;
+ char *cp = NULL;
+ const char *msg;
+
+ DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
+ pipein, pipeout));
+
+ if (iop->io_fd == IODEFAULT) /* take default */
+ iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
+
+ if (pipein && iop->io_fd == 0)
+ return 0;
+
+ if (pipeout && iop->io_fd == 1)
+ return 0;
+
+ msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
if ((iop->io_flag & IOHERE) == 0) {
- cp = iop->io_name;
- if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL)
- return(1);
+ cp = iop->io_name; /* huh?? */
+ cp = evalstr(cp, DOSUB | DOTRIM);
+ if (cp == NULL)
+ return 1;
}
+
if (iop->io_flag & IODUP) {
if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
prs(cp);
err(": illegal >& argument");
- return(1);
+ return 1;
}
if (*cp == '-')
iop->io_flag = IOCLOSE;
- iop->io_flag &= ~(IOREAD|IOWRITE);
+ iop->io_flag &= ~(IOREAD | IOWRITE);
}
+
switch (iop->io_flag) {
case IOREAD:
- u = open(cp, 0);
+ u = open(cp, O_RDONLY);
break;
case IOHERE:
- case IOHERE|IOXHERE:
- u = herein(iop->io_name, iop->io_flag&IOXHERE);
- cp = "here file";
+ case IOHERE | IOXHERE:
+ u = herein(iop->io_name, iop->io_flag & IOXHERE);
+ cp = (char*)"here file";
break;
- case IOWRITE|IOCAT:
- if ((u = open(cp, 1)) >= 0) {
- lseek(u, (long)0, 2);
+ case IOWRITE | IOCAT:
+ u = open(cp, O_WRONLY);
+ if (u >= 0) {
+ lseek(u, (long) 0, SEEK_END);
break;
}
+ /* fall through to creation if >>file doesn't exist */
+
case IOWRITE:
u = creat(cp, 0666);
break;
case IODUP:
- u = dup2(*cp-'0', iop->io_unit);
+ u = dup2(*cp - '0', iop->io_fd);
break;
case IOCLOSE:
- close(iop->io_unit);
- return(0);
+ close(iop->io_fd);
+ return 0;
}
+
if (u < 0) {
prs(cp);
- prs(": cannot ");
+ prs(": can't ");
warn(msg);
- return(1);
- } else {
- if (u != iop->io_unit) {
- dup2(u, iop->io_unit);
- close(u);
- }
+ return 1;
}
- return(0);
-}
-
-static void
-echo(wp)
-register char **wp;
-{
- register int i;
-
- prs("+");
- for (i=0; wp[i]; i++) {
- if (i)
- prs(" ");
- prs(wp[i]);
- }
- prs("\n");
-}
-
-static struct op **
-find1case(t, w)
-struct op *t;
-char *w;
-{
- register struct op *t1;
- struct op **tp;
- register char **wp, *cp;
-
- if (t == NULL)
- return((struct op **)NULL);
- if (t->type == TLIST) {
- if ((tp = find1case(t->left, w)) != NULL)
- return(tp);
- t1 = t->right; /* TPAT */
- } else
- t1 = t;
- for (wp = t1->words; *wp;)
- if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp))
- return(&t1->left);
- return((struct op **)NULL);
-}
-
-static struct op *
-findcase(t, w)
-struct op *t;
-char *w;
-{
- register struct op **tp;
-
- return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL);
+ xmove_fd(u, iop->io_fd);
+ return 0;
}
/*
* Enter a new loop level (marked for break/continue).
*/
-static void
-brkset(bc)
-struct brkcon *bc;
+static void brkset(struct brkcon *bc)
{
bc->nextlev = brklist;
brklist = bc;
@@ -2758,14 +2977,11 @@ struct brkcon *bc;
* Ignore interrupt signals while waiting
* unless `canintr' is true.
*/
-static int
-waitfor(lastpid, canintr)
-register int lastpid;
-int canintr;
+static int waitfor(int lastpid, int canintr)
{
- register int pid, rv;
+ int pid, rv;
int s;
- int oheedint = heedint;
+ smallint oheedint = heedint;
heedint = 0;
rv = 0;
@@ -2775,8 +2991,9 @@ int canintr;
if (errno != EINTR || canintr)
break;
} else {
- if ((rv = WAITSIG(s)) != 0) {
- if (rv < NSIGNAL) {
+ rv = WAITSIG(s);
+ if (rv != 0) {
+ if (rv < ARRAY_SIZE(signame)) {
if (signame[rv] != NULL) {
if (pid != lastpid) {
prn(pid);
@@ -2789,13 +3006,15 @@ int canintr;
prn(pid);
prs(": ");
}
- prs("Signal "); prn(rv); prs(" ");
+ prs("Signal ");
+ prn(rv);
+ prs(" ");
}
if (WAITCORE(s))
prs(" - core dumped");
- if (rv >= NSIGNAL || signame[rv])
+ if (rv >= ARRAY_SIZE(signame) || signame[rv])
prs("\n");
- rv = -1;
+ rv |= 0x80;
} else
rv = WAITVAL(s);
}
@@ -2806,20 +3025,19 @@ int canintr;
if (canintr)
intr = 0;
} else {
- if (exstat == 0) exstat = rv;
+ if (exstat == 0)
+ exstat = rv;
onintr(0);
}
}
- return(rv);
+ return rv;
}
-static int
-setstatus(s)
-register int s;
+static int setstatus(int s)
{
exstat = s;
setval(lookup("?"), putn(s));
- return(s);
+ return s;
}
/*
@@ -2827,74 +3045,77 @@ register int s;
* If getenv("PATH") were kept up-to-date,
* execvp might be used.
*/
-static char *
-rexecve(c, v, envp)
-char *c, **v, **envp;
+static const char *rexecve(char *c, char **v, char **envp)
{
- register int i;
- register char *sp, *tp;
- int eacces = 0, asis = 0;
-
-#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+ const char *sp;
+ char *tp;
+ int asis = 0;
char *name = c;
-#ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
- name = bb_get_last_path_component(name);
-#endif
- optind = 1;
- if (find_applet_by_name(name)) {
- /* We have to exec here since we vforked. Running
- * run_applet_by_name() won't work and bad things
- * will happen. */
- execve("/proc/self/exe", v, envp);
- execve("busybox", v, envp);
+
+ if (ENABLE_FEATURE_SH_STANDALONE) {
+ if (find_applet_by_name(name) >= 0) {
+ /* We have to exec here since we vforked. Running
+ * run_applet_and_exit() won't work and bad things
+ * will happen. */
+ execve(bb_busybox_exec_path, v, envp);
+ }
}
-#endif
- sp = any('/', c)? "": path->value;
- asis = *sp == '\0';
+ DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
+
+ sp = any('/', c) ? "" : path->value;
+ asis = (*sp == '\0');
while (asis || *sp != '\0') {
asis = 0;
- tp = e.linep;
- for (; *sp != '\0'; tp++)
- if ((*tp = *sp++) == ':') {
- asis = *sp == '\0';
+ tp = global_env.linep;
+ for (; *sp != '\0'; tp++) {
+ *tp = *sp++;
+ if (*tp == ':') {
+ asis = (*sp == '\0');
break;
}
- if (tp != e.linep)
+ }
+ if (tp != global_env.linep)
*tp++ = '/';
- for (i = 0; (*tp++ = c[i++]) != '\0';)
- ;
+ strcpy(tp, c);
+
+ DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
+
+ execve(global_env.linep, v, envp);
- execve(e.linep, v, envp);
switch (errno) {
case ENOEXEC:
- *v = e.linep;
- tp = *--v;
- *v = e.linep;
- execve(shellname, v, envp);
+ /* File is executable but file format isnt recognized */
+ /* Run it as a shell script */
+ /* (execve above didnt do it itself, unlike execvp) */
+ *v = global_env.linep;
+ v--;
+ tp = *v;
+ *v = (char*)DEFAULT_SHELL;
+ execve(DEFAULT_SHELL, v, envp);
*v = tp;
- return("no Shell");
+ return "no shell";
case ENOMEM:
- return((char*)bb_msg_memory_exhausted);
+ return (char *) bb_msg_memory_exhausted;
case E2BIG:
- return("argument list too long");
-
- case EACCES:
- eacces++;
- break;
+ return "argument list too long";
}
}
- return(errno==ENOENT ? "not found" : "cannot execute");
+ if (errno == ENOENT) {
+ exstat = 127; /* standards require this */
+ return "not found";
+ }
+ exstat = 126; /* mimic bash */
+ return "can't execute";
}
/*
* Run the command produced by generator `f'
* applied to stream `arg'.
*/
-static int
-run(struct ioarg *argp, int (*f)(struct ioarg *))
+static int run(struct ioarg *argp, int (*f) (struct ioarg *))
{
struct op *otree;
struct wdblock *swdlist;
@@ -2908,28 +3129,38 @@ run(struct ioarg *argp, int (*f)(struct ioarg *))
(void) &rv;
#endif
+ DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
+ areanum, outtree, failpt));
+
areanum++;
swdlist = wdlist;
siolist = iolist;
otree = outtree;
ofail = failpt;
rv = -1;
- if (newenv(setjmp(errpt = ev)) == 0) {
- wdlist = 0;
- iolist = 0;
+
+ errpt = ev;
+ if (newenv(setjmp(errpt)) == 0) {
+ wdlist = NULL;
+ iolist = NULL;
pushio(argp, f);
- e.iobase = e.iop;
+ global_env.iobase = global_env.iop;
yynerrs = 0;
- if (setjmp(failpt = rt) == 0 && yyparse() == 0)
- rv = execute(outtree, NOPIPE, NOPIPE, 0);
+ failpt = rt;
+ if (setjmp(failpt) == 0 && yyparse() == 0)
+ rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
quitenv();
+ } else {
+ DBGPRINTF(("RUN: error from newenv()!\n"));
}
+
wdlist = swdlist;
iolist = siolist;
failpt = ofail;
outtree = otree;
freearea(areanum--);
- return(rv);
+
+ return rv;
}
/* -------- do.c -------- */
@@ -2938,287 +3169,307 @@ run(struct ioarg *argp, int (*f)(struct ioarg *))
* built-in commands: doX
*/
-static int dohelp(struct op *t )
+static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
{
int col;
const struct builtincmd *x;
- printf("\nBuilt-in commands:\n");
- printf("-------------------\n");
+ printf("\n"
+ "Built-in commands:\n"
+ "------------------\n");
- for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) {
- if (!x->name)
- continue;
- col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
+ col = 0;
+ x = builtincmds;
+ while (x->name) {
+ col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
if (col > 60) {
- printf("\n");
+ bb_putchar('\n');
col = 0;
}
+ x++;
}
-#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
+#if ENABLE_FEATURE_SH_STANDALONE
{
- int i;
- const struct BB_applet *applet;
- extern const struct BB_applet applets[];
- extern const size_t NUM_APPLETS;
+ const char *applet = applet_names;
- for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
- if (!applet->name)
- continue;
-
- col += printf("%s%s", ((col == 0) ? "\t" : " "),
- applet->name);
+ while (*applet) {
+ col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
if (col > 60) {
- printf("\n");
+ bb_putchar('\n');
col = 0;
}
+ applet += strlen(applet) + 1;
}
}
#endif
- printf("\n\n");
+ puts("\n");
return EXIT_SUCCESS;
}
-
-
-static int dolabel(struct op *t )
+static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
{
- return(0);
+ return 0;
}
-static int
-dochdir(t)
-register struct op *t;
+static int dochdir(struct op *t UNUSED_PARAM, char **args)
{
- register char *cp, *er;
+ const char *cp, *er;
- if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
+ cp = args[1];
+ if (cp == NULL) {
+ cp = homedir->value;
+ if (cp != NULL)
+ goto do_cd;
er = ": no home directory";
- else if(chdir(cp) < 0)
+ } else {
+ do_cd:
+ if (chdir(cp) >= 0)
+ return 0;
er = ": bad directory";
- else
- return(0);
- prs(cp != NULL? cp: "cd");
+ }
+ prs(cp != NULL ? cp : "cd");
err(er);
- return(1);
+ return 1;
}
-static int
-doshift(t)
-register struct op *t;
+static int doshift(struct op *t UNUSED_PARAM, char **args)
{
- register int n;
+ int n;
- n = t->words[1]? getn(t->words[1]): 1;
- if(dolc < n) {
+ n = args[1] ? getn(args[1]) : 1;
+ if (dolc < n) {
err("nothing to shift");
- return(1);
+ return 1;
}
dolv[n] = dolv[0];
dolv += n;
dolc -= n;
setval(lookup("#"), putn(dolc));
- return(0);
+ return 0;
}
/*
* execute login and newgrp directly
*/
-static int
-dologin(t)
-struct op *t;
+static int dologin(struct op *t UNUSED_PARAM, char **args)
{
- register char *cp;
+ const char *cp;
if (interactive) {
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
}
- cp = rexecve(t->words[0], t->words, makenv());
- prs(t->words[0]); prs(": "); err(cp);
- return(1);
+ cp = rexecve(args[0], args, makenv(0, NULL));
+ prs(args[0]);
+ prs(": ");
+ err(cp);
+ return 1;
}
-static int
-doumask(t)
-register struct op *t;
+static int doumask(struct op *t UNUSED_PARAM, char **args)
{
- register int i, n;
- register char *cp;
+ int i;
+ char *cp;
- if ((cp = t->words[1]) == NULL) {
+ cp = args[1];
+ if (cp == NULL) {
i = umask(0);
umask(i);
- for (n=3*4; (n-=3) >= 0;)
- putc('0'+((i>>n)&07), stderr);
- putc('\n', stderr);
+ printf("%04o\n", i);
} else {
- for (n=0; *cp>='0' && *cp<='9'; cp++)
- n = n*8 + (*cp-'0');
- umask(n);
+ i = bb_strtou(cp, NULL, 8);
+ if (errno) {
+ err("umask: bad octal number");
+ return 1;
+ }
+ umask(i);
}
- return(0);
+ return 0;
}
-static int
-doexec(t)
-register struct op *t;
+static int doexec(struct op *t, char **args)
{
- register int i;
jmp_buf ex;
xint *ofail;
+ char **sv_words;
t->ioact = NULL;
- for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++)
- ;
- if (i == 0)
- return(1);
+ if (!args[1])
+ return 1;
+
execflg = 1;
ofail = failpt;
- if (setjmp(failpt = ex) == 0)
- execute(t, NOPIPE, NOPIPE, FEXEC);
+ failpt = ex;
+
+ sv_words = t->op_words;
+ t->op_words = args + 1;
+// TODO: test what will happen with "exec break" -
+// will it leave t->op_words pointing to garbage?
+// (see http://bugs.busybox.net/view.php?id=846)
+ if (setjmp(failpt) == 0)
+ execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
+ t->op_words = sv_words;
+
failpt = ofail;
execflg = 0;
- return(1);
+
+ return 1;
}
-static int
-dodot(t)
-struct op *t;
+static int dodot(struct op *t UNUSED_PARAM, char **args)
{
- register int i;
- register char *sp, *tp;
+ int i;
+ const char *sp;
+ char *tp;
char *cp;
+ int maltmp;
+
+ DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
+ t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
+
+ cp = args[1];
+ if (cp == NULL) {
+ DBGPRINTF(("DODOT: bad args, ret 0\n"));
+ return 0;
+ }
+ DBGPRINTF(("DODOT: cp is %s\n", cp));
+
+ sp = any('/', cp) ? ":" : path->value;
+
+ DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
+ ((sp == NULL) ? "NULL" : sp),
+ ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
- if ((cp = t->words[1]) == NULL)
- return(0);
- sp = any('/', cp)? ":": path->value;
while (*sp) {
- tp = e.linep;
+ tp = global_env.linep;
while (*sp && (*tp = *sp++) != ':')
tp++;
- if (tp != e.linep)
+ if (tp != global_env.linep)
*tp++ = '/';
- for (i = 0; (*tp++ = cp[i++]) != '\0';)
- ;
- if ((i = open(e.linep, 0)) >= 0) {
+ strcpy(tp, cp);
+
+ /* Original code */
+ i = open(global_env.linep, O_RDONLY);
+ if (i >= 0) {
exstat = 0;
- next(remap(i));
- return(exstat);
+ maltmp = remap(i);
+ DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
+ maltmp, exstat, global_env.iofd, i, global_env.linep));
+
+ next(maltmp); /* Basically a PUSHIO */
+
+ DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
+
+ return exstat;
}
- }
+ } /* while */
+
prs(cp);
err(": not found");
- return(-1);
+
+ return -1;
}
-static int
-dowait(t)
-struct op *t;
+static int dowait(struct op *t UNUSED_PARAM, char **args)
{
- register int i;
- register char *cp;
+ int i;
+ char *cp;
- if ((cp = t->words[1]) != NULL) {
+ cp = args[1];
+ if (cp != NULL) {
i = getn(cp);
if (i == 0)
- return(0);
+ return 0;
} else
i = -1;
setstatus(waitfor(i, 1));
- return(0);
+ return 0;
}
-static int
-doread(t)
-struct op *t;
+static int doread(struct op *t UNUSED_PARAM, char **args)
{
- register char *cp, **wp;
- register int nb = 0;
- register int nl = 0;
+ char *cp, **wp;
+ int nb = 0;
+ int nl = 0;
- if (t->words[1] == NULL) {
+ if (args[1] == NULL) {
err("Usage: read name ...");
- return(1);
+ return 1;
}
- for (wp = t->words+1; *wp; wp++) {
- for (cp = e.linep; !nl && cp < elinep-1; cp++)
- if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
- (nl = (*cp == '\n')) ||
- (wp[1] && any(*cp, ifs->value)))
+ for (wp = args + 1; *wp; wp++) {
+ for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
+ nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
+ if (nb != sizeof(*cp))
+ break;
+ nl = (*cp == '\n');
+ if (nl || (wp[1] && any(*cp, ifs->value)))
break;
- *cp = 0;
+ }
+ *cp = '\0';
if (nb <= 0)
break;
- setval(lookup(*wp), e.linep);
+ setval(lookup(*wp), global_env.linep);
}
- return(nb <= 0);
+ return nb <= 0;
}
-static int
-doeval(t)
-register struct op *t;
+static int doeval(struct op *t UNUSED_PARAM, char **args)
{
- return(RUN(awordlist, t->words+1, wdchar));
+ return RUN(awordlist, args + 1, wdchar);
}
-static int
-dotrap(t)
-register struct op *t;
+static int dotrap(struct op *t UNUSED_PARAM, char **args)
{
- register int n, i;
- register int resetsig;
+ int n, i;
+ int resetsig;
- if (t->words[1] == NULL) {
- for (i=0; i<=_NSIG; i++)
+ if (args[1] == NULL) {
+ for (i = 0; i <= _NSIG; i++)
if (trap[i]) {
prn(i);
prs(": ");
prs(trap[i]);
prs("\n");
}
- return(0);
+ return 0;
}
- resetsig = isdigit(*t->words[1]);
- for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
- n = getsig(t->words[i]);
+ resetsig = isdigit(args[1][0]);
+ for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
+ n = getsig(args[i]);
freecell(trap[n]);
trap[n] = 0;
if (!resetsig) {
- if (*t->words[1] != '\0') {
- trap[n] = strsave(t->words[1], 0);
+ if (args[1][0] != '\0') {
+ trap[n] = strsave(args[1], 0);
setsig(n, sig);
} else
setsig(n, SIG_IGN);
} else {
- if (interactive)
+ if (interactive) {
if (n == SIGINT)
setsig(n, onintr);
else
- setsig(n, n == SIGQUIT ? SIG_IGN
- : SIG_DFL);
- else
+ setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
+ } else
setsig(n, SIG_DFL);
}
}
- return(0);
+ return 0;
}
-static int
-getsig(s)
-char *s;
+static int getsig(char *s)
{
- register int n;
+ int n;
- if ((n = getn(s)) < 0 || n > _NSIG) {
+ n = getn(s);
+ if (n < 0 || n > _NSIG) {
err("trap: bad signal number");
n = 0;
}
- return(n);
+ return n;
}
-static void
-setsig( register int n, sighandler_t f)
+static void setsig(int n, sighandler_t f)
{
if (n == 0)
return;
@@ -3228,12 +3479,10 @@ setsig( register int n, sighandler_t f)
}
}
-static int
-getn(as)
-char *as;
+static int getn(char *as)
{
- register char *s;
- register int n, m;
+ char *s;
+ int n, m;
s = as;
m = 1;
@@ -3242,96 +3491,92 @@ char *as;
s++;
}
for (n = 0; isdigit(*s); s++)
- n = (n*10) + (*s-'0');
+ n = (n * 10) + (*s - '0');
if (*s) {
prs(as);
err(": bad number");
}
- return(n*m);
+ return n * m;
}
-static int
-dobreak(t)
-struct op *t;
+static int dobreak(struct op *t UNUSED_PARAM, char **args)
{
- return(brkcontin(t->words[1], 1));
+ return brkcontin(args[1], 1);
}
-static int
-docontinue(t)
-struct op *t;
+static int docontinue(struct op *t UNUSED_PARAM, char **args)
{
- return(brkcontin(t->words[1], 0));
+ return brkcontin(args[1], 0);
}
-static int
-brkcontin(cp, val)
-register char *cp;
-int val;
+static int brkcontin(char *cp, int val)
{
- register struct brkcon *bc;
- register int nl;
+ struct brkcon *bc;
+ int nl;
- nl = cp == NULL? 1: getn(cp);
+ nl = cp == NULL ? 1 : getn(cp);
if (nl <= 0)
nl = 999;
do {
- if ((bc = brklist) == NULL)
+ bc = brklist;
+ if (bc == NULL)
break;
brklist = bc->nextlev;
} while (--nl);
if (nl) {
err("bad break/continue level");
- return(1);
+ return 1;
}
- isbreak = val;
+ isbreak = (val != 0);
longjmp(bc->brkpt, 1);
/* NOTREACHED */
}
-static int
-doexit(t)
-struct op *t;
+static int doexit(struct op *t UNUSED_PARAM, char **args)
{
- register char *cp;
+ char *cp;
execflg = 0;
- if ((cp = t->words[1]) != NULL)
+ cp = args[1];
+ if (cp != NULL)
setstatus(getn(cp));
+
+ DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
+
leave();
/* NOTREACHED */
- return(0);
+ return 0;
}
-static int
-doexport(t)
-struct op *t;
+static int doexport(struct op *t UNUSED_PARAM, char **args)
{
- rdexp(t->words+1, export, EXPORT);
- return(0);
+ rdexp(args + 1, export, EXPORT);
+ return 0;
}
-static int
-doreadonly(t)
-struct op *t;
+static int doreadonly(struct op *t UNUSED_PARAM, char **args)
{
- rdexp(t->words+1, ronly, RONLY);
- return(0);
+ rdexp(args + 1, ronly, RONLY);
+ return 0;
}
-static void rdexp (char **wp, void (*f)(struct var *), int key)
+static void rdexp(char **wp, void (*f) (struct var *), int key)
{
+ DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
+ DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
+
if (*wp != NULL) {
for (; *wp != NULL; wp++) {
if (isassign(*wp)) {
char *cp;
+
assign(*wp, COPYV);
for (cp = *wp; *cp != '='; cp++)
- ;
+ continue;
*cp = '\0';
}
if (checkname(*wp))
- (*f)(lookup(*wp));
+ (*f) (lookup(*wp));
else
badid(*wp);
}
@@ -3339,68 +3584,62 @@ static void rdexp (char **wp, void (*f)(struct var *), int key)
putvlist(key, 1);
}
-static void
-badid(s)
-register char *s;
+static void badid(char *s)
{
prs(s);
err(": bad identifier");
}
-static int
-doset(t)
-register struct op *t;
+static int doset(struct op *t UNUSED_PARAM, char **args)
{
- register struct var *vp;
- register char *cp;
- register int n;
+ struct var *vp;
+ char *cp;
+ int n;
- if ((cp = t->words[1]) == NULL) {
+ cp = args[1];
+ if (cp == NULL) {
for (vp = vlist; vp; vp = vp->next)
- varput(vp->name, 1);
- return(0);
+ varput(vp->name, STDOUT_FILENO);
+ return 0;
}
if (*cp == '-') {
- /* bad: t->words++; */
- for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++)
- ;
+ args++;
if (*++cp == 0)
- flag['x'] = flag['v'] = 0;
- else
- for (; *cp; cp++)
+ FLAG['x'] = FLAG['v'] = 0;
+ else {
+ for (; *cp; cp++) {
switch (*cp) {
case 'e':
if (!interactive)
- flag['e']++;
+ FLAG['e']++;
break;
default:
- if (*cp>='a' && *cp<='z')
- flag[(int)*cp]++;
+ if (*cp >= 'a' && *cp <= 'z')
+ FLAG[(int) *cp]++;
break;
}
+ }
+ }
setdash();
}
- if (t->words[1]) {
- t->words[0] = dolv[0];
- for (n=1; t->words[n]; n++)
- setarea((char *)t->words[n], 0);
- dolc = n-1;
- dolv = t->words;
+ if (args[1]) {
+ args[0] = dolv[0];
+ for (n = 1; args[n]; n++)
+ setarea((char *) args[n], 0);
+ dolc = n - 1;
+ dolv = args;
setval(lookup("#"), putn(dolc));
- setarea((char *)(dolv-1), 0);
+ setarea((char *) (dolv - 1), 0);
}
- return(0);
+ return 0;
}
-static void
-varput(s, out)
-register char *s;
-int out;
+static void varput(char *s, int out)
{
if (isalnum(*s) || *s == '_') {
- write(out, s, strlen(s));
- write(out, "\n", 1);
+ xwrite_str(out, s);
+ xwrite(out, "\n", 1);
}
}
@@ -3409,36 +3648,44 @@ int out;
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
* This file contains code for the times builtin.
*/
-static int dotimes(struct op *t )
+static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
{
- struct tms buf;
- long int clk_tck = sysconf(_SC_CLK_TCK);
-
- times(&buf);
- printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
- (int) (buf.tms_utime / clk_tck / 60),
- ((double) buf.tms_utime) / clk_tck,
- (int) (buf.tms_stime / clk_tck / 60),
- ((double) buf.tms_stime) / clk_tck,
- (int) (buf.tms_cutime / clk_tck / 60),
- ((double) buf.tms_cutime) / clk_tck,
- (int) (buf.tms_cstime / clk_tck / 60),
- ((double) buf.tms_cstime) / clk_tck);
- return 0;
+ unsigned min, sec;
+ if (sizeof(val) > sizeof(int))
+ sec = ((unsigned long)val) / clk_tck;
+ else
+ sec = ((unsigned)val) / clk_tck;
+ min = sec / 60;
+#if ENABLE_DESKTOP
+ sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
+ /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
+ );
+#else
+ sprintf(buf, "%um%us", min, (sec - min * 60));
+#endif
}
-
-static int(*inbuilt(char *s))(struct op *)
+static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
{
- const struct builtincmd *bp;
+ struct tms buf;
+ unsigned clk_tck = sysconf(_SC_CLK_TCK);
+ /* How much do we need for "NmN.NNNs" ? */
+ enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
+ char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
+ char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
- for (bp = builtincmds; bp->name != NULL; bp++)
- if (strcmp(bp->name, s) == 0)
- return(bp->builtinfunc);
+ times(&buf);
+
+ times_fmt(u, buf.tms_utime, clk_tck);
+ times_fmt(s, buf.tms_stime, clk_tck);
+ times_fmt(cu, buf.tms_cutime, clk_tck);
+ times_fmt(cs, buf.tms_cstime, clk_tck);
- return(NULL);
+ printf("%s %s\n%s %s\n", u, s, cu, cs);
+ return 0;
}
+
/* -------- eval.c -------- */
/*
@@ -3449,7 +3696,7 @@ static int(*inbuilt(char *s))(struct op *)
* glob
*/
-static char ** eval( char **ap, int f)
+static char **eval(char **ap, int f)
{
struct wdblock *wb;
char **wp;
@@ -3461,129 +3708,146 @@ static char ** eval( char **ap, int f)
(void) &wp;
(void) &ap;
#endif
+
+ DBGPRINTF4(("EVAL: enter, f=%d\n", f));
+
wp = NULL;
wb = NULL;
wf = NULL;
- if (newenv(setjmp(errpt = ev)) == 0) {
+ errpt = ev;
+ if (newenv(setjmp(errpt)) == 0) {
while (*ap && isassign(*ap))
expand(*ap++, &wb, f & ~DOGLOB);
- if (flag['k']) {
+ if (FLAG['k']) {
for (wf = ap; *wf; wf++) {
if (isassign(*wf))
expand(*wf, &wb, f & ~DOGLOB);
}
}
- for (wb = addword((char *)0, wb); *ap; ap++) {
- if (!flag['k'] || !isassign(*ap))
+ for (wb = addword((char *) NULL, wb); *ap; ap++) {
+ if (!FLAG['k'] || !isassign(*ap))
expand(*ap, &wb, f & ~DOKEY);
}
- wb = addword((char *)0, wb);
+ wb = addword((char *) 0, wb);
wp = getwords(wb);
quitenv();
} else
gflg = 1;
- return(gflg? (char **)NULL: wp);
+
+ return gflg ? (char **) NULL : wp;
}
+
/*
* Make the exported environment from the exported
* names in the dictionary. Keyword assignments
* will already have been done.
*/
-static char **
-makenv()
-
+static char **makenv(int all, struct wdblock *wb)
{
- register struct wdblock *wb;
- register struct var *vp;
+ struct var *vp;
+
+ DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
- wb = NULL;
for (vp = vlist; vp; vp = vp->next)
- if (vp->status & EXPORT)
+ if (all || vp->status & EXPORT)
wb = addword(vp->name, wb);
- wb = addword((char *)0, wb);
- return(getwords(wb));
+ wb = addword((char *) 0, wb);
+ return getwords(wb);
}
-static char *
-evalstr(cp, f)
-register char *cp;
-int f;
-{
- struct wdblock *wb;
-
- wb = NULL;
- if (expand(cp, &wb, f)) {
- if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
- cp = "";
- DELETE(wb);
- } else
- cp = NULL;
- return(cp);
-}
-
-static int
-expand( char *cp, register struct wdblock **wbp, int f)
+static int expand(const char *cp, struct wdblock **wbp, int f)
{
jmp_buf ev;
+ char *xp;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &cp;
#endif
+
+ DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
+
gflg = 0;
+
if (cp == NULL)
- return(0);
- if (!anys("$`'\"", cp) &&
- !anys(ifs->value, cp) &&
- ((f&DOGLOB)==0 || !anys("[*?", cp))) {
- cp = strsave(cp, areanum);
+ return 0;
+
+ if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
+ && ((f & DOGLOB) == 0 || !anys("[*?", cp))
+ ) {
+ xp = strsave(cp, areanum);
if (f & DOTRIM)
- unquote(cp);
- *wbp = addword(cp, *wbp);
- return(1);
+ unquote(xp);
+ *wbp = addword(xp, *wbp);
+ return 1;
}
- if (newenv(setjmp(errpt = ev)) == 0) {
+ errpt = ev;
+ if (newenv(setjmp(errpt)) == 0) {
PUSHIO(aword, cp, strchar);
- e.iobase = e.iop;
- while ((cp = blank(f)) && gflg == 0) {
- e.linep = cp;
- cp = strsave(cp, areanum);
- if ((f&DOGLOB) == 0) {
+ global_env.iobase = global_env.iop;
+ while ((xp = blank(f)) && gflg == 0) {
+ global_env.linep = xp;
+ xp = strsave(xp, areanum);
+ if ((f & DOGLOB) == 0) {
if (f & DOTRIM)
- unquote(cp);
- *wbp = addword(cp, *wbp);
+ unquote(xp);
+ *wbp = addword(xp, *wbp);
} else
- *wbp = glob(cp, *wbp);
+ *wbp = glob(xp, *wbp);
}
quitenv();
} else
gflg = 1;
- return(gflg == 0);
+ return gflg == 0;
}
+static char *evalstr(char *cp, int f)
+{
+ struct wdblock *wb;
+
+ DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
+
+ wb = NULL;
+ if (expand(cp, &wb, f)) {
+ if (wb == NULL || wb->w_nword == 0
+ || (cp = wb->w_words[0]) == NULL
+ ) {
+// TODO: I suspect that
+// char *evalstr(char *cp, int f) is actually
+// const char *evalstr(const char *cp, int f)!
+ cp = (char*)"";
+ }
+ DELETE(wb);
+ } else
+ cp = NULL;
+ return cp;
+}
+
+
/*
* Blank interpretation and quoting
*/
-static char *
-blank(f)
-int f;
+static char *blank(int f)
{
- register int c, c1;
- register char *sp;
+ int c, c1;
+ char *sp;
int scanequals, foundequals;
- sp = e.linep;
+ DBGPRINTF3(("BLANK: enter, f=%d\n", f));
+
+ sp = global_env.linep;
scanequals = f & DOKEY;
foundequals = 0;
-loop:
- switch (c = subgetc('"', foundequals)) {
+ loop:
+ c = subgetc('"', foundequals);
+ switch (c) {
case 0:
- if (sp == e.linep)
- return(0);
- *e.linep++ = 0;
- return(sp);
+ if (sp == global_env.linep)
+ return 0;
+ *global_env.linep++ = 0;
+ return sp;
default:
if (f & DOBLANK && any(c, ifs->value))
@@ -3600,7 +3864,7 @@ loop:
break;
if (c == '\'' || !any(c, "$`\""))
c |= QUOTE;
- *e.linep++ = c;
+ *global_env.linep++ = c;
}
c = 0;
}
@@ -3610,9 +3874,9 @@ loop:
for (;;) {
c = subgetc('"', foundequals);
if (c == 0 ||
- f & (DOBLANK && any(c, ifs->value)) ||
- (!INSUB() && any(c, "\"'"))) {
- scanequals = 0;
+ f & (DOBLANK && any(c, ifs->value)) ||
+ (!INSUB() && any(c, "\"'"))) {
+ scanequals = 0;
unget(c);
if (any(c, "\"'"))
goto loop;
@@ -3621,91 +3885,93 @@ loop:
if (scanequals) {
if (c == '=') {
foundequals = 1;
- scanequals = 0;
- }
- else if (!isalnum(c) && c != '_')
+ scanequals = 0;
+ } else if (!isalnum(c) && c != '_')
scanequals = 0;
}
- *e.linep++ = c;
+ *global_env.linep++ = c;
}
- *e.linep++ = 0;
- return(sp);
+ *global_env.linep++ = 0;
+ return sp;
}
/*
* Get characters, substituting for ` and $
*/
-static int
-subgetc(ec, quoted)
-register char ec;
-int quoted;
+static int subgetc(char ec, int quoted)
{
- register char c;
+ char c;
-again:
+ DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
+
+ again:
c = my_getc(ec);
if (!INSUB() && ec != '\'') {
if (c == '`') {
if (grave(quoted) == 0)
- return(0);
- e.iop->task = XGRAVE;
+ return 0;
+ global_env.iop->task = XGRAVE;
goto again;
}
- if (c == '$' && (c = dollar(quoted)) == 0) {
- e.iop->task = XDOLL;
- goto again;
+ if (c == '$') {
+ c = dollar(quoted);
+ if (c == 0) {
+ global_env.iop->task = XDOLL;
+ goto again;
+ }
}
}
- return(c);
+ return c;
}
/*
* Prepare to generate the string returned by ${} substitution.
*/
-static int
-dollar(quoted)
-int quoted;
+static int dollar(int quoted)
{
int otask;
struct io *oiop;
char *dolp;
- register char *s, c, *cp=NULL;
+ char *s, c, *cp = NULL;
struct var *vp;
+ DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
+
c = readc();
- s = e.linep;
+ s = global_env.linep;
if (c != '{') {
- *e.linep++ = c;
+ *global_env.linep++ = c;
if (isalpha(c) || c == '_') {
- while ((c = readc())!=0 && (isalnum(c) || c == '_'))
- if (e.linep < elinep)
- *e.linep++ = c;
+ while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
+ if (global_env.linep < elinep)
+ *global_env.linep++ = c;
unget(c);
}
c = 0;
} else {
- oiop = e.iop;
- otask = e.iop->task;
- e.iop->task = XOTHER;
- while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
- if (e.linep < elinep)
- *e.linep++ = c;
- if (oiop == e.iop)
- e.iop->task = otask;
+ oiop = global_env.iop;
+ otask = global_env.iop->task;
+
+ global_env.iop->task = XOTHER;
+ while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
+ if (global_env.linep < elinep)
+ *global_env.linep++ = c;
+ if (oiop == global_env.iop)
+ global_env.iop->task = otask;
if (c != '}') {
err("unclosed ${");
- gflg++;
- return(c);
+ gflg = 1;
+ return c;
}
}
- if (e.linep >= elinep) {
+ if (global_env.linep >= elinep) {
err("string in ${} too long");
- gflg++;
- e.linep -= 10;
+ gflg = 1;
+ global_env.linep -= 10;
}
- *e.linep = 0;
+ *global_env.linep = 0;
if (*s)
- for (cp = s+1; *cp; cp++)
+ for (cp = s + 1; *cp; cp++)
if (any(*cp, "=-+?")) {
c = *cp;
*cp++ = 0;
@@ -3715,21 +3981,22 @@ int quoted;
if (dolc > 1) {
/* currently this does not distinguish $* and $@ */
/* should check dollar */
- e.linep = s;
- PUSHIO(awordlist, dolv+1, dolchar);
- return(0);
- } else { /* trap the nasty ${=} */
+ global_env.linep = s;
+ PUSHIO(awordlist, dolv + 1, dolchar);
+ return 0;
+ } else { /* trap the nasty ${=} */
s[0] = '1';
- s[1] = 0;
+ s[1] = '\0';
}
}
vp = lookup(s);
- if ((dolp = vp->value) == null) {
+ dolp = vp->value;
+ if (dolp == null) {
switch (c) {
case '=':
if (isdigit(*s)) {
- err("cannot use ${...=...} with $n");
- gflg++;
+ err("can't use ${...=...} with $n");
+ gflg = 1;
break;
}
setval(vp, cp);
@@ -3746,54 +4013,55 @@ int quoted;
err(s);
} else
err(cp);
- gflg++;
+ gflg = 1;
break;
}
} else if (c == '+')
dolp = strsave(cp, areanum);
- if (flag['u'] && dolp == null) {
+ if (FLAG['u'] && dolp == null) {
prs("unset variable: ");
err(s);
- gflg++;
+ gflg = 1;
}
- e.linep = s;
+ global_env.linep = s;
PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
- return(0);
+ return 0;
}
/*
* Run the command in `...` and read its output.
*/
-static int
-grave(quoted)
-int quoted;
+static int grave(int quoted)
{
- char *cp;
- register int i;
+ /* moved to G: static char child_cmd[LINELIM]; */
+
+ const char *cp;
+ int i;
int j;
int pf[2];
- static char child_cmd[LINELIM];
- char *src;
+ const char *src;
char *dest;
int count;
int ignore;
int ignore_once;
char *argument_list[4];
+ struct wdblock *wb = NULL;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &cp;
#endif
-
- for (cp = e.iop->argp->aword; *cp != '`'; cp++)
+
+ for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
if (*cp == 0) {
err("no closing `");
- return(0);
+ return 0;
}
+ }
/* string copy with dollar expansion */
- src = e.iop->argp->aword;
+ src = global_env.iop->argp->aword;
dest = child_cmd;
count = 0;
ignore = 0;
@@ -3805,8 +4073,12 @@ int quoted;
ignore_once = 1;
if (*src == '$' && !ignore && !ignore_once) {
struct var *vp;
+ /* moved to G to reduce stack usage
char var_name[LINELIM];
char alt_value[LINELIM];
+ */
+#define var_name (G.grave__var_name)
+#define alt_value (G.grave__alt_value)
int var_index = 0;
int alt_index = 0;
char operator = 0;
@@ -3820,7 +4092,7 @@ int quoted;
}
var_name[var_index++] = *src++;
- while (isalnum(*src))
+ while (isalnum(*src) || *src=='_')
var_name[var_index++] = *src++;
var_name[var_index] = 0;
@@ -3832,13 +4104,13 @@ int quoted;
case '=':
case '+':
case '?':
- operator = *src;
+ operator = * src;
break;
default:
err("unclosed ${\n");
- return(0);
+ return 0;
}
- if (operator) {
+ if (operator) {
src++;
while (*src && (*src != '}')) {
alt_value[alt_index++] = *src++;
@@ -3846,29 +4118,56 @@ int quoted;
alt_value[alt_index] = 0;
if (*src != '}') {
err("unclosed ${\n");
- return(0);
+ return 0;
}
}
src++;
}
- vp = lookup(var_name);
- if (vp->value != null)
- value = (operator == '+')? alt_value : vp->value;
- else if (operator == '?') {
- err(alt_value);
- return(0);
- } else if (alt_index && (operator != '+')) {
- value = alt_value;
- if (operator == '=')
- setval(vp, value);
- } else
- continue;
+ if (isalpha(*var_name)) {
+ /* let subshell handle it instead */
+
+ char *namep = var_name;
+
+ *dest++ = '$';
+ if (braces)
+ *dest++ = '{';
+ while (*namep)
+ *dest++ = *namep++;
+ if (operator) {
+ char *altp = alt_value;
+ *dest++ = operator;
+ while (*altp)
+ *dest++ = *altp++;
+ }
+ if (braces)
+ *dest++ = '}';
- while (*value && (count < LINELIM)) {
- *dest++ = *value++;
- count++;
+ wb = addword(lookup(var_name)->name, wb);
+ } else {
+ /* expand */
+
+ vp = lookup(var_name);
+ if (vp->value != null)
+ value = (operator == '+') ?
+ alt_value : vp->value;
+ else if (operator == '?') {
+ err(alt_value);
+ return 0;
+ } else if (alt_index && (operator != '+')) {
+ value = alt_value;
+ if (operator == '=')
+ setval(vp, value);
+ } else
+ continue;
+
+ while (*value && (count < LINELIM)) {
+ *dest++ = *value++;
+ count++;
+ }
}
+#undef var_name
+#undef alt_value
} else {
*dest++ = *src++;
count++;
@@ -3876,52 +4175,65 @@ int quoted;
}
}
*dest = '\0';
-
+
if (openpipe(pf) < 0)
- return(0);
+ return 0;
+
while ((i = vfork()) == -1 && errno == EAGAIN)
- ;
+ continue;
+
+ DBGPRINTF3(("GRAVE: i is %p\n", io));
+
if (i < 0) {
closepipe(pf);
- err((char*)bb_msg_memory_exhausted);
- return(0);
+ err((char *) bb_msg_memory_exhausted);
+ return 0;
}
if (i != 0) {
- waitpid(i, NULL, 0);
- e.iop->argp->aword = ++cp;
+ waitpid(i, NULL, 0); // safe_waitpid?
+ global_env.iop->argp->aword = ++cp;
close(pf[1]);
- PUSHIO(afile, remap(pf[0]), (int(*)(struct ioarg *))((quoted)? qgravechar: gravechar));
- return(1);
+ PUSHIO(afile, remap(pf[0]),
+ (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
+ return 1;
}
/* allow trapped signals */
/* XXX - Maybe this signal stuff should go as well? */
- for (j=0; j<=_NSIG; j++)
+ for (j = 0; j <= _NSIG; j++)
if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
signal(j, SIG_DFL);
-
- dup2(pf[1], 1);
- closepipe(pf);
- argument_list[0] = shellname;
- argument_list[1] = "-c";
+ /* Testcase where below checks are needed:
+ * close stdout & run this script:
+ * files=`ls`
+ * echo "$files" >zz
+ */
+ xmove_fd(pf[1], 1);
+ if (pf[0] != 1)
+ close(pf[0]);
+
+ argument_list[0] = (char *) DEFAULT_SHELL;
+ argument_list[1] = (char *) "-c";
argument_list[2] = child_cmd;
- argument_list[3] = 0;
+ argument_list[3] = NULL;
- prs(rexecve(argument_list[0], argument_list, makenv()));
- _exit(1);
+ cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
+ prs(argument_list[0]);
+ prs(": ");
+ err(cp);
+ _exit(EXIT_FAILURE);
}
-static char *
-unquote(as)
-register char *as;
+static char *unquote(char *as)
{
- register char *s;
+ char *s;
- if ((s = as) != NULL)
+ s = as;
+ if (s != NULL)
while (*s)
*s++ &= ~QUOTE;
- return(as);
+ return as;
}
/* -------- glob.c -------- */
@@ -3934,19 +4246,16 @@ register char *as;
#define BLKSIZ 512
#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
-static struct wdblock *cl, *nl;
-static char spcl[] = "[?*";
+static struct wdblock *cl, *nl;
+static const char spcl[] ALIGN1= "[?*";
-static struct wdblock *
-glob(cp, wb)
-char *cp;
-struct wdblock *wb;
+static struct wdblock *glob(char *cp, struct wdblock *wb)
{
- register int i;
- register char *pp;
+ int i;
+ char *pp;
if (cp == 0)
- return(wb);
+ return wb;
i = 0;
for (pp = cp; *pp; pp++)
if (any(*pp, spcl))
@@ -3954,9 +4263,9 @@ struct wdblock *wb;
else if (!any(*pp & ~QUOTE, spcl))
*pp &= ~QUOTE;
if (i != 0) {
- for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
- nl = newword(cl->w_nword*2);
- for(i=0; i<cl->w_nword; i++) { /* for each argument */
+ for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
+ nl = newword(cl->w_nword * 2);
+ for (i = 0; i < cl->w_nword; i++) { /* for each argument */
for (pp = cl->w_words[i]; *pp; pp++)
if (any(*pp, spcl)) {
globname(cl->w_words[i], pp);
@@ -3965,45 +4274,44 @@ struct wdblock *wb;
if (*pp == '\0')
nl = addword(scopy(cl->w_words[i]), nl);
}
- for(i=0; i<cl->w_nword; i++)
+ for (i = 0; i < cl->w_nword; i++)
DELETE(cl->w_words[i]);
DELETE(cl);
}
- for(i=0; i<cl->w_nword; i++)
- unquote(cl->w_words[i]);
- glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
if (cl->w_nword) {
- for (i=0; i<cl->w_nword; i++)
+ for (i = 0; i < cl->w_nword; i++)
+ unquote(cl->w_words[i]);
+ qsort_string_vector(cl->w_words, cl->w_nword);
+ for (i = 0; i < cl->w_nword; i++)
wb = addword(cl->w_words[i], wb);
DELETE(cl);
- return(wb);
+ return wb;
}
}
wb = addword(unquote(cp), wb);
- return(wb);
+ return wb;
}
-static void
-globname(we, pp)
-char *we;
-register char *pp;
+static void globname(char *we, char *pp)
{
- register char *np, *cp;
+ char *np, *cp;
char *name, *gp, *dp;
int k;
DIR *dirp;
struct dirent *de;
- char dname[NAME_MAX+1];
+ char dname[NAME_MAX + 1];
struct stat dbuf;
for (np = we; np != pp; pp--)
if (pp[-1] == '/')
break;
- for (dp = cp = space((int)(pp-np)+3); np < pp;)
+ dp = cp = get_space((int) (pp - np) + 3);
+ while (np < pp)
*cp++ = *np++;
*cp++ = '.';
*cp = '\0';
- for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
+ gp = cp = get_space(strlen(pp) + 1);
+ while (*np && *np != '/')
*cp++ = *np++;
*cp = '\0';
dirp = opendir(dp);
@@ -4013,29 +4321,27 @@ register char *pp;
return;
}
dname[NAME_MAX] = '\0';
- while ((de=readdir(dirp))!=NULL) {
+ while ((de = readdir(dirp)) != NULL) {
/* XXX Hmmm... What this could be? (abial) */
- /*
- if (ent[j].d_ino == 0)
- continue;
- */
+ /* if (ent[j].d_ino == 0) continue;
+ */
strncpy(dname, de->d_name, NAME_MAX);
- if (dname[0] == '.')
- if (*gp != '.')
+ if (dname[0] == '.')
+ if (*gp != '.')
+ continue;
+ for (k = 0; k < NAME_MAX; k++)
+ if (any(dname[k], spcl))
+ dname[k] |= QUOTE;
+ if (gmatch(dname, gp)) {
+ name = generate(we, pp, dname, np);
+ if (*np && !anys(np, spcl)) {
+ if (stat(name, &dbuf)) {
+ DELETE(name);
continue;
- for(k=0; k<NAME_MAX; k++)
- if (any(dname[k], spcl))
- dname[k] |= QUOTE;
- if (gmatch(dname, gp)) {
- name = generate(we, pp, dname, np);
- if (*np && !anys(np, spcl)) {
- if (stat(name,&dbuf)) {
- DELETE(name);
- continue;
- }
}
- nl = addword(name, nl);
}
+ nl = addword(name, nl);
+ }
}
closedir(dirp);
DELETE(dp);
@@ -4047,223 +4353,85 @@ register char *pp;
* start..end1 / middle end
* the slashes come for free
*/
-static char *
-generate(start1, end1, middle, end)
-char *start1;
-register char *end1;
-char *middle, *end;
+static char *generate(char *start1, char *end1, char *middle, char *end)
{
char *p;
- register char *op, *xp;
+ char *op, *xp;
- p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
- for (xp = start1; xp != end1;)
+ p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
+ xp = start1;
+ while (xp != end1)
*op++ = *xp++;
- for (xp = middle; (*op++ = *xp++) != '\0';)
- ;
- op--;
- for (xp = end; (*op++ = *xp++) != '\0';)
- ;
- return(p);
+ xp = middle;
+ while (*xp != '\0')
+ *op++ = *xp++;
+ strcpy(op, end);
+ return p;
}
-static int
-anyspcl(wb)
-register struct wdblock *wb;
+static int anyspcl(struct wdblock *wb)
{
- register int i;
- register char **wd;
+ int i;
+ char **wd;
wd = wb->w_words;
- for (i=0; i<wb->w_nword; i++)
+ for (i = 0; i < wb->w_nword; i++)
if (anys(spcl, *wd++))
- return(1);
- return(0);
+ return 1;
+ return 0;
}
-static int
-xstrcmp(p1, p2)
-char *p1, *p2;
-{
- return(strcmp(*(char **)p1, *(char **)p2));
-}
/* -------- word.c -------- */
-static struct wdblock *
-newword(nw)
-register int nw;
+static struct wdblock *newword(int nw)
{
- register struct wdblock *wb;
+ struct wdblock *wb;
- wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
+ wb = get_space(sizeof(*wb) + nw * sizeof(char *));
wb->w_bsize = nw;
wb->w_nword = 0;
- return(wb);
+ return wb;
}
-static struct wdblock *
-addword(wd, wb)
-char *wd;
-register struct wdblock *wb;
+static struct wdblock *addword(char *wd, struct wdblock *wb)
{
- register struct wdblock *wb2;
- register int nw;
+ struct wdblock *wb2;
+ int nw;
if (wb == NULL)
wb = newword(NSTART);
- if ((nw = wb->w_nword) >= wb->w_bsize) {
+ nw = wb->w_nword;
+ if (nw >= wb->w_bsize) {
wb2 = newword(nw * 2);
- memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
+ memcpy((char *) wb2->w_words, (char *) wb->w_words,
+ nw * sizeof(char *));
wb2->w_nword = nw;
DELETE(wb);
wb = wb2;
}
wb->w_words[wb->w_nword++] = wd;
- return(wb);
+ return wb;
}
-static
-char **
-getwords(wb)
-register struct wdblock *wb;
+
+static char **getwords(struct wdblock *wb)
{
- register char **wd;
- register int nb;
+ char **wd;
+ int nb;
if (wb == NULL)
- return((char **)NULL);
+ return NULL;
if (wb->w_nword == 0) {
DELETE(wb);
- return((char **)NULL);
+ return NULL;
}
- wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
- memcpy((char *)wd, (char *)wb->w_words, nb);
- DELETE(wb); /* perhaps should done by caller */
- return(wd);
+ nb = sizeof(*wd) * wb->w_nword;
+ wd = get_space(nb);
+ memcpy(wd, wb->w_words, nb);
+ DELETE(wb); /* perhaps should done by caller */
+ return wd;
}
-int (*func)(char *, char *);
-int globv;
-
-static void
-glob0(a0, a1, a2, a3)
-char *a0;
-unsigned a1;
-int a2;
-int (*a3) (char *, char *);
-{
- func = a3;
- globv = a2;
- glob1(a0, a0 + a1 * a2);
-}
-
-static void
-glob1(base, lim)
-char *base, *lim;
-{
- register char *i, *j;
- int v2;
- char *lptr, *hptr;
- int c;
- unsigned n;
-
-
- v2 = globv;
-
-top:
- if ((n=(int)(lim-base)) <= v2)
- return;
- n = v2 * (n / (2*v2));
- hptr = lptr = base+n;
- i = base;
- j = lim-v2;
- for(;;) {
- if (i < lptr) {
- if ((c = (*func)(i, lptr)) == 0) {
- glob2(i, lptr -= v2);
- continue;
- }
- if (c < 0) {
- i += v2;
- continue;
- }
- }
-
-begin:
- if (j > hptr) {
- if ((c = (*func)(hptr, j)) == 0) {
- glob2(hptr += v2, j);
- goto begin;
- }
- if (c > 0) {
- if (i == lptr) {
- glob3(i, hptr += v2, j);
- i = lptr += v2;
- goto begin;
- }
- glob2(i, j);
- j -= v2;
- i += v2;
- continue;
- }
- j -= v2;
- goto begin;
- }
-
-
- if (i == lptr) {
- if (lptr-base >= lim-hptr) {
- glob1(hptr+v2, lim);
- lim = lptr;
- } else {
- glob1(base, lptr);
- base = hptr+v2;
- }
- goto top;
- }
-
-
- glob3(j, lptr -= v2, i);
- j = hptr -= v2;
- }
-}
-
-static void
-glob2(i, j)
-char *i, *j;
-{
- register char *index1, *index2, c;
- int m;
-
- m = globv;
- index1 = i;
- index2 = j;
- do {
- c = *index1;
- *index1++ = *index2;
- *index2++ = c;
- } while(--m);
-}
-
-static void
-glob3(i, j, k)
-char *i, *j, *k;
-{
- register char *index1, *index2, *index3;
- int c;
- int m;
-
- m = globv;
- index1 = i;
- index2 = j;
- index3 = k;
- do {
- c = *index1;
- *index1++ = *index3;
- *index3++ = *index2;
- *index2++ = c;
- } while(--m);
-}
/* -------- io.c -------- */
@@ -4271,146 +4439,174 @@ char *i, *j, *k;
* shell IO
*/
-static int my_getc( int ec)
+static int my_getc(int ec)
{
- register int c;
+ int c;
- if(e.linep > elinep) {
- while((c=readc()) != '\n' && c)
- ;
+ if (global_env.linep > elinep) {
+ while ((c = readc()) != '\n' && c)
+ continue;
err("input line too long");
- gflg++;
- return(c);
+ gflg = 1;
+ return c;
}
c = readc();
- if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
- if(c == '\\') {
+ if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
+ if (c == '\\') {
c = readc();
if (c == '\n' && ec != '\"')
- return(my_getc(ec));
+ return my_getc(ec);
c |= QUOTE;
}
}
- return(c);
+ return c;
}
-static void
-unget(c)
-int c;
+static void unget(int c)
{
- if (e.iop >= e.iobase)
- e.iop->peekc = c;
+ if (global_env.iop >= global_env.iobase)
+ global_env.iop->peekc = c;
}
-static int
-eofc()
-
+static int eofc(void)
{
- return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
+ return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
}
-static int
-readc()
+static int readc(void)
{
- register int c;
+ int c;
- for (; e.iop >= e.iobase; e.iop--)
- if ((c = e.iop->peekc) != '\0') {
- e.iop->peekc = 0;
- return(c);
+ RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
+
+ for (; global_env.iop >= global_env.iobase; global_env.iop--) {
+ RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
+ c = global_env.iop->peekc;
+ if (c != '\0') {
+ global_env.iop->peekc = 0;
+ return c;
}
- else {
- if (e.iop->prev != 0) {
- if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
- if (c == -1) {
- e.iop++;
- continue;
- }
- if (e.iop == iostack)
- ioecho(c);
- return(e.iop->prev = c);
- }
- else if (e.iop->task == XIO && e.iop->prev != '\n') {
- e.iop->prev = 0;
- if (e.iop == iostack)
+ if (global_env.iop->prev != 0) {
+ c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
+ if (c != '\0') {
+ if (c == -1) {
+ global_env.iop++;
+ continue;
+ }
+ if (global_env.iop == iostack)
+ ioecho(c);
+ global_env.iop->prev = c;
+ return c;
+ }
+ if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
+ global_env.iop->prev = 0;
+ if (global_env.iop == iostack)
ioecho('\n');
- return '\n';
- }
- }
- if (e.iop->task == XIO) {
- if (multiline)
- return e.iop->prev = 0;
- if (interactive && e.iop == iostack+1) {
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
- current_prompt=prompt->value;
+ return '\n';
+ }
+ }
+ if (global_env.iop->task == XIO) {
+ if (multiline) {
+ global_env.iop->prev = 0;
+ return 0;
+ }
+ if (interactive && global_env.iop == iostack + 1) {
+#if ENABLE_FEATURE_EDITING
+ current_prompt = prompt->value;
#else
- prs(prompt->value);
+ prs(prompt->value);
#endif
}
- }
}
- if (e.iop >= iostack)
- return(0);
+ } /* FOR */
+
+ if (global_env.iop >= iostack) {
+ RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
+ return 0;
+ }
+
+ DBGPRINTF(("READC: leave()...\n"));
leave();
/* NOTREACHED */
- return(0);
+ return 0;
}
-static void
-ioecho(c)
-char c;
+static void ioecho(char c)
{
- if (flag['v'])
- write(2, &c, sizeof c);
+ if (FLAG['v'])
+ write(STDERR_FILENO, &c, sizeof c);
}
-static void
-pushio(struct ioarg *argp, int (*fn)(struct ioarg *))
+static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
{
- if (++e.iop >= &iostack[NPUSH]) {
- e.iop--;
+ DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
+ argp->afid, global_env.iop));
+
+ /* Set env ptr for io source to next array spot and check for array overflow */
+ if (++global_env.iop >= &iostack[NPUSH]) {
+ global_env.iop--;
err("Shell input nested too deeply");
- gflg++;
+ gflg = 1;
return;
}
- e.iop->iofn = (int (*)(struct ioarg *, struct io *))fn;
+
+ /* We did not overflow the NPUSH array spots so setup data structs */
+
+ global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
if (argp->afid != AFID_NOBUF)
- e.iop->argp = argp;
+ global_env.iop->argp = argp;
else {
- e.iop->argp = ioargstack + (e.iop - iostack);
- *e.iop->argp = *argp;
- e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
- if (isatty(e.iop->argp->afile) == 0 &&
- (e.iop == &iostack[0] ||
- lseek(e.iop->argp->afile, 0L, 1) != -1)) {
- if (++bufid == AFID_NOBUF)
- bufid = AFID_ID;
- e.iop->argp->afid = bufid;
- }
- }
-
- e.iop->prev = ~'\n';
- e.iop->peekc = 0;
- e.iop->xchar = 0;
- e.iop->nlcount = 0;
+
+ global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
+ *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
+
+ /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
+
+ if (global_env.iop == &iostack[0])
+ global_env.iop->argp->afbuf = &mainbuf;
+ else
+ global_env.iop->argp->afbuf = &sharedbuf;
+
+ /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
+ /* This line appears to be active when running scripts from command line */
+ if ((isatty(global_env.iop->argp->afile) == 0)
+ && (global_env.iop == &iostack[0]
+ || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
+ if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
+ bufid = AFID_ID; /* AFID_ID = 0 */
+
+ global_env.iop->argp->afid = bufid; /* assign buffer id */
+ }
+
+ DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
+ iostack, global_env.iop, global_env.iop->argp->afbuf));
+ DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
+ &mainbuf, &sharedbuf, bufid, global_env.iop));
+
+ }
+
+ global_env.iop->prev = ~'\n';
+ global_env.iop->peekc = 0;
+ global_env.iop->xchar = 0;
+ global_env.iop->nlcount = 0;
+
if (fn == filechar || fn == linechar)
- e.iop->task = XIO;
- else if (fn == (int(*)(struct ioarg *))gravechar || fn == (int(*)(struct ioarg *))qgravechar)
- e.iop->task = XGRAVE;
+ global_env.iop->task = XIO;
+ else if (fn == (int (*)(struct ioarg *)) gravechar
+ || fn == (int (*)(struct ioarg *)) qgravechar)
+ global_env.iop->task = XGRAVE;
else
- e.iop->task = XOTHER;
+ global_env.iop->task = XOTHER;
}
-static struct io *
-setbase(ip)
-struct io *ip;
+static struct io *setbase(struct io *ip)
{
- register struct io *xp;
+ struct io *xp;
- xp = e.iobase;
- e.iobase = ip;
- return(xp);
+ xp = global_env.iobase;
+ global_env.iobase = ip;
+ return xp;
}
/*
@@ -4418,199 +4614,188 @@ struct io *ip;
*/
/*
- * Produce the characters of a string, then a newline, then EOF.
+ * Produce the characters of a string, then a newline, then NUL.
*/
-static int
-nlchar(ap)
-register struct ioarg *ap;
+static int nlchar(struct ioarg *ap)
{
- register int c;
+ char c;
if (ap->aword == NULL)
- return(0);
- if ((c = *ap->aword++) == 0) {
+ return '\0';
+ c = *ap->aword++;
+ if (c == '\0') {
ap->aword = NULL;
- return('\n');
+ return '\n';
}
- return(c);
+ return c;
}
/*
* Given a list of words, produce the characters
* in them, with a space after each word.
*/
-static int
-wdchar(ap)
-register struct ioarg *ap;
+static int wdchar(struct ioarg *ap)
{
- register char c;
- register char **wl;
+ char c;
+ char **wl;
- if ((wl = ap->awordlist) == NULL)
- return(0);
+ wl = ap->awordlist;
+ if (wl == NULL)
+ return 0;
if (*wl != NULL) {
- if ((c = *(*wl)++) != 0)
- return(c & 0177);
+ c = *(*wl)++;
+ if (c != 0)
+ return c & 0177;
ap->awordlist++;
- return(' ');
+ return ' ';
}
ap->awordlist = NULL;
- return('\n');
+ return '\n';
}
/*
* Return the characters of a list of words,
* producing a space between them.
*/
-static int
-dolchar(ap)
-register struct ioarg *ap;
+static int dolchar(struct ioarg *ap)
{
- register char *wp;
+ char *wp;
- if ((wp = *ap->awordlist++) != NULL) {
- PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
- return(-1);
+ wp = *ap->awordlist++;
+ if (wp != NULL) {
+ PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
+ return -1;
}
- return(0);
+ return 0;
}
-static int
-xxchar(ap)
-register struct ioarg *ap;
+static int xxchar(struct ioarg *ap)
{
- register int c;
+ int c;
if (ap->aword == NULL)
- return(0);
- if ((c = *ap->aword++) == '\0') {
+ return 0;
+ c = *ap->aword++;
+ if (c == '\0') {
ap->aword = NULL;
- return(' ');
+ return ' ';
}
- return(c);
+ return c;
}
/*
* Produce the characters from a single word (string).
*/
-static int
-strchar(ap)
-register struct ioarg *ap;
+static int strchar(struct ioarg *ap)
{
- register int c;
-
- if (ap->aword == NULL || (c = *ap->aword++) == 0)
- return(0);
- return(c);
+ if (ap->aword == NULL)
+ return 0;
+ return *ap->aword++;
}
/*
* Produce quoted characters from a single word (string).
*/
-static int
-qstrchar(ap)
-register struct ioarg *ap;
+static int qstrchar(struct ioarg *ap)
{
- register int c;
+ int c;
- if (ap->aword == NULL || (c = *ap->aword++) == 0)
- return(0);
- return(c|QUOTE);
+ if (ap->aword == NULL)
+ return 0;
+ c = *ap->aword++;
+ if (c)
+ c |= QUOTE;
+ return c;
}
/*
* Return the characters from a file.
*/
-static int
-filechar(ap)
-register struct ioarg *ap;
+static int filechar(struct ioarg *ap)
{
- register int i;
+ int i;
char c;
struct iobuf *bp = ap->afbuf;
if (ap->afid != AFID_NOBUF) {
- if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
- if (i)
- lseek(ap->afile, ap->afpos, 0);
- i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
- if (i <= 0) {
- closef(ap->afile);
- return 0;
- }
- bp->id = ap->afid;
- bp->ebufp = (bp->bufp = bp->buf) + i;
- }
- ap->afpos++;
- return *bp->bufp++ & 0177;
- }
-
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
+ i = (ap->afid != bp->id);
+ if (i || bp->bufp == bp->ebufp) {
+ if (i)
+ lseek(ap->afile, ap->afpos, SEEK_SET);
+
+ i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
+ if (i <= 0) {
+ closef(ap->afile);
+ return 0;
+ }
+
+ bp->id = ap->afid;
+ bp->bufp = bp->buf;
+ bp->ebufp = bp->bufp + i;
+ }
+
+ ap->afpos++;
+ return *bp->bufp++ & 0177;
+ }
+#if ENABLE_FEATURE_EDITING
if (interactive && isatty(ap->afile)) {
- static char mycommand[BUFSIZ];
- static int position = 0, size = 0;
-
- while (size == 0 || position >= size) {
- cmdedit_read_input(current_prompt, mycommand);
- size = strlen(mycommand);
- position = 0;
- }
- c = mycommand[position];
- position++;
- return(c);
- } else
-#endif
- {
- i = safe_read(ap->afile, &c, sizeof(c));
- return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
+ /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
+ static int position = 0, size = 0;
+
+ while (size == 0 || position >= size) {
+ size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
+ if (size < 0) /* Error/EOF */
+ exit(EXIT_SUCCESS);
+ position = 0;
+ /* if Ctrl-C, size == 0 and loop will repeat */
+ }
+ c = filechar_cmdbuf[position];
+ position++;
+ return c;
}
+#endif
+ i = nonblock_safe_read(ap->afile, &c, sizeof(c));
+ return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
}
/*
* Return the characters from a here temp file.
*/
-static int
-herechar(ap)
-register struct ioarg *ap;
+static int herechar(struct ioarg *ap)
{
char c;
-
- if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
+ if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
close(ap->afile);
- c = 0;
+ c = '\0';
}
- return (c);
-
+ return c;
}
/*
* Return the characters produced by a process (`...`).
* Quote them if required, and remove any trailing newline characters.
*/
-static int
-gravechar(ap, iop)
-struct ioarg *ap;
-struct io *iop;
+static int gravechar(struct ioarg *ap, struct io *iop)
{
- register int c;
+ int c;
- if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
+ c = qgravechar(ap, iop) & ~QUOTE;
+ if (c == '\n')
c = ' ';
- return(c);
+ return c;
}
-static int
-qgravechar(ap, iop)
-register struct ioarg *ap;
-struct io *iop;
+static int qgravechar(struct ioarg *ap, struct io *iop)
{
- register int c;
+ int c;
+
+ DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
if (iop->xchar) {
if (iop->nlcount) {
iop->nlcount--;
- return('\n'|QUOTE);
+ return '\n' | QUOTE;
}
c = iop->xchar;
iop->xchar = 0;
@@ -4620,200 +4805,176 @@ struct io *iop;
iop->nlcount++;
iop->xchar = c;
if (c == 0)
- return(c);
+ return c;
iop->nlcount--;
c = '\n';
}
- return(c!=0? c|QUOTE: 0);
+ return c != 0 ? c | QUOTE : 0;
}
/*
* Return a single command (usually the first line) from a file.
*/
-static int
-linechar(ap)
-register struct ioarg *ap;
+static int linechar(struct ioarg *ap)
{
- register int c;
+ int c;
- if ((c = filechar(ap)) == '\n') {
+ c = filechar(ap);
+ if (c == '\n') {
if (!multiline) {
closef(ap->afile);
- ap->afile = -1; /* illegal value */
+ ap->afile = -1; /* illegal value */
}
}
- return(c);
-}
-
-static void
-prs(s)
-register char *s;
-{
- if (*s)
- write(2, s, strlen(s));
-}
-
-static void
-prn(u)
-unsigned u;
-{
- prs(itoa(u));
-}
-
-static void
-closef(i)
-register int i;
-{
- if (i > 2)
- close(i);
-}
-
-static void
-closeall()
-{
- register int u;
-
- for (u=NUFILE; u<NOFILE;)
- close(u++);
+ return c;
}
/*
- * remap fd into Shell's fd space
+ * Remap fd into shell's fd space
*/
-static int
-remap(fd)
-register int fd;
+static int remap(int fd)
{
- register int i;
+ int i;
int map[NOFILE];
+ int newfd;
+
+ DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
- if (fd < e.iofd) {
- for (i=0; i<NOFILE; i++)
+ if (fd < global_env.iofd) {
+ for (i = 0; i < NOFILE; i++)
map[i] = 0;
+
do {
map[fd] = 1;
- fd = dup(fd);
- } while (fd >= 0 && fd < e.iofd);
- for (i=0; i<NOFILE; i++)
+ newfd = dup(fd);
+ fd = newfd;
+ } while (fd >= 0 && fd < global_env.iofd);
+
+ for (i = 0; i < NOFILE; i++)
if (map[i])
close(i);
+
if (fd < 0)
err("too many files open in shell");
}
- return(fd);
+
+ return fd;
}
-static int
-openpipe(pv)
-register int *pv;
+static int openpipe(int *pv)
{
- register int i;
+ int i;
- if ((i = pipe(pv)) < 0)
+ i = pipe(pv);
+ if (i < 0)
err("can't create pipe - try again");
- return(i);
+ return i;
}
-static void
-closepipe(pv)
-register int *pv;
+static void closepipe(int *pv)
{
if (pv != NULL) {
- close(*pv++);
- close(*pv);
+ close(pv[0]);
+ close(pv[1]);
}
}
+
/* -------- here.c -------- */
/*
* here documents
*/
-static void
-markhere(s, iop)
-register char *s;
-struct ioword *iop;
+static void markhere(char *s, struct ioword *iop)
{
- register struct here *h, *lh;
+ struct here *h, *lh;
- h = (struct here *) space(sizeof(struct here));
- if (h == 0)
+ DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
+
+ h = get_space(sizeof(struct here));
+ if (h == NULL)
return;
+
h->h_tag = evalstr(s, DOSUB);
if (h->h_tag == 0)
return;
+
h->h_iop = iop;
iop->io_name = 0;
h->h_next = NULL;
if (inhere == 0)
inhere = h;
- else
- for (lh = inhere; lh!=NULL; lh = lh->h_next)
+ else {
+ for (lh = inhere; lh != NULL; lh = lh->h_next) {
if (lh->h_next == 0) {
lh->h_next = h;
break;
}
- iop->io_flag |= IOHERE|IOXHERE;
- for (s = h->h_tag; *s; s++)
+ }
+ }
+ iop->io_flag |= IOHERE | IOXHERE;
+ for (s = h->h_tag; *s; s++) {
if (*s & QUOTE) {
- iop->io_flag &= ~ IOXHERE;
- *s &= ~ QUOTE;
+ iop->io_flag &= ~IOXHERE;
+ *s &= ~QUOTE;
}
- h->h_dosub = iop->io_flag & IOXHERE;
+ }
+ h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
}
-static void
-gethere()
+static void gethere(void)
{
- register struct here *h, *hp;
+ struct here *h, *hp;
+
+ DBGPRINTF7(("GETHERE: enter...\n"));
/* Scan here files first leaving inhere list in place */
for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
- readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
+ readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
/* Make inhere list active - keep list intact for scraphere */
if (hp != NULL) {
- hp->h_next = acthere;
- acthere = inhere;
- inhere = NULL;
+ hp->h_next = acthere;
+ acthere = inhere;
+ inhere = NULL;
}
}
-static void
-readhere(name, s, ec)
-char **name;
-register char *s;
-int ec;
+static void readhere(char **name, char *s, int ec)
{
int tf;
char tname[30] = ".msh_XXXXXX";
- register int c;
+ int c;
jmp_buf ev;
- char myline [LINELIM+1];
+ char myline[LINELIM + 1];
char *thenext;
+ DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
+
tf = mkstemp(tname);
if (tf < 0)
return;
+
*name = strsave(tname, areanum);
- if (newenv(setjmp(errpt = ev)) != 0)
+ errpt = ev;
+ if (newenv(setjmp(errpt)) != 0)
unlink(tname);
else {
- pushio(e.iop->argp, (int(*)(struct ioarg *))e.iop->iofn);
- e.iobase = e.iop;
+ pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
+ global_env.iobase = global_env.iop;
for (;;) {
- if (interactive && e.iop <= iostack) {
-#ifdef CONFIG_FEATURE_COMMAND_EDITING
- current_prompt=cprompt->value;
+ if (interactive && global_env.iop <= iostack) {
+#if ENABLE_FEATURE_EDITING
+ current_prompt = cprompt->value;
#else
- prs(cprompt->value);
+ prs(cprompt->value);
#endif
}
thenext = myline;
while ((c = my_getc(ec)) != '\n' && c) {
if (ec == '\'')
- c &= ~ QUOTE;
+ c &= ~QUOTE;
if (thenext >= &myline[LINELIM]) {
c = 0;
break;
@@ -4824,10 +4985,12 @@ int ec;
if (strcmp(s, myline) == 0 || c == 0)
break;
*thenext++ = '\n';
- write (tf, myline, (int)(thenext-myline));
+ write(tf, myline, (int) (thenext - myline));
}
if (c == 0) {
- prs("here document `"); prs(s); err("' unclosed");
+ prs("here document `");
+ prs(s);
+ err("' unclosed");
}
quitenv();
}
@@ -4838,70 +5001,73 @@ int ec;
* open here temp file.
* if unquoted here, expand here temp file into second temp file.
*/
-static int
-herein(hname, xdoll)
-char *hname;
-int xdoll;
+static int herein(char *hname, int xdoll)
{
- register int hf;
+ int hf;
int tf;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &tf;
#endif
- if (hname == 0)
- return(-1);
- hf = open(hname, 0);
+ if (hname == NULL)
+ return -1;
+
+ DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
+
+ hf = open(hname, O_RDONLY);
if (hf < 0)
- return (-1);
+ return -1;
+
if (xdoll) {
char c;
char tname[30] = ".msh_XXXXXX";
jmp_buf ev;
-
+
tf = mkstemp(tname);
if (tf < 0)
- return (-1);
- if (newenv(setjmp(errpt = ev)) == 0) {
+ return -1;
+ errpt = ev;
+ if (newenv(setjmp(errpt)) == 0) {
PUSHIO(afile, hf, herechar);
- setbase(e.iop);
+ setbase(global_env.iop);
while ((c = subgetc(0, 0)) != 0) {
- c &= ~ QUOTE;
+ c &= ~QUOTE;
write(tf, &c, sizeof c);
}
quitenv();
} else
unlink(tname);
close(tf);
- tf = open(tname, 0);
+ tf = open(tname, O_RDONLY);
unlink(tname);
- return (tf);
- } else
- return (hf);
+ return tf;
+ }
+ return hf;
}
-static void
-scraphere()
+static void scraphere(void)
{
- register struct here *h;
+ struct here *h;
+
+ DBGPRINTF7(("SCRAPHERE: enter...\n"));
for (h = inhere; h != NULL; h = h->h_next) {
if (h->h_iop && h->h_iop->io_name)
- unlink(h->h_iop->io_name);
+ unlink(h->h_iop->io_name);
}
inhere = NULL;
}
/* unlink here temp files before a freearea(area) */
-static void
-freehere(area)
-int area;
+static void freehere(int area)
{
- register struct here *h, *hl;
+ struct here *h, *hl;
+
+ DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
hl = NULL;
- for (h = acthere; h != NULL; h = h->h_next)
+ for (h = acthere; h != NULL; h = h->h_next) {
if (getarea((char *) h) >= area) {
if (h->h_iop->io_name != NULL)
unlink(h->h_iop->io_name);
@@ -4909,33 +5075,250 @@ int area;
acthere = h->h_next;
else
hl->h_next = h->h_next;
- } else
+ } else {
hl = h;
+ }
+ }
}
+/* -------- sh.c -------- */
+/*
+ * shell
+ */
+
+int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int msh_main(int argc, char **argv)
+{
+ int f;
+ char *s;
+ int cflag;
+ char *name, **ap;
+ int (*iof) (struct ioarg *);
+
+ INIT_G();
+
+ sharedbuf.id = AFID_NOBUF;
+ mainbuf.id = AFID_NOBUF;
+ elinep = line + sizeof(line) - 5;
+
+#if ENABLE_FEATURE_EDITING
+ line_input_state = new_line_input_t(FOR_SHELL);
+#endif
+
+ DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
+
+ initarea();
+ ap = environ;
+ if (ap != NULL) {
+ while (*ap)
+ assign(*ap++, !COPYV);
+ for (ap = environ; *ap;)
+ export(lookup(*ap++));
+ }
+ closeall();
+ areanum = 1;
+
+ shell = lookup("SHELL");
+ if (shell->value == null)
+ setval(shell, (char *)DEFAULT_SHELL);
+ export(shell);
+
+ homedir = lookup("HOME");
+ if (homedir->value == null)
+ setval(homedir, "/");
+ export(homedir);
+
+ setval(lookup("$"), putn(getpid()));
+
+ path = lookup("PATH");
+ if (path->value == null) {
+ /* Can be merged with same string elsewhere in bbox */
+ if (geteuid() == 0)
+ setval(path, bb_default_root_path);
+ else
+ setval(path, bb_default_path);
+ }
+ export(path);
+
+ ifs = lookup("IFS");
+ if (ifs->value == null)
+ setval(ifs, " \t\n");
+
+#ifdef MSHDEBUG
+ mshdbg_var = lookup("MSHDEBUG");
+ if (mshdbg_var->value == null)
+ setval(mshdbg_var, "0");
+#endif
+
+ prompt = lookup("PS1");
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ if (prompt->value == null)
+#endif
+ setval(prompt, DEFAULT_USER_PROMPT);
+ if (geteuid() == 0) {
+ setval(prompt, DEFAULT_ROOT_PROMPT);
+ prompt->status &= ~EXPORT;
+ }
+ cprompt = lookup("PS2");
+#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
+ if (cprompt->value == null)
+#endif
+ setval(cprompt, "> ");
+
+ iof = filechar;
+ cflag = 0;
+ name = *argv++;
+ if (--argc >= 1) {
+ if (argv[0][0] == '-' && argv[0][1] != '\0') {
+ for (s = argv[0] + 1; *s; s++)
+ switch (*s) {
+ case 'c':
+ prompt->status &= ~EXPORT;
+ cprompt->status &= ~EXPORT;
+ setval(prompt, "");
+ setval(cprompt, "");
+ cflag = 1;
+ if (--argc > 0)
+ PUSHIO(aword, *++argv, iof = nlchar);
+ break;
+
+ case 'q':
+ qflag = SIG_DFL;
+ break;
+
+ case 's':
+ /* standard input */
+ break;
+
+ case 't':
+ prompt->status &= ~EXPORT;
+ setval(prompt, "");
+ iof = linechar;
+ break;
+
+ case 'i':
+ interactive = 1;
+ default:
+ if (*s >= 'a' && *s <= 'z')
+ FLAG[(int) *s]++;
+ }
+ } else {
+ argv--;
+ argc++;
+ }
+
+ if (iof == filechar && --argc > 0) {
+ setval(prompt, "");
+ setval(cprompt, "");
+ prompt->status &= ~EXPORT;
+ cprompt->status &= ~EXPORT;
+
+/* Shell is non-interactive, activate printf-based debug */
+#ifdef MSHDEBUG
+ mshdbg = mshdbg_var->value[0] - '0';
+ if (mshdbg < 0)
+ mshdbg = 0;
+#endif
+ DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
+
+ name = *++argv;
+ if (newfile(name))
+ exit(EXIT_FAILURE); /* Exit on error */
+ }
+ }
+
+ setdash();
+
+ /* This won't be true if PUSHIO has been called, say from newfile() above */
+ if (global_env.iop < iostack) {
+ PUSHIO(afile, 0, iof);
+ if (isatty(0) && isatty(1) && !cflag) {
+ interactive = 1;
+#if !ENABLE_FEATURE_SH_EXTRA_QUIET
+#ifdef MSHDEBUG
+ printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
+#else
+ printf("\n\n%s built-in shell (msh)\n", bb_banner);
+#endif
+ printf("Enter 'help' for a list of built-in commands.\n\n");
+#endif
+ }
+ }
+
+ signal(SIGQUIT, qflag);
+ if (name && name[0] == '-') {
+ interactive = 1;
+ f = open(".profile", O_RDONLY);
+ if (f >= 0)
+ next(remap(f));
+ f = open("/etc/profile", O_RDONLY);
+ if (f >= 0)
+ next(remap(f));
+ }
+ if (interactive)
+ signal(SIGTERM, sig);
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, onintr);
+
+/* Handle "msh SCRIPT VAR=val params..." */
+/* Disabled: bash does not do it! */
+#if 0
+ argv++;
+ /* skip leading args of the form VAR=val */
+ while (*argv && assign(*argv, !COPYV)) {
+ argc--;
+ argv++;
+ }
+ argv--;
+#endif
+ dolv = argv;
+ dolc = argc;
+ dolv[0] = name;
+
+ setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
+
+ DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
+
+ for (;;) {
+ if (interactive && global_env.iop <= iostack) {
+#if ENABLE_FEATURE_EDITING
+ current_prompt = prompt->value;
+#else
+ prs(prompt->value);
+#endif
+ }
+ onecommand();
+ /* Ensure that getenv("PATH") stays current */
+ setenv("PATH", path->value, 1);
+ }
+
+ DBGPRINTF(("MSH_MAIN: returning.\n"));
+}
+
/*
* Copyright (c) 1987,1997, Prentice Hall
* All rights reserved.
- *
+ *
* Redistribution and use of the MINIX operating system in source and
* binary forms, with or without modification, are permitted provided
* that the following conditions are met:
- *
+ *
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
- *
+ *
* Neither the name of Prentice Hall nor the names of the software
* authors or contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -4950,4 +5333,3 @@ int area;
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-