diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-04-07 23:32:29 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-04-13 16:02:59 +0200 |
commit | 69b114fb8a2566e14ce125f7736add9dacf6e18d (patch) | |
tree | 0cc71c61e0fc30d3349e686fbee545e6d56e528e /miscutils/less.c | |
parent | 32afd3aa6039b911816a68972b2366095cb777de (diff) | |
download | busybox-w32-69b114fb8a2566e14ce125f7736add9dacf6e18d.tar.gz busybox-w32-69b114fb8a2566e14ce125f7736add9dacf6e18d.tar.bz2 busybox-w32-69b114fb8a2566e14ce125f7736add9dacf6e18d.zip |
less: fix bugs discovered with "git log -p | less -m" on kernel tree
function old new delta
read_lines 685 733 +48
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'miscutils/less.c')
-rw-r--r-- | miscutils/less.c | 38 |
1 files changed, 24 insertions, 14 deletions
diff --git a/miscutils/less.c b/miscutils/less.c index 574f222e0..36d0a0bd9 100644 --- a/miscutils/less.c +++ b/miscutils/less.c | |||
@@ -404,6 +404,9 @@ static void fill_match_lines(unsigned pos); | |||
404 | * last_line_pos - screen line position of next char to be read | 404 | * last_line_pos - screen line position of next char to be read |
405 | * (takes into account tabs and backspaces) | 405 | * (takes into account tabs and backspaces) |
406 | * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error | 406 | * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error |
407 | * | ||
408 | * "git log -p | less -m" on the kernel git tree is a good test for EAGAINs, | ||
409 | * "/search on very long input" and "reaching max line count" corner cases. | ||
407 | */ | 410 | */ |
408 | static void read_lines(void) | 411 | static void read_lines(void) |
409 | { | 412 | { |
@@ -414,9 +417,13 @@ static void read_lines(void) | |||
414 | #if ENABLE_FEATURE_LESS_REGEXP | 417 | #if ENABLE_FEATURE_LESS_REGEXP |
415 | unsigned old_max_fline = max_fline; | 418 | unsigned old_max_fline = max_fline; |
416 | time_t last_time = 0; | 419 | time_t last_time = 0; |
417 | unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */ | 420 | int had_progress = 2; |
418 | #endif | 421 | #endif |
419 | 422 | ||
423 | /* (careful: max_fline can be -1) */ | ||
424 | if (max_fline + 1 > MAXLINES) | ||
425 | return; | ||
426 | |||
420 | if (option_mask32 & FLAG_N) | 427 | if (option_mask32 & FLAG_N) |
421 | w -= 8; | 428 | w -= 8; |
422 | 429 | ||
@@ -441,6 +448,7 @@ static void read_lines(void) | |||
441 | char c; | 448 | char c; |
442 | /* if no unprocessed chars left, eat more */ | 449 | /* if no unprocessed chars left, eat more */ |
443 | if (readpos >= readeof) { | 450 | if (readpos >= readeof) { |
451 | errno = 0; | ||
444 | ndelay_on(0); | 452 | ndelay_on(0); |
445 | eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); | 453 | eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); |
446 | ndelay_off(0); | 454 | ndelay_off(0); |
@@ -448,6 +456,7 @@ static void read_lines(void) | |||
448 | readeof = eof_error; | 456 | readeof = eof_error; |
449 | if (eof_error <= 0) | 457 | if (eof_error <= 0) |
450 | goto reached_eof; | 458 | goto reached_eof; |
459 | had_progress = 1; | ||
451 | } | 460 | } |
452 | c = readbuf[readpos]; | 461 | c = readbuf[readpos]; |
453 | /* backspace? [needed for manpages] */ | 462 | /* backspace? [needed for manpages] */ |
@@ -519,31 +528,23 @@ static void read_lines(void) | |||
519 | #endif | 528 | #endif |
520 | } | 529 | } |
521 | if (eof_error <= 0) { | 530 | if (eof_error <= 0) { |
522 | if (eof_error < 0) { | ||
523 | if (errno == EAGAIN) { | ||
524 | /* not yet eof or error, reset flag (or else | ||
525 | * we will hog CPU - select() will return | ||
526 | * immediately */ | ||
527 | eof_error = 1; | ||
528 | } else { | ||
529 | print_statusline(bb_msg_read_error); | ||
530 | } | ||
531 | } | ||
532 | #if !ENABLE_FEATURE_LESS_REGEXP | 531 | #if !ENABLE_FEATURE_LESS_REGEXP |
533 | break; | 532 | break; |
534 | #else | 533 | #else |
535 | if (wanted_match < num_matches) { | 534 | if (wanted_match < num_matches) { |
536 | break; | 535 | break; |
537 | } else { /* goto_match called us */ | 536 | } /* else: goto_match() called us */ |
537 | if (errno == EAGAIN) { | ||
538 | time_t t = time(NULL); | 538 | time_t t = time(NULL); |
539 | if (t != last_time) { | 539 | if (t != last_time) { |
540 | last_time = t; | 540 | last_time = t; |
541 | if (--seconds_p1 == 0) | 541 | if (--had_progress < 0) |
542 | break; | 542 | break; |
543 | } | 543 | } |
544 | sched_yield(); | 544 | sched_yield(); |
545 | goto again0; /* go loop again (max 2 seconds) */ | 545 | goto again0; |
546 | } | 546 | } |
547 | break; | ||
547 | #endif | 548 | #endif |
548 | } | 549 | } |
549 | max_fline++; | 550 | max_fline++; |
@@ -551,6 +552,15 @@ static void read_lines(void) | |||
551 | p = current_line; | 552 | p = current_line; |
552 | last_line_pos = 0; | 553 | last_line_pos = 0; |
553 | } /* end of "read lines until we reach cur_fline" loop */ | 554 | } /* end of "read lines until we reach cur_fline" loop */ |
555 | |||
556 | if (eof_error < 0) { | ||
557 | if (errno == EAGAIN) { | ||
558 | eof_error = 1; | ||
559 | } else { | ||
560 | print_statusline(bb_msg_read_error); | ||
561 | } | ||
562 | } | ||
563 | |||
554 | fill_match_lines(old_max_fline); | 564 | fill_match_lines(old_max_fline); |
555 | #if ENABLE_FEATURE_LESS_REGEXP | 565 | #if ENABLE_FEATURE_LESS_REGEXP |
556 | /* prevent us from being stuck in search for a match */ | 566 | /* prevent us from being stuck in search for a match */ |