aboutsummaryrefslogtreecommitdiff
path: root/miscutils/less.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-25 01:23:02 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-25 01:23:02 +0000
commit5a4f0994b0ddd8ba8d96675382c42040ef516753 (patch)
tree23fb8e56edac5f408e95bad153af86ee5bd71331 /miscutils/less.c
parent7a50a64986758e0890e76411d5997c4a07d9c698 (diff)
downloadbusybox-w32-5a4f0994b0ddd8ba8d96675382c42040ef516753.tar.gz
busybox-w32-5a4f0994b0ddd8ba8d96675382c42040ef516753.tar.bz2
busybox-w32-5a4f0994b0ddd8ba8d96675382c42040ef516753.zip
less: fix regexp search '/' on large files
Diffstat (limited to 'miscutils/less.c')
-rw-r--r--miscutils/less.c118
1 files changed, 71 insertions, 47 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index 290635d32..60c54e610 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -11,14 +11,14 @@
11 * TODO: 11 * TODO:
12 * - Add more regular expression support - search modifiers, certain matches, etc. 12 * - Add more regular expression support - search modifiers, certain matches, etc.
13 * - Add more complex bracket searching - currently, nested brackets are 13 * - Add more complex bracket searching - currently, nested brackets are
14 * not considered. 14 * not considered.
15 * - Add support for "F" as an input. This causes less to act in 15 * - Add support for "F" as an input. This causes less to act in
16 * a similar way to tail -f. 16 * a similar way to tail -f.
17 * - Allow horizontal scrolling. 17 * - Allow horizontal scrolling.
18 * 18 *
19 * Notes: 19 * Notes:
20 * - the inp file pointer is used so that keyboard input works after 20 * - the inp file pointer is used so that keyboard input works after
21 * redirected input has been read from stdin 21 * redirected input has been read from stdin
22 */ 22 */
23 23
24#include "busybox.h" 24#include "busybox.h"
@@ -130,7 +130,6 @@ static void less_exit(int code)
130 * and restore it when we exit. Less does this with the 130 * and restore it when we exit. Less does this with the
131 * "ti" and "te" termcap commands; can this be done with 131 * "ti" and "te" termcap commands; can this be done with
132 * only termios.h? */ 132 * only termios.h? */
133
134 putchar('\n'); 133 putchar('\n');
135 fflush_stdout_and_exit(code); 134 fflush_stdout_and_exit(code);
136} 135}
@@ -158,12 +157,18 @@ static void print_statusline(const char *str)
158 printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str); 157 printf(HIGHLIGHT"%.*s"NORMAL, width - 1, str);
159} 158}
160 159
160#if ENABLE_FEATURE_LESS_REGEXP
161static void fill_match_lines(unsigned pos);
162#else
163#define fill_match_lines(pos) ((void)0)
164#endif
165
166
161static void read_lines(void) 167static void read_lines(void)
162{ 168{
163 /* TODO: regexp match array should be updated too */
164
165#define readbuf bb_common_bufsiz1 169#define readbuf bb_common_bufsiz1
166 char *current_line, *p; 170 char *current_line, *p;
171 unsigned old_max_fline = max_fline;
167 int w = width; 172 int w = width;
168 char last_terminated = terminated; 173 char last_terminated = terminated;
169 174
@@ -179,6 +184,8 @@ static void read_lines(void)
179 cp += 8; 184 cp += 8;
180 strcpy(current_line, cp); 185 strcpy(current_line, cp);
181 p += strlen(current_line); 186 p += strlen(current_line);
187 } else {
188 linepos = 0;
182 } 189 }
183 190
184 while (1) { 191 while (1) {
@@ -188,9 +195,9 @@ static void read_lines(void)
188 while (1) { 195 while (1) {
189 char c; 196 char c;
190 if (readpos >= readeof) { 197 if (readpos >= readeof) {
191ndelay_on(0); 198 ndelay_on(0);
192 eof_error = safe_read(0, readbuf, sizeof(readbuf)); 199 eof_error = safe_read(0, readbuf, sizeof(readbuf));
193ndelay_off(0); 200 ndelay_off(0);
194 readpos = 0; 201 readpos = 0;
195 readeof = eof_error; 202 readeof = eof_error;
196 if (eof_error < 0) { 203 if (eof_error < 0) {
@@ -254,16 +261,16 @@ ndelay_off(0);
254 p = current_line; 261 p = current_line;
255 linepos = 0; 262 linepos = 0;
256 } 263 }
264 fill_match_lines(old_max_fline);
257#undef readbuf 265#undef readbuf
258} 266}
259 267
260#if ENABLE_FEATURE_LESS_FLAGS 268#if ENABLE_FEATURE_LESS_FLAGS
261
262/* Interestingly, writing calc_percent as a function saves around 32 bytes 269/* Interestingly, writing calc_percent as a function saves around 32 bytes
263 * on my build. */ 270 * on my build. */
264static int calc_percent(void) 271static int calc_percent(void)
265{ 272{
266 unsigned p = 100 * (cur_fline + max_displayed_line) / (max_fline + 1); 273 unsigned p = (100 * (cur_fline+max_displayed_line+1) + max_fline/2) / (max_fline+1);
267 return p <= 100 ? p : 100; 274 return p <= 100 ? p : 100;
268} 275}
269 276
@@ -288,7 +295,6 @@ static void m_status_print(void)
288 percentage = calc_percent(); 295 percentage = calc_percent();
289 printf("%i%%"NORMAL, percentage); 296 printf("%i%%"NORMAL, percentage);
290} 297}
291
292#endif 298#endif
293 299
294/* Print the status line */ 300/* Print the status line */
@@ -479,9 +485,12 @@ static void buffer_up(int nlines)
479 485
480static void buffer_line(int linenum) 486static void buffer_line(int linenum)
481{ 487{
488 if (linenum < 0)
489 linenum = 0;
490 cur_fline = linenum;
491 read_lines();
482 if (linenum + max_displayed_line > max_fline) 492 if (linenum + max_displayed_line > max_fline)
483 linenum = max_fline - max_displayed_line + TILDES; 493 linenum = max_fline - max_displayed_line + TILDES;
484 if (linenum < 0) linenum = 0;
485 cur_fline = linenum; 494 cur_fline = linenum;
486 buffer_fill_and_print(); 495 buffer_fill_and_print();
487} 496}
@@ -523,15 +532,24 @@ static void reinitialize(void)
523 buffer_fill_and_print(); 532 buffer_fill_and_print();
524} 533}
525 534
526static char* getch_nowait(void) 535static void getch_nowait(char* input, int sz)
527{ 536{
528 static char input[16]; 537 ssize_t rd;
529 ssize_t sz;
530 fd_set readfds; 538 fd_set readfds;
531 again: 539 again:
532 fflush(stdout); 540 fflush(stdout);
541
542 /* NB: select returns whenever read will not block. Therefore:
543 * (a) with O_NONBLOCK'ed fds select will return immediately
544 * (b) if eof is reached, select will also return
545 * because read will immediately return 0 bytes.
546 * Even if select says that input is available, read CAN block
547 * (switch fd into O_NONBLOCK'ed mode to avoid it)
548 */
533 FD_ZERO(&readfds); 549 FD_ZERO(&readfds);
534 if (max_fline <= cur_fline + max_displayed_line && eof_error > 0) { 550 if (max_fline <= cur_fline + max_displayed_line
551 && eof_error > 0 /* did NOT reach eof yet */
552 ) {
535 /* We are interested in stdin */ 553 /* We are interested in stdin */
536 FD_SET(0, &readfds); 554 FD_SET(0, &readfds);
537 } 555 }
@@ -541,17 +559,16 @@ static char* getch_nowait(void)
541 559
542 input[0] = '\0'; 560 input[0] = '\0';
543 ndelay_on(kbd_fd); 561 ndelay_on(kbd_fd);
544 sz = read(kbd_fd, input, sizeof(input)); 562 rd = read(kbd_fd, input, sz);
545 ndelay_off(kbd_fd); 563 ndelay_off(kbd_fd);
546 if (sz < 0) { 564 if (rd < 0) {
547 /* No keyboard input, but we have input on stdin! */ 565 /* No keyboard input, but we have input on stdin! */
548 if (errno != EAGAIN) /* Huh?? */ 566 if (errno != EAGAIN) /* Huh?? */
549 return input; 567 return;
550 read_lines(); 568 read_lines();
551 buffer_fill_and_print(); 569 buffer_fill_and_print();
552 goto again; 570 goto again;
553 } 571 }
554 return input;
555} 572}
556 573
557/* Grab a character from input without requiring the return key. If the 574/* Grab a character from input without requiring the return key. If the
@@ -559,10 +576,10 @@ static char* getch_nowait(void)
559 * special return codes. Note that this function works best with raw input. */ 576 * special return codes. Note that this function works best with raw input. */
560static int less_getch(void) 577static int less_getch(void)
561{ 578{
562 char *input; 579 char input[16];
563 unsigned i; 580 unsigned i;
564 again: 581 again:
565 input = getch_nowait(); 582 getch_nowait(input, sizeof(input));
566 /* Detect escape sequences (i.e. arrow keys) and handle 583 /* Detect escape sequences (i.e. arrow keys) and handle
567 * them accordingly */ 584 * them accordingly */
568 585
@@ -718,6 +735,24 @@ static void goto_match(int match)
718 buffer_line(match_lines[normalize_match_pos(match)]); 735 buffer_line(match_lines[normalize_match_pos(match)]);
719} 736}
720 737
738static void fill_match_lines(unsigned pos)
739{
740 if (!pattern_valid)
741 return;
742 /* Run the regex on each line of the current file */
743 while (pos <= max_fline) {
744 /* If this line matches */
745 if (regexec(&pattern, flines[pos], 0, NULL, 0) == 0
746 /* and we didn't match it last time */
747 && !(num_matches && match_lines[num_matches-1] == pos)
748 ) {
749 match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
750 match_lines[num_matches++] = pos;
751 }
752 pos++;
753 }
754}
755
721static void regex_process(void) 756static void regex_process(void)
722{ 757{
723 char *uncomp_regex, *err; 758 char *uncomp_regex, *err;
@@ -751,24 +786,21 @@ static void regex_process(void)
751 return; 786 return;
752 } 787 }
753 pattern_valid = 1; 788 pattern_valid = 1;
789 match_pos = 0;
754 790
755 /* Run the regex on each line of the current file */ 791 fill_match_lines(0);
756 for (match_pos = 0; match_pos <= max_fline; match_pos++) {
757 if (regexec(&pattern, flines[match_pos], 0, NULL, 0) == 0) {
758 match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
759 match_lines[num_matches++] = match_pos;
760 }
761 }
762 792
763 if (num_matches == 0 || max_fline <= max_displayed_line) { 793 if (num_matches == 0 || max_fline <= max_displayed_line) {
764 buffer_print(); 794 buffer_print();
765 return; 795 return;
766 } 796 }
767 for (match_pos = 0; match_pos < num_matches; match_pos++) { 797 while (match_pos < num_matches) {
768 if (match_lines[match_pos] > cur_fline) 798 if (match_lines[match_pos] > cur_fline)
769 break; 799 break;
800 match_pos++;
770 } 801 }
771 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) match_pos--; 802 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS)
803 match_pos--;
772 buffer_line(match_lines[normalize_match_pos(match_pos)]); 804 buffer_line(match_lines[normalize_match_pos(match_pos)]);
773} 805}
774#endif 806#endif
@@ -809,11 +841,9 @@ static void number_process(int first_digit)
809 switch (keypress) { 841 switch (keypress) {
810 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015': 842 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
811 buffer_down(num); 843 buffer_down(num);
812 buffer_print();
813 break; 844 break;
814 case KEY_UP: case 'b': case 'w': case 'y': case 'u': 845 case KEY_UP: case 'b': case 'w': case 'y': case 'u':
815 buffer_up(num); 846 buffer_up(num);
816 buffer_print();
817 break; 847 break;
818 case 'g': case '<': case 'G': case '>': 848 case 'g': case '<': case 'G': case '>':
819 cur_fline = num + max_displayed_line; 849 cur_fline = num + max_displayed_line;
@@ -898,12 +928,13 @@ static void show_flag_status(void)
898 } 928 }
899 929
900 clear_line(); 930 clear_line();
901 printf(HIGHLIGHT"%s%u"NORMAL, "The status of the flag is: ", flag_val != 0); 931 printf(HIGHLIGHT"The status of the flag is: %u"NORMAL, flag_val != 0);
902} 932}
903#endif 933#endif
904 934
905static void save_input_to_file(void) 935static void save_input_to_file(void)
906{ 936{
937 const char *msg = "";
907 char *current_line; 938 char *current_line;
908 int i; 939 int i;
909 FILE *fp; 940 FILE *fp;
@@ -912,19 +943,18 @@ static void save_input_to_file(void)
912 current_line = less_gets(sizeof("Log file: ")-1); 943 current_line = less_gets(sizeof("Log file: ")-1);
913 if (strlen(current_line) > 0) { 944 if (strlen(current_line) > 0) {
914 fp = fopen(current_line, "w"); 945 fp = fopen(current_line, "w");
915 free(current_line);
916 if (!fp) { 946 if (!fp) {
917 print_statusline("Error opening log file"); 947 msg = "Error opening log file";
918 return; 948 goto ret;
919 } 949 }
920 for (i = 0; i < max_fline; i++) 950 for (i = 0; i <= max_fline; i++)
921 fprintf(fp, "%s\n", flines[i]); 951 fprintf(fp, "%s\n", flines[i]);
922 fclose(fp); 952 fclose(fp);
923 buffer_print(); 953 msg = "Done";
924 return;
925 } 954 }
955 ret:
956 print_statusline(msg);
926 free(current_line); 957 free(current_line);
927 print_statusline("No log file");
928} 958}
929 959
930#if ENABLE_FEATURE_LESS_MARKS 960#if ENABLE_FEATURE_LESS_MARKS
@@ -1033,27 +1063,21 @@ static void keypress_process(int keypress)
1033 switch (keypress) { 1063 switch (keypress) {
1034 case KEY_DOWN: case 'e': case 'j': case 0x0d: 1064 case KEY_DOWN: case 'e': case 'j': case 0x0d:
1035 buffer_down(1); 1065 buffer_down(1);
1036 buffer_print();
1037 break; 1066 break;
1038 case KEY_UP: case 'y': case 'k': 1067 case KEY_UP: case 'y': case 'k':
1039 buffer_up(1); 1068 buffer_up(1);
1040 buffer_print();
1041 break; 1069 break;
1042 case PAGE_DOWN: case ' ': case 'z': 1070 case PAGE_DOWN: case ' ': case 'z':
1043 buffer_down(max_displayed_line + 1); 1071 buffer_down(max_displayed_line + 1);
1044 buffer_print();
1045 break; 1072 break;
1046 case PAGE_UP: case 'w': case 'b': 1073 case PAGE_UP: case 'w': case 'b':
1047 buffer_up(max_displayed_line + 1); 1074 buffer_up(max_displayed_line + 1);
1048 buffer_print();
1049 break; 1075 break;
1050 case 'd': 1076 case 'd':
1051 buffer_down((max_displayed_line + 1) / 2); 1077 buffer_down((max_displayed_line + 1) / 2);
1052 buffer_print();
1053 break; 1078 break;
1054 case 'u': 1079 case 'u':
1055 buffer_up((max_displayed_line + 1) / 2); 1080 buffer_up((max_displayed_line + 1) / 2);
1056 buffer_print();
1057 break; 1081 break;
1058 case KEY_HOME: case 'g': case 'p': case '<': case '%': 1082 case KEY_HOME: case 'g': case 'p': case '<': case '%':
1059 buffer_line(0); 1083 buffer_line(0);