diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-01 09:35:39 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-01 09:35:39 +0000 |
| commit | fe2188378c352255b7d0407513ca73ec3f933153 (patch) | |
| tree | 01fcce006eb6d8b0fe1e448bc10ba68615049f1d /shell | |
| parent | 8a2e421f26623773b9f79f322b808a757ff055c0 (diff) | |
| download | busybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.tar.gz busybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.tar.bz2 busybox-w32-fe2188378c352255b7d0407513ca73ec3f933153.zip | |
msh: fix for bug 846 ("break" didn't work second time)
msh: don't use floating point in "times" builtin
+4 bytes difference
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/msh.c | 204 | ||||
| -rw-r--r-- | shell/msh_test/TODO_bug846 | 29 |
2 files changed, 148 insertions, 85 deletions
diff --git a/shell/msh.c b/shell/msh.c index 569011bbd..e98c6017a 100644 --- a/shell/msh.c +++ b/shell/msh.c | |||
| @@ -489,36 +489,37 @@ static char **getwords(struct wdblock *wb); | |||
| 489 | 489 | ||
| 490 | /* -------- misc stuff -------- */ | 490 | /* -------- misc stuff -------- */ |
| 491 | 491 | ||
| 492 | static int dolabel(struct op *t, char **args); | ||
| 493 | static int dohelp(struct op *t, char **args); | ||
| 494 | static int dochdir(struct op *t, char **args); | ||
| 495 | static int doshift(struct op *t, char **args); | ||
| 496 | static int dologin(struct op *t, char **args); | ||
| 497 | static int doumask(struct op *t, char **args); | ||
| 498 | static int doexec(struct op *t, char **args); | ||
| 499 | static int dodot(struct op *t, char **args); | ||
| 500 | static int dowait(struct op *t, char **args); | ||
| 501 | static int doread(struct op *t, char **args); | ||
| 502 | static int doeval(struct op *t, char **args); | ||
| 503 | static int dotrap(struct op *t, char **args); | ||
| 504 | static int dobreak(struct op *t, char **args); | ||
| 505 | static int doexit(struct op *t, char **args); | ||
| 506 | static int doexport(struct op *t, char **args); | ||
| 507 | static int doreadonly(struct op *t, char **args); | ||
| 508 | static int doset(struct op *t, char **args); | ||
| 509 | static int dotimes(struct op *t, char **args); | ||
| 510 | static int docontinue(struct op *t, char **args); | ||
| 511 | |||
| 492 | static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp); | 512 | static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp); |
| 493 | static int execute(struct op *t, int *pin, int *pout, int no_fork); | 513 | static int execute(struct op *t, int *pin, int *pout, int no_fork); |
| 494 | static int iosetup(struct ioword *iop, int pipein, int pipeout); | 514 | static int iosetup(struct ioword *iop, int pipein, int pipeout); |
| 495 | static void brkset(struct brkcon *bc); | 515 | static void brkset(struct brkcon *bc); |
| 496 | static int dolabel(struct op *t); | ||
| 497 | static int dohelp(struct op *t); | ||
| 498 | static int dochdir(struct op *t); | ||
| 499 | static int doshift(struct op *t); | ||
| 500 | static int dologin(struct op *t); | ||
| 501 | static int doumask(struct op *t); | ||
| 502 | static int doexec(struct op *t); | ||
| 503 | static int dodot(struct op *t); | ||
| 504 | static int dowait(struct op *t); | ||
| 505 | static int doread(struct op *t); | ||
| 506 | static int doeval(struct op *t); | ||
| 507 | static int dotrap(struct op *t); | ||
| 508 | static int getsig(char *s); | 516 | static int getsig(char *s); |
| 509 | static void setsig(int n, sighandler_t f); | 517 | static void setsig(int n, sighandler_t f); |
| 510 | static int getn(char *as); | 518 | static int getn(char *as); |
| 511 | static int dobreak(struct op *t); | ||
| 512 | static int docontinue(struct op *t); | ||
| 513 | static int brkcontin(char *cp, int val); | 519 | static int brkcontin(char *cp, int val); |
| 514 | static int doexit(struct op *t); | ||
| 515 | static int doexport(struct op *t); | ||
| 516 | static int doreadonly(struct op *t); | ||
| 517 | static void rdexp(char **wp, void (*f) (struct var *), int key); | 520 | static void rdexp(char **wp, void (*f) (struct var *), int key); |
| 518 | static void badid(char *s); | 521 | static void badid(char *s); |
| 519 | static int doset(struct op *t); | ||
| 520 | static void varput(char *s, int out); | 522 | static void varput(char *s, int out); |
| 521 | static int dotimes(struct op *t); | ||
| 522 | static int expand(const char *cp, struct wdblock **wbp, int f); | 523 | static int expand(const char *cp, struct wdblock **wbp, int f); |
| 523 | static char *blank(int f); | 524 | static char *blank(int f); |
| 524 | static int dollar(int quoted); | 525 | static int dollar(int quoted); |
| @@ -559,7 +560,7 @@ static const char *const signame[] = { | |||
| 559 | }; | 560 | }; |
| 560 | 561 | ||
| 561 | 562 | ||
| 562 | typedef int (*builtin_func_ptr)(struct op *); | 563 | typedef int (*builtin_func_ptr)(struct op *, char **); |
| 563 | 564 | ||
| 564 | struct builtincmd { | 565 | struct builtincmd { |
| 565 | const char *name; | 566 | const char *name; |
| @@ -1821,7 +1822,7 @@ static struct op *command(int cf) | |||
| 1821 | t->type = (c == WHILE ? TWHILE : TUNTIL); | 1822 | t->type = (c == WHILE ? TWHILE : TUNTIL); |
| 1822 | t->left = c_list(); | 1823 | t->left = c_list(); |
| 1823 | t->right = dogroup(1); | 1824 | t->right = dogroup(1); |
| 1824 | t->words = NULL; | 1825 | /* t->words = NULL; - newtp() did this */ |
| 1825 | multiline--; | 1826 | multiline--; |
| 1826 | break; | 1827 | break; |
| 1827 | 1828 | ||
| @@ -2741,7 +2742,13 @@ static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp) | |||
| 2741 | } | 2742 | } |
| 2742 | 2743 | ||
| 2743 | forked = 0; | 2744 | forked = 0; |
| 2744 | t->words = wp; | 2745 | // We were pointing t->words to temporary (expanded) arg list: |
| 2746 | // t->words = wp; | ||
| 2747 | // and restored it later (in execute()), but "break" | ||
| 2748 | // longjmps away (at "Run builtin" below), leaving t->words clobbered! | ||
| 2749 | // See http://bugs.busybox.net/view.php?id=846. | ||
| 2750 | // Now we do not touch t->words, but separately pass wp as param list | ||
| 2751 | // to builtins | ||
| 2745 | DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin, | 2752 | DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin, |
| 2746 | no_fork, owp)); | 2753 | no_fork, owp)); |
| 2747 | /* Don't fork if it is a lone builtin (not in pipe) | 2754 | /* Don't fork if it is a lone builtin (not in pipe) |
| @@ -2836,7 +2843,8 @@ static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp) | |||
| 2836 | _exit(-1); | 2843 | _exit(-1); |
| 2837 | return -1; | 2844 | return -1; |
| 2838 | } | 2845 | } |
| 2839 | i = setstatus(bltin(t)); | 2846 | /* Run builtin */ |
| 2847 | i = setstatus(bltin(t, wp)); | ||
| 2840 | if (forked) | 2848 | if (forked) |
| 2841 | _exit(i); | 2849 | _exit(i); |
| 2842 | DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); | 2850 | DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); |
| @@ -3156,7 +3164,7 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *)) | |||
| 3156 | * built-in commands: doX | 3164 | * built-in commands: doX |
| 3157 | */ | 3165 | */ |
| 3158 | 3166 | ||
| 3159 | static int dohelp(struct op *t) | 3167 | static int dohelp(struct op *t, char **args) |
| 3160 | { | 3168 | { |
| 3161 | int col; | 3169 | int col; |
| 3162 | const struct builtincmd *x; | 3170 | const struct builtincmd *x; |
| @@ -3192,16 +3200,16 @@ static int dohelp(struct op *t) | |||
| 3192 | return EXIT_SUCCESS; | 3200 | return EXIT_SUCCESS; |
| 3193 | } | 3201 | } |
| 3194 | 3202 | ||
| 3195 | static int dolabel(struct op *t) | 3203 | static int dolabel(struct op *t, char **args) |
| 3196 | { | 3204 | { |
| 3197 | return 0; | 3205 | return 0; |
| 3198 | } | 3206 | } |
| 3199 | 3207 | ||
| 3200 | static int dochdir(struct op *t) | 3208 | static int dochdir(struct op *t, char **args) |
| 3201 | { | 3209 | { |
| 3202 | const char *cp, *er; | 3210 | const char *cp, *er; |
| 3203 | 3211 | ||
| 3204 | cp = t->words[1]; | 3212 | cp = args[1]; |
| 3205 | if (cp == NULL) { | 3213 | if (cp == NULL) { |
| 3206 | cp = homedir->value; | 3214 | cp = homedir->value; |
| 3207 | if (cp != NULL) | 3215 | if (cp != NULL) |
| @@ -3218,11 +3226,11 @@ static int dochdir(struct op *t) | |||
| 3218 | return 1; | 3226 | return 1; |
| 3219 | } | 3227 | } |
| 3220 | 3228 | ||
| 3221 | static int doshift(struct op *t) | 3229 | static int doshift(struct op *t, char **args) |
| 3222 | { | 3230 | { |
| 3223 | int n; | 3231 | int n; |
| 3224 | 3232 | ||
| 3225 | n = t->words[1] ? getn(t->words[1]) : 1; | 3233 | n = args[1] ? getn(args[1]) : 1; |
| 3226 | if (dolc < n) { | 3234 | if (dolc < n) { |
| 3227 | err("nothing to shift"); | 3235 | err("nothing to shift"); |
| 3228 | return 1; | 3236 | return 1; |
| @@ -3237,7 +3245,7 @@ static int doshift(struct op *t) | |||
| 3237 | /* | 3245 | /* |
| 3238 | * execute login and newgrp directly | 3246 | * execute login and newgrp directly |
| 3239 | */ | 3247 | */ |
| 3240 | static int dologin(struct op *t) | 3248 | static int dologin(struct op *t, char **args) |
| 3241 | { | 3249 | { |
| 3242 | const char *cp; | 3250 | const char *cp; |
| 3243 | 3251 | ||
| @@ -3245,19 +3253,19 @@ static int dologin(struct op *t) | |||
| 3245 | signal(SIGINT, SIG_DFL); | 3253 | signal(SIGINT, SIG_DFL); |
| 3246 | signal(SIGQUIT, SIG_DFL); | 3254 | signal(SIGQUIT, SIG_DFL); |
| 3247 | } | 3255 | } |
| 3248 | cp = rexecve(t->words[0], t->words, makenv(0, NULL)); | 3256 | cp = rexecve(args[0], args, makenv(0, NULL)); |
| 3249 | prs(t->words[0]); | 3257 | prs(args[0]); |
| 3250 | prs(": "); | 3258 | prs(": "); |
| 3251 | err(cp); | 3259 | err(cp); |
| 3252 | return 1; | 3260 | return 1; |
| 3253 | } | 3261 | } |
| 3254 | 3262 | ||
| 3255 | static int doumask(struct op *t) | 3263 | static int doumask(struct op *t, char **args) |
| 3256 | { | 3264 | { |
| 3257 | int i; | 3265 | int i; |
| 3258 | char *cp; | 3266 | char *cp; |
| 3259 | 3267 | ||
| 3260 | cp = t->words[1]; | 3268 | cp = args[1]; |
| 3261 | if (cp == NULL) { | 3269 | if (cp == NULL) { |
| 3262 | i = umask(0); | 3270 | i = umask(0); |
| 3263 | umask(i); | 3271 | umask(i); |
| @@ -3273,28 +3281,36 @@ static int doumask(struct op *t) | |||
| 3273 | return 0; | 3281 | return 0; |
| 3274 | } | 3282 | } |
| 3275 | 3283 | ||
| 3276 | static int doexec(struct op *t) | 3284 | static int doexec(struct op *t, char **args) |
| 3277 | { | 3285 | { |
| 3278 | int i; | ||
| 3279 | jmp_buf ex; | 3286 | jmp_buf ex; |
| 3280 | xint *ofail; | 3287 | xint *ofail; |
| 3288 | char **sv_words; | ||
| 3281 | 3289 | ||
| 3282 | t->ioact = NULL; | 3290 | t->ioact = NULL; |
| 3283 | for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++) | 3291 | if (!args[1]) |
| 3284 | continue; | ||
| 3285 | if (i == 0) | ||
| 3286 | return 1; | 3292 | return 1; |
| 3293 | |||
| 3287 | execflg = 1; | 3294 | execflg = 1; |
| 3288 | ofail = failpt; | 3295 | ofail = failpt; |
| 3289 | failpt = ex; | 3296 | failpt = ex; |
| 3297 | |||
| 3298 | sv_words = t->words; | ||
| 3299 | t->words = args + 1; | ||
| 3300 | // TODO: test what will happen with "exec break" - | ||
| 3301 | // will it leave t->words pointing to garbage? | ||
| 3302 | // (see http://bugs.busybox.net/view.php?id=846) | ||
| 3290 | if (setjmp(failpt) == 0) | 3303 | if (setjmp(failpt) == 0) |
| 3291 | execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1); | 3304 | execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1); |
| 3305 | t->words = sv_words; | ||
| 3306 | |||
| 3292 | failpt = ofail; | 3307 | failpt = ofail; |
| 3293 | execflg = 0; | 3308 | execflg = 0; |
| 3309 | |||
| 3294 | return 1; | 3310 | return 1; |
| 3295 | } | 3311 | } |
| 3296 | 3312 | ||
| 3297 | static int dodot(struct op *t) | 3313 | static int dodot(struct op *t, char **args) |
| 3298 | { | 3314 | { |
| 3299 | int i; | 3315 | int i; |
| 3300 | const char *sp; | 3316 | const char *sp; |
| @@ -3305,7 +3321,7 @@ static int dodot(struct op *t) | |||
| 3305 | DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n", | 3321 | DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n", |
| 3306 | t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep))); | 3322 | t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep))); |
| 3307 | 3323 | ||
| 3308 | cp = t->words[1]; | 3324 | cp = args[1]; |
| 3309 | if (cp == NULL) { | 3325 | if (cp == NULL) { |
| 3310 | DBGPRINTF(("DODOT: bad args, ret 0\n")); | 3326 | DBGPRINTF(("DODOT: bad args, ret 0\n")); |
| 3311 | return 0; | 3327 | return 0; |
| @@ -3349,12 +3365,12 @@ static int dodot(struct op *t) | |||
| 3349 | return -1; | 3365 | return -1; |
| 3350 | } | 3366 | } |
| 3351 | 3367 | ||
| 3352 | static int dowait(struct op *t) | 3368 | static int dowait(struct op *t, char **args) |
| 3353 | { | 3369 | { |
| 3354 | int i; | 3370 | int i; |
| 3355 | char *cp; | 3371 | char *cp; |
| 3356 | 3372 | ||
| 3357 | cp = t->words[1]; | 3373 | cp = args[1]; |
| 3358 | if (cp != NULL) { | 3374 | if (cp != NULL) { |
| 3359 | i = getn(cp); | 3375 | i = getn(cp); |
| 3360 | if (i == 0) | 3376 | if (i == 0) |
| @@ -3365,17 +3381,17 @@ static int dowait(struct op *t) | |||
| 3365 | return 0; | 3381 | return 0; |
| 3366 | } | 3382 | } |
| 3367 | 3383 | ||
| 3368 | static int doread(struct op *t) | 3384 | static int doread(struct op *t, char **args) |
| 3369 | { | 3385 | { |
| 3370 | char *cp, **wp; | 3386 | char *cp, **wp; |
| 3371 | int nb = 0; | 3387 | int nb = 0; |
| 3372 | int nl = 0; | 3388 | int nl = 0; |
| 3373 | 3389 | ||
| 3374 | if (t->words[1] == NULL) { | 3390 | if (args[1] == NULL) { |
| 3375 | err("Usage: read name ..."); | 3391 | err("Usage: read name ..."); |
| 3376 | return 1; | 3392 | return 1; |
| 3377 | } | 3393 | } |
| 3378 | for (wp = t->words + 1; *wp; wp++) { | 3394 | for (wp = args + 1; *wp; wp++) { |
| 3379 | for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) { | 3395 | for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) { |
| 3380 | nb = nonblock_safe_read(0, cp, sizeof(*cp)); | 3396 | nb = nonblock_safe_read(0, cp, sizeof(*cp)); |
| 3381 | if (nb != sizeof(*cp)) | 3397 | if (nb != sizeof(*cp)) |
| @@ -3392,17 +3408,17 @@ static int doread(struct op *t) | |||
| 3392 | return nb <= 0; | 3408 | return nb <= 0; |
| 3393 | } | 3409 | } |
| 3394 | 3410 | ||
| 3395 | static int doeval(struct op *t) | 3411 | static int doeval(struct op *t, char **args) |
| 3396 | { | 3412 | { |
| 3397 | return RUN(awordlist, t->words + 1, wdchar); | 3413 | return RUN(awordlist, args + 1, wdchar); |
| 3398 | } | 3414 | } |
| 3399 | 3415 | ||
| 3400 | static int dotrap(struct op *t) | 3416 | static int dotrap(struct op *t, char **args) |
| 3401 | { | 3417 | { |
| 3402 | int n, i; | 3418 | int n, i; |
| 3403 | int resetsig; | 3419 | int resetsig; |
| 3404 | 3420 | ||
| 3405 | if (t->words[1] == NULL) { | 3421 | if (args[1] == NULL) { |
| 3406 | for (i = 0; i <= _NSIG; i++) | 3422 | for (i = 0; i <= _NSIG; i++) |
| 3407 | if (trap[i]) { | 3423 | if (trap[i]) { |
| 3408 | prn(i); | 3424 | prn(i); |
| @@ -3412,14 +3428,14 @@ static int dotrap(struct op *t) | |||
| 3412 | } | 3428 | } |
| 3413 | return 0; | 3429 | return 0; |
| 3414 | } | 3430 | } |
| 3415 | resetsig = isdigit(*t->words[1]); | 3431 | resetsig = isdigit(args[1][0]); |
| 3416 | for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { | 3432 | for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) { |
| 3417 | n = getsig(t->words[i]); | 3433 | n = getsig(args[i]); |
| 3418 | freecell(trap[n]); | 3434 | freecell(trap[n]); |
| 3419 | trap[n] = 0; | 3435 | trap[n] = 0; |
| 3420 | if (!resetsig) { | 3436 | if (!resetsig) { |
| 3421 | if (*t->words[1] != '\0') { | 3437 | if (args[1][0] != '\0') { |
| 3422 | trap[n] = strsave(t->words[1], 0); | 3438 | trap[n] = strsave(args[1], 0); |
| 3423 | setsig(n, sig); | 3439 | setsig(n, sig); |
| 3424 | } else | 3440 | } else |
| 3425 | setsig(n, SIG_IGN); | 3441 | setsig(n, SIG_IGN); |
| @@ -3478,14 +3494,14 @@ static int getn(char *as) | |||
| 3478 | return n * m; | 3494 | return n * m; |
| 3479 | } | 3495 | } |
| 3480 | 3496 | ||
| 3481 | static int dobreak(struct op *t) | 3497 | static int dobreak(struct op *t, char **args) |
| 3482 | { | 3498 | { |
| 3483 | return brkcontin(t->words[1], 1); | 3499 | return brkcontin(args[1], 1); |
| 3484 | } | 3500 | } |
| 3485 | 3501 | ||
| 3486 | static int docontinue(struct op *t) | 3502 | static int docontinue(struct op *t, char **args) |
| 3487 | { | 3503 | { |
| 3488 | return brkcontin(t->words[1], 0); | 3504 | return brkcontin(args[1], 0); |
| 3489 | } | 3505 | } |
| 3490 | 3506 | ||
| 3491 | static int brkcontin(char *cp, int val) | 3507 | static int brkcontin(char *cp, int val) |
| @@ -3511,12 +3527,12 @@ static int brkcontin(char *cp, int val) | |||
| 3511 | /* NOTREACHED */ | 3527 | /* NOTREACHED */ |
| 3512 | } | 3528 | } |
| 3513 | 3529 | ||
| 3514 | static int doexit(struct op *t) | 3530 | static int doexit(struct op *t, char **args) |
| 3515 | { | 3531 | { |
| 3516 | char *cp; | 3532 | char *cp; |
| 3517 | 3533 | ||
| 3518 | execflg = 0; | 3534 | execflg = 0; |
| 3519 | cp = t->words[1]; | 3535 | cp = args[1]; |
| 3520 | if (cp != NULL) | 3536 | if (cp != NULL) |
| 3521 | setstatus(getn(cp)); | 3537 | setstatus(getn(cp)); |
| 3522 | 3538 | ||
| @@ -3527,15 +3543,15 @@ static int doexit(struct op *t) | |||
| 3527 | return 0; | 3543 | return 0; |
| 3528 | } | 3544 | } |
| 3529 | 3545 | ||
| 3530 | static int doexport(struct op *t) | 3546 | static int doexport(struct op *t, char **args) |
| 3531 | { | 3547 | { |
| 3532 | rdexp(t->words + 1, export, EXPORT); | 3548 | rdexp(args + 1, export, EXPORT); |
| 3533 | return 0; | 3549 | return 0; |
| 3534 | } | 3550 | } |
| 3535 | 3551 | ||
| 3536 | static int doreadonly(struct op *t) | 3552 | static int doreadonly(struct op *t, char **args) |
| 3537 | { | 3553 | { |
| 3538 | rdexp(t->words + 1, ronly, RONLY); | 3554 | rdexp(args + 1, ronly, RONLY); |
| 3539 | return 0; | 3555 | return 0; |
| 3540 | } | 3556 | } |
| 3541 | 3557 | ||
| @@ -3568,21 +3584,20 @@ static void badid(char *s) | |||
| 3568 | err(": bad identifier"); | 3584 | err(": bad identifier"); |
| 3569 | } | 3585 | } |
| 3570 | 3586 | ||
| 3571 | static int doset(struct op *t) | 3587 | static int doset(struct op *t, char **args) |
| 3572 | { | 3588 | { |
| 3573 | struct var *vp; | 3589 | struct var *vp; |
| 3574 | char *cp; | 3590 | char *cp; |
| 3575 | int n; | 3591 | int n; |
| 3576 | 3592 | ||
| 3577 | cp = t->words[1]; | 3593 | cp = args[1]; |
| 3578 | if (cp == NULL) { | 3594 | if (cp == NULL) { |
| 3579 | for (vp = vlist; vp; vp = vp->next) | 3595 | for (vp = vlist; vp; vp = vp->next) |
| 3580 | varput(vp->name, 1); | 3596 | varput(vp->name, 1); |
| 3581 | return 0; | 3597 | return 0; |
| 3582 | } | 3598 | } |
| 3583 | if (*cp == '-') { | 3599 | if (*cp == '-') { |
| 3584 | /* bad: t->words++; */ | 3600 | args++; |
| 3585 | for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); | ||
| 3586 | if (*++cp == 0) | 3601 | if (*++cp == 0) |
| 3587 | FLAG['x'] = FLAG['v'] = 0; | 3602 | FLAG['x'] = FLAG['v'] = 0; |
| 3588 | else { | 3603 | else { |
| @@ -3602,12 +3617,12 @@ static int doset(struct op *t) | |||
| 3602 | } | 3617 | } |
| 3603 | setdash(); | 3618 | setdash(); |
| 3604 | } | 3619 | } |
| 3605 | if (t->words[1]) { | 3620 | if (args[1]) { |
| 3606 | t->words[0] = dolv[0]; | 3621 | args[0] = dolv[0]; |
| 3607 | for (n = 1; t->words[n]; n++) | 3622 | for (n = 1; args[n]; n++) |
| 3608 | setarea((char *) t->words[n], 0); | 3623 | setarea((char *) args[n], 0); |
| 3609 | dolc = n - 1; | 3624 | dolc = n - 1; |
| 3610 | dolv = t->words; | 3625 | dolv = args; |
| 3611 | setval(lookup("#"), putn(dolc)); | 3626 | setval(lookup("#"), putn(dolc)); |
| 3612 | setarea((char *) (dolv - 1), 0); | 3627 | setarea((char *) (dolv - 1), 0); |
| 3613 | } | 3628 | } |
| @@ -3627,21 +3642,40 @@ static void varput(char *s, int out) | |||
| 3627 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> | 3642 | * Copyright (c) 1999 Herbert Xu <herbert@debian.org> |
| 3628 | * This file contains code for the times builtin. | 3643 | * This file contains code for the times builtin. |
| 3629 | */ | 3644 | */ |
| 3630 | static int dotimes(struct op *t) | 3645 | static void times_fmt(char *buf, clock_t val, unsigned clk_tck) |
| 3646 | { | ||
| 3647 | unsigned min, sec; | ||
| 3648 | if (sizeof(val) > sizeof(int)) | ||
| 3649 | sec = ((unsigned long)val) / clk_tck; | ||
| 3650 | else | ||
| 3651 | sec = ((unsigned)val) / clk_tck; | ||
| 3652 | min = sec / 60; | ||
| 3653 | #if ENABLE_DESKTOP | ||
| 3654 | sprintf(buf, "%um%u.%03us", min, (sec - min * 60), | ||
| 3655 | /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck | ||
| 3656 | ); | ||
| 3657 | #else | ||
| 3658 | sprintf(buf, "%um%us", min, (sec - min * 60)); | ||
| 3659 | #endif | ||
| 3660 | } | ||
| 3661 | |||
| 3662 | static int dotimes(struct op *t, char **args) | ||
| 3631 | { | 3663 | { |
| 3632 | struct tms buf; | 3664 | struct tms buf; |
| 3633 | long clk_tck = sysconf(_SC_CLK_TCK); | 3665 | unsigned clk_tck = sysconf(_SC_CLK_TCK); |
| 3666 | /* How much do we need for "NmN.NNNs" ? */ | ||
| 3667 | enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 }; | ||
| 3668 | char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE]; | ||
| 3669 | char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE]; | ||
| 3634 | 3670 | ||
| 3635 | times(&buf); | 3671 | times(&buf); |
| 3636 | printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", | 3672 | |
| 3637 | (int) (buf.tms_utime / clk_tck / 60), | 3673 | times_fmt(u, buf.tms_utime, clk_tck); |
| 3638 | ((double) buf.tms_utime) / clk_tck, | 3674 | times_fmt(s, buf.tms_stime, clk_tck); |
| 3639 | (int) (buf.tms_stime / clk_tck / 60), | 3675 | times_fmt(cu, buf.tms_cutime, clk_tck); |
| 3640 | ((double) buf.tms_stime) / clk_tck, | 3676 | times_fmt(cs, buf.tms_cstime, clk_tck); |
| 3641 | (int) (buf.tms_cutime / clk_tck / 60), | 3677 | |
| 3642 | ((double) buf.tms_cutime) / clk_tck, | 3678 | printf("%s %s\n%s %s\n", u, s, cu, cs); |
| 3643 | (int) (buf.tms_cstime / clk_tck / 60), | ||
| 3644 | ((double) buf.tms_cstime) / clk_tck); | ||
| 3645 | return 0; | 3679 | return 0; |
| 3646 | } | 3680 | } |
| 3647 | 3681 | ||
diff --git a/shell/msh_test/TODO_bug846 b/shell/msh_test/TODO_bug846 new file mode 100644 index 000000000..5c777fedb --- /dev/null +++ b/shell/msh_test/TODO_bug846 | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # For future msh testsuite: | ||
| 3 | # Testcase for http://bugs.busybox.net/view.php?id=846 | ||
| 4 | |||
| 5 | n=0 | ||
| 6 | while : | ||
| 7 | do | ||
| 8 | echo A | ||
| 9 | while : | ||
| 10 | do | ||
| 11 | echo B | ||
| 12 | break | ||
| 13 | done | ||
| 14 | echo iteration | ||
| 15 | [ $n = 1 ] && break | ||
| 16 | echo C | ||
| 17 | n=`expr $n + 1` | ||
| 18 | done | ||
| 19 | echo D | ||
| 20 | |||
| 21 | # output should be: | ||
| 22 | # A | ||
| 23 | # B | ||
| 24 | # iteration | ||
| 25 | # C | ||
| 26 | # A | ||
| 27 | # B | ||
| 28 | # iteration | ||
| 29 | # D | ||
