less: fix regexp search '/' on large files
This commit is contained in:
parent
7a50a64986
commit
5a4f0994b0
108
miscutils/less.c
108
miscutils/less.c
@ -130,7 +130,6 @@ static void less_exit(int code)
|
|||||||
* and restore it when we exit. Less does this with the
|
* and restore it when we exit. Less does this with the
|
||||||
* "ti" and "te" termcap commands; can this be done with
|
* "ti" and "te" termcap commands; can this be done with
|
||||||
* only termios.h? */
|
* only termios.h? */
|
||||||
|
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
fflush_stdout_and_exit(code);
|
fflush_stdout_and_exit(code);
|
||||||
}
|
}
|
||||||
@ -158,12 +157,18 @@ static void print_statusline(const char *str)
|
|||||||
printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
|
printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_FEATURE_LESS_REGEXP
|
||||||
|
static void fill_match_lines(unsigned pos);
|
||||||
|
#else
|
||||||
|
#define fill_match_lines(pos) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void read_lines(void)
|
static void read_lines(void)
|
||||||
{
|
{
|
||||||
/* TODO: regexp match array should be updated too */
|
|
||||||
|
|
||||||
#define readbuf bb_common_bufsiz1
|
#define readbuf bb_common_bufsiz1
|
||||||
char *current_line, *p;
|
char *current_line, *p;
|
||||||
|
unsigned old_max_fline = max_fline;
|
||||||
int w = width;
|
int w = width;
|
||||||
char last_terminated = terminated;
|
char last_terminated = terminated;
|
||||||
|
|
||||||
@ -179,6 +184,8 @@ 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);
|
||||||
|
} else {
|
||||||
|
linepos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -254,16 +261,16 @@ ndelay_off(0);
|
|||||||
p = current_line;
|
p = current_line;
|
||||||
linepos = 0;
|
linepos = 0;
|
||||||
}
|
}
|
||||||
|
fill_match_lines(old_max_fline);
|
||||||
#undef readbuf
|
#undef readbuf
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_FEATURE_LESS_FLAGS
|
#if ENABLE_FEATURE_LESS_FLAGS
|
||||||
|
|
||||||
/* Interestingly, writing calc_percent as a function saves around 32 bytes
|
/* Interestingly, writing calc_percent as a function saves around 32 bytes
|
||||||
* on my build. */
|
* on my build. */
|
||||||
static int calc_percent(void)
|
static int calc_percent(void)
|
||||||
{
|
{
|
||||||
unsigned p = 100 * (cur_fline + max_displayed_line) / (max_fline + 1);
|
unsigned p = (100 * (cur_fline+max_displayed_line+1) + max_fline/2) / (max_fline+1);
|
||||||
return p <= 100 ? p : 100;
|
return p <= 100 ? p : 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +295,6 @@ static void m_status_print(void)
|
|||||||
percentage = calc_percent();
|
percentage = calc_percent();
|
||||||
printf("%i%%"NORMAL, percentage);
|
printf("%i%%"NORMAL, percentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Print the status line */
|
/* Print the status line */
|
||||||
@ -479,9 +485,12 @@ static void buffer_up(int nlines)
|
|||||||
|
|
||||||
static void buffer_line(int linenum)
|
static void buffer_line(int linenum)
|
||||||
{
|
{
|
||||||
|
if (linenum < 0)
|
||||||
|
linenum = 0;
|
||||||
|
cur_fline = linenum;
|
||||||
|
read_lines();
|
||||||
if (linenum + max_displayed_line > max_fline)
|
if (linenum + max_displayed_line > max_fline)
|
||||||
linenum = max_fline - max_displayed_line + TILDES;
|
linenum = max_fline - max_displayed_line + TILDES;
|
||||||
if (linenum < 0) linenum = 0;
|
|
||||||
cur_fline = linenum;
|
cur_fline = linenum;
|
||||||
buffer_fill_and_print();
|
buffer_fill_and_print();
|
||||||
}
|
}
|
||||||
@ -523,15 +532,24 @@ static void reinitialize(void)
|
|||||||
buffer_fill_and_print();
|
buffer_fill_and_print();
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* getch_nowait(void)
|
static void getch_nowait(char* input, int sz)
|
||||||
{
|
{
|
||||||
static char input[16];
|
ssize_t rd;
|
||||||
ssize_t sz;
|
|
||||||
fd_set readfds;
|
fd_set readfds;
|
||||||
again:
|
again:
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* NB: select returns whenever read will not block. Therefore:
|
||||||
|
* (a) with O_NONBLOCK'ed fds select will return immediately
|
||||||
|
* (b) if eof is reached, select will also return
|
||||||
|
* because read will immediately return 0 bytes.
|
||||||
|
* Even if select says that input is available, read CAN block
|
||||||
|
* (switch fd into O_NONBLOCK'ed mode to avoid it)
|
||||||
|
*/
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
if (max_fline <= cur_fline + max_displayed_line && eof_error > 0) {
|
if (max_fline <= cur_fline + max_displayed_line
|
||||||
|
&& eof_error > 0 /* did NOT reach eof yet */
|
||||||
|
) {
|
||||||
/* We are interested in stdin */
|
/* We are interested in stdin */
|
||||||
FD_SET(0, &readfds);
|
FD_SET(0, &readfds);
|
||||||
}
|
}
|
||||||
@ -541,17 +559,16 @@ static char* getch_nowait(void)
|
|||||||
|
|
||||||
input[0] = '\0';
|
input[0] = '\0';
|
||||||
ndelay_on(kbd_fd);
|
ndelay_on(kbd_fd);
|
||||||
sz = read(kbd_fd, input, sizeof(input));
|
rd = read(kbd_fd, input, sz);
|
||||||
ndelay_off(kbd_fd);
|
ndelay_off(kbd_fd);
|
||||||
if (sz < 0) {
|
if (rd < 0) {
|
||||||
/* No keyboard input, but we have input on stdin! */
|
/* No keyboard input, but we have input on stdin! */
|
||||||
if (errno != EAGAIN) /* Huh?? */
|
if (errno != EAGAIN) /* Huh?? */
|
||||||
return input;
|
return;
|
||||||
read_lines();
|
read_lines();
|
||||||
buffer_fill_and_print();
|
buffer_fill_and_print();
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
return input;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Grab a character from input without requiring the return key. If the
|
/* Grab a character from input without requiring the return key. If the
|
||||||
@ -559,10 +576,10 @@ static char* getch_nowait(void)
|
|||||||
* special return codes. Note that this function works best with raw input. */
|
* special return codes. Note that this function works best with raw input. */
|
||||||
static int less_getch(void)
|
static int less_getch(void)
|
||||||
{
|
{
|
||||||
char *input;
|
char input[16];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
again:
|
again:
|
||||||
input = getch_nowait();
|
getch_nowait(input, sizeof(input));
|
||||||
/* Detect escape sequences (i.e. arrow keys) and handle
|
/* Detect escape sequences (i.e. arrow keys) and handle
|
||||||
* them accordingly */
|
* them accordingly */
|
||||||
|
|
||||||
@ -718,6 +735,24 @@ static void goto_match(int match)
|
|||||||
buffer_line(match_lines[normalize_match_pos(match)]);
|
buffer_line(match_lines[normalize_match_pos(match)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void fill_match_lines(unsigned pos)
|
||||||
|
{
|
||||||
|
if (!pattern_valid)
|
||||||
|
return;
|
||||||
|
/* Run the regex on each line of the current file */
|
||||||
|
while (pos <= max_fline) {
|
||||||
|
/* If this line matches */
|
||||||
|
if (regexec(&pattern, flines[pos], 0, NULL, 0) == 0
|
||||||
|
/* and we didn't match it last time */
|
||||||
|
&& !(num_matches && match_lines[num_matches-1] == pos)
|
||||||
|
) {
|
||||||
|
match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
|
||||||
|
match_lines[num_matches++] = pos;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void regex_process(void)
|
static void regex_process(void)
|
||||||
{
|
{
|
||||||
char *uncomp_regex, *err;
|
char *uncomp_regex, *err;
|
||||||
@ -751,24 +786,21 @@ static void regex_process(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pattern_valid = 1;
|
pattern_valid = 1;
|
||||||
|
match_pos = 0;
|
||||||
|
|
||||||
/* Run the regex on each line of the current file */
|
fill_match_lines(0);
|
||||||
for (match_pos = 0; match_pos <= max_fline; match_pos++) {
|
|
||||||
if (regexec(&pattern, flines[match_pos], 0, NULL, 0) == 0) {
|
|
||||||
match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
|
|
||||||
match_lines[num_matches++] = match_pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_matches == 0 || max_fline <= max_displayed_line) {
|
if (num_matches == 0 || max_fline <= max_displayed_line) {
|
||||||
buffer_print();
|
buffer_print();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (match_pos = 0; match_pos < num_matches; match_pos++) {
|
while (match_pos < num_matches) {
|
||||||
if (match_lines[match_pos] > cur_fline)
|
if (match_lines[match_pos] > cur_fline)
|
||||||
break;
|
break;
|
||||||
|
match_pos++;
|
||||||
}
|
}
|
||||||
if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) match_pos--;
|
if (option_mask32 & LESS_STATE_MATCH_BACKWARDS)
|
||||||
|
match_pos--;
|
||||||
buffer_line(match_lines[normalize_match_pos(match_pos)]);
|
buffer_line(match_lines[normalize_match_pos(match_pos)]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -809,11 +841,9 @@ static void number_process(int first_digit)
|
|||||||
switch (keypress) {
|
switch (keypress) {
|
||||||
case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
|
case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
|
||||||
buffer_down(num);
|
buffer_down(num);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case KEY_UP: case 'b': case 'w': case 'y': case 'u':
|
case KEY_UP: case 'b': case 'w': case 'y': case 'u':
|
||||||
buffer_up(num);
|
buffer_up(num);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case 'g': case '<': case 'G': case '>':
|
case 'g': case '<': case 'G': case '>':
|
||||||
cur_fline = num + max_displayed_line;
|
cur_fline = num + max_displayed_line;
|
||||||
@ -898,12 +928,13 @@ static void show_flag_status(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear_line();
|
clear_line();
|
||||||
printf(HIGHLIGHT"%s%u"NORMAL, "The status of the flag is: ", flag_val != 0);
|
printf(HIGHLIGHT"The status of the flag is: %u"NORMAL, flag_val != 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void save_input_to_file(void)
|
static void save_input_to_file(void)
|
||||||
{
|
{
|
||||||
|
const char *msg = "";
|
||||||
char *current_line;
|
char *current_line;
|
||||||
int i;
|
int i;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -912,19 +943,18 @@ static void save_input_to_file(void)
|
|||||||
current_line = less_gets(sizeof("Log file: ")-1);
|
current_line = less_gets(sizeof("Log file: ")-1);
|
||||||
if (strlen(current_line) > 0) {
|
if (strlen(current_line) > 0) {
|
||||||
fp = fopen(current_line, "w");
|
fp = fopen(current_line, "w");
|
||||||
free(current_line);
|
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
print_statusline("Error opening log file");
|
msg = "Error opening log file";
|
||||||
return;
|
goto ret;
|
||||||
}
|
}
|
||||||
for (i = 0; i < max_fline; i++)
|
for (i = 0; i <= max_fline; i++)
|
||||||
fprintf(fp, "%s\n", flines[i]);
|
fprintf(fp, "%s\n", flines[i]);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
buffer_print();
|
msg = "Done";
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
ret:
|
||||||
|
print_statusline(msg);
|
||||||
free(current_line);
|
free(current_line);
|
||||||
print_statusline("No log file");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_FEATURE_LESS_MARKS
|
#if ENABLE_FEATURE_LESS_MARKS
|
||||||
@ -1033,27 +1063,21 @@ static void keypress_process(int keypress)
|
|||||||
switch (keypress) {
|
switch (keypress) {
|
||||||
case KEY_DOWN: case 'e': case 'j': case 0x0d:
|
case KEY_DOWN: case 'e': case 'j': case 0x0d:
|
||||||
buffer_down(1);
|
buffer_down(1);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case KEY_UP: case 'y': case 'k':
|
case KEY_UP: case 'y': case 'k':
|
||||||
buffer_up(1);
|
buffer_up(1);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case PAGE_DOWN: case ' ': case 'z':
|
case PAGE_DOWN: case ' ': case 'z':
|
||||||
buffer_down(max_displayed_line + 1);
|
buffer_down(max_displayed_line + 1);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case PAGE_UP: case 'w': case 'b':
|
case PAGE_UP: case 'w': case 'b':
|
||||||
buffer_up(max_displayed_line + 1);
|
buffer_up(max_displayed_line + 1);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
buffer_down((max_displayed_line + 1) / 2);
|
buffer_down((max_displayed_line + 1) / 2);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
buffer_up((max_displayed_line + 1) / 2);
|
buffer_up((max_displayed_line + 1) / 2);
|
||||||
buffer_print();
|
|
||||||
break;
|
break;
|
||||||
case KEY_HOME: case 'g': case 'p': case '<': case '%':
|
case KEY_HOME: case 'g': case 'p': case '<': case '%':
|
||||||
buffer_line(0);
|
buffer_line(0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user