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 | |
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
-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 | ||