svn commit: trunk/busybox/miscutils

vda at busybox.net vda at busybox.net
Mon Dec 25 01:23:03 UTC 2006


Author: vda
Date: 2006-12-24 17:23:02 -0800 (Sun, 24 Dec 2006)
New Revision: 17073

Log:
less: fix regexp search '/' on large files


Modified:
   trunk/busybox/miscutils/less.c


Changeset:
Modified: trunk/busybox/miscutils/less.c
===================================================================
--- trunk/busybox/miscutils/less.c	2006-12-24 17:40:16 UTC (rev 17072)
+++ trunk/busybox/miscutils/less.c	2006-12-25 01:23:02 UTC (rev 17073)
@@ -11,14 +11,14 @@
  * TODO:
  * - Add more regular expression support - search modifiers, certain matches, etc.
  * - Add more complex bracket searching - currently, nested brackets are
- * not considered.
+ *   not considered.
  * - Add support for "F" as an input. This causes less to act in
- * a similar way to tail -f.
+ *   a similar way to tail -f.
  * - Allow horizontal scrolling.
  *
  * Notes:
  * - the inp file pointer is used so that keyboard input works after
- * redirected input has been read from stdin
+ *   redirected input has been read from stdin
  */
 
 #include "busybox.h"
@@ -130,7 +130,6 @@
 	 * and restore it when we exit. Less does this with the
 	 * "ti" and "te" termcap commands; can this be done with
 	 * only termios.h? */
-
 	putchar('\n');
 	fflush_stdout_and_exit(code);
 }
@@ -158,12 +157,18 @@
 	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)
 {
-	/* TODO: regexp match array should be updated too */
-
 #define readbuf bb_common_bufsiz1
 	char *current_line, *p;
+	unsigned old_max_fline = max_fline;
 	int w = width;
 	char last_terminated = terminated;
 
@@ -179,6 +184,8 @@
 			cp += 8;
 		strcpy(current_line, cp);
 		p += strlen(current_line);
+	} else {
+		linepos = 0;
 	}
 
 	while (1) {
@@ -188,9 +195,9 @@
 		while (1) {
 			char c;
 			if (readpos >= readeof) {
-ndelay_on(0);
+				ndelay_on(0);
 				eof_error = safe_read(0, readbuf, sizeof(readbuf));
-ndelay_off(0);
+				ndelay_off(0);
 				readpos = 0;
 				readeof = eof_error;
 				if (eof_error < 0) {
@@ -254,16 +261,16 @@
 		p = current_line;
 		linepos = 0;
 	}
+	fill_match_lines(old_max_fline);
 #undef readbuf
 }
 
 #if ENABLE_FEATURE_LESS_FLAGS
-
 /* Interestingly, writing calc_percent as a function saves around 32 bytes
  * on my build. */
 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;
 }
 
@@ -288,7 +295,6 @@
 	percentage = calc_percent();
 	printf("%i%%"NORMAL, percentage);
 }
-
 #endif
 
 /* Print the status line */
@@ -479,9 +485,12 @@
 
 static void buffer_line(int linenum)
 {
+	if (linenum < 0)
+		linenum = 0;
+	cur_fline = linenum;
+	read_lines();
 	if (linenum + max_displayed_line > max_fline)
 		linenum = max_fline - max_displayed_line + TILDES;
-	if (linenum < 0) linenum = 0;
 	cur_fline = linenum;
 	buffer_fill_and_print();
 }
@@ -523,15 +532,24 @@
 	buffer_fill_and_print();
 }
 
-static char* getch_nowait(void)
+static void getch_nowait(char* input, int sz)
 {
-	static char input[16];
-	ssize_t sz;
+	ssize_t rd;
 	fd_set readfds;
  again:
 	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);
-	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 */
 		FD_SET(0, &readfds);
 	}
@@ -541,17 +559,16 @@
 
 	input[0] = '\0';
 	ndelay_on(kbd_fd);
