less: fix regexp search '/' on large files

This commit is contained in:
Denis Vlasenko 2006-12-25 01:23:02 +00:00
parent 7a50a64986
commit 5a4f0994b0

View File

@ -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);