ash: better fix for ash -c 'echo 5&' and ash -c 'sleep 5&' with testcase
No binary (build failed)
—
(log yok)
| @@ -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) | |
| @@ -0,0 +1,2 @@ | |
| + | 3 |
| + | End |
| @@ -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 |