summaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-17 08:38:45 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-17 08:38:45 +0000
commit107fe7c081c2e0ab96628b431d9d812cdf9c82b2 (patch)
tree653d231e2dc06c990044882dffb445c726dad791 /miscutils
parentaefed941c26aade36c5b51c8ef5ea6f740cc0e5d (diff)
downloadbusybox-w32-107fe7c081c2e0ab96628b431d9d812cdf9c82b2.tar.gz
busybox-w32-107fe7c081c2e0ab96628b431d9d812cdf9c82b2.tar.bz2
busybox-w32-107fe7c081c2e0ab96628b431d9d812cdf9c82b2.zip
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
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/less.c114
1 files changed, 64 insertions, 50 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index 8d4f7ecd4..3a9dea039 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -98,8 +98,8 @@ struct globals {
98 unsigned max_lineno; /* this one tracks linewrap */ 98 unsigned max_lineno; /* this one tracks linewrap */
99 unsigned width; 99 unsigned width;
100 ssize_t eof_error; /* eof if 0, error if < 0 */ 100 ssize_t eof_error; /* eof if 0, error if < 0 */
101 size_t readpos; 101 ssize_t readpos;
102 size_t readeof; 102 ssize_t readeof; /* must be signed */
103 const char **buffer; 103 const char **buffer;
104 const char **flines; 104 const char **flines;
105 const char *empty_line_marker; 105 const char *empty_line_marker;
@@ -114,7 +114,8 @@ struct globals {
114#if ENABLE_FEATURE_LESS_REGEXP 114#if ENABLE_FEATURE_LESS_REGEXP
115 unsigned *match_lines; 115 unsigned *match_lines;
116 int match_pos; /* signed! */ 116 int match_pos; /* signed! */
117 unsigned num_matches; 117 int wanted_match; /* signed! */
118 int num_matches;
118 regex_t pattern; 119 regex_t pattern;
119 smallint pattern_valid; 120 smallint pattern_valid;
120#endif 121#endif
@@ -146,6 +147,7 @@ struct globals {
146#define match_lines (G.match_lines ) 147#define match_lines (G.match_lines )
147#define match_pos (G.match_pos ) 148#define match_pos (G.match_pos )
148#define num_matches (G.num_matches ) 149#define num_matches (G.num_matches )
150#define wanted_match (G.wanted_match )
149#define pattern (G.pattern ) 151#define pattern (G.pattern )
150#define pattern_valid (G.pattern_valid ) 152#define pattern_valid (G.pattern_valid )
151#endif 153#endif
@@ -160,6 +162,7 @@ struct globals {
160 current_file = 1; \ 162 current_file = 1; \
161 eof_error = 1; \ 163 eof_error = 1; \
162 terminated = 1; \ 164 terminated = 1; \
165 USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
163} while (0) 166} while (0)
164 167
165/* Reset terminal input to normal */ 168/* Reset terminal input to normal */
@@ -235,15 +238,20 @@ static void read_lines(void)
235{ 238{
236#define readbuf bb_common_bufsiz1 239#define readbuf bb_common_bufsiz1
237 char *current_line, *p; 240 char *current_line, *p;
238 USE_FEATURE_LESS_REGEXP(unsigned old_max_fline = max_fline;)
239 int w = width; 241 int w = width;
240 char last_terminated = terminated; 242 char last_terminated = terminated;
243#if ENABLE_FEATURE_LESS_REGEXP
244 unsigned old_max_fline = max_fline;
245 time_t last_time = 0;
246 unsigned seconds_p1 = 3; /* seconds_to_loop + 1 */
247#endif
241 248
242 if (option_mask32 & FLAG_N) 249 if (option_mask32 & FLAG_N)
243 w -= 8; 250 w -= 8;
244 251
245 current_line = xmalloc(w); 252 USE_FEATURE_LESS_REGEXP(again0:)
246 p = current_line; 253
254 p = current_line = xmalloc(w);
247 max_fline += last_terminated; 255 max_fline += last_terminated;
248 if (!last_terminated) { 256 if (!last_terminated) {
249 const char *cp = flines[max_fline]; 257 const char *cp = flines[max_fline];
@@ -251,49 +259,26 @@ static void read_lines(void)
251 cp += 8; 259 cp += 8;
252 strcpy(current_line, cp); 260 strcpy(current_line, cp);
253 p += strlen(current_line); 261 p += strlen(current_line);
262 free((char*)flines[max_fline]);
254 /* linepos is still valid from previous read_lines() */ 263 /* linepos is still valid from previous read_lines() */
255 } else { 264 } else {
256 linepos = 0; 265 linepos = 0;
257 } 266 }
258 267
259 while (1) { 268 while (1) { /* read lines until we reach cur_fline or wanted_match */
260 again:
261 *p = '\0'; 269 *p = '\0';
262 terminated = 0; 270 terminated = 0;
263 while (1) { 271 while (1) { /* read chars until we have a line */
264 char c; 272 char c;
265 /* if no unprocessed chars left, eat more */ 273 /* if no unprocessed chars left, eat more */
266 if (readpos >= readeof) { 274 if (readpos >= readeof) {
267 smallint yielded = 0;
268
269 ndelay_on(0); 275 ndelay_on(0);
270 read_again:
271 eof_error = safe_read(0, readbuf, sizeof(readbuf)); 276 eof_error = safe_read(0, readbuf, sizeof(readbuf));
277 ndelay_off(0);
272 readpos = 0; 278 readpos = 0;
273 readeof = eof_error; 279 readeof = eof_error;
274 if (eof_error < 0) { 280 if (eof_error <= 0)
275 if (errno == EAGAIN && !yielded) {
276 /* We can hit EAGAIN while searching for regexp match.
277 * Yield is not 100% reliable solution in general,
278 * but for less it should be good enough -
279 * we give stdin supplier some CPU time to produce
280 * more input. We do it just once.
281 * Currently, we do not stop when we found the Nth
282 * occurrence we were looking for. We read till end
283 * (or double EAGAIN). TODO? */
284 sched_yield();
285 yielded = 1;
286 goto read_again;
287 }
288 readeof = 0;
289 if (errno != EAGAIN)
290 print_statusline("read error");
291 }
292 ndelay_off(0);
293
294 if (eof_error <= 0) {
295 goto reached_eof; 281 goto reached_eof;
296 }
297 } 282 }
298 c = readbuf[readpos]; 283 c = readbuf[readpos];
299 /* backspace? [needed for manpages] */ 284 /* backspace? [needed for manpages] */
@@ -327,13 +312,13 @@ static void read_lines(void)
327 if (c == '\0') c = '\n'; 312 if (c == '\0') c = '\n';
328 *p++ = c; 313 *p++ = c;
329 *p = '\0'; 314 *p = '\0';
330 } 315 } /* end of "read chars until we have a line" loop */
331 /* Corner case: linewrap with only "" wrapping to next line */ 316 /* Corner case: linewrap with only "" wrapping to next line */
332 /* Looks ugly on screen, so we do not store this empty line */ 317 /* Looks ugly on screen, so we do not store this empty line */
333 if (!last_terminated && !current_line[0]) { 318 if (!last_terminated && !current_line[0]) {
334 last_terminated = 1; 319 last_terminated = 1;
335 max_lineno++; 320 max_lineno++;
336 goto again; 321 continue;
337 } 322 }
338 reached_eof: 323 reached_eof:
339 last_terminated = terminated; 324 last_terminated = terminated;
@@ -353,22 +338,51 @@ static void read_lines(void)
353 eof_error = 0; /* Pretend we saw EOF */ 338 eof_error = 0; /* Pretend we saw EOF */
354 break; 339 break;
355 } 340 }
356 if (max_fline > cur_fline + max_displayed_line) 341 if (max_fline > cur_fline + max_displayed_line) {
342#if !ENABLE_FEATURE_LESS_REGEXP
357 break; 343 break;
344#else
345 if (wanted_match >= num_matches) { /* goto_match called us */
346 fill_match_lines(old_max_fline);
347 old_max_fline = max_fline;
348 }
349 if (wanted_match < num_matches)
350 break;
351#endif
352 }
358 if (eof_error <= 0) { 353 if (eof_error <= 0) {
359 if (eof_error < 0 && errno == EAGAIN) { 354 if (eof_error < 0) {
360 /* not yet eof or error, reset flag (or else 355 if (errno == EAGAIN) {
361 * we will hog CPU - select() will return 356 /* not yet eof or error, reset flag (or else
362 * immediately */ 357 * we will hog CPU - select() will return
363 eof_error = 1; 358 * immediately */
359 eof_error = 1;
360 } else {
361 print_statusline("read error");
362 }
364 } 363 }
364#if !ENABLE_FEATURE_LESS_REGEXP
365 break; 365 break;
366#else
367 if (wanted_match < num_matches) {
368 break;
369 } else { /* goto_match called us */
370 time_t t = time(NULL);
371 if (t != last_time) {
372 last_time = t;
373 if (--seconds_p1 == 0)
374 break;
375 }
376 sched_yield();
377 goto again0; /* go loop again (max 2 seconds) */
378 }
379#endif
366 } 380 }
367 max_fline++; 381 max_fline++;
368 current_line = xmalloc(w); 382 current_line = xmalloc(w);
369 p = current_line; 383 p = current_line;
370 linepos = 0; 384 linepos = 0;
371 } 385 } /* end of "read lines until we reach cur_fline" loop */
372 fill_match_lines(old_max_fline); 386 fill_match_lines(old_max_fline);
373#undef readbuf 387#undef readbuf
374} 388}
@@ -884,24 +898,24 @@ static void normalize_match_pos(int match)
884 898
885static void goto_match(int match) 899static void goto_match(int match)
886{ 900{
887 int sv;
888
889 if (!pattern_valid) 901 if (!pattern_valid)
890 return; 902 return;
891 if (match < 0) 903 if (match < 0)
892 match = 0; 904 match = 0;
893 sv = cur_fline;
894 /* Try to find next match if eof isn't reached yet */ 905 /* Try to find next match if eof isn't reached yet */
895 if (match >= num_matches && eof_error > 0) { 906 if (match >= num_matches && eof_error > 0) {
896 cur_fline = MAXLINES; /* look as far as needed */ 907 wanted_match = match;
897 read_lines(); 908 read_lines();
909 if (wanted_match >= num_matches) {
910 /* We still failed to find it. Prevent future
911 * read_lines() from trying... */
912 wanted_match = num_matches - 1;
913 }
898 } 914 }
899 if (num_matches) { 915 if (num_matches) {
900 cap_cur_fline(cur_fline);
901 normalize_match_pos(match); 916 normalize_match_pos(match);
902 buffer_line(match_lines[match_pos]); 917 buffer_line(match_lines[match_pos]);
903 } else { 918 } else {
904 cur_fline = sv;
905 print_statusline("No matches found"); 919 print_statusline("No matches found");
906 } 920 }
907} 921}
@@ -1370,7 +1384,7 @@ int less_main(int argc, char **argv)
1370 get_terminal_width_height(kbd_fd, &width, &max_displayed_line); 1384 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1371 /* 20: two tabstops + 4 */ 1385 /* 20: two tabstops + 4 */
1372 if (width < 20 || max_displayed_line < 3) 1386 if (width < 20 || max_displayed_line < 3)
1373 bb_error_msg_and_die("too narrow here"); 1387 return bb_cat(argv);
1374 max_displayed_line -= 2; 1388 max_displayed_line -= 2;
1375 1389
1376 buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); 1390 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));