aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2014-04-07 23:32:29 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2014-04-13 16:02:59 +0200
commit69b114fb8a2566e14ce125f7736add9dacf6e18d (patch)
tree0cc71c61e0fc30d3349e686fbee545e6d56e528e
parent32afd3aa6039b911816a68972b2366095cb777de (diff)
downloadbusybox-69b114fb8a2566e14ce125f7736add9dacf6e18d.tar.gz
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.c38
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 */