aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-11-28 03:41:47 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-11-28 03:41:47 +0000
commit727752d2d2968e67784935dd35c32a97c0c13a7c (patch)
tree3cf5e79044841dd0b342cc0d8e0843b5f9be87b1
parent9e0a7c9c414e3e155d965c8b8b1dfed42ca21ec5 (diff)
downloadbusybox-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.c75
-rw-r--r--shell/ash_test/ash-misc/last_amp.right2
-rwxr-xr-xshell/ash_test/ash-misc/last_amp.tests8
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
9084enum { 9082enum {
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)
9193static int 9192static int
9194preadbuffer(void) 9193preadbuffer(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
9267static int 9284static int
9268pgetc(void) 9285pgetc(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)
9325static void 9343static void
9326pungetc(void) 9344pungetc(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
9343pushstring(char *s, struct alias *ap) 9359pushstring(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 @@
13
2End
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&'
2d=`date`
3while test "`date`" = "$d"; do true; done
4d1=`date`
5$THIS_SH -c 'sleep 1&'
6d2=`date`
7test "$d1" = "$d2" || echo BAD
8echo End