[BusyBox] busybox ash upgrade patches

Mark Hatle fray at mvista.com
Wed Dec 19 06:54:52 UTC 2001


Well.. I ran into a couple of minor annoyances in BB's ASH.. (And
honestly I don't even remember what they are anymore..)

Anyway.. so I read the BB ash.c and saw it was based on Debian's ash
0.3.8-5, and I decided to "upgrade".

Attached to this email are 28 patches that proceed to upgrade BB ash to
"Debian ash 0.3.8-32".

Patch order: expandmeta-diff needs to be one of the last applied as it
gets a rej.  The others seem to be failry independent.  The clean-diff
should be the last diff applied as it cleans up warnings and extra
functions.

The "argstr-diff" patch gave me a lot of troubles.. if you play with
this in a piecemeal fashion, this is the last one to play with.  It
apparently depends on another patch to keep things from going haywire. 
I never did figure out which other patch it depended on.. but if you use
only that patch it won't work.

In the _rmescapes function you'll see a #if 0 wrapping a section. 
Unfortunatly I do not understand what is being attempted here..
(compared to the "real" ash.)  It works in teh real ash, doesn't work in
BB ash.  I could not figure out the cause.  If anyone has suggestions
please let me know!

Any questions please let me know.  (If you are interested in a changelog
type thing just get the debian ash package, look at it's changelog
between 0.3.8-5 and 0.3.8-32 for a pretty complete change list.)

Any problems/suggestions/flames let me know.
(I am not subscribed to the busybox lists, but I do look at them
occasionally.. so I would prefer if you CCed me on any emails.)

Thanx,
Mark
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 16:13:22 2001
+++ ash.c	Mon Dec 10 16:22:20 2001
@@ -5489,12 +5489,10 @@
 static void
 addfname(const char *name)
 {
-	char *p;
 	struct strlist *sp;
 
-	p = sstrdup(name);
 	sp = (struct strlist *)stalloc(sizeof *sp);
-	sp->text = p;
+	sp->text = sstrdup(name);
 	*exparg.lastp = sp;
 	exparg.lastp = &sp->next;
 }
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:33:28 2001
+++ ash.c	Tue Dec 11 14:36:43 2001
@@ -1137,6 +1137,8 @@
 	"}"
 };
 
+const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
+#define DOLATSTRLEN 4
 
 static int plinno = 1;          /* input line number */
 
@@ -4737,66 +4739,131 @@
 	char *p;
 	int flag;
 {
-	char c;
+	static const char spclchars[] = {
+		'=',
+		':',
+		CTLQUOTEMARK,
+		CTLENDVAR,
+		CTLESC,
+		CTLVAR,
+		CTLBACKQ,
+		CTLBACKQ | CTLQUOTE,
+		CTLENDARI,
+		0
+	};
+	const char *reject = spclchars;
+	int c;
 	int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
-	int firsteq = 1;
+	int breakall = flag & EXP_WORD;
+	int inquotes;
+	size_t length;
+	int startloc;
 
-	if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
+	if (!(flag & EXP_VARTILDE)) {
+		reject += 2;
+	} else if (flag & EXP_VARTILDE2) {
+		reject++;
+	}
+	inquotes = 0;
+	length = 0;
+	if (flag & EXP_TILDE) {
+		flag &= ~EXP_TILDE;
+tilde:
 		p = exptilde(p, flag);
+	}
+start:
+	startloc = expdest - stackblock();
 	for (;;) {
-		switch (c = *p++) {
+		length += strcspn(p + length, reject);
+		c = p[length];
+		if ((c && !(c & 0x80)) || c == CTLENDARI) {
+			/* c == '=' || c == ':' || c == CTLENDARI */
+			length++;
+		}
+		if (length > 0) {
+			int newloc;
+			/* expdest = stnputs(p, length, expdest); */
+			CHECKSTRSPACE(length, expdest);
+			expdest = mempcpy(expdest, p, length);
+			sstrnleft -= length;
+			newloc = expdest - stackblock();
+			if (breakall && !inquotes && newloc > startloc) {
+				recordregion(startloc, newloc, 0);
+			}
+			startloc = newloc;
+		}
+		p += length + 1;
+		length = 0;
+
+		switch (c) {
 		case '\0':
+			goto breakloop;
+		case '=':
+			if (flag & EXP_VARTILDE2) {
+				p--;
+				continue;
+			}
+			flag |= EXP_VARTILDE2;
+			reject++;
+			/* fall through */
+		case ':':
+			/*
+			 * sort of a hack - expand tildes in variable
+			 * assignments (after the first '=' and after ':'s).
+			 */
+			if (*--p == '~') {
+				goto tilde;
+			}
+			continue;
+		}
+
+		switch (c) {
 		case CTLENDVAR: /* ??? */
 			goto breakloop;
 		case CTLQUOTEMARK:
 			/* "$@" syntax adherence hack */
-			if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
-				break;
-			if ((flag & EXP_FULL) != 0)
-				STPUTC(c, expdest);
+			if (
+				!inquotes &&
+				!memcmp(p, dolatstr, DOLATSTRLEN) &&
+				(p[4] == CTLQUOTEMARK || (
+					p[4] == CTLENDVAR &&
+					p[5] == CTLQUOTEMARK
+				))
+			) {
+				p = evalvar(p + 1, flag) + 1;
+				goto start;
+			}
+			inquotes = !inquotes;
+addquote:
+			if (quotes) {
+				p--;
+				length++;
+				startloc++;
+			}
 			break;
 		case CTLESC:
-			if (quotes)
-				STPUTC(c, expdest);
-			c = *p++;
-			STPUTC(c, expdest);
-			break;
+			startloc++;
+			length++;
+			goto addquote;
 		case CTLVAR:
 			p = evalvar(p, flag);
-			break;
+			goto start;
 		case CTLBACKQ:
+			c = 0;
 		case CTLBACKQ|CTLQUOTE:
-			expbackq(argbackq->n, c & CTLQUOTE, flag);
+			expbackq(argbackq->n, c, quotes);
 			argbackq = argbackq->next;
-			break;
-#ifdef ASH_MATH_SUPPORT
+			goto start;
 		case CTLENDARI:
-			expari(flag);
-			break;
+#ifdef ASH_MATH_SUPPORT
+			p--;
+			expari(quotes);
+			goto start;
 #endif
-		case ':':
-		case '=':
-			/*
-			 * sort of a hack - expand tildes in variable
-			 * assignments (after the first '=' and after ':'s).
-			 */
-			STPUTC(c, expdest);
-			if (flag & EXP_VARTILDE && *p == '~') {
-				if (c == '=') {
-					if (firsteq)
-						firsteq = 0;
-					else
-						break;
-				}
-				p = exptilde(p, flag);
-			}
-			break;
-		default:
-			STPUTC(c, expdest);
 		}
 	}
-breakloop:;
-	return;
+breakloop:
+	;
 }
 
 static char *
@@ -9563,14 +9563,6 @@
 	n1 = NULL;
 	rpp = &redir;
 
-	/* Check for redirection which may precede command */
-	while (readtoken() == TREDIR) {
-		*rpp = n2 = redirnode;
-		rpp = &n2->nfile.next;
-		parsefname();
-	}
-	tokpushback++;
-
 	switch (readtoken()) {
 	case TIF:
 		n1 = (union node *)stalloc(sizeof (struct nif));
@@ -9637,11 +9629,9 @@
 			if (lasttoken != TNL && lasttoken != TSEMI)
 				synexpect(-1);
 		} else {
-			static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
-								   '@', '=', '\0'};
 			n2 = (union node *)stalloc(sizeof (struct narg));
 			n2->type = NARG;
-			n2->narg.text = argvars;
+			n2->narg.text = (char *)dolatstr;
 			n2->narg.backquote = NULL;
 			n2->narg.next = NULL;
 			n1->nfor.args = n2;
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:18:04 2001
+++ ash.c	Sat Dec  8 19:18:53 2001
@@ -3209,6 +3209,8 @@
 {
 	int n = argc > 1 ? number(argv[1]) : 1;
 
+	if (n <= 0)
+		error("Illegal number: %s", argv[1]);
 	if (n > loopnest)
 		n = loopnest;
 	if (n > 0) {
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:52:39 2001
+++ ash.c	Tue Dec 11 14:58:04 2001
@@ -1171,8 +1171,6 @@
 static void dotrap (void);
 static int  decode_signal (const char *, int);
 
-static void shprocvar(void);
-static void deletefuncs(void);
 static void setparam (char **);
 static void freeparam (volatile struct shparam *);
 
@@ -1757,7 +1755,6 @@
 };
 #define NUMBUILTINS  (sizeof (builtincmds) / sizeof (struct builtincmd) )
 
-static const struct builtincmd *DOTCMD = &builtincmds[0];
 static struct builtincmd *BLTINCMD;
 static struct builtincmd *EXECCMD;
 static struct builtincmd *EVALCMD;
@@ -3403,65 +3400,6 @@
 }
 
 
-static void
-initshellproc(void) {
-
-#ifdef ASH_ALIAS
-      /* from alias.c: */
-      {
-	      rmaliases();
-      }
-#endif
-      /* from eval.c: */
-      {
-	      exitstatus = 0;
-      }
-
-      /* from exec.c: */
-      {
-	      deletefuncs();
-      }
-
-      /* from jobs.c: */
-      {
-	      backgndpid = -1;
-#ifdef JOBS
-	      jobctl = 0;
-#endif
-      }
-
-      /* from options.c: */
-      {
-	      int i;
-
-	      for (i = 0; i < NOPTS; i++)
-		      optent_val(i) = 0;
-	      optschanged();
-
-      }
-
-      /* from redir.c: */
-      {
-	      clearredir();
-      }
-
-      /* from trap.c: */
-      {
-	      char *sm;
-
-	      clear_traps();
-	      for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
-		      if (*sm == S_IGN)
-			      *sm = S_HARD_IGN;
-	      }
-      }
-
-      /* from var.c: */
-      {
-	      shprocvar();
-      }
-}
-
 static int preadbuffer(void);
 static void pushfile (void);
 
@@ -4150,34 +4088,6 @@
 
 
 /*
- * Delete all functions.
- */
-
-static void
-deletefuncs(void) {
-	struct tblentry **tblp;
-	struct tblentry **pp;
-	struct tblentry *cmdp;
-
-	INTOFF;
-	for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
-		pp = tblp;
-		while ((cmdp = *pp) != NULL) {
-			if (cmdp->cmdtype == CMDFUNCTION) {
-				*pp = cmdp->next;
-				freefunc(cmdp->param.func);
-				ckfree(cmdp);
-			} else {
-				pp = &cmdp->next;
-			}
-		}
-	}
-	INTON;
-}
-
-
-
-/*
  * Locate a command in the command hash table.  If "add" is nonzero,
  * add the command to the table if it is not already present.  The
  * variable "lastcmdentry" is set to point to the address of the link
@@ -11113,7 +11023,7 @@
 {
 	union node *n;
 	struct redirtab *sv = NULL;
-	int i;
+	int i = 0;
 	int fd;
 	int newfd;
 	int try;
@@ -12544,39 +12454,6 @@
 	*ep = NULL;
 	return env;
 }
-
-
-/*
- * Called when a shell procedure is invoked to clear out nonexported
- * variables.  It is also necessary to reallocate variables of with
- * VSTACK set since these are currently allocated on the stack.
- */
-
-static void
-shprocvar(void) {
-	struct var **vpp;
-	struct var *vp, **prev;
-
-	for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
-		for (prev = vpp ; (vp = *prev) != NULL ; ) {
-			if ((vp->flags & VEXPORT) == 0) {
-				*prev = vp->next;
-				if ((vp->flags & VTEXTFIXED) == 0)
-					ckfree(vp->text);
-				if ((vp->flags & VSTRFIXED) == 0)
-					ckfree(vp);
-			} else {
-				if (vp->flags & VSTACK) {
-					vp->text = savestr(vp->text);
-					vp->flags &=~ VSTACK;
-				}
-				prev = &vp->next;
-			}
-		}
-	}
-	initvar();
-}
-
 
 
 /*
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 12:11:00 2001
+++ ash.c	Fri Nov 30 12:12:08 2001
@@ -2198,7 +2198,7 @@
 
 struct errname {
 	short errcode;          /* error number */
