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 | |
parent | 32afd3aa6039b911816a68972b2366095cb777de (diff) |
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>
-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); * last_line_pos - screen line position of next char to be read * (takes into account tabs and backspaces) * eof_error - < 0 error, == 0 EOF, > 0 not EOF/error + * + * "git log -p | less -m" on the kernel git tree is a good test for EAGAINs, + * "/search on very long input" and "reaching max line count" corner cases. */ static void read_lines(void) { @@ -414,9 +417,13 @@ static void read_lines(void) #if ENABLE_FEATURE_LESS_REGEXP unsigned old_max_fline = max_fline; time_t last_time = 0; - unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */ + int had_progress = 2; #endif + /* (careful: max_fline can be -1) */ + if (max_fline + 1 > MAXLINES) + return; + if (option_mask32 & FLAG_N) w -= 8; @@ -441,6 +448,7 @@ static void read_lines(void) char c; /* if no unprocessed chars left, eat more */ if (readpos >= readeof) { + errno = 0; ndelay_on(0); eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); ndelay_off(0); @@ -448,6 +456,7 @@ static void read_lines(void) readeof = eof_error; if (eof_error <= 0) goto reached_eof; + had_progress = 1; } c = readbuf[readpos]; /* backspace? [needed for manpages] */ @@ -519,31 +528,23 @@ static void read_lines(void) #endif } if (eof_error <= 0) { - if (eof_error < 0) { - if (errno == EAGAIN) { - /* not yet eof or error, reset flag (or else - * we will hog CPU - select() will return - * immediately */ - eof_error = 1; - } else { - print_statusline(bb_msg_read_error); - } - } #if !ENABLE_FEATURE_LESS_REGEXP break; #else if (wanted_match < num_matches) { break; - } else { /* goto_match called us */ + } /* else: goto_match() called us */ + if (errno == EAGAIN) { time_t t = time(NULL); if (t != last_time) { last_time = t; - if (--seconds_p1 == 0) + if (--had_progress < 0) break; } sched_yield(); - goto again0; /* go loop again (max 2 seconds) */ + goto again0; } + break; #endif } max_fline++; @@ -551,6 +552,15 @@ static void read_lines(void) p = current_line; last_line_pos = 0; } /* end of "read lines until we reach cur_fline" loop */ + + if (eof_error < 0) { + if (errno == EAGAIN) { + eof_error = 1; + } else { + print_statusline(bb_msg_read_error); + } + } + fill_match_lines(old_max_fline); #if ENABLE_FEATURE_LESS_REGEXP /* prevent us from being stuck in search for a match */ |