From 727752d2d2968e67784935dd35c32a97c0c13a7c Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 28 Nov 2008 03:41:47 +0000 Subject: [PATCH] ash: better fix for ash -c 'echo 5&' and ash -c 'sleep 5&' with testcase --- shell/ash.c | 75 +++++++++++++++++++++------------- shell/ash_test/ash-misc/last_amp.right | 2 + shell/ash_test/ash-misc/last_amp.tests | 8 ++++ 3 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 shell/ash_test/ash-misc/last_amp.right create mode 100755 shell/ash_test/ash-misc/last_amp.tests diff --git a/shell/ash.c b/shell/ash.c index 66bfa67..e1df894 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9079,8 +9079,6 @@ breakcmd(int argc UNUSED_PARAM, char **argv) * This implements the input routines used by the parser. */ -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ - enum { INPUT_PUSH_FILE = 1, INPUT_NOFILE_OK = 2, @@ -9121,7 +9119,6 @@ popstring(void) #endif parsenextc = sp->prevstring; parsenleft = sp->prevnleft; -/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ g_parsefile->strpush = sp->prev; if (sp != &(g_parsefile->basestrpush)) free(sp); @@ -9137,7 +9134,7 @@ preadfd(void) #if ENABLE_FEATURE_EDITING retry: - if (!iflag || g_parsefile->fd) + if (!iflag || g_parsefile->fd != STDIN_FILENO) nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); else { #if ENABLE_FEATURE_TAB_COMPLETION @@ -9185,56 +9182,76 @@ preadfd(void) * Refill the input buffer and return the next input character: * * 1) If a string was pushed back on the input, pop it; - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading + * 2) If an EOF was pushed back (parsenleft < -BIGNUM) or we are reading * from a string so we can't refill the buffer, return EOF. * 3) If the is more stuff in this buffer, use it else call read to fill it. * 4) Process input up to the next newline, deleting nul characters. */ +//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) +#define pgetc_debug(...) ((void)0) static int preadbuffer(void) { char *q; int more; - char savec; while (g_parsefile->strpush) { #if ENABLE_ASH_ALIAS if (parsenleft == -1 && g_parsefile->strpush->ap && parsenextc[-1] != ' ' && parsenextc[-1] != '\t' ) { + pgetc_debug("preadbuffer PEOA"); return PEOA; } #endif popstring(); + /* try "pgetc" now: */ + pgetc_debug("internal pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); if (--parsenleft >= 0) return signed_char2int(*parsenextc++); } - if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL) + /* on both branches above parsenleft < 0. + * "pgetc" needs refilling. + */ + + /* -90 is -BIGNUM. Below we use -99 to mark "EOF on read", + * pungetc() may decrement it a few times. -90 is enough. + */ + if (parsenleft < -90 || g_parsefile->buf == NULL) { + pgetc_debug("preadbuffer PEOF1"); + /* even in failure keep them in lock step, + * for correct pungetc. */ + parsenextc++; return PEOF; - flush_stdout_stderr(); + } more = parselleft; if (more <= 0) { + flush_stdout_stderr(); again: more = preadfd(); if (more <= 0) { - parselleft = parsenleft = EOF_NLEFT; + parselleft = parsenleft = -99; + pgetc_debug("preadbuffer PEOF2"); + parsenextc++; return PEOF; } } + /* Find out where's the end of line. + * Set parsenleft/parselleft acordingly. + * NUL chars are deleted. + */ q = parsenextc; - - /* delete nul characters */ for (;;) { - int c; + char c; more--; - c = *q; - if (!c) + c = *q; + if (c == '\0') { memmove(q, q + 1, more); - else { + } else { q++; if (c == '\n') { parsenleft = q - parsenextc - 1; @@ -9251,22 +9268,23 @@ preadbuffer(void) } parselleft = more; - savec = *q; - *q = '\0'; - if (vflag) { + char save = *q; + *q = '\0'; out2str(parsenextc); + *q = save; } - *q = savec; - + pgetc_debug("preadbuffer at %d:%p'%s'", parsenleft, parsenextc, parsenextc); return signed_char2int(*parsenextc++); } #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer()) + static int pgetc(void) { + pgetc_debug("pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); return pgetc_as_macro(); } @@ -9325,11 +9343,9 @@ pfgets(char *line, int len) static void pungetc(void) { - /* check is needed for ash -c 'echo 5&' + BASH_COMPAT to work */ - if (parsenleft < 0) - return; parsenleft++; parsenextc--; + pgetc_debug("pushed back to %d:%p'%s'", parsenleft, parsenextc, parsenextc); } /* @@ -9343,16 +9359,17 @@ static void pushstring(char *s, struct alias *ap) { struct strpush *sp; - size_t len; + int len; len = strlen(s); INT_OFF; if (g_parsefile->strpush) { - sp = ckzalloc(sizeof(struct strpush)); + sp = ckzalloc(sizeof(*sp)); sp->prev = g_parsefile->strpush; - g_parsefile->strpush = sp; - } else - sp = g_parsefile->strpush = &(g_parsefile->basestrpush); + } else { + sp = &(g_parsefile->basestrpush); + } + g_parsefile->strpush = sp; sp->prevstring = parsenextc; sp->prevnleft = parsenleft; #if ENABLE_ASH_ALIAS @@ -9442,7 +9459,7 @@ setinputfd(int fd, int push) close_on_exec_on(fd); if (push) { pushfile(); - g_parsefile->buf = 0; + g_parsefile->buf = NULL; } g_parsefile->fd = fd; if (g_parsefile->buf == NULL) diff --git a/shell/ash_test/ash-misc/last_amp.right b/shell/ash_test/ash-misc/last_amp.right new file mode 100644 index 0000000..3da21ae --- /dev/null +++ b/shell/ash_test/ash-misc/last_amp.right @@ -0,0 +1,2 @@ +3 +End diff --git a/shell/ash_test/ash-misc/last_amp.tests b/shell/ash_test/ash-misc/last_amp.tests new file mode 100755 index 0000000..1609376 --- /dev/null +++ b/shell/ash_test/ash-misc/last_amp.tests @@ -0,0 +1,8 @@ +$THIS_SH -c 'echo 3&' +d=`date` +while test "`date`" = "$d"; do true; done +d1=`date` +$THIS_SH -c 'sleep 1&' +d2=`date` +test "$d1" = "$d2" || echo BAD +echo End -- 2.7.4