diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-28 03:41:47 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-28 03:41:47 +0000 |
commit | 727752d2d2968e67784935dd35c32a97c0c13a7c (patch) | |
tree | 3cf5e79044841dd0b342cc0d8e0843b5f9be87b1 | |
parent | 9e0a7c9c414e3e155d965c8b8b1dfed42ca21ec5 (diff) | |
download | busybox-w32-727752d2d2968e67784935dd35c32a97c0c13a7c.tar.gz busybox-w32-727752d2d2968e67784935dd35c32a97c0c13a7c.tar.bz2 busybox-w32-727752d2d2968e67784935dd35c32a97c0c13a7c.zip |
ash: better fix for ash -c 'echo 5&' and ash -c 'sleep 5&'
with testcase
-rw-r--r-- | shell/ash.c | 75 | ||||
-rw-r--r-- | shell/ash_test/ash-misc/last_amp.right | 2 | ||||
-rwxr-xr-x | shell/ash_test/ash-misc/last_amp.tests | 8 |
3 files changed, 56 insertions, 29 deletions
diff --git a/shell/ash.c b/shell/ash.c index 66bfa67ba..e1df89418 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -9079,8 +9079,6 @@ breakcmd(int argc UNUSED_PARAM, char **argv) | |||
9079 | * This implements the input routines used by the parser. | 9079 | * This implements the input routines used by the parser. |
9080 | */ | 9080 | */ |
9081 | 9081 | ||
9082 | #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ | ||
9083 | |||
9084 | enum { | 9082 | enum { |
9085 | INPUT_PUSH_FILE = 1, | 9083 | INPUT_PUSH_FILE = 1, |
9086 | INPUT_NOFILE_OK = 2, | 9084 | INPUT_NOFILE_OK = 2, |
@@ -9121,7 +9119,6 @@ popstring(void) | |||
9121 | #endif | 9119 | #endif |
9122 | parsenextc = sp->prevstring; | 9120 | parsenextc = sp->prevstring; |
9123 | parsenleft = sp->prevnleft; | 9121 | parsenleft = sp->prevnleft; |
9124 | /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ | ||
9125 | g_parsefile->strpush = sp->prev; | 9122 | g_parsefile->strpush = sp->prev; |
9126 | if (sp != &(g_parsefile->basestrpush)) | 9123 | if (sp != &(g_parsefile->basestrpush)) |
9127 | free(sp); | 9124 | free(sp); |
@@ -9137,7 +9134,7 @@ preadfd(void) | |||
9137 | 9134 | ||
9138 | #if ENABLE_FEATURE_EDITING | 9135 | #if ENABLE_FEATURE_EDITING |
9139 | retry: | 9136 | retry: |
9140 | if (!iflag || g_parsefile->fd) | 9137 | if (!iflag || g_parsefile->fd != STDIN_FILENO) |
9141 | nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); | 9138 | nr = nonblock_safe_read(g_parsefile->fd, buf, BUFSIZ - 1); |
9142 | else { | 9139 | else { |
9143 | #if ENABLE_FEATURE_TAB_COMPLETION | 9140 | #if ENABLE_FEATURE_TAB_COMPLETION |
@@ -9185,56 +9182,76 @@ preadfd(void) | |||
9185 | * Refill the input buffer and return the next input character: | 9182 | * Refill the input buffer and return the next input character: |
9186 | * | 9183 | * |
9187 | * 1) If a string was pushed back on the input, pop it; | 9184 | * 1) If a string was pushed back on the input, pop it; |
9188 | * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading | 9185 | * 2) If an EOF was pushed back (parsenleft < -BIGNUM) or we are reading |
9189 | * from a string so we can't refill the buffer, return EOF. | 9186 | * from a string so we can't refill the buffer, return EOF. |
9190 | * 3) If the is more stuff in this buffer, use it else call read to fill it. | 9187 | * 3) If the is more stuff in this buffer, use it else call read to fill it. |
9191 | * 4) Process input up to the next newline, deleting nul characters. | 9188 | * 4) Process input up to the next newline, deleting nul characters. |
9192 | */ | 9189 | */ |
9190 | //#define pgetc_debug(...) bb_error_msg(__VA_ARGS__) | ||
9191 | #define pgetc_debug(...) ((void)0) | ||
9193 | static int | 9192 | static int |
9194 | preadbuffer(void) | 9193 | preadbuffer(void) |
9195 | { | 9194 | { |
9196 | char *q; | 9195 | char *q; |
9197 | int more; | 9196 | int more; |
9198 | char savec; | ||
9199 | 9197 | ||
9200 | while (g_parsefile->strpush) { | 9198 | while (g_parsefile->strpush) { |
9201 | #if ENABLE_ASH_ALIAS | 9199 | #if ENABLE_ASH_ALIAS |
9202 | if (parsenleft == -1 && g_parsefile->strpush->ap | 9200 | if (parsenleft == -1 && g_parsefile->strpush->ap |
9203 | && parsenextc[-1] != ' ' && parsenextc[-1] != '\t' | 9201 | && parsenextc[-1] != ' ' && parsenextc[-1] != '\t' |
9204 | ) { | 9202 | ) { |
9203 | pgetc_debug("preadbuffer PEOA"); | ||
9205 | return PEOA; | 9204 | return PEOA; |
9206 | } | 9205 | } |
9207 | #endif | 9206 | #endif |
9208 | popstring(); | 9207 | popstring(); |
9208 | /* try "pgetc" now: */ | ||
9209 | pgetc_debug("internal pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||
9209 | if (--parsenleft >= 0) | 9210 | if (--parsenleft >= 0) |
9210 | return signed_char2int(*parsenextc++); | 9211 | return signed_char2int(*parsenextc++); |
9211 | } | 9212 | } |
9212 | if (parsenleft == EOF_NLEFT || g_parsefile->buf == NULL) | 9213 | /* on both branches above parsenleft < 0. |
9214 | * "pgetc" needs refilling. | ||
9215 | */ | ||
9216 | |||
9217 | /* -90 is -BIGNUM. Below we use -99 to mark "EOF on read", | ||
9218 | * pungetc() may decrement it a few times. -90 is enough. | ||
9219 | */ | ||
9220 | if (parsenleft < -90 || g_parsefile->buf == NULL) { | ||
9221 | pgetc_debug("preadbuffer PEOF1"); | ||
9222 | /* even in failure keep them in lock step, | ||
9223 | * for correct pungetc. */ | ||
9224 | parsenextc++; | ||
9213 | return PEOF; | 9225 | return PEOF; |
9214 | flush_stdout_stderr(); | 9226 | } |
9215 | 9227 | ||
9216 | more = parselleft; | 9228 | more = parselleft; |
9217 | if (more <= 0) { | 9229 | if (more <= 0) { |
9230 | flush_stdout_stderr(); | ||
9218 | again: | 9231 | again: |
9219 | more = preadfd(); | 9232 | more = preadfd(); |
9220 | if (more <= 0) { | 9233 | if (more <= 0) { |
9221 | parselleft = parsenleft = EOF_NLEFT; | 9234 | parselleft = parsenleft = -99; |
9235 | pgetc_debug("preadbuffer PEOF2"); | ||
9236 | parsenextc++; | ||
9222 | return PEOF; | 9237 | return PEOF; |
9223 | } | 9238 | } |
9224 | } | 9239 | } |
9225 | 9240 | ||
9241 | /* Find out where's the end of line. | ||
9242 | * Set parsenleft/parselleft acordingly. | ||
9243 | * NUL chars are deleted. | ||
9244 | */ | ||
9226 | q = parsenextc; | 9245 | q = parsenextc; |
9227 | |||
9228 | /* delete nul characters */ | ||
9229 | for (;;) { | 9246 | for (;;) { |
9230 | int c; | 9247 | char c; |
9231 | 9248 | ||
9232 | more--; | 9249 | more--; |
9233 | c = *q; | ||
9234 | 9250 | ||
9235 | if (!c) | 9251 | c = *q; |
9252 | if (c == '\0') { | ||
9236 | memmove(q, q + 1, more); | 9253 | memmove(q, q + 1, more); |
9237 | else { | 9254 | } else { |
9238 | q++; | 9255 | q++; |
9239 | if (c == '\n') { | 9256 | if (c == '\n') { |
9240 | parsenleft = q - parsenextc - 1; | 9257 | parsenleft = q - parsenextc - 1; |
@@ -9251,22 +9268,23 @@ preadbuffer(void) | |||
9251 | } | 9268 | } |
9252 | parselleft = more; | 9269 | parselleft = more; |
9253 | 9270 | ||
9254 | savec = *q; | ||
9255 | *q = '\0'; | ||
9256 | |||
9257 | if (vflag) { | 9271 | if (vflag) { |
9272 | char save = *q; | ||
9273 | *q = '\0'; | ||
9258 | out2str(parsenextc); | 9274 | out2str(parsenextc); |
9275 | *q = save; | ||
9259 | } | 9276 | } |
9260 | 9277 | ||
9261 | *q = savec; | 9278 | pgetc_debug("preadbuffer at %d:%p'%s'", parsenleft, parsenextc, parsenextc); |
9262 | |||
9263 | return signed_char2int(*parsenextc++); | 9279 | return signed_char2int(*parsenextc++); |
9264 | } | 9280 | } |
9265 | 9281 | ||
9266 | #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer()) | 9282 | #define pgetc_as_macro() (--parsenleft >= 0 ? signed_char2int(*parsenextc++) : preadbuffer()) |
9283 | |||
9267 | static int | 9284 | static int |
9268 | pgetc(void) | 9285 | pgetc(void) |
9269 | { | 9286 | { |
9287 | pgetc_debug("pgetc at %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||
9270 | return pgetc_as_macro(); | 9288 | return pgetc_as_macro(); |
9271 | } | 9289 | } |
9272 | 9290 | ||
@@ -9325,11 +9343,9 @@ pfgets(char *line, int len) | |||
9325 | static void | 9343 | static void |
9326 | pungetc(void) | 9344 | pungetc(void) |
9327 | { | 9345 | { |
9328 | /* check is needed for ash -c 'echo 5&' + BASH_COMPAT to work */ | ||
9329 | if (parsenleft < 0) | ||
9330 | return; | ||
9331 | parsenleft++; | 9346 | parsenleft++; |
9332 | parsenextc--; | 9347 | parsenextc--; |
9348 | pgetc_debug("pushed back to %d:%p'%s'", parsenleft, parsenextc, parsenextc); | ||
9333 | } | 9349 | } |
9334 | 9350 | ||
9335 | /* | 9351 | /* |
@@ -9343,16 +9359,17 @@ static void | |||
9343 | pushstring(char *s, struct alias *ap) | 9359 | pushstring(char *s, struct alias *ap) |
9344 | { | 9360 | { |
9345 | struct strpush *sp; | 9361 | struct strpush *sp; |
9346 | size_t len; | 9362 | int len; |
9347 | 9363 | ||
9348 | len = strlen(s); | 9364 | len = strlen(s); |
9349 | INT_OFF; | 9365 | INT_OFF; |
9350 | if (g_parsefile->strpush) { | 9366 | if (g_parsefile->strpush) { |
9351 | sp = ckzalloc(sizeof(struct strpush)); | 9367 | sp = ckzalloc(sizeof(*sp)); |
9352 | sp->prev = g_parsefile->strpush; | 9368 | sp->prev = g_parsefile->strpush; |
9353 | g_parsefile->strpush = sp; | 9369 | } else { |
9354 | } else | 9370 | sp = &(g_parsefile->basestrpush); |
9355 | sp = g_parsefile->strpush = &(g_parsefile->basestrpush); | 9371 | } |
9372 | g_parsefile->strpush = sp; | ||
9356 | sp->prevstring = parsenextc; | 9373 | sp->prevstring = parsenextc; |
9357 | sp->prevnleft = parsenleft; | 9374 | sp->prevnleft = parsenleft; |
9358 | #if ENABLE_ASH_ALIAS | 9375 | #if ENABLE_ASH_ALIAS |
@@ -9442,7 +9459,7 @@ setinputfd(int fd, int push) | |||
9442 | close_on_exec_on(fd); | 9459 | close_on_exec_on(fd); |
9443 | if (push) { | 9460 | if (push) { |
9444 | pushfile(); | 9461 | pushfile(); |
9445 | g_parsefile->buf = 0; | 9462 | g_parsefile->buf = NULL; |
9446 | } | 9463 | } |
9447 | g_parsefile->fd = fd; | 9464 | g_parsefile->fd = fd; |
9448 | if (g_parsefile->buf == NULL) | 9465 | 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 000000000..3da21aec2 --- /dev/null +++ b/shell/ash_test/ash-misc/last_amp.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 3 | ||
2 | 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 000000000..160937644 --- /dev/null +++ b/shell/ash_test/ash-misc/last_amp.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | $THIS_SH -c 'echo 3&' | ||
2 | d=`date` | ||
3 | while test "`date`" = "$d"; do true; done | ||
4 | d1=`date` | ||
5 | $THIS_SH -c 'sleep 1&' | ||
6 | d2=`date` | ||
7 | test "$d1" = "$d2" || echo BAD | ||
8 | echo End | ||