-	char  action;           /* operation which encountered the error */
+	short action;           /* operation which encountered the error */
 };
 
 /*
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 12:42:22 2001
+++ ash.c	Fri Nov 30 15:03:54 2001
@@ -2451,6 +2451,7 @@
 
 	loopnest++;
 	status = 0;
+	flags &= EV_TESTED;
 	for (;;) {
 		evaltree(n->nbinary.ch1, EV_TESTED);
 		if (evalskip) {
@@ -2469,7 +2470,7 @@
 			if (exitstatus == 0)
 				break;
 		}
-		evaltree(n->nbinary.ch2, flags & EV_TESTED);
+		evaltree(n->nbinary.ch2, flags);
 		status = exitstatus;
 		if (evalskip)
 			goto skipping;
@@ -2498,9 +2499,10 @@
 
 	exitstatus = 0;
 	loopnest++;
+	flags &= EV_TESTED;
 	for (sp = arglist.list ; sp ; sp = sp->next) {
 		setvar(n->nfor.var, sp->text, 0);
-		evaltree(n->nfor.body, flags & EV_TESTED);
+		evaltree(n->nfor.body, flags);
 		if (evalskip) {
 			if (evalskip == SKIPCONT && --skipcount <= 0) {
 				evalskip = 0;
@@ -2550,8 +2552,9 @@
  */
 
 static inline void
-evalpipe(n)
+evalpipe(n, flags)
 	union node *n;
+	int flags;
 {
 	struct job *jp;
 	struct nodelist *lp;
@@ -2563,6 +2566,7 @@
 	pipelen = 0;
 	for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
 		pipelen++;
+	flags |= EV_EXIT;
 	INTOFF;
 	jp = makejob(n, pipelen);
 	prevfd = -1;
@@ -2577,38 +2581,29 @@
 		}
 		if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
 			INTON;
+			if (pip[1] >= 0) {
+				close(pip[0]);
+			}
 			if (prevfd > 0) {
-				close(0);
-				dup_as_newfd(prevfd, 0);
+				dup2(prevfd, 0);
 				close(prevfd);
-				if (pip[0] == 0) {
-					pip[0] = -1;
-				}
 			}
-			if (pip[1] >= 0) {
-				if (pip[0] >= 0) {
-					close(pip[0]);
-				}
-				if (pip[1] != 1) {
-					close(1);
-					dup_as_newfd(pip[1], 1);
-					close(pip[1]);
-				}
+			if (pip[1] > 1) {
+				dup2(pip[1], 1);
+				close(pip[1]);
 			}
-			evaltree(lp->n, EV_EXIT);
+			evaltree(lp->n, flags);
 		}
 		if (prevfd >= 0)
 			close(prevfd);
 		prevfd = pip[0];
 		close(pip[1]);
 	}
-	INTON;
 	if (n->npipe.backgnd == 0) {
-		INTOFF;
 		exitstatus = waitforjob(jp);
 		TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
-		INTON;
 	}
+	INTON;
 }
 
 static void find_command (const char *, struct cmdentry *, int, const char *);
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 15:07:05 2001
+++ ash.c	Sat Dec  8 19:11:26 2001
@@ -2081,6 +2081,7 @@
 #define EXERROR 1       /* a generic error */
 #define EXSHELLPROC 2   /* execute a shell procedure */
 #define EXEXEC 3        /* command execution failed */
+#define EXREDIR 4	/* redirection error */
 
 static struct jmploc *handler;
 static int exception;
@@ -2640,7 +2641,7 @@
 	volatile int e;
 	char *lastarg;
 	const char *path;
-	const struct builtincmd *firstbltin;
+	int spclbltin;
 	struct jmploc *volatile savehandler;
 	struct jmploc jmploc;
 #if __GNUC__
@@ -2663,25 +2664,9 @@
 	for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
 		expandarg(argp, &varlist, EXP_VARTILDE);
 	}
-	for (
-		argp = cmd->ncmd.args; argp && !arglist.list;
-		argp = argp->narg.next
-	) {
+	for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
 		expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
 	}
-	if (argp) {
-		struct builtincmd *bcmd;
-		int pseudovarflag;
-		bcmd = find_builtin(arglist.list->text);
-		pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
-		for (; argp; argp = argp->narg.next) {
-			if (pseudovarflag && isassignment(argp->narg.text)) {
-				expandarg(argp, &arglist, EXP_VARTILDE);
-				continue;
-			}
-			expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
-		}
-	}
 	*arglist.lastp = NULL;
 	*varlist.lastp = NULL;
 	expredir(cmd->ncmd.redirect);
@@ -2711,7 +2696,8 @@
 	/* Now locate the command. */
 	if (argc == 0) {
 		cmdentry.cmdtype = CMDBUILTIN;
-		firstbltin = cmdentry.u.cmd = BLTINCMD;
+		cmdentry.u.cmd = BLTINCMD;
+		spclbltin = 1;
 	} else {
 		const char *oldpath;
 		int findflag = DO_ERR;
@@ -2728,7 +2714,7 @@
 			}
 		oldpath = path;
 		oldfindflag = findflag;
