mirror of
https://github.com/sheumann/hush.git
synced 2025-01-14 12:30:40 +00:00
less: improve search when data is not supplied fast enough by stdin -
now will try reading for 1-2 seconds before declaring that there is no match. This fixes a very common annoyance with long manpages. function old new delta read_lines 653 719 +66 buffer_down 28 83 +55 goto_match 140 141 +1 cap_cur_fline 72 - -72 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 3/0 up/down: 122/-72) Total: 50 bytes text data bss dec hex filename 798734 661 7428 806823 c4fa7 busybox_old 798768 661 7428 806857 c4fc9 busybox_unstripped
This commit is contained in:
parent
aefed941c2
commit
107fe7c081
116
miscutils/less.c
116
miscutils/less.c
@ -98,8 +98,8 @@ struct globals {
|
|||||||
unsigned max_lineno; /* this one tracks linewrap */
|
unsigned max_lineno; /* this one tracks linewrap */
|
||||||
unsigned width;
|
unsigned width;
|
||||||
ssize_t eof_error; /* eof if 0, error if < 0 */
|
ssize_t eof_error; /* eof if 0, error if < 0 */
|
||||||
size_t readpos;
|
ssize_t readpos;
|
||||||
size_t readeof;
|
ssize_t readeof; /* must be signed */
|
||||||
const char **buffer;
|
const char **buffer;
|
||||||
const char **flines;
|
const char **flines;
|
||||||
const char *empty_line_marker;
|
const char *empty_line_marker;
|
||||||
@ -114,7 +114,8 @@ struct globals {
|
|||||||
#if ENABLE_FEATURE_LESS_REGEXP
|
#if ENABLE_FEATURE_LESS_REGEXP
|
||||||
unsigned *match_lines;
|
unsigned *match_lines;
|
||||||
int match_pos; /* signed! */
|
int match_pos; /* signed! */
|
||||||
unsigned num_matches;
|
int wanted_match; /* signed! */
|
||||||
|
int num_matches;
|
||||||
regex_t pattern;
|
regex_t pattern;
|
||||||
smallint pattern_valid;
|
smallint pattern_valid;
|
||||||
#endif
|
#endif
|
||||||
@ -146,6 +147,7 @@ struct globals {
|
|||||||
#define match_lines (G.match_lines )
|
#define match_lines (G.match_lines )
|
||||||
#define match_pos (G.match_pos )
|
#define match_pos (G.match_pos )
|
||||||
#define num_matches (G.num_matches )
|
#define num_matches (G.num_matches )
|
||||||
|
#define wanted_match (G.wanted_match )
|
||||||
#define pattern (G.pattern )
|
#define pattern (G.pattern )
|
||||||
#define pattern_valid (G.pattern_valid )
|
#define pattern_valid (G.pattern_valid )
|
||||||
#endif
|
#endif
|
||||||
@ -160,6 +162,7 @@ struct globals {
|
|||||||
current_file = 1; \
|
current_file = 1; \
|
||||||
eof_error = 1; \
|
eof_error = 1; \
|
||||||
terminated = 1; \
|
terminated = 1; \
|
||||||
|
USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Reset terminal input to normal */
|
/* Reset terminal input to normal */
|
||||||
@ -235,15 +238,20 @@ static void read_lines(void)
|
|||||||
{
|
{
|
||||||
#define readbuf bb_common_bufsiz1
|
#define readbuf bb_common_bufsiz1
|
||||||
char *current_line, *p;
|
char *current_line, *p;
|
||||||
USE_FEATURE_LESS_REGEXP(unsigned old_max_fline = max_fline;)
|
|
||||||
int w = width;
|
int w = width;
|
||||||
char last_terminated = terminated;
|
char last_terminated = terminated;
|
||||||
|
#if ENABLE_FEATURE_LESS_REGEXP
|
||||||
|
unsigned old_max_fline = max_fline;
|
||||||
|
time_t last_time = 0;
|
||||||
|
unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */
|
||||||
|
#endif
|
||||||
|
|
||||||
if (option_mask32 & FLAG_N)
|
if (option_mask32 & FLAG_N)
|
||||||
w -= 8;
|
w -= 8;
|
||||||
|
|
||||||
current_line = xmalloc(w);
|
USE_FEATURE_LESS_REGEXP(again0:)
|
||||||
p = current_line;
|
|
||||||
|
p = current_line = xmalloc(w);
|
||||||
max_fline += last_terminated;
|
max_fline += last_terminated;
|
||||||
if (!last_terminated) {
|
if (!last_terminated) {
|
||||||
const char *cp = flines[max_fline];
|
const char *cp = flines[max_fline];
|
||||||
@ -251,49 +259,26 @@ static void read_lines(void)
|
|||||||
cp += 8;
|
cp += 8;
|
||||||
strcpy(current_line, cp);
|
strcpy(current_line, cp);
|
||||||
p += strlen(current_line);
|
p += strlen(current_line);
|
||||||
|
free((char*)flines[max_fline]);
|
||||||
/* linepos is still valid from previous read_lines() */
|
/* linepos is still valid from previous read_lines() */
|
||||||
} else {
|
} else {
|
||||||
linepos = 0;
|
linepos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) { /* read lines until we reach cur_fline or wanted_match */
|
||||||
again:
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
terminated = 0;
|
terminated = 0;
|
||||||
while (1) {
|
while (1) { /* read chars until we have a line */
|
||||||
char c;
|
char c;
|
||||||
/* if no unprocessed chars left, eat more */
|
/* if no unprocessed chars left, eat more */
|
||||||
if (readpos >= readeof) {
|
if (readpos >= readeof) {
|
||||||
smallint yielded = 0;
|
|
||||||
|
|
||||||
ndelay_on(0);
|
ndelay_on(0);
|
||||||
read_again:
|
|
||||||
eof_error = safe_read(0, readbuf, sizeof(readbuf));
|
eof_error = safe_read(0, readbuf, sizeof(readbuf));
|
||||||
|
ndelay_off(0);
|
||||||
readpos = 0;
|
readpos = 0;
|
||||||
readeof = eof_error;
|
readeof = eof_error;
|
||||||
if (eof_error < 0) {
|
if (eof_error <= 0)
|
||||||
if (errno == EAGAIN && !yielded) {
|
|
||||||
/* We can hit EAGAIN while searching for regexp match.
|
|
||||||
* Yield is not 100% reliable solution in general,
|
|
||||||
* but for less it should be good enough -
|
|
||||||
* we give stdin supplier some CPU time to produce
|
|
||||||
* more input. We do it just once.
|
|
||||||
* Currently, we do not stop when we found the Nth
|
|
||||||
* occurrence we were looking for. We read till end
|
|
||||||
* (or double EAGAIN). TODO? */
|
|
||||||
sched_yield();
|
|
||||||
yielded = 1;
|
|
||||||
goto read_again;
|
|
||||||
}
|
|
||||||
readeof = 0;
|
|
||||||
if (errno != EAGAIN)
|
|
||||||
print_statusline("read error");
|
|
||||||
}
|
|
||||||
ndelay_off(0);
|
|
||||||
|
|
||||||
if (eof_error <= 0) {
|
|
||||||
goto reached_eof;
|
goto reached_eof;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
c = readbuf[readpos];
|
c = readbuf[readpos];
|
||||||
/* backspace? [needed for manpages] */
|
/* backspace? [needed for manpages] */
|
||||||
@ -327,13 +312,13 @@ static void read_lines(void)
|
|||||||
if (c == '\0') c = '\n';
|
if (c == '\0') c = '\n';
|
||||||
*p++ = c;
|
*p++ = c;
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
}
|
} /* end of "read chars until we have a line" loop */
|
||||||
/* Corner case: linewrap with only "" wrapping to next line */
|
/* Corner case: linewrap with only "" wrapping to next line */
|
||||||
/* Looks ugly on screen, so we do not store this empty line */
|
/* Looks ugly on screen, so we do not store this empty line */
|
||||||
if (!last_terminated && !current_line[0]) {
|
if (!last_terminated && !current_line[0]) {
|
||||||
last_terminated = 1;
|
last_terminated = 1;
|
||||||
max_lineno++;
|
max_lineno++;
|
||||||
goto again;
|
continue;
|
||||||
}
|
}
|
||||||
reached_eof:
|
reached_eof:
|
||||||
last_terminated = terminated;
|
last_terminated = terminated;
|
||||||
@ -353,22 +338,51 @@ static void read_lines(void)
|
|||||||
eof_error = 0; /* Pretend we saw EOF */
|
eof_error = 0; /* Pretend we saw EOF */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (max_fline > cur_fline + max_displayed_line)
|
if (max_fline > cur_fline + max_displayed_line) {
|
||||||
|
#if !ENABLE_FEATURE_LESS_REGEXP
|
||||||
break;
|
break;
|
||||||
if (eof_error <= 0) {
|
#else
|
||||||
if (eof_error < 0 && errno == EAGAIN) {
|
if (wanted_match >= num_matches) { /* goto_match called us */
|
||||||
/* not yet eof or error, reset flag (or else
|
fill_match_lines(old_max_fline);
|
||||||
* we will hog CPU - select() will return
|
old_max_fline = max_fline;
|
||||||
* immediately */
|
|
||||||
eof_error = 1;
|
|
||||||
}
|
}
|
||||||
|
if (wanted_match < num_matches)
|
||||||
|
break;
|
||||||
|
#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("read error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if !ENABLE_FEATURE_LESS_REGEXP
|
||||||
break;
|
break;
|
||||||
|
#else
|
||||||
|
if (wanted_match < num_matches) {
|
||||||
|
break;
|
||||||
|
} else { /* goto_match called us */
|
||||||
|
time_t t = time(NULL);
|
||||||
|
if (t != last_time) {
|
||||||
|
last_time = t;
|
||||||
|
if (--seconds_p1 == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sched_yield();
|
||||||
|
goto again0; /* go loop again (max 2 seconds) */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
max_fline++;
|
max_fline++;
|
||||||
current_line = xmalloc(w);
|
current_line = xmalloc(w);
|
||||||
p = current_line;
|
p = current_line;
|
||||||
linepos = 0;
|
linepos = 0;
|
||||||
}
|
} /* end of "read lines until we reach cur_fline" loop */
|
||||||
fill_match_lines(old_max_fline);
|
fill_match_lines(old_max_fline);
|
||||||
#undef readbuf
|
#undef readbuf
|
||||||
}
|
}
|
||||||
@ -884,24 +898,24 @@ static void normalize_match_pos(int match)
|
|||||||
|
|
||||||
static void goto_match(int match)
|
static void goto_match(int match)
|
||||||
{
|
{
|
||||||
int sv;
|
|
||||||
|
|
||||||
if (!pattern_valid)
|
if (!pattern_valid)
|
||||||
return;
|
return;
|
||||||
if (match < 0)
|
if (match < 0)
|
||||||
match = 0;
|
match = 0;
|
||||||
sv = cur_fline;
|
|
||||||
/* Try to find next match if eof isn't reached yet */
|
/* Try to find next match if eof isn't reached yet */
|
||||||
if (match >= num_matches && eof_error > 0) {
|
if (match >= num_matches && eof_error > 0) {
|
||||||
cur_fline = MAXLINES; /* look as far as needed */
|
wanted_match = match;
|
||||||
read_lines();
|
read_lines();
|
||||||
|
if (wanted_match >= num_matches) {
|
||||||
|
/* We still failed to find it. Prevent future
|
||||||
|
* read_lines() from trying... */
|
||||||
|
wanted_match = num_matches - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (num_matches) {
|
if (num_matches) {
|
||||||
cap_cur_fline(cur_fline);
|
|
||||||
normalize_match_pos(match);
|
normalize_match_pos(match);
|
||||||
buffer_line(match_lines[match_pos]);
|
buffer_line(match_lines[match_pos]);
|
||||||
} else {
|
} else {
|
||||||
cur_fline = sv;
|
|
||||||
print_statusline("No matches found");
|
print_statusline("No matches found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1370,7 +1384,7 @@ int less_main(int argc, char **argv)
|
|||||||
get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
|
get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
|
||||||
/* 20: two tabstops + 4 */
|
/* 20: two tabstops + 4 */
|
||||||
if (width < 20 || max_displayed_line < 3)
|
if (width < 20 || max_displayed_line < 3)
|
||||||
bb_error_msg_and_die("too narrow here");
|
return bb_cat(argv);
|
||||||
max_displayed_line -= 2;
|
max_displayed_line -= 2;
|
||||||
|
|
||||||
buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
|
buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user