-	sz = read(kbd_fd, input, sizeof(input));
+	rd = read(kbd_fd, input, sz);
 	ndelay_off(kbd_fd);
-	if (sz < 0) {
+	if (rd < 0) {
 		/* No keyboard input, but we have input on stdin! */
 		if (errno != EAGAIN) /* Huh?? */
-			return input;
+			return;
 		read_lines();
 		buffer_fill_and_print();
 		goto again;
 	}
-	return input;
 }
 
 /* Grab a character from input without requiring the return key. If the
@@ -559,10 +576,10 @@
  * special return codes. Note that this function works best with raw input. */
 static int less_getch(void)
 {
-	char *input;
+	char input[16];
 	unsigned i;
  again:
-	input = getch_nowait();
+	getch_nowait(input, sizeof(input));
 	/* Detect escape sequences (i.e. arrow keys) and handle
 	 * them accordingly */
 
@@ -718,6 +735,24 @@
 		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)
 {
 	char *uncomp_regex, *err;
@@ -751,24 +786,21 @@
 		return;
 	}
 	pattern_valid = 1;
+	match_pos = 0;
 
-	/* Run the regex on each line of the current file */
-	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;
-		}
-	}
+	fill_match_lines(0);
 
 	if (num_matches == 0 || max_fline <= max_displayed_line) {
 		buffer_print();
 		return;
 	}
-	for (match_pos = 0; match_pos < num_matches; match_pos++) {
+	while (match_pos < num_matches) {
 		if (match_lines[match_pos] > cur_fline)
 			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)]);
 }
 #endif
@@ -809,11 +841,9 @@
 	switch (keypress) {
 	case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
 		buffer_down(num);
-		buffer_print();
 		break;
 	case KEY_UP: case 'b': case 'w': case 'y': case 'u':
 		buffer_up(num);
-		buffer_print();
 		break;
 	case 'g': case '<': case 'G': case '>':
 		cur_fline = num + max_displayed_line;
@@ -898,12 +928,13 @@
 	}
 
 	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
 
 static void save_input_to_file(void)
 {
+	const char *msg = "";
 	char *current_line;
 	int i;
 	FILE *fp;
@@ -912,19 +943,18 @@
 	current_line = less_gets(sizeof("Log file: ")-1);
 	if (strlen(current_line) > 0) {
 		fp = fopen(current_line, "w");
-		free(current_line);
 		if (!fp) {
-			print_statusline("Error opening log file");
-			return;
+			msg = "Error opening log file";
+			goto ret;
 		}
-		for (i = 0; i < max_fline; i++)
+		for (i = 0; i <= max_fline; i++)
 			fprintf(fp, "%s\n", flines[i]);
 		fclose(fp);
-		buffer_print();
-		return;
+		msg = "Done";
 	}
+ ret:
+	print_statusline(msg);
 	free(current_line);
-	print_statusline("No log file");
 }
 
 #if ENABLE_FEATURE_LESS_MARKS
@@ -1033,27 +1063,21 @@
 	switch (keypress) {
 	case KEY_DOWN: case 'e': case 'j': case 0x0d:
 		buffer_down(1);
-		buffer_print();
 		break;
 	case KEY_UP: case 'y': case 'k':
 		buffer_up(1);
-		buffer_print();
 		break;
 	case PAGE_DOWN: case ' ': case 'z':
 		buffer_down(max_displayed_line + 1);
-		buffer_print();
 		break;
 	case PAGE_UP: case 'w': case 'b':
 		buffer_up(max_displayed_line + 1);
-		buffer_print();
 		break;
 	case 'd':
 		buffer_down((max_displayed_line + 1) / 2);
-		buffer_print();
 		break;
 	case 'u':
 		buffer_up((max_displayed_line + 1) / 2);
-		buffer_print();
 		break;
 	case KEY_HOME: case 'g': case 'p': case '<': case '%':
 		buffer_line(0);




More information about the busybox-cvs mailing list