-		firstbltin = 0;
+		spclbltin = -1;
 		for(;;) {
 			find_command(argv[0], &cmdentry, findflag, path);
 			if (cmdentry.cmdtype == CMDUNKNOWN) {   /* command not found */
@@ -2739,8 +2725,12 @@
 			if (cmdentry.cmdtype != CMDBUILTIN) {
 				break;
 			}
-			if (!firstbltin) {
-				firstbltin = cmdentry.u.cmd;
+			if (spclbltin < 0) {
+				spclbltin =
+					!!(
+						IS_BUILTIN_SPECIAL(cmdentry.u.cmd)
+					) * 2
+				;
 			}
 			if (cmdentry.u.cmd == BLTINCMD) {
 				for(;;) {
@@ -2789,14 +2779,21 @@
 	}
 
 	/* Fork off a child process if necessary. */
-	if (cmd->ncmd.backgnd
-	 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
+	if (
+		cmd->ncmd.backgnd || (
+	 		cmdentry.cmdtype == CMDNORMAL && 
+			(!(flags & EV_EXIT) || trap[0])
+		)
 	) {
+		INTOFF;
 		jp = makejob(cmd, 1);
 		mode = cmd->ncmd.backgnd;
 		if (forkshell(jp, cmd, mode) != 0)
 			goto parent;    /* at end of routine */
+		FORCEINTON;
 		flags |= EV_EXIT;
+	} else {
+		flags &= ~EV_EXIT;
 	}
 
 	/* This is the child process if a fork occurred. */
@@ -2806,7 +2803,6 @@
 		trputs("Shell function:  ");  trargs(argv);
 #endif
 		exitstatus = oexitstatus;
-		redirect(cmd->ncmd.redirect, REDIR_PUSH);
 		saveparam = shellparam;
 		shellparam.malloc = 0;
 		shellparam.nparam = argc - 1;
@@ -2816,15 +2812,14 @@
 		localvars = NULL;
 		INTON;
 		if (setjmp(jmploc.loc)) {
-			if (exception == EXSHELLPROC) {
-				freeparam((volatile struct shparam *)
-				    &saveparam);
-			} else {
-				saveparam.optind = shellparam.optind;
-				saveparam.optoff = shellparam.optoff;
-				freeparam(&shellparam);
-				shellparam = saveparam;
-			}
+			if (exception == EXREDIR) {
+				exitstatus = 2;
+				goto funcdone;
+			}
+			saveparam.optind = shellparam.optind;
+			saveparam.optoff = shellparam.optoff;
+			freeparam(&shellparam);
+			shellparam = saveparam;
 			poplocalvars();
 			localvars = savelocalvars;
 			handler = savehandler;
@@ -2832,11 +2827,12 @@
 		}
 		savehandler = handler;
 		handler = &jmploc;
-		for (sp = varlist.list ; sp ; sp = sp->next)
-			mklocal(sp->text);
+		redirect(cmd->ncmd.redirect, REDIR_PUSH);
+		listsetvar(varlist.list);
 		funcnest++;
 		evaltree(cmdentry.u.func, flags & EV_TESTED);
 		funcnest--;
+funcdone:
 		INTOFF;
 		poplocalvars();
 		localvars = savelocalvars;
@@ -2851,16 +2847,14 @@
 			evalskip = 0;
 			skipcount = 0;
 		}
-		if (flags & EV_EXIT)
-			exitshell(exitstatus);
 	} else if (cmdentry.cmdtype == CMDBUILTIN) {
+		int redir;
 #ifdef DEBUG
 		trputs("builtin command:  ");  trargs(argv);
 #endif
-		mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
-		redirect(cmd->ncmd.redirect, mode);
+		redir = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
 		savecmdname = commandname;
-		if (IS_BUILTIN_SPECIAL(firstbltin)) {
+		if (spclbltin) {
 			listsetvar(varlist.list);
 		} else {
 			cmdenviron = varlist.list;
@@ -2873,6 +2867,7 @@
 		}
 		savehandler = handler;
 		handler = &jmploc;
+		redirect(cmd->ncmd.redirect, redir);
 		commandname = argv[0];
 		argptr = argv + 1;
 		optptr = NULL;                  /* initialize nextopt */
@@ -2880,19 +2875,13 @@
 		flushall();
 cmddone:
 		cmdenviron = NULL;
-		if (e != EXSHELLPROC) {
-			commandname = savecmdname;
-			if (flags & EV_EXIT)
-				exitshell(exitstatus);
-		}
+		commandname = savecmdname;
 		handler = savehandler;
 		if (e != -1) {
-			if ((e != EXERROR && e != EXEXEC)
-			   || cmdentry.u.cmd == BLTINCMD
-			   || cmdentry.u.cmd == DOTCMD
-			   || cmdentry.u.cmd == EVALCMD
-			   || cmdentry.u.cmd == EXECCMD)
-				exraise(e);
+			if (e == EXINT || spclbltin & 2) {
+				if (e == EXREDIR)
+					exraise(e);
+			}
 			FORCEINTON;
 		}
 		if (cmdentry.u.cmd != EXECCMD)
@@ -2912,10 +2901,9 @@
 
 parent: /* parent process gets here (if we forked) */
 	if (mode == 0) {        /* argument to fork */
-		INTOFF;
 		exitstatus = waitforjob(jp);
-		INTON;
 	}
+	INTON;
 
 out:
 	if (lastarg)
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:12:35 2001
+++ ash.c	Sat Dec  8 19:17:03 2001
@@ -3041,17 +3041,22 @@
 	int backgnd = (n->type == NBACKGND);
 
 	expredir(n->nredir.redirect);
+	if (!backgnd && flags & EV_EXIT && !trap[0])
+		goto nofork;
+	INTOFF;
 	jp = makejob(n, 1);
 	if (forkshell(jp, n, backgnd) == 0) {
+		INTON;
+		flags |= EV_EXIT;
 		if (backgnd)
 			flags &=~ EV_TESTED;
+nofork:
 		redirect(n->nredir.redirect, 0);
-		evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
+		evaltreenr(n->nredir.n, flags);
+		/* never returns */
 	}
 	if (! backgnd) {
-		INTOFF;
 		exitstatus = waitforjob(jp);
-		INTON;
 	}
 }
 
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 12:24:29 2001
+++ ash.c	Fri Nov 30 12:40:02 2001
@@ -2311,10 +2311,12 @@
 static int exitstatus;                  /* exit status of last command */
 static int oexitstatus;         /* saved exit status */
 
+static int defun (char *, union node *);
 static void evalsubshell (const union node *, int);
 static void expredir (union node *);
 static void prehash (union node *);
 static void eprintlist (struct strlist *);
+static void evaltreenr __P((union node *, int)) __attribute__ ((noreturn));
 
 static union node *parsecmd(int);
 /*
@@ -2359,7 +2361,7 @@
  * Execute a command or commands contained in a string.
  */
 
-static void evaltree (union node *, int);
+static void evaltree (const union node *, int);
 static void setinputstring (char *);
 static void popfile (void);
 static void setstackmark(struct stackmark *mark);
@@ -2624,7 +2626,7 @@
 
 
 static void
-evalcommand(union node *cmd, int flags)
+evalcommand(const union node *cmd, int flags)
 {
 	struct stackmark smark;
 	union node *argp;
@@ -2930,105 +2932,107 @@
  * Evaluate a parse tree.  The value is left in the global variable
  * exitstatus.
  */
+
 static void
 evaltree(n, flags)
-	union node *n;
+	const union node *n;
 	int flags;
 {
 	int checkexit = 0;
+	void (*evalfn)(const union node *, int);
+	unsigned isor;
+	struct jmploc jmploc;
+	struct jmploc *volatile savehandler;
 	if (n == NULL) {
 		TRACE(("evaltree(NULL) called\n"));
 		goto out;
 	}
 	TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
 	switch (n->type) {
-	case NSEMI:
-		evaltree(n->nbinary.ch1, flags & EV_TESTED);
-		if (evalskip)
-			goto out;
-		evaltree(n->nbinary.ch2, flags);
-		break;
-	case NAND:
-		evaltree(n->nbinary.ch1, EV_TESTED);
-		if (evalskip || exitstatus != 0)
-			goto out;
-		evaltree(n->nbinary.ch2, flags);
-		break;
-	case NOR:
-		evaltree(n->nbinary.ch1, EV_TESTED);
-		if (evalskip || exitstatus == 0)
-			goto out;
-		evaltree(n->nbinary.ch2, flags);
+	default:
+#ifdef DEBUG
+		printf("Node type = %d\n", n->type);
 		break;
+#endif
+	case NFOR:
+		evalfn = evalfor;
+		goto calleval;
 	case NREDIR:
 		expredir(n->nredir.redirect);
+		if (setjmp(jmploc.loc)) {
+			exitstatus = 2;
+			handler = savehandler;
+			goto redirdone;
+		}
+		savehandler = handler;
+		handler = &jmploc;
 		redirect(n->nredir.redirect, REDIR_PUSH);
-		evaltree(n->nredir.n, flags);
+		handler = savehandler;
+		evaltree(n->nredir.n, flags & EV_TESTED);
+redirdone:
 		popredir();
 		break;
-	case NSUBSHELL:
-		evalsubshell(n, flags);
-		break;
-	case NBACKGND:
-		evalsubshell(n, flags);
-		break;
-	case NIF: {
-		evaltree(n->nif.test, EV_TESTED);
-		if (evalskip)
-			goto out;
-		if (exitstatus == 0)
-			evaltree(n->nif.ifpart, flags);
-		else if (n->nif.elsepart)
-			evaltree(n->nif.elsepart, flags);
-		else
-			exitstatus = 0;
-		break;
-	}
 	case NWHILE:
 	case NUNTIL:
-		evalloop(n, flags);
-		break;
-	case NFOR:
-		evalfor(n, flags);
-		break;
+		evalfn = evalloop;
+		goto calleval;
+	case NSUBSHELL:
+	case NBACKGND:
+		evalfn = evalsubshell;
+		goto calleval;
 	case NCASE:
-		evalcase(n, flags);
+		evalfn = evalcase;
+calleval:
+		evalfn(n, flags);
 		break;
-	case NDEFUN: {
-		struct builtincmd *bcmd;
-		struct cmdentry entry;
-		if (
-			(bcmd = find_builtin(n->narg.text)) &&
-			IS_BUILTIN_SPECIAL(bcmd)
-		) {
-			out2fmt("%s is a special built-in\n", n->narg.text);
-			exitstatus = 1;
-			break;
-		}
-		entry.cmdtype = CMDFUNCTION;
-		entry.u.func = copyfunc(n->narg.next);
-		addcmdentry(n->narg.text, &entry);
-		exitstatus = 0;
+	case NDEFUN:
+		exitstatus = defun(n->narg.text, n->narg.next);
 		break;
-	}
+	case NPIPE:
+		evalfn = evalpipe;
+		goto checkexit;
+	case NCMD:
+		evalfn = evalcommand;
+checkexit:
+		checkexit = 1;
+		goto calleval;
 	case NNOT:
 		evaltree(n->nnot.com, EV_TESTED);
 		exitstatus = !exitstatus;
 		break;
-
-	case NPIPE:
-		evalpipe(n);
-		checkexit = 1;
-		break;
-	case NCMD:
-		evalcommand(n, flags);
-		checkexit = 1;
+	case NAND:
+	case NOR:
+	case NSEMI:
+#if NAND + 1 != NOR 
+#error NAND + 1 != NOR
+#endif
+		isor = n->type - NAND;
+		evaltree(
+			n->nbinary.ch1,
+			(flags | ((isor >> 1) - 1)) & EV_TESTED
+		);
+		if (!exitstatus == isor)
+			break;
+		if (!evalskip) {
+			n = n->nbinary.ch2;
+evaln:
+			evalfn = evaltree;
+			goto calleval;
+		}
 		break;
-#ifdef DEBUG
-	default:
-		printf("Node type = %d\n", n->type);
+	case NIF:
+		evaltree(n->nif.test, EV_TESTED);
+		if (evalskip)
+			break;
+		if (exitstatus == 0) {
+			n = n->nif.ifpart;
+			goto evaln;
+		} else if (n->nif.elsepart) {
+			n = n->nif.elsepart;
+			goto evaln;
+		} else
+			exitstatus = 0;
 		break;
-#endif
 	}
 out:
 	if (pendingsigs)
@@ -3040,6 +3044,9 @@
 		exitshell(exitstatus);
 }
 
+
+static void evaltreenr(union node *, int) __attribute__ ((alias("evaltree")));
+
 /*
  * Kick off a subshell to evaluate a tree.
  */
@@ -4222,7 +4229,29 @@
 }
 
 
+/*
+ * Define a shell function.
+ */
 
+static int
+defun(char *name, union node *func)
+{
+	struct cmdentry entry;
+	struct builtincmd *bcmd;
+
+	if (
+		(bcmd = find_builtin(name)) &&
+		IS_BUILTIN_SPECIAL(bcmd)
+	) {
+		out2fmt("%s is a special built-in\n", name);
+		return 1;
+	}
+
+	entry.cmdtype = CMDFUNCTION;
+	entry.u.func = copyfunc(func);
+	addcmdentry(name, &entry);
+	return 0;
+}
 
 
 static const short nodesize[26] = {
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:31:07 2001
+++ ash.c	Sat Dec  8 19:42:38 2001
@@ -411,7 +411,9 @@
 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
 #define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
-
+#define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
+#define EXP_WORD        0x80    /* expand word parameter expansion */
+#define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
 
 #define NOPTS   16
 
@@ -4546,9 +4548,11 @@
 	int varlen;
 	int easy;
 	int quotes = flag & (EXP_FULL | EXP_CASE);
+	int quoted;
 
 	varflags = *p++;
 	subtype = varflags & VSTYPE;
+	quoted = varflags & VSQUOTE;
 	var = p;
 	special = 0;
 	if (! is_name(*p))
@@ -4571,7 +4575,7 @@
 	if (set && subtype != VSPLUS) {
 		/* insert the value of the variable */
 		if (special) {
-			varvalue(var, varflags & VSQUOTE, flag);
+			varvalue(var, quoted, flag);
 			if (subtype == VSLENGTH) {
 				varlen = expdest - stackblock() - startloc;
 				STADJUST(-varlen, expdest);
@@ -4582,8 +4586,7 @@
 			} else {
 				strtodest(
 					val,
-					varflags & VSQUOTE ?
-						DQSYNTAX : BASESYNTAX,
+					quoted ? DQSYNTAX : BASESYNTAX,
 					quotes
 				);
 			}
@@ -4593,27 +4596,29 @@
 	if (subtype == VSPLUS)
 		set = ! set;
 
-	easy = ((varflags & VSQUOTE) == 0 ||
+	easy = (!quoted ||
 		(*var == '@' && shellparam.nparam != 1));
 
 
 	switch (subtype) {
 	case VSLENGTH:
-		expdest = cvtnum(varlen, expdest);
+		cvtnum(varlen, expdest);
 		goto record;
 
 	case VSNORMAL:
 		if (!easy)
 			break;
 record:
-		recordregion(startloc, expdest - stackblock(),
-			     varflags & VSQUOTE);
+		recordregion(startloc, expdest - stackblock(), quoted);
 		break;
 
 	case VSPLUS:
 	case VSMINUS:
 		if (!set) {
-			argstr(p, flag);
+			argstr(
+				p, flag | EXP_TILDE |
+					(quoted ?  EXP_QWORD : EXP_WORD)
+			);
 			break;
 		}
 		if (easy)
@@ -4645,7 +4650,7 @@
 	case VSQUESTION:
 		if (!set) {
 			if (subevalvar(p, var, 0, subtype, startloc,
-				       varflags, quotes)) {
+				       varflags, 0)) {
 				varflags &= ~VSNUL;
 				/*
 				 * Remove any recorded regions beyond
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 16:23:32 2001
+++ ash.c	Mon Dec 10 16:46:57 2001
@@ -5508,18 +5508,19 @@
 	struct strlist *str;
 	int flag;
 {
-	const char *p;
-	glob_t pglob;
 	/* TODO - EXP_REDIR */
 
 	while (str) {
+		const char *p;
+		glob_t pglob;
+
 		if (fflag)
 			goto nometa;
 		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_GROW);
 		INTOFF;
-		switch (glob(p, 0, 0, &pglob)) {
+		switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
 		case 0:
-			if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
+			if (!(pglob.gl_flags & GLOB_MAGCHAR))
 				goto nometa2;
 			addglob(&pglob);
 			globfree(&pglob);
@@ -5567,32 +5568,33 @@
 	struct strlist *str;
 	int flag;
 {
-	char *p;
-	struct strlist **savelastp;
-	struct strlist *sp;
-	char c;
+	static const char metachars[] = {
+		'*', '?', '[', 0
+	};
 	/* TODO - EXP_REDIR */
 
 	while (str) {
+		struct strlist **savelastp;
+		struct strlist *sp;
+		char *p;
+
 		if (fflag)
 			goto nometa;
-		p = str->text;
-		for (;;) {                      /* fast check for meta chars */
-			if ((c = *p++) == '\0')
+		if (!strpbrk(str->text, metachars))
 				goto nometa;
-			if (c == '*' || c == '?' || c == '[' || c == '!')
-				break;
-		}
 		savelastp = exparg.lastp;
+
 		INTOFF;
-		if (expdir == NULL) {
+		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+		{
 			int i = strlen(str->text);
 			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
 		}
 
-		expmeta(expdir, str->text);
+		expmeta(expdir, p);
 		ckfree(expdir);
-		expdir = NULL;
+		if (p != str->text)
+			ckfree(p);
 		INTON;
 		if (exparg.lastp == savelastp) {
 			/*
@@ -5625,7 +5627,6 @@
 	{
 	char *p;
 	const char *cp;
-	char *q;
 	char *start;
 	char *endname;
 	int metaflag;
@@ -5637,17 +5638,15 @@
 
 	metaflag = 0;
 	start = name;
-	for (p = name ; ; p++) {
+	for (p = name; *p; p++) {
 		if (*p == '*' || *p == '?')
 			metaflag = 1;
 		else if (*p == '[') {
-			q = p + 1;
+			char *q = p + 1;
 			if (*q == '!')
 				q++;
 			for (;;) {
-				while (*q == CTLQUOTEMARK)
-					q++;
-				if (*q == CTLESC)
+				if (*q == '\\')
 					q++;
 				if (*q == '/' || *q == '\0')
 					break;
@@ -5656,46 +5655,36 @@
 					break;
 				}
 			}
-		} else if (*p == '!' && p[1] == '!'     && (p == name || p[-1] == '/')) {
-			metaflag = 1;
-		} else if (*p == '\0')
-			break;
-		else if (*p == CTLQUOTEMARK)
-			continue;
-		else if (*p == CTLESC)
+		} else if (*p == '\\')
 			p++;
-		if (*p == '/') {
+		else if (*p == '/') {
 			if (metaflag)
-				break;
+				goto out;
 			start = p + 1;
 		}
 	}
+out:
 	if (metaflag == 0) {    /* we've reached the end of the file name */
 		if (enddir != expdir)
 			metaflag++;
-		for (p = name ; ; p++) {
-			if (*p == CTLQUOTEMARK)
-				continue;
-			if (*p == CTLESC)
+		p = name;
+		do {
+			if (*p == '\\')
 				p++;
 			*enddir++ = *p;
-			if (*p == '\0')
-				break;
-		}
+		} while (*p++);
 		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
 			addfname(expdir);
 		return;
 	}
 	endname = p;
-	if (start != name) {
+	if (name < start) {
 		p = name;
-		while (p < start) {
-			while (*p == CTLQUOTEMARK)
-				p++;
-			if (*p == CTLESC)
+		do {
+			if (*p == '\\')
 				p++;
 			*enddir++ = *p++;
-		}
+		} while (p < start);
 	}
 	if (enddir == expdir) {
 		cp = ".";
@@ -5717,16 +5706,14 @@
 	}
 	matchdot = 0;
 	p = start;
-	while (*p == CTLQUOTEMARK)
-		p++;
-	if (*p == CTLESC)
+	if (*p == '\\')
 		p++;
 	if (*p == '.')
 		matchdot++;
 	while (! int_pending() && (dp = readdir(dirp)) != NULL) {
 		if (dp->d_name[0] == '.' && ! matchdot)
 			continue;
-		if (patmatch(start, dp->d_name, 0)) {
+		if (pmatch(start, dp->d_name)) {
 			if (atend) {
 				strcpy(enddir, dp->d_name);
 				addfname(expdir);
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 15:21:29 2001
+++ ash.c	Mon Dec 10 15:56:27 2001
@@ -4899,39 +4902,45 @@
  * evaluate, place result in (backed up) result, adjust string position.
  */
 static void
-expari(int flag)
+expari(quotes)
+	int quotes;
 {
 	char *p, *start;
-	int errcode;
-	int result;
 	int begoff;
-	int quotes = flag & (EXP_FULL | EXP_CASE);
 	int quoted;
+	int errcode;
+	int result;
 
 	/*      ifsfree(); */
 
 	/*
 	 * This routine is slightly over-complicated for
-	 * efficiency.  First we make sure there is
-	 * enough space for the result, which may be bigger
-	 * than the expression if we add exponentation.  Next we
-	 * scan backwards looking for the start of arithmetic.  If the
-	 * next previous character is a CTLESC character, then we
-	 * have to rescan starting from the beginning since CTLESC
-	 * characters have to be processed left to right.
+	 * efficiency.  Next we scan backwards looking for the
+	 * start of arithmetic.
 	 */
-	CHECKSTRSPACE(10, expdest);
-	USTPUTC('\0', expdest);
 	start = stackblock();
 	p = expdest - 1;
-	while (*p != CTLARI && p >= start)
-		--p;
-	if (*p != CTLARI)
+	*p = '\0';
+	p--;
+	do {
+		int esc;
+
+		while (*p != CTLARI) {
+			p--;
+#ifdef DEBUG
+			if (p < start) {
 		error("missing CTLARI (shouldn't happen)");
-	if (p > start && *(p-1) == CTLESC)
-		for (p = start; *p != CTLARI; p++)
-			if (*p == CTLESC)
-				p++;
+			}
+#endif
+		}
+
+		esc = esclen(start, p);
+		if (!(esc % 2)) {
+			break;
+		}
+
+		p -= esc + 1;
+	} while (1);
 
 	if (p[1] == '"')
 		quoted=1;
@@ -4941,22 +4952,22 @@
 	removerecordregions(begoff);
 	if (quotes)
 		rmescapes(p+2);
-	result = arith(p+2, &errcode);
+
+	start = grabstackstr(expdest);
+	result = arith(p + 2, &errcode);
 	if (errcode < 0) {
 		if(errcode == -2)
-			error("divide by zero");
+			error("arithmetic expression: division by zero: \"%s \"", p+2);
 		else
-			error("syntax error: \"%s\"\n", p+2);
+			error("arith: syntax error: \"%s \"\n", p+2);
 	}
-	snprintf(p, 12, "%d", result);
+	ungrabstackstr(start, p);
+	expdest = p;
 
-	while (*p++)
-		;
+	cvtnum(result);
 
 	if (quoted == 0)
-		recordregion(begoff, p - 1 - start, 0);
-	result = expdest - p + 1;
-	STADJUST(-result, expdest);
+		recordregion(begoff, expdest - stackblock(), 0);
 }
 #endif
 
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 15:59:13 2001
+++ ash.c	Mon Dec 10 16:08:07 2001
@@ -4440,7 +4440,8 @@
 static void expbackq (union node *, int, int);
 static const char *subevalvar (char *, char *, int, int, int, int, int);
 static int varisset (char *, int);
-static void strtodest (const char *, const char *, int);
+static void memtodest(const char *, size_t, const char *, int);
+static inline void strtodest (const char *, const char *, int);
 static void varvalue (char *, int, int);
 static void recordregion (int, int, int);
 static void removerecordregions (int);
@@ -4976,99 +4977,71 @@
  */
 
 static void
-expbackq(cmd, quoted, flag)
+expbackq(cmd, quoted, quotes)
 	union node *cmd;
 	int quoted;
-	int flag;
+	int quotes;
 {
-	volatile struct backcmd in;
+	struct backcmd in;
 	int i;
 	char buf[128];
 	char *p;
 	char *dest = expdest;
-	volatile struct ifsregion saveifs;
-	struct ifsregion *volatile savelastp;
-	struct nodelist *volatile saveargbackq;
-	char lastc;
+	struct ifsregion saveifs;
+	struct ifsregion *savelastp;
+	struct nodelist *saveargbackq;
 	int startloc = dest - stackblock();
 	char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
-	volatile int saveherefd;
-	int quotes = flag & (EXP_FULL | EXP_CASE);
-	struct jmploc jmploc;
-	struct jmploc *volatile savehandler;
-	int ex;
-
-#if __GNUC__
-	/* Avoid longjmp clobbering */
-	(void) &dest;
-	(void) &syntax;
-#endif
+	int saveherefd;
 
 	in.fd = -1;
 	in.buf = 0;
 	in.jp = 0;
 
-	INTOFF;
 	saveifs = ifsfirst;
 	savelastp = ifslastp;
 	saveargbackq = argbackq;
 	saveherefd = herefd;
 	herefd = -1;
-	if ((ex = setjmp(jmploc.loc))) {
-		goto err1;
-	}
-	savehandler = handler;
-	handler = &jmploc;
-	INTON;
 	p = grabstackstr(dest);
+
+	INTOFF;
 	evalbackcmd(cmd, (struct backcmd *) &in);
 	ungrabstackstr(p, dest);
-err1:
-	INTOFF;
 	ifsfirst = saveifs;
 	ifslastp = savelastp;
 	argbackq = saveargbackq;
 	herefd = saveherefd;
-	if (ex) {
-		goto err2;
-	}
 
 	p = in.buf;
-	lastc = '\0';
+	i = in.nleft;
+	if (i == 0)
+		goto read;
 	for (;;) {
-		if (--in.nleft < 0) {
+		memtodest(p, i, syntax, quotes);
+read:
 			if (in.fd < 0)
 				break;
-			i = safe_read(in.fd, buf, sizeof buf);
+		while ((i = safe_read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
 			TRACE(("expbackq: read returns %d\n", i));
 			if (i <= 0)
 				break;
 			p = buf;
-			in.nleft = i - 1;
-		}
-		lastc = *p++;
-		if (lastc != '\0') {
-			if (quotes && syntax[(int)lastc] == CCTL)
-				STPUTC(CTLESC, dest);
-			STPUTC(lastc, dest);
-		}
 	}
 
+	dest = expdest;
+
 	/* Eat all trailing newlines */
 	for (; dest > stackblock() && dest[-1] == '\n';)
 		STUNPUTC(dest);
 
-err2:
 	if (in.fd >= 0)
 		close(in.fd);
 	if (in.buf)
 		ckfree(in.buf);
 	if (in.jp)
 		exitstatus = waitforjob(in.jp);
-	handler = savehandler;
-	if (ex) {
-		longjmp(handler->loc, 1);
-	}
+	INTON;
 	if (quoted == 0)
 		recordregion(startloc, dest - stackblock(), 0);
 	TRACE(("evalbackq: size=%d: \"%.*s\"\n",
@@ -5076,7 +5049,6 @@
 		(dest - stackblock()) - startloc,
 		stackblock() + startloc));
 	expdest = dest;
-	INTON;
 }
 
 static char *
@@ -5273,16 +5245,31 @@
  */
 
 static void
+memtodest(const char *p, size_t len, const char *syntax, int quotes) {
+	char *q = expdest;
+
+	CHECKSTRSPACE(len * 2, q);
+
+	while (len--) {
+		int c = *p++;
+		if (!c)
+			continue;
+		if (quotes && (syntax[c] == CCTL || syntax[c] == CBACK))
+			USTPUTC(CTLESC, q);
+		USTPUTC(c, q);
+	}
+
+	expdest = q;
+}
+
+
+static inline void
 strtodest(p, syntax, quotes)
 	const char *p;
 	const char *syntax;
 	int quotes;
 {
-	while (*p) {
-		if (quotes && syntax[(int) *p] == CCTL)
-			STPUTC(CTLESC, expdest);
-		STPUTC(*p++, expdest);
-	}
+	memtodest(p, strlen(p), syntax, quotes);
 }
 
 /*
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 15:13:52 2001
+++ ash.c	Mon Dec 10 15:18:00 2001
@@ -4793,11 +4801,21 @@
 	int flag;
 {
 	char c, *startp = p;
+	char *name;
 	struct passwd *pw;
 	const char *home;
 	int quotes = flag & (EXP_FULL | EXP_CASE);
+	int startloc;
 
-	while ((c = *p) != '\0') {
+	if (*p == CTLESC && (flag & EXP_QWORD)) {
+		p++;
+	}
+	if (*p != '~') {
+		return startp;
+	}
+	name = p + 1;
+
+	while ((c = *++p) != '\0') {
 		switch(c) {
 		case CTLESC:
 			return (startp);
@@ -4808,24 +4826,26 @@
 				goto done;
 			break;
 		case '/':
+		case CTLENDVAR:
 			goto done;
 		}
-		p++;
 	}
 done:
 	*p = '\0';
-	if (*(startp+1) == '\0') {
+	if (*name == '\0') {
 		if ((home = lookupvar("HOME")) == NULL)
 			goto lose;
 	} else {
-		if ((pw = getpwnam(startp+1)) == NULL)
+		if ((pw = getpwnam(name)) == NULL)
 			goto lose;
 		home = pw->pw_dir;
 	}
 	if (*home == '\0')
 		goto lose;
 	*p = c;
+	startloc = expdest - stackblock();
 	strtodest(home, SQSYNTAX, quotes);
+	recordregion(startloc, expdest - stackblock(), 0);
 	return (p);
 lose:
 	*p = c;
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:41:30 2001
+++ ash.c	Tue Dec 11 14:47:25 2001
@@ -6673,9 +6673,7 @@
 	tcsetpgrp(2, pgrp);
 #endif
 	restartjob(jp);
-	INTOFF;
 	status = waitforjob(jp);
-	INTON;
 	return status;
 }
 
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 16:48:30 2001
+++ ash.c	Tue Dec 11 13:58:21 2001
@@ -7007,17 +7006,9 @@
 			setsignal(SIGTSTP);
 			setsignal(SIGTTOU);
 		} else if (mode == FORK_BG) {
-			ignoresig(SIGINT);
-			ignoresig(SIGQUIT);
-			if ((jp == NULL || jp->nprocs == 0) &&
-			    ! fd0_redirected_p ()) {
-				close(0);
-				if (open(devnull, O_RDONLY) != 0)
-					error(nullerr, devnull);
-			}
-		}
 #else
 		if (mode == FORK_BG) {
+#endif
 			ignoresig(SIGINT);
 			ignoresig(SIGQUIT);
 			if ((jp == NULL || jp->nprocs == 0) &&
@@ -7027,7 +7018,6 @@
 					error(nullerr, devnull);
 			}
 		}
-#endif
 		for (i = njobs, p = jobtab ; --i >= 0 ; p++)
 			if (p->used)
 				freejob(p);
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:19:46 2001
+++ ash.c	Sat Dec  8 19:30:34 2001
@@ -3723,7 +3723,7 @@
 			clearcmdentry(0);
 			return 0;
 		} else if (c == 'v' || c == 'V') {
-			verbose = c;
+			verbose++;
 		}
 	}
 	if (*argptr == NULL) {
@@ -3737,7 +3737,7 @@
 		return 0;
 	}
 	c = 0;
-	while ((name = *argptr++) != NULL) {
+	while ((name = *argptr) != NULL) {
 		if ((cmdp = cmdlookup(name, 0)) != NULL
 		 && (cmdp->cmdtype == CMDNORMAL
 		     || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
@@ -3745,7 +3745,7 @@
 #ifdef ASH_ALIAS
 	/* Then look at the aliases */
 		if ((ap = lookupalias(name, 0)) != NULL) {
-			if (verbose=='v')
+			if (verbose)
 				printf("%s is an alias for %s\n", name, ap->val);
 			else
 				printalias(ap);
@@ -3754,7 +3754,7 @@
 #endif
 			/* First look at the keywords */
 		if (findkwd(name)!=0) {
-			if (verbose=='v')
+			if (verbose)
 				printf("%s is a shell keyword\n", name);
 			else
 				printf(snlfmt, name);
@@ -3765,9 +3765,10 @@
 		if (entry.cmdtype == CMDUNKNOWN) c = 1;
 		else if (verbose) {
 			cmdp = cmdlookup(name, 0);
-			if (cmdp) printentry(cmdp, verbose=='v');
+			if (cmdp) printentry(cmdp, verbose);
 			flushall();
 		}
+		argptr++;
 	}
 	return c;
 }
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:41:30 2001
+++ ash.c	Tue Dec 11 14:45:35 2001
@@ -12320,7 +12320,7 @@
 	 * PS1 depends on uid
 	 */
 	if ((vps1.flags & VEXPORT) == 0) {
-		vpp = hashvar("PS1=");
+		vpp = hashvar("PS1=$ ");
 		vps1.next = *vpp;
 		*vpp = &vps1;
 		vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 12:13:07 2001
+++ ash.c	Fri Nov 30 12:14:43 2001
@@ -291,15 +291,13 @@
 
 #define INTOFF suppressint++
+#ifdef ASH_OPTIMIZE_FOR_SIZE
-#ifndef ASH_OPTIMIZE_FOR_SIZE
-#define INTON { if (--suppressint == 0 && intpending) onint(); }
-#define FORCEINTON {suppressint = 0; if (intpending) onint();}
-#else
 static void __inton (void);
-static void forceinton (void);
 #define INTON __inton()
-#define FORCEINTON forceinton()
+#else
+#define INTON { if (--suppressint == 0 && intpending) onint(); }
 #endif
 
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
 #define CLEAR_PENDING_INT intpending = 0
 #define int_pending() intpending
 
@@ -2295,11 +2293,6 @@
 	if (--suppressint == 0 && intpending) {
 		onint();
 	}
-}
-static void forceinton (void) {
-	suppressint = 0;
-	if (intpending)
-		onint();
 }
 #endif
 
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:00:25 2001
+++ ash.c	Tue Dec 11 14:18:19 2001
@@ -1230,7 +1230,7 @@
 static void readcmdfile (const char *);
 
 static int number (const char *);
-static int is_number (const char *, int *num);
+static int is_number (const char *);
 static char *single_quote (const char *);
 static int nextopt (const char *);
 
@@ -6868,7 +6868,8 @@
 			if (found)
 				return found;
 		}
-	} else if (is_number(name, &pid)) {
+	} else if (is_number(name)) {
+		pid = number(name);
 		for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
 			if (jp->used && jp->nprocs > 0
 			 && jp->ps[jp->nprocs - 1].pid == pid)
@@ -8483,19 +8484,12 @@
  */
 
 static int
-is_number(const char *p, int *intptr)
+is_number(const char *p)
 {
-	int ret = 0;
-
 	do {
 		if (! is_digit(*p))
 			return 0;
-		ret *= 10;
-		ret += digit_val(*p);
-		p++;
-	} while (*p != '\0');
-
-	*intptr = ret;
+	} while (*++p != '\0');
 	return 1;
 }
 
@@ -8507,10 +8501,9 @@
 static int
 number(const char *s)
 {
-	int i;
-	if (! is_number(s, &i))
+	if (! is_number(s))
 		error("Illegal number: %s", s);
-	return i;
+	return atoi(s);
 }
 
 /*
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:48:01 2001
+++ ash.c	Tue Dec 11 14:51:16 2001
@@ -1626,6 +1626,9 @@
 static int histcmd (int, char **);
 static int hashcmd (int, char **);
 static int helpcmd (int, char **);
+#ifdef JOBS
+static int jobidcmd (int, char **);
+#endif
 static int jobscmd (int, char **);
 static int localcmd (int, char **);
 #ifndef BB_PWD
@@ -1720,6 +1723,9 @@
 #endif
 	{ BUILTIN_NOSPEC    "hash", hashcmd },
 	{ BUILTIN_NOSPEC    "help", helpcmd },
+#ifdef JOBS
+	{ BUILTIN_REGULAR   "jobid", jobidcmd },
+#endif
 	{ BUILTIN_REGULAR   "jobs", jobscmd },
 #ifdef JOBS
 	{ BUILTIN_REGULAR   "kill", killcmd },
@@ -6886,6 +6892,28 @@
 	}
 }
 
+
+#ifdef JOBS
+static int
+jobidcmd(argc, argv)
+	int argc;
+	char **argv;
+{
+	struct job *jp;
+	int i;
+
+	jp = getjob(argv[1]);
+	printf("%s %d %ld\n", argv[1], jp->nprocs, (long)jp->ps[0].pid);
+	for (i = 0 ; i < jp->nprocs ; ) {
+		printf(
+			"%d %ld%c", i, (long)jp->ps[i].pid,
+			i+1 < jp->nprocs? ' ' : '\n'
+		);
+		i++;
+	}
+	return 0;
+}
+#endif
 
 
 /*
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 15:21:29 2001
+++ ash.c	Mon Dec 10 15:56:27 2001
@@ -1645,7 +1645,7 @@
 static int ulimitcmd (int, char **);
 static int timescmd (int, char **);
 #ifdef ASH_MATH_SUPPORT
-static int letcmd (int, char **);
+static int expcmd (int, char **);
 #endif
 static int typecmd (int, char **);
 #ifdef ASH_GETOPTS
@@ -1704,6 +1704,9 @@
 	{ BUILTIN_SPECIAL   "eval", evalcmd },
 	{ BUILTIN_SPECIAL   "exec", execcmd },
 	{ BUILTIN_SPECIAL   "exit", exitcmd },
+#ifdef ASH_MATH_SUPPORT
+	{ BUILTIN_REGULAR   "exp", expcmd },
+#endif
 	{ BUILTIN_SPEC_ASSG "export", exportcmd },
 	{ BUILTIN_REGULAR   "false", false_main },
 	{ BUILTIN_REGULAR   "fc", histcmd },
@@ -1720,7 +1723,7 @@
 	{ BUILTIN_REGULAR   "kill", killcmd },
 #endif
 #ifdef ASH_MATH_SUPPORT
-	{ BUILTIN_REGULAR    "let", letcmd },
+	{ BUILTIN_REGULAR    "let", expcmd },
 #endif
 	{ BUILTIN_ASSIGN    "local", localcmd },
 #ifndef BB_PWD
@@ -12864,38 +12875,48 @@
 }
 
 #ifdef ASH_MATH_SUPPORT
-/* The let builtin.  */
-int letcmd(int argc, char **argv)
+/* 
+ * The exp/let builtin.
+ */
+int expcmd(int argc, char **argv)
 {
+	const char *p;
+	char *concat;
+	char **ap;
 	int errcode;
-	long result=0;
-	if (argc == 2) {
-		char *tmp, *expression, p[13];
-		expression = strchr(argv[1], '=');
-		if (!expression) {
-			/* Cannot use 'error()' here, or the return code
-			 * will be incorrect */
-			out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
-			return 0;
+	long i;
+
+	if (argc > 1) {
+		p = argv[1];
+		if (argc > 2) {
+			/*
+			 * concatenate arguments
+			 */
+			STARTSTACKSTR(concat);
+			ap = argv + 2;
+			for (;;) {
+				while (*p)
+					STPUTC(*p++, concat);
+				if ((p = *ap++) == NULL)
+					break;
+				STPUTC(' ', concat);
 		}
-		*expression = '\0';
-		tmp = ++expression;
-		result = arith(tmp, &errcode);
+			STPUTC('\0', concat);
+			p = grabstackstr(concat);
+		}
+	} else
+		p = "";
+
+	i = arith(p, &errcode);
 		if (errcode < 0) {
-			/* Cannot use 'error()' here, or the return code
-			 * will be incorrect */
-			out2fmt("sh: let: ");
 			if(errcode == -2)
-				out2fmt("divide by zero");
+			error("arithmetic expression: division by zero: \"%s\"", p);
 			else
-				out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
-			return 0;
+			error("syntax error: \"%s\"\n", p);
 		}
-		snprintf(p, 12, "%ld", result);
-		setvar(argv[1], savestr(p), 0);
-	} else if (argc >= 3)
-		synerror("invalid operand");
-	return !result;
+
+	printf("%ld\n", i);
+	return (! i);
 }
 #endif
 
-------------- next part --------------
--- ash.c.orig	Fri Nov 30 12:04:36 2001
+++ ash.c	Fri Nov 30 12:08:34 2001
@@ -2115,10 +2115,8 @@
  * Called from trap.c when a SIGINT is received.  (If the user specifies
  * that SIGINT is to be trapped or ignored using the trap builtin, then
  * this routine is not called.)  Suppressint is nonzero when interrupts
- * are held using the INTOFF macro.  The call to _exit is necessary because
- * there is a short period after a fork before the signal handlers are
- * set to the appropriate value for the child.  (The test for iflag is
- * just defensive programming.)
+ * are held using the INTOFF macro.  (The test for iflag is just
+ * defensive programming.)
  */
 
 static void
@@ -2132,12 +2130,11 @@
 	intpending = 0;
 	sigemptyset(&mysigset);
 	sigprocmask(SIG_SETMASK, &mysigset, NULL);
-	if (rootshell && iflag)
-		exraise(EXINT);
-	else {
+	if (!(rootshell && iflag)) {
 		signal(SIGINT, SIG_DFL);
 		raise(SIGINT);
 	}
+	exraise(EXINT);
 	/* NOTREACHED */
 }
 
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:43:52 2001
+++ ash.c	Mon Dec 10 15:01:22 2001
@@ -233,10 +233,10 @@
 #define VSPLUS          0x3             /* ${var+text} */
 #define VSQUESTION      0x4             /* ${var?message} */
 #define VSASSIGN        0x5             /* ${var=text} */
-#define VSTRIMLEFT      0x6             /* ${var#pattern} */
-#define VSTRIMLEFTMAX   0x7             /* ${var##pattern} */
-#define VSTRIMRIGHT     0x8             /* ${var%pattern} */
-#define VSTRIMRIGHTMAX  0x9             /* ${var%%pattern} */
+#define VSTRIMRIGHT     0x6             /* ${var%pattern} */
+#define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
+#define VSTRIMLEFT      0x8             /* ${var#pattern} */
+#define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
 #define VSLENGTH        0xa             /* ${#var} */
 
 /* values of checkkwd variable */
@@ -1222,13 +1224,8 @@
 };
 
 
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
 #define rmescapes(p) _rmescapes((p), 0)
 static char *_rmescapes (char *, int);
-#else
-static void rmescapes (char *);
-#endif
-
 static int  casematch (union node *, const char *);
 static void clearredir(void);
 static void popstring(void);
@@ -4406,6 +4403,9 @@
  */
 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
+#define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
+#define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
+#define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
 
 /*
  * Structure specifying which parts of the string should be searched
@@ -4429,7 +4429,7 @@
 static void argstr (char *, int);
 static char *exptilde (char *, int);
 static void expbackq (union node *, int, int);
-static int subevalvar (char *, char *, int, int, int, int, int);
+static const char *subevalvar (char *, char *, int, int, int, int, int);
 static int varisset (char *, int);
 static void strtodest (const char *, const char *, int);
 static void varvalue (char *, int, int);
@@ -4439,7 +4439,7 @@
 static void ifsfree (void);
 static void expandmeta (struct strlist *, int);
 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
+static inline char * preglob(const char *, int, int);
 #if !defined(GLOB_BROKEN)
 static void addglob (const glob_t *);
 #endif
@@ -4451,14 +4451,38 @@
 static struct strlist *expsort (struct strlist *);
 static struct strlist *msort (struct strlist *, int);
 #endif
-static int patmatch (char *, char *, int);
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-static int patmatch2 (char *, char *, int);
+static inline int patmatch (char *, const char *);
+#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
+static int pmatch (const char *, const char *);
 #else
-static int pmatch (char *, char *, int);
-#define patmatch2 patmatch
+#define pmatch(a, b) !fnmatch((a), (b), 0)
 #endif
-static char *cvtnum (int, char *);
+static void cvtnum (int);
+
+/*
+ * Prepare a pattern for a glob(3) call.
+ *
+ * Returns an stalloced string.
+ */
+
+static inline char *
+preglob(const char *pattern, int quoted, int flag) {
+	flag |= RMESCAPE_GLOB;
+	if (quoted) {
+		flag |= RMESCAPE_QUOTED;
+	}
+	return _rmescapes((char *)pattern, flag);
+}
+
+static size_t
+esclen(const char *start, const char *p) {
+	size_t esc = 0;
+
+	while (p > start && *--p == CTLESC) {
+		esc++;
+	}
+	return esc;
+}
 
 /*
  * Expand shell variables and backquotes inside a here document.
@@ -4602,7 +4626,7 @@
 
 	switch (subtype) {
 	case VSLENGTH:
-		cvtnum(varlen, expdest);
+		cvtnum(varlen);
 		goto record;
 
 	case VSNORMAL:
@@ -5026,7 +5115,74 @@
 	INTON;
 }
 
-static int
+static char *
+scanleft(
+	char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+	int zero
+) {
+	char *loc;
+	char *loc2;
+	char c;
+
+	loc = startp;
+	loc2 = rmesc;
+	do {
+		int match;
+		const char *s = loc2;
+		c = *loc2;
+		if (zero) {
+			*loc2 = '\0';
+			s = rmesc;
+		}
+		match = pmatch(str, s);
+		*loc2 = c;
+		if (match)
+			return loc;
+		if (quotes && *loc == CTLESC)
+			loc++;
+		loc++;
+		loc2++;
+	} while (c);
+	return 0;
+}
+
+
+static char *
+scanright(
+	char *startp, char *rmesc, char *rmescend, char *str, int quotes,
+	int zero
+) {
+	int esc = 0;
+	char *loc;
+	char *loc2;
+
+	for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
+		int match;
+		char c = *loc2;
+		const char *s = loc2;
+		if (zero) {
+			*loc2 = '\0';
+			s = rmesc;
+		}
+		match = pmatch(str, s);
+		*loc2 = c;
+		if (match)
+			return loc;
+		loc--;
+		if (quotes) {
+			if (--esc < 0) {
+				esc = esclen(startp, loc);
+			}
+			if (esc % 2) {
+				esc--;
+				loc--;
+			}
+		}
+	}
+	return 0;
+}
+
+static const char *
 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
 	char *p;
 	char *str;
@@ -5037,31 +5193,27 @@
 	int quotes;
 {
 	char *startp;
-	char *loc = NULL;
-	char *q;
-	int c = 0;
+	char *loc;
 	int saveherefd = herefd;
 	struct nodelist *saveargbackq = argbackq;
 	int amount;
+	char *rmesc, *rmescend;
+	int zero;
+	char *(*scan)(char *, char *, char *, char *, int , int);
 
 	herefd = -1;
 	argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
-	STACKSTRNUL(expdest);
+	STPUTC('\0', expdest);
 	herefd = saveherefd;
 	argbackq = saveargbackq;
 	startp = stackblock() + startloc;
-	if (str == NULL)
-	    str = stackblock() + strloc;
 
 	switch (subtype) {
 	case VSASSIGN:
 		setvar(str, startp, 0);
 		amount = startp - expdest;
 		STADJUST(amount, expdest);
-		varflags &= ~VSNUL;
-		if (c != 0)
-			*loc = c;
-		return 1;
+		return startp;
 
 	case VSQUESTION:
 		if (*p != CTLENDVAR) {
@@ -5072,84 +5224,45 @@
 		      str, (varflags & VSNUL) ? "null or "
 					      : nullstr);
 		/* NOTREACHED */
-
-	case VSTRIMLEFT:
-		for (loc = startp; loc < str; loc++) {
-			c = *loc;
-			*loc = '\0';
-			if (patmatch2(str, startp, quotes))
-				goto recordleft;
-			*loc = c;
-			if (quotes && *loc == CTLESC)
-				loc++;
 		}
-		return 0;
-
-	case VSTRIMLEFTMAX:
-		for (loc = str - 1; loc >= startp;) {
-			c = *loc;
-			*loc = '\0';
-			if (patmatch2(str, startp, quotes))
-				goto recordleft;
-			*loc = c;
-			loc--;
-			if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-				for (q = startp; q < loc; q++)
-					if (*q == CTLESC)
-						q++;
-				if (q > loc)
-					loc--;
-			}
-		}
-		return 0;
-
-	case VSTRIMRIGHT:
-		for (loc = str - 1; loc >= startp;) {
-			if (patmatch2(str, loc, quotes))
-				goto recordright;
-			loc--;
-			if (quotes && loc > startp && *(loc - 1) == CTLESC) {
-				for (q = startp; q < loc; q++)
-					if (*q == CTLESC)
-						q++;
-				if (q > loc)
-					loc--;
-			}
-		}
-		return 0;
-
-	case VSTRIMRIGHTMAX:
-		for (loc = startp; loc < str - 1; loc++) {
-			if (patmatch2(str, loc, quotes))
-				goto recordright;
-			if (quotes && *loc == CTLESC)
-				loc++;
-		}
-		return 0;
 
+	subtype -= VSTRIMRIGHT;
 #ifdef DEBUG
-	default:
+	if (subtype < 0 || subtype > 3)
 		abort();
 #endif
+
+	rmesc = startp;
+	rmescend = stackblock() + strloc;
+	if (quotes) {
+		rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
+		if (rmesc != startp) {
+			rmescend = expdest;
+			startp = stackblock() + startloc;
+		}
 	}
+	rmescend--;
+	str = stackblock() + strloc;
+	preglob(str, varflags & VSQUOTE, 0);
 
-recordleft:
-	*loc = c;
-	amount = ((str - 1) - (loc - startp)) - expdest;
-	STADJUST(amount, expdest);
-	while (loc != str - 1)
-		*startp++ = *loc++;
-	return 1;
+	/* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
+	zero = subtype >> 1;
+	/* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
+	scan = (subtype & 1) ^ zero ? scanleft : scanright;
 
-recordright:
+	loc = scan(startp, rmesc, rmescend, str, quotes, zero);
+	if (loc) {
+		if (zero) {
+			memmove(startp, loc, str - loc);
+			loc = startp + (str - loc) - 1;
+		}
+		*loc = '\0';
 	amount = loc - expdest;
 	STADJUST(amount, expdest);
-	STPUTC('\0', expdest);
-	STADJUST(-1, expdest);
-	return 1;
+	}
+	return loc;
 }
 
-
 /*
  * Test whether a specialized variable is set.
  */
@@ -5242,7 +5355,7 @@
 	case '!':
 		num = backgndpid;
 numvar:
-		expdest = cvtnum(num, expdest);
+		cvtnum(num);
 		break;
 	case '-':
 		for (i = 0 ; i < NOPTS ; i++) {
@@ -5453,7 +5566,7 @@
 	while (str) {
 		if (fflag)
 			goto nometa;
-		p = preglob(str->text);
+		p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_GROW);
 		INTOFF;
 		switch (glob(p, 0, 0, &pglob)) {
 		case 0:
@@ -5755,44 +5868,17 @@
  * Returns true if the pattern matches the string.
  */
 
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
-/* squoted: string might have quote chars */
-static int
-patmatch(char *pattern, char *string, int squoted)
-{
-	const char *p;
-	char *q;
-
-	p = preglob(pattern);
-	q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
-
-	return !fnmatch(p, q, 0);
-}
-
-
-static int
-patmatch2(char *pattern, char *string, int squoted)
+static inline int
+patmatch(char *pattern, const char *string)
 {
-	char *p;
-	int res;
-
-	sstrnleft--;
-	p = grabstackstr(expdest);
-	res = patmatch(pattern, string, squoted);
-	ungrabstackstr(p, expdest);
-	return res;
-}
-#else
-static int
-patmatch(char *pattern, char *string, int squoted) {
-	return pmatch(pattern, string, squoted);
+	return pmatch(preglob(pattern, 0, 0), string);
 }
 
-
+#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
 static int
 pmatch(char *pattern, char *string, int squoted)
 {
-	char *p, *q;
+	const char *p, *q;
 	char c;
 
 	p = pattern;
@@ -5801,46 +5887,33 @@
 		switch (c = *p++) {
 		case '\0':
 			goto breakloop;
-		case CTLESC:
-			if (squoted && *q == CTLESC)
-				q++;
-			if (*q++ != *p++)
-				return 0;
-			break;
-		case CTLQUOTEMARK:
-			continue;
+		case '\\':
+			if (*p) {
+				c = *p++;
+			}
+			goto dft;
 		case '?':
-			if (squoted && *q == CTLESC)
-				q++;
 			if (*q++ == '\0')
 				return 0;
 			break;
 		case '*':
 			c = *p;
-			while (c == CTLQUOTEMARK || c == '*')
+			while (c == '*')
 				c = *++p;
-			if (c != CTLESC &&  c != CTLQUOTEMARK &&
-			    c != '?' && c != '*' && c != '[') {
+			if (c != '\\' && c != '?' && c != '*' && c != '[') {
 				while (*q != c) {
-					if (squoted && *q == CTLESC &&
-					    q[1] == c)
-						break;
 					if (*q == '\0')
 						return 0;
-					if (squoted && *q == CTLESC)
-						q++;
 					q++;
 				}
 			}
 			do {
-				if (pmatch(p, q, squoted))
+				if (pmatch(p, q))
 					return 1;
-				if (squoted && *q == CTLESC)
-					q++;
 			} while (*q++ != '\0');
 			return 0;
 		case '[': {
-			char *endp;
+			const char *endp;
 			int invert, found;
 			char chr;
 
@@ -5848,11 +5921,9 @@
 			if (*endp == '!')
 				endp++;
 			for (;;) {
-				while (*endp == CTLQUOTEMARK)
-					endp++;
 				if (*endp == '\0')
 					goto dft;               /* no matching ] */
-				if (*endp == CTLESC)
+				if (*endp == '\\')
 					endp++;
 				if (*++endp == ']')
 					break;
@@ -5864,21 +5935,15 @@
 			}
 			found = 0;
 			chr = *q++;
-			if (squoted && chr == CTLESC)
-				chr = *q++;
 			if (chr == '\0')
 				return 0;
 			c = *p++;
 			do {
-				if (c == CTLQUOTEMARK)
-					continue;
-				if (c == CTLESC)
+				if (c == '\\')
 					c = *p++;
 				if (*p == '-' && p[1] != ']') {
 					p++;
-					while (*p == CTLQUOTEMARK)
-						p++;
-					if (*p == CTLESC)
+					if (*p == '\\')
 						p++;
 					if (chr >= c && chr <= *p)
 						found = 1;
@@ -5893,8 +5958,6 @@
 			break;
 		}
 dft:            default:
-			if (squoted && *q == CTLESC)
-				q++;
 			if (*q++ != c)
 				return 0;
 			break;
@@ -5913,12 +5976,16 @@
  * Remove any CTLESC characters from a string.
  */
 
-#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
 static char *
-_rmescapes(char *str, int flag)
+_rmescapes(str, flag)
+	char *str;
+	int flag;
 {
 	char *p, *q, *r;
 	static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
+	unsigned inquotes;
+	int notescaped;
+	int globbing;
 
 	p = strpbrk(str, qchars);
 	if (!p) {
@@ -5928,54 +5995,57 @@
 	r = str;
 	if (flag & RMESCAPE_ALLOC) {
 		size_t len = p - str;
-		q = r = stalloc(strlen(p) + len + 1);
+		size_t fulllen = len + strlen(p) + 1;
+
+		r = stalloc(fulllen);
+#if 0
+		/* Why doesn't RMESCAPE_GROW work right? */
+		if (flag & RMESCAPE_GROW) {
+			CHECKSTRSPACE(fulllen, expdest);
+			r = expdest;
+		} else if (flag & RMESCAPE_HEAP) {
+			r = ckmalloc(fulllen);
+		} else {
+			r = stalloc(fulllen);
+		}
+#endif
+		q = r;
 		if (len > 0) {
 			memcpy(q, str, len);
 			q += len;
 		}
 	}
+	inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
+	globbing = flag & RMESCAPE_GLOB;
+	notescaped = globbing;
 	while (*p) {
 		if (*p == CTLQUOTEMARK) {
+			inquotes = ~inquotes;
 			p++;
+			notescaped = globbing;
 			continue;
 		}
+		if (*p == '\\') {
+			/* naked back slash */
+			notescaped = 0;
+			goto copy;
+		}
 		if (*p == CTLESC) {
 			p++;
-			if (flag & RMESCAPE_GLOB && *p != '/') {
+			if (notescaped && inquotes && *p != '/') {
 				*q++ = '\\';
 			}
 		}
+		notescaped = globbing;
+copy:
 		*q++ = *p++;
 	}
 	*q = '\0';
-	return r;
-}
-#else
-static void
-rmescapes(str)
-	char *str;
-{
-	char *p, *q;
-
-	p = str;
-	while (*p != CTLESC && *p != CTLQUOTEMARK) {
-		if (*p++ == '\0')
-			return;
-	}
-	q = p;
-	while (*p) {
-		if (*p == CTLQUOTEMARK) {
-			p++;
-			continue;
-		}
-		if (*p == CTLESC)
-			p++;
-		*q++ = *p++;
+	if (flag & RMESCAPE_GROW) {
+		STADJUST(q - r + 1, expdest);
 	}
-	*q = '\0';
+	return r;
 }
-#endif
-
 
 
 /*
@@ -5996,7 +6066,7 @@
 	argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
 	STPUTC('\0', expdest);
 	p = grabstackstr(expdest);
-	result = patmatch(p, (char *)val, 0);
+	result = patmatch(p, (char *)val);
 	popstackmark(&smark);
 	return result;
 }
@@ -6005,18 +6075,15 @@
  * Our own itoa().
  */
 
-static char *
-cvtnum(num, buf)
-	int num;
-	char *buf;
-	{
+static void
+cvtnum(int num) {
 	int len;
 
-	CHECKSTRSPACE(32, buf);
-	len = sprintf(buf, "%d", num);
-	STADJUST(len, buf);
-	return buf;
+        CHECKSTRSPACE(32, expdest);
+        len = snprintf(expdest, 32, "%d", num);
+        STADJUST(len, expdest);
 }
+
 /*
  * Editline and history functions (and glue).
  */
@@ -10186,7 +10253,7 @@
 	loop: { /* for each line, until end of word */
 		CHECKEND();     /* set c to PEOF if at end of here document */
 		for (;;) {      /* until end of line or end of word */
-			CHECKSTRSPACE(3, out);  /* permit 3 calls to USTPUTC */
+			CHECKSTRSPACE(4, out);	/* permit 4 calls to USTPUTC */
 			switch(syntax[c]) {
 			case CNL:       /* '\n' */
 				if (syntax == BASESYNTAX)
@@ -10203,14 +10270,14 @@
 				USTPUTC(c, out);
 				break;
 			case CCTL:
-				if ((eofmark == NULL || dblquote) &&
-				    dqvarnest == 0)
+				if (eofmark == NULL || dblquote)
 					USTPUTC(CTLESC, out);
 				USTPUTC(c, out);
 				break;
 			case CBACK:     /* backslash */
 				c = pgetc2();
 				if (c == PEOF) {
+					USTPUTC(CTLESC, out);
 					USTPUTC('\\', out);
 					pungetc();
 				} else if (c == '\n') {
@@ -10219,42 +10286,45 @@
 					else
 						setprompt(0);
 				} else {
-					if (dblquote && c != '\\' && c != '`' && c != '$'
-							 && (c != '"' || eofmark != NULL))
+					if (
+						dblquote &&
+						c != '\\' && c != '`' &&
+						c != '$' && (
+							c != '"' ||
+							eofmark != NULL
+						)
+					) {
+						USTPUTC(CTLESC, out);
 						USTPUTC('\\', out);
+					}
 					if (SQSYNTAX[c] == CCTL)
 						USTPUTC(CTLESC, out);
-					else if (eofmark == NULL)
-						USTPUTC(CTLQUOTEMARK, out);
 					USTPUTC(c, out);
 					quotef++;
 				}
 				break;
 			case CSQUOTE:
-				if (eofmark == NULL)
-					USTPUTC(CTLQUOTEMARK, out);
 				syntax = SQSYNTAX;
+quotemark:
+				if (eofmark == NULL) {
+					USTPUTC(CTLQUOTEMARK, out);
+				}
 				break;
 			case CDQUOTE:
-				if (eofmark == NULL)
-					USTPUTC(CTLQUOTEMARK, out);
 				syntax = DQSYNTAX;
 				dblquote = 1;
-				break;
+				goto quotemark;
 			case CENDQUOTE:
 				if (eofmark != NULL && arinest == 0 &&
 				    varnest == 0) {
 					USTPUTC(c, out);
 				} else {
-					if (arinest) {
-						syntax = ARISYNTAX;
-						dblquote = 0;
-					} else if (eofmark == NULL &&
-						   dqvarnest == 0) {
+					if (dqvarnest == 0) {
 						syntax = BASESYNTAX;
 						dblquote = 0;
 					}
 					quotef++;
+					goto quotemark;
 				}
 				break;
 			case CVAR:      /* '$' */
@@ -10313,10 +10383,10 @@
 				if (varnest == 0)
 					goto endword;   /* exit outer loop */
 #ifdef ASH_ALIAS
-				if (c != PEOA)
-#endif
+				if (c != PEOA) {
 					USTPUTC(c, out);
-
+				}
+#endif
 			}
 			c = pgetc_macro();
 		}
@@ -10551,7 +10621,7 @@
 		*(stackblock() + typeloc) = subtype | flags;
 		if (subtype != VSNORMAL) {
 			varnest++;
-			if (dblquote) {
+			if (dblquote || arinest) {
 				dqvarnest++;
 			}
 		}
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 16:48:30 2001
+++ ash.c	Mon Dec 10 16:49:33 2001
@@ -6099,8 +6099,7 @@
 
       /* from input.c: */
       {
-	      if (exception != EXSHELLPROC)
-		      parselleft = parsenleft = 0;      /* clear input buffer */
+	      parselleft = parsenleft = 0;      /* clear input buffer */
 	      popallfiles();
       }
 
-------------- next part --------------
--- ash.c.orig	Tue Dec 11 14:23:29 2001
+++ ash.c	Tue Dec 11 14:24:17 2001
@@ -239,6 +239,11 @@
 #define VSTRIMRIGHTMAX  0x9             /* ${var%%pattern} */
 #define VSLENGTH        0xa             /* ${#var} */
 
+/* values of checkkwd variable */
+#define CHKALIAS	0x1
+#define CHKKWD		0x2
+#define CHKNL		0x4
+
 /* flags passed to redirect */
 #define REDIR_PUSH 01           /* save previous values of file descriptors */
 #define REDIR_BACKQ 02          /* save the command output to pipe */
@@ -6207,7 +6212,7 @@
 	if (sp->ap) {
 		if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
 			if (!checkalias) {
-				checkalias = 1;
+				checkalias |= CHKALIAS;
 			}
 		}
 		if (sp->string != sp->ap->val) {
@@ -9411,7 +9416,7 @@
 	union node *n1, *n2, *n3;
 	int tok;
 
-	checkkwd = 2;
+	checkkwd = CHKNL | CHKKWD | CHKALIAS;
 	if (nlflag == 0 && tokendlist[peektoken()])
 		return NULL;
 	n1 = NULL;
@@ -9454,7 +9459,7 @@
 			} else {
 				tokpushback++;
 			}
-			checkkwd = 2;
+			checkkwd = CHKNL | CHKKWD | CHKALIAS;
 			if (tokendlist[peektoken()])
 				return n1;
 			break;
@@ -9480,7 +9485,7 @@
 	union node *n1, *n2, *n3;
 	int t;
 
-	checkkwd = 1;
+	checkkwd = CHKKWD | CHKALIAS;
 	n1 = pipeline();
 	for (;;) {
 		if ((t = readtoken()) == TAND) {
@@ -9491,7 +9496,7 @@
 			tokpushback++;
 			return n1;
 		}
-		checkkwd = 2;
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
 		n2 = pipeline();
 		n3 = (union node *)stalloc(sizeof (struct nbinary));
 		n3->type = t;
@@ -9513,7 +9518,7 @@
 	TRACE(("pipeline: entered\n"));
 	if (readtoken() == TNOT) {
 		negate = !negate;
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 	} else
 		tokpushback++;
 	n1 = command();
@@ -9527,7 +9532,7 @@
 		do {
 			prev = lp;
 			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
-			checkkwd = 2;
+			checkkwd = CHKNL | CHKKWD | CHKALIAS;
 			lp->n = command();
 			prev->next = lp;
 		} while (readtoken() == TPIPE);
@@ -9592,7 +9597,7 @@
 		}
 		if (readtoken() != TFI)
 			synexpect(TFI);
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TWHILE:
 	case TUNTIL: {
@@ -9607,7 +9612,7 @@
 		n1->nbinary.ch2 = list(0);
 		if (readtoken() != TDONE)
 			synexpect(TDONE);
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	}
 	case TFOR:
@@ -9616,7 +9621,7 @@
 		n1 = (union node *)stalloc(sizeof (struct nfor));
 		n1->type = NFOR;
 		n1->nfor.var = wordtext;
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		if (readtoken() == TIN) {
 			app = &ap;
 			while (readtoken() == TWORD) {
@@ -9647,13 +9652,13 @@
 			if (lasttoken != TNL && lasttoken != TSEMI)
 				tokpushback++;
 		}
-		checkkwd = 2;
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
 		if (readtoken() != TDO)
 			synexpect(TDO);
 		n1->nfor.body = list(0);
 		if (readtoken() != TDONE)
 			synexpect(TDONE);
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TCASE:
 		n1 = (union node *)stalloc(sizeof (struct ncase));
@@ -9666,12 +9671,13 @@
 		n2->narg.backquote = backquotelist;
 		n2->narg.next = NULL;
 		do {
-			checkkwd = 1;
+			checkkwd = CHKKWD | CHKALIAS;
 		} while (readtoken() == TNL);
 		if (lasttoken != TIN)
 			synerror("expecting \"in\"");
 		cpp = &n1->ncase.cases;
-		checkkwd = 2, readtoken();
+		checkkwd = CHKNL | CHKKWD | CHKALIAS;
+		readtoken();
 		do {
 			if (lasttoken == TLP)
 				readtoken();
@@ -9683,7 +9689,8 @@
 				ap->type = NARG;
 				ap->narg.text = wordtext;
 				ap->narg.backquote = backquotelist;
-				if (checkkwd = 2, readtoken() != TPIPE)
+				checkkwd = CHKNL | CHKKWD | CHKALIAS;
+				if (readtoken() != TPIPE)
 					break;
 				app = &ap->narg.next;
 				readtoken();
@@ -9693,17 +9700,19 @@
 				synexpect(TRP);
 			cp->nclist.body = list(0);
 
-			checkkwd = 2;
+			checkkwd = CHKNL | CHKKWD | CHKALIAS;
 			if ((t = readtoken()) != TESAC) {
 				if (t != TENDCASE)
 					synexpect(TENDCASE);
-				else
-					checkkwd = 2, readtoken();
+				else {
+					checkkwd = CHKNL | CHKKWD | CHKALIAS;
+					readtoken();
+				}
 			}
 			cpp = &cp->nclist.next;
 		} while(lasttoken != TESAC);
 		*cpp = NULL;
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TLP:
 		n1 = (union node *)stalloc(sizeof (struct nredir));
@@ -9712,13 +9721,13 @@
 		n1->nredir.redirect = NULL;
 		if (readtoken() != TRP)
 			synexpect(TRP);
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	case TBEGIN:
 		n1 = list(0);
 		if (readtoken() != TEND)
 			synexpect(TEND);
-		checkkwd = 1;
+		checkkwd = CHKKWD | CHKALIAS;
 		break;
 	/* Handle an empty command like other simple commands.  */
 	case TSEMI:
@@ -9735,6 +9744,7 @@
 		if (!redir)
 			synexpect(-1);
 	case TWORD:
+	case TREDIR:
 		tokpushback++;
 		n1 = simplecmd();
 		return n1;
@@ -9771,6 +9781,7 @@
 	union node *n = NULL;
 	union node *vars, **vpp;
 	union node **rpp, *redir;
+	int savecheckkwd;
 
 	args = NULL;
 	app = &args;
@@ -9779,27 +9790,28 @@
 	redir = NULL;
 	rpp = &redir;
 
-	checkalias = 2;
+	savecheckkwd = CHKALIAS;
 	for (;;) {
+		checkkwd = savecheckkwd;
 		switch (readtoken()) {
 		case TWORD:
-		case TASSIGN:
 			n = (union node *)stalloc(sizeof (struct narg));
 			n->type = NARG;
 			n->narg.text = wordtext;
 			n->narg.backquote = backquotelist;
-			if (lasttoken == TWORD) {
-				*app = n;
-				app = &n->narg.next;
-			} else {
+			if (savecheckkwd && isassignment(wordtext)) {
 				*vpp = n;
 				vpp = &n->narg.next;
+			} else {
+				*app = n;
+				app = &n->narg.next;
+				savecheckkwd = 0;
 			}
 			break;
 		case TREDIR:
 			*rpp = n = redirnode;
 			rpp = &n->nfile.next;
-			parsefname();   /* read name of redirection file */
+			parsefname();	/* read name of redirection file */
 			break;
 		case TLP:
 			if (
@@ -9810,7 +9822,7 @@
 				if (readtoken() != TRP)
 					synexpect(TRP);
 				n->type = NDEFUN;
-				checkkwd = 2;
+				checkkwd = CHKNL | CHKKWD | CHKALIAS;
 				n->narg.next = command();
 				return n;
 			}
@@ -9941,13 +9953,6 @@
 static int
 readtoken() {
 	int t;
-
-#ifdef ASH_ALIAS
-	int savecheckalias = checkalias;
-	int savecheckkwd = checkkwd;
-	struct alias *ap;
-#endif
-
 #ifdef DEBUG
 	int alreadyseen = tokpushback;
 #endif
@@ -9955,65 +9960,53 @@
 #ifdef ASH_ALIAS
 top:
 #endif
-
 	t = xxreadtoken();
 
-#ifdef ASH_ALIAS
-	checkalias = savecheckalias;
-#endif
-
-	if (checkkwd) {
-		/*
-		 * eat newlines
-		 */
-		if (checkkwd == 2) {
-			checkkwd = 0;
-			while (t == TNL) {
-				parseheredoc();
-				t = xxreadtoken();
-			}
+	/*
+	 * eat newlines
+	 */
+	if (checkkwd & CHKNL) {
+		while (t == TNL) {
+			parseheredoc();
+			t = xxreadtoken();
 		}
-		checkkwd = 0;
-		/*
-		 * check for keywords
-		 */
-		if (t == TWORD && !quoteflag)
-		{
-			const char *const *pp;
+	}
 
-			if ((pp = findkwd(wordtext))) {
-				lasttoken = t = pp - parsekwd + KWDOFFSET;
-				TRACE(("keyword %s recognized\n", tokname[t]));
-				goto out;
-			}
-		}
+	if (t != TWORD || quoteflag) {
+		goto out;
 	}
 
+	/*
+	 * check for keywords
+	 */
+	if (checkkwd & CHKKWD) {
+		const char *const *pp;
 
-	if (t != TWORD) {
-		if (t != TREDIR) {
-			checkalias = 0;
+		if ((pp = findkwd(wordtext))) {
+			lasttoken = t = pp - parsekwd + KWDOFFSET;
+			TRACE(("keyword %s recognized\n", tokname[t]));
+			goto out;
 		}
-	} else if (checkalias == 2 && isassignment(wordtext)) {
-		lasttoken = t = TASSIGN;
+	}
+
 #ifdef ASH_ALIAS
-	} else if (checkalias) {
-		if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
+	if (checkkwd & CHKALIAS) {
+		struct alias *ap;
+		if ((ap = lookupalias(wordtext, 1)) != NULL) {
 			if (*ap->val) {
 				pushstring(ap->val, strlen(ap->val), ap);
 			}
-			checkkwd = savecheckkwd;
 			goto top;
 		}
-		checkalias = 0;
-#endif
 	}
+#endif
 out:
+	checkkwd = 0;
 #ifdef DEBUG
 	if (!alreadyseen)
-	    TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
+	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
 	else
-	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
+	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
 #endif
 	return (t);
 }
-------------- next part --------------
--- ash.c.orig	Sat Dec  8 19:19:46 2001
+++ ash.c	Sat Dec  8 19:25:57 2001
@@ -3597,8 +3597,10 @@
 static void
 tryexec(char *cmd, char **argv, char **envp)
 {
-	int e;
+	int repeated = 0;
 
+repeat:
+	{
 #ifdef BB_FEATURE_SH_STANDALONE_SHELL
 	char *name = cmd;
 	char** argv_l=argv;
@@ -3614,17 +3616,23 @@
 	optind = 1;
 	run_applet_by_name(name, argc_l, argv);
 #endif
+	}
 	execve(cmd, argv, envp);
-	e = errno;
-	if (e == ENOEXEC) {
-		INTOFF;
-		initshellproc();
-		setinputfile(cmd, 0);
-		commandname = arg0 = savestr(argv[0]);
-		setparam(argv + 1);
-		exraise(EXSHELLPROC);
+	if (repeated++) {
+		ckfree(argv);
+	} else if (errno == ENOEXEC) {
+		char **ap;
+		char **new;
+ 
+		for (ap = argv; *ap; ap++)
+			;
+		ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
+		*ap++ = cmd = "/bin/sh";
+		while ((*ap++ = *argv++))
+			;
+		argv = new;
+		goto repeat;
 	}
-	errno = e;
 }
 
 static char *commandtext (const union node *);
-------------- next part --------------
--- ash.c.orig	Mon Dec 10 16:13:22 2001
+++ ash.c	Mon Dec 10 16:16:14 2001
@@ -5323,7 +5323,7 @@
 	case '*':
 		sep = ifsset() ? ifsval()[0] : ' ';
 		if (quotes) {
-			sepq = syntax[(int) sep] == CCTL;
+			sepq = syntax[(int) sep] == CCTL || syntax[(int) sep] == CBACK;
 		}
 param:
 		for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {


More information about the busybox mailing list