svn commit: trunk/busybox/miscutils

vda at busybox.net vda at busybox.net
Mon Mar 17 08:38:45 UTC 2008


Author: vda
Date: 2008-03-17 01:38:45 -0700 (Mon, 17 Mar 2008)
New Revision: 21345

Log:
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



Modified:
   trunk/busybox/miscutils/less.c


Changeset:
Modified: trunk/busybox/miscutils/less.c
===================================================================
--- trunk/busybox/miscutils/less.c	2008-03-17 08:35:44 UTC (rev 21344)
+++ trunk/busybox/miscutils/less.c	2008-03-17 08:38:45 UTC (rev 21345)
@@ -98,8 +98,8 @@
 	unsigned max_lineno; /* this one tracks linewrap */
 	unsigned width;
 	ssize_t eof_error; /* eof if 0, error if < 0 */
-	size_t readpos;
-	size_t readeof;
+	ssize_t readpos;
+	ssize_t readeof; /* must be signed */
 	const char **buffer;
 	const char **flines;
 	const char *empty_line_marker;
@@ -114,7 +114,8 @@
 #if ENABLE_FEATURE_LESS_REGEXP
 	unsigned *match_lines;
 	int match_pos; /* signed! */
-	unsigned num_matches;
+	int wanted_match; /* signed! */
+	int num_matches;
 	regex_t pattern;
 	smallint pattern_valid;
 #endif
@@ -146,6 +147,7 @@
 #define match_lines         (G.match_lines       )
 #define match_pos           (G.match_pos         )
 #define num_matches         (G.num_matches       )
+#define wanted_match        (G.wanted_match      )
 #define pattern             (G.pattern           )
 #define pattern_valid       (G.pattern_valid     )
 #endif
@@ -160,6 +162,7 @@
 	current_file = 1; \
 	eof_error = 1; \
 	terminated = 1; \
+	USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
 } while (0)
 
 /* Reset terminal input to normal */
@@ -235,15 +238,20 @@
 {
 #define readbuf bb_common_bufsiz1
 	char *current_line, *p;
-	USE_FEATURE_LESS_REGEXP(unsigned old_max_fline = max_fline;)
 	int w = width;
 	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)
 		w -= 8;
 
-	current_line = xmalloc(w);
-	p = current_line;
+ USE_FEATURE_LESS_REGEXP(again0:)
+
+	p = current_line = xmalloc(w);
 	max_fline += last_terminated;
 	if (!last_terminated) {
 		const char *cp = flines[max_fline];
@@ -251,49 +259,26 @@
 			cp += 8;
 		strcpy(current_line, cp);
 		p += strlen(current_line);
+		free((char*)flines[max_fline]);
 		/* linepos is still valid from previous read_lines() */
 	} else {
 		linepos = 0;
 	}
 
-	while (1) {
- again:
+	while (1) { /* read lines until we reach cur_fline or wanted_match */
 		*p = '\0';
 		terminated = 0;
-		while (1) {
+		while (1) { /* read chars until we have a line */
 			char c;
 			/* if no unprocessed chars left, eat more */
 			if (readpos >= readeof) {
-				smallint yielded = 0;
-
 				ndelay_on(0);
- read_again:
 				eof_error = safe_read(0, readbuf, sizeof(readbuf));
+				ndelay_off(0);
 				readpos = 0;
 				readeof = eof_error;
-				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) {
+				if (eof_error <= 0)
 					goto reached_eof;
-				}
 			}
 			c = readbuf[readpos];
 			/* backspace? [needed for manpages] */
@@ -327,13 +312,13 @@
 			if (c == '\0') c = '\n';
 			*p++ = c;
 			*p = '\0';
-		}
+		} /* end of "read chars until we have a line" loop */
 		/* Corner case: linewrap with only "" wrapping to next line */
 		/* Looks ugly on screen, so we do not store this empty line */
 		if (!last_terminated && !current_line[0]) {
 			last_terminated = 1;
 			max_lineno++;
-			goto again;
+			continue;
 		}
  reached_eof:
 		last_terminated = terminated;
@@ -353,22 +338,51 @@
 			eof_error = 0; /* Pretend we saw EOF */
 			break;
 		}
-		if (max_fline > cur_fline + max_displayed_line)
+		if (max_fline > cur_fline + max_displayed_line) {
+#if !ENABLE_FEATURE_LESS_REGEXP
 			break;
+#else
+			if (wanted_match >= num_matches) { /* goto_match called us */
+				fill_match_lines(old_max_fline);
+				old_max_fline = max_fline;
+			}
+			if (wanted_match < num_matches)
+				break;
+#endif
+		}
 		if (eof_error <= 0) {
-			if (eof_error < 0 && errno == EAGAIN) {
-				/* not yet eof or error, reset flag (or else
-				 * we will hog CPU - select() will return
-				 * immediately */
-				eof_error = 1;
+			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;
+#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++;
 		current_line = xmalloc(w);
 		p = current_line;
 		linepos = 0;
-	}
+	} /* end of "read lines until we reach cur_fline" loop */
 	fill_match_lines(old_max_fline);
 #undef readbuf
 }
@@ -884,24 +898,24 @@
 
 static void goto_match(int match)
 {
-	int sv;
-
 	if (!pattern_valid)
 		return;
 	if (match < 0)
 		match = 0;
-	sv = cur_fline;
 	/* Try to find next match if eof isn't reached yet */
 	if (match >= num_matches && eof_error > 0) {
-		cur_fline = MAXLINES; /* look as far as needed */
+		wanted_match = match;
 		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) {
-		cap_cur_fline(cur_fline);
 		normalize_match_pos(match);
 		buffer_line(match_lines[match_pos]);
 	} else {
-		cur_fline = sv;
 		print_statusline("No matches found");
 	}
 }
@@ -1370,7 +1384,7 @@
 	get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
 	/* 20: two tabstops + 4 */
 	if (width < 20 || max_displayed_line < 3)
-		bb_error_msg_and_die("too narrow here");
+		return bb_cat(argv);
 	max_displayed_line -= 2;
 
 	buffer = xmalloc((max_displayed_line+1) * sizeof(char *));




More information about the busybox-cvs mailing list