less: fix bugs discovered with "git log -p | less -m" on kernel tree
No binary (build failed)
—
(log yok)
| @@ -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 */ | |