aboutsummaryrefslogtreecommitdiff
path: root/miscutils/less.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-21 00:22:03 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-21 00:22:03 +0000
commit3f3190e34c5d39986fae0ec03f37cf5509dd9c93 (patch)
tree15ecde8cea8fcd622729c9210abfbd5ae2fef5ce /miscutils/less.c
parent9a7cef930f7e299c0e5d9d1ddeb3f95db6749eb7 (diff)
downloadbusybox-w32-3f3190e34c5d39986fae0ec03f37cf5509dd9c93.tar.gz
busybox-w32-3f3190e34c5d39986fae0ec03f37cf5509dd9c93.tar.bz2
busybox-w32-3f3190e34c5d39986fae0ec03f37cf5509dd9c93.zip
less: total cleanup and bugfix.
Doesn't die horribly on binary files anymore. In fact, they _100%_ work now. Control chars are in reverse video, including DEL and that idiocy of VT-10x, Meta-ESC [inventor of which should be prohibited from reproducing]. Regex search is fixed also. When you specify search ('/' key), control chars turn into dots (unhighlighted), and found occurrences highlighted instead. This is reversible. Memory management fixed (was leaky as hell) and optimized. Linewrapping fixed and thoroughly tested. Max buffer size made configurable. ~ 600 bytes saved.
Diffstat (limited to 'miscutils/less.c')
-rw-r--r--miscutils/less.c484
1 files changed, 236 insertions, 248 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index 73500671d..6843dddcb 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -8,30 +8,20 @@
8 */ 8 */
9 9
10/* 10/*
11 * This program needs a lot of development, so consider it in a beta stage 11 * TODO:
12 * at best. 12 * - Add more regular expression support - search modifiers, certain matches, etc.
13 * - Add more complex bracket searching - currently, nested brackets are
14 * not considered.
15 * - Add support for "F" as an input. This causes less to act in
16 * a similar way to tail -f.
17 * - Allow horizontal scrolling.
13 * 18 *
14 * TODO: 19 * Notes:
15 * - Add more regular expression support - search modifiers, certain matches, etc. 20 * - the inp file pointer is used so that keyboard input works after
16 * - Add more complex bracket searching - currently, nested brackets are 21 * redirected input has been read from stdin
17 * not considered. 22 */
18 * - Add support for "F" as an input. This causes less to act in
19 * a similar way to tail -f.
20 * - Check for binary files, and prompt the user if a binary file
21 * is detected.
22 * - Allow horizontal scrolling. Currently, lines simply continue onto
23 * the next line, per the terminal's discretion
24 *
25 * Notes:
26 * - filename is an array and not a pointer because that avoids all sorts
27 * of complications involving the fact that something that is pointed to
28 * will be changed if the pointer is changed.
29 * - the inp file pointer is used so that keyboard input works after
30 * redirected input has been read from stdin
31*/
32 23
33#include "busybox.h" 24#include "busybox.h"
34
35#if ENABLE_FEATURE_LESS_REGEXP 25#if ENABLE_FEATURE_LESS_REGEXP
36#include "xregex.h" 26#include "xregex.h"
37#endif 27#endif
@@ -70,12 +60,13 @@ static int height;
70static int width; 60static int width;
71static char **files; 61static char **files;
72static char *filename; 62static char *filename;
73static char **buffer; 63static const char **buffer;
74static char **flines; 64static char **flines;
75static int current_file = 1; 65static int current_file = 1;
76static int line_pos; 66static int line_pos;
77static int num_flines; 67static int num_flines;
78static int num_files = 1; 68static int num_files = 1;
69static const char *empty_line_marker = "~";
79 70
80/* Command line options */ 71/* Command line options */
81#define FLAG_E 1 72#define FLAG_E 1
@@ -84,7 +75,6 @@ static int num_files = 1;
84#define FLAG_N (1<<3) 75#define FLAG_N (1<<3)
85#define FLAG_TILDE (1<<4) 76#define FLAG_TILDE (1<<4)
86/* hijack command line options variable for internal state vars */ 77/* hijack command line options variable for internal state vars */
87#define LESS_STATE_PAST_EOF (1<<5)
88#define LESS_STATE_MATCH_BACKWARDS (1<<6) 78#define LESS_STATE_MATCH_BACKWARDS (1<<6)
89 79
90#if ENABLE_FEATURE_LESS_MARKS 80#if ENABLE_FEATURE_LESS_MARKS
@@ -93,11 +83,11 @@ static int num_marks;
93#endif 83#endif
94 84
95#if ENABLE_FEATURE_LESS_REGEXP 85#if ENABLE_FEATURE_LESS_REGEXP
96static int match_found;
97static int *match_lines; 86static int *match_lines;
98static int match_pos; 87static int match_pos;
99static int num_matches; 88static int num_matches;
100static regex_t old_pattern; 89static regex_t pattern;
90static int pattern_valid;
101#endif 91#endif
102 92
103/* Needed termios structures */ 93/* Needed termios structures */
@@ -174,52 +164,57 @@ static void data_readlines(void)
174 unsigned i; 164 unsigned i;
175 unsigned n = 1; 165 unsigned n = 1;
176 int w = width; 166 int w = width;
177 char *last_nl = (char*)1; /* "not NULL" */ 167 /* "remained unused space" in a line (0 if line fills entire width) */
178 char *current_line; 168 int rem, last_rem = 1; /* "not 0" */
169 char *current_line, *p;
179 FILE *fp; 170 FILE *fp;
180 171
181 fp = filename ? xfopen(filename, "r") : stdin; 172 fp = filename ? xfopen(filename, "r") : stdin;
182 flines = NULL; 173 flines = NULL;
183 if (option_mask32 & FLAG_N) { 174 if (option_mask32 & FLAG_N) {
184 w -= 6; 175 w -= 6;
185 if (w < 1) w = 1; /* paranoia */
186 } 176 }
187 for (i = 0; !feof(fp) && i <= MAXLINES; i++) { 177 for (i = 0; !feof(fp) && i <= MAXLINES; i++) {
188 flines = xrealloc(flines, (i+1) * sizeof(char *)); 178 flines = xrealloc(flines, (i+1) * sizeof(char *));
189
190 current_line = xmalloc(w); 179 current_line = xmalloc(w);
191 again: 180 again:
192 current_line[0] = '\0'; 181 p = current_line;
193 fgets(current_line, w, fp); 182 rem = w - 1;
183 do {
184 int c = getc(fp);
185 if (c == EOF) break;
186 if (c == '\n') break;
187 /* NUL is substituted by '\n'! */
188 if (c == '\0') c = '\n';
189 *p++ = c;
190 } while (--rem);
191 *p = '\0';
194 if (fp != stdin) 192 if (fp != stdin)
195 die_if_ferror(fp, filename); 193 die_if_ferror(fp, filename);
196 194
197 /* Corner case: linewrap with only '\n' wrapping */ 195 /* Corner case: linewrap with only "" wrapping to next line */
198 /* Looks ugly on screen, so we handle it specially */ 196 /* Looks ugly on screen, so we do not store this empty line */
199 if (!last_nl && current_line[0] == '\n') { 197 if (!last_rem && !current_line[0]) {
200 last_nl = (char*)1; /* "not NULL" */ 198 last_rem = 1; /* "not 0" */
201 n++; 199 n++;
202 goto again; 200 goto again;
203 } 201 }
204 last_nl = last_char_is(current_line, '\n'); 202 last_rem = rem;
205 if (last_nl)
206 *last_nl = '\0';
207 if (option_mask32 & FLAG_N) { 203 if (option_mask32 & FLAG_N) {
208 flines[i] = xasprintf((n <= 99999) ? "%5u %s" : "%05u %s", 204 flines[i] = xasprintf((n <= 99999) ? "%5u %s" : "%05u %s",
209 n % 100000, current_line); 205 n % 100000, current_line);
210 free(current_line); 206 free(current_line);
211 if (last_nl) 207 if (rem)
212 n++; 208 n++;
213 } else { 209 } else {
214 flines[i] = xrealloc(current_line, strlen(current_line)+1); 210 flines[i] = xrealloc(current_line, strlen(current_line)+1);
215 } 211 }
216 } 212 }
217 num_flines = i - 2; 213 num_flines = i - 1; /* buggie: 'num_flines' must be 'max_fline' */
218 214
219 /* Reset variables for a new file */ 215 /* Reset variables for a new file */
220 216
221 line_pos = 0; 217 line_pos = 0;
222 option_mask32 &= ~LESS_STATE_PAST_EOF;
223 218
224 fclose(fp); 219 fclose(fp);
225} 220}
@@ -238,36 +233,28 @@ static void m_status_print(void)
238{ 233{
239 int percentage; 234 int percentage;
240 235
241 if (!(option_mask32 & LESS_STATE_PAST_EOF)) { 236 if (!line_pos) {
242 if (!line_pos) { 237 if (num_files > 1) {
243 if (num_files > 1) { 238 printf("%s%s %s%i%s%i%s%i-%i/%i ", HIGHLIGHT,
244 printf("%s%s %s%i%s%i%s%i-%i/%i ", HIGHLIGHT, 239 filename, "(file ", current_file, " of ", num_files, ") lines ",
245 filename, "(file ", current_file, " of ", num_files, ") lines ",
246 line_pos + 1, line_pos + height - 1, num_flines + 1);
247 } else {
248 printf("%s%s lines %i-%i/%i ", HIGHLIGHT,
249 filename, line_pos + 1, line_pos + height - 1,
250 num_flines + 1);
251 }
252 } else {
253 printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename,
254 line_pos + 1, line_pos + height - 1, num_flines + 1); 240 line_pos + 1, line_pos + height - 1, num_flines + 1);
255 }
256
257 if (line_pos == num_flines - height + 2) {
258 printf("(END) %s", NORMAL);
259 if ((num_files > 1) && (current_file != num_files))
260 printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL);
261 } else { 241 } else {
262 percentage = calc_percent(); 242 printf("%s%s lines %i-%i/%i ", HIGHLIGHT,
263 printf("%i%% %s", percentage, NORMAL); 243 filename, line_pos + 1, line_pos + height - 1,
244 num_flines + 1);
264 } 245 }
265 } else { 246 } else {
266 printf("%s%s lines %i-%i/%i (END) ", HIGHLIGHT, filename, 247 printf("%s %s lines %i-%i/%i ", HIGHLIGHT, filename,
267 line_pos + 1, num_flines + 1, num_flines + 1); 248 line_pos + 1, line_pos + height - 1, num_flines + 1);
249 }
250
251 if (line_pos >= num_flines - height + 2) {
252 printf("(END) %s", NORMAL);
268 if ((num_files > 1) && (current_file != num_files)) 253 if ((num_files > 1) && (current_file != num_files))
269 printf("- Next: %s", files[current_file]); 254 printf("%s- Next: %s%s", HIGHLIGHT, files[current_file], NORMAL);
270 printf("%s", NORMAL); 255 } else {
256 percentage = calc_percent();
257 printf("%i%% %s", percentage, NORMAL);
271 } 258 }
272} 259}
273 260
@@ -315,22 +302,123 @@ static void status_print(void)
315#endif 302#endif
316} 303}
317 304
305static char controls[] =
306 /**/"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
307 "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
308 "\x7f\x9b"; /* DEL and infamous Meta-ESC :( */
309static char ctrlconv[] =
310 /* Note that on input NUL is converted to '\n' ('\x0a') */
311 /* Therefore we subst '\n' with '@', not 'J' */
312 "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x40\x4b\x4c\x4d\x4e\x4f"
313 "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f";
314
315static void print_found(const char *line)
316{
317 int match_status;
318 int eflags;
319 char *growline;
320 regmatch_t match_structs;
321
322 char buf[width];
323 const char *str = line;
324 char *p = buf;
325 size_t n;
326
327 while (*str) {
328 n = strcspn(str, controls);
329 if (n) {
330 if (!str[n]) break;
331 memcpy(p, str, n);
332 p += n;
333 str += n;
334 }
335 n = strspn(str, controls);
336 memset(p, '.', n);
337 p += n;
338 str += n;
339 /*
340 do {
341 if (*str == '\x7f') { *p++ = '?'; str++; }
342 else if (*str == '\x9b') { *p++ = '{'; str++; }
343 else *p++ = ctrlconv[(unsigned char)*str++];
344 } while (--n);
345 */
346 }
347 strcpy(p, str);
348
349 /* buf[] holds quarantined version of str */
350
351 /* Each part of the line that matches has the HIGHLIGHT
352 and NORMAL escape sequences placed around it.
353 NB: we regex against line, but insert text
354 from quarantined copy (buf[]) */
355 str = buf;
356 growline = NULL;
357 eflags = 0;
358 goto start;
359
360 while (match_status == 0) {
361 char *new = xasprintf("%s" "%.*s" "%s" "%.*s" "%s",
362 growline ? : "",
363 match_structs.rm_so, str,
364 HIGHLIGHT,
365 match_structs.rm_eo - match_structs.rm_so,
366 str + match_structs.rm_so,
367 NORMAL);
368 free(growline); growline = new;
369 str += match_structs.rm_eo;
370 line += match_structs.rm_eo;
371 eflags = REG_NOTBOL;
372 start:
373 /* Most of the time doesn't find the regex, optimize for that */
374 match_status = regexec(&pattern, line, 1, &match_structs, eflags);
375 }
376
377 if (!growline) {
378 puts(str);
379 return;
380 }
381 printf("%s%s\n", growline, str);
382 free(growline);
383}
384
385static void print_ascii(const char *str)
386{
387 char buf[width];
388 char *p;
389 size_t n;
390
391 while (*str) {
392 n = strcspn(str, controls);
393 if (n) {
394 if (!str[n]) break;
395 printf("%.*s", n, str);
396 str += n;
397 }
398 n = strspn(str, controls);
399 p = buf;
400 do {
401 if (*str == '\x7f') { *p++ = '?'; str++; }
402 else if (*str == '\x9b') { *p++ = '{'; str++; }
403 else *p++ = ctrlconv[(unsigned char)*str++];
404 } while (--n);
405 *p = '\0';
406 printf("%s%s%s", HIGHLIGHT, buf, NORMAL);
407 }
408 puts(str);
409}
410
318/* Print the buffer */ 411/* Print the buffer */
319static void buffer_print(void) 412static void buffer_print(void)
320{ 413{
321 int i; 414 int i;
322 415
323 printf("%s", CLEAR); 416 printf("%s", CLEAR);
324 if (num_flines >= height - 2) { 417 for (i = 0; i < height - 1; i++)
325 for (i = 0; i < height - 1; i++) 418 if (pattern_valid)
326 printf("%.*s\n", width, buffer[i]); 419 print_found(buffer[i]);
327 } else { 420 else
328 for (i = 1; i < (height - 1 - num_flines); i++) 421 print_ascii(buffer[i]);
329 putchar('\n');
330 for (i = 0; i < height - 1; i++)
331 printf("%.*s\n", width, buffer[i]);
332 }
333
334 status_print(); 422 status_print();
335} 423}
336 424
@@ -339,20 +427,20 @@ static void buffer_init(void)
339{ 427{
340 int i; 428 int i;
341 429
342 if (buffer == NULL) { 430 if (!buffer) {
343 /* malloc the number of lines needed for the buffer */ 431 /* malloc the number of lines needed for the buffer */
344 buffer = xmalloc(height * sizeof(char *)); 432 buffer = xmalloc(height * sizeof(char *));
345 } 433 }
346 434
347 /* Fill the buffer until the end of the file or the 435 /* Fill the buffer until the end of the file or the
348 end of the buffer is reached */ 436 end of the buffer is reached */
349 for (i = 0; (i < (height - 1)) && (i <= num_flines); i++) { 437 for (i = 0; i < height - 1 && i <= num_flines; i++) {
350 buffer[i] = flines[i]; 438 buffer[i] = flines[i];
351 } 439 }
352 440
353 /* If the buffer still isn't full, fill it with blank lines */ 441 /* If the buffer still isn't full, fill it with blank lines */
354 for (; i < (height - 1); i++) { 442 for (; i < height - 1; i++) {
355 buffer[i] = ""; 443 buffer[i] = empty_line_marker;
356 } 444 }
357} 445}
358 446
@@ -361,72 +449,38 @@ static void buffer_down(int nlines)
361{ 449{
362 int i; 450 int i;
363 451
364 if (!(option_mask32 & LESS_STATE_PAST_EOF)) { 452 if (line_pos + (height - 3) + nlines < num_flines) {
365 if (line_pos + (height - 3) + nlines < num_flines) { 453 line_pos += nlines;
366 line_pos += nlines; 454 for (i = 0; i < (height - 1); i++) {
455 buffer[i] = flines[line_pos + i];
456 }
457 } else {
458 /* As the number of lines requested was too large, we just move
459 to the end of the file */
460 while (line_pos + (height - 3) + 1 < num_flines) {
461 line_pos += 1;
367 for (i = 0; i < (height - 1); i++) { 462 for (i = 0; i < (height - 1); i++) {
368 buffer[i] = flines[line_pos + i]; 463 buffer[i] = flines[line_pos + i];
369 } 464 }
370 } else {
371 /* As the number of lines requested was too large, we just move
372 to the end of the file */
373 while (line_pos + (height - 3) + 1 < num_flines) {
374 line_pos += 1;
375 for (i = 0; i < (height - 1); i++) {
376 buffer[i] = flines[line_pos + i];
377 }
378 }
379 } 465 }
380
381 /* We exit if the -E flag has been set */
382 if ((option_mask32 & FLAG_E) && (line_pos + (height - 2) == num_flines))
383 tless_exit(0);
384 } 466 }
467
468 /* We exit if the -E flag has been set */
469 if ((option_mask32 & FLAG_E) && (line_pos + (height - 2) == num_flines))
470 tless_exit(0);
385} 471}
386 472
387static void buffer_up(int nlines) 473static void buffer_up(int nlines)
388{ 474{
389 int i; 475 int i;
390 int tilde_line;
391 476
392 if (!(option_mask32 & LESS_STATE_PAST_EOF)) { 477 line_pos -= nlines;
393 if (line_pos - nlines >= 0) { 478 if (line_pos < 0) line_pos = 0;
394 line_pos -= nlines; 479 for (i = 0; i < height - 1; i++) {
395 for (i = 0; i < (height - 1); i++) { 480 if (line_pos + i <= num_flines) {
396 buffer[i] = flines[line_pos + i]; 481 buffer[i] = flines[line_pos + i];
397 }
398 } else {
399 /* As the requested number of lines to move was too large, we
400 move one line up at a time until we can't. */
401 while (line_pos != 0) {
402 line_pos -= 1;
403 for (i = 0; i < (height - 1); i++) {
404 buffer[i] = flines[line_pos + i];
405 }
406 }
407 }
408 }
409 else {
410 /* Work out where the tildes start */
411 tilde_line = num_flines - line_pos + 3;
412
413 line_pos -= nlines;
414 /* Going backwards nlines lines has taken us to a point where
415 nothing is past the EOF, so we revert to normal. */
416 if (line_pos < num_flines - height + 3) {
417 option_mask32 &= ~LESS_STATE_PAST_EOF;
418 buffer_up(nlines);
419 } else { 482 } else {
420 /* We only move part of the buffer, as the rest 483 buffer[i] = empty_line_marker;
421 is past the EOF */
422 for (i = 0; i < (height - 1); i++) {
423 if (i < tilde_line - nlines + 1) {
424 buffer[i] = flines[line_pos + i];
425 } else {
426 if (line_pos >= num_flines - height + 2)
427 buffer[i] = "~";
428 }
429 }
430 } 484 }
431 } 485 }
432} 486}
@@ -434,28 +488,19 @@ static void buffer_up(int nlines)
434static void buffer_line(int linenum) 488static void buffer_line(int linenum)
435{ 489{
436 int i; 490 int i;
437 option_mask32 &= ~LESS_STATE_PAST_EOF;
438 491
439 if (linenum < 0 || linenum > num_flines) { 492 if (linenum < 0 || linenum > num_flines) {
440 clear_line(); 493 clear_line();
441 printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum + 1, NORMAL); 494 printf("%s%s%i%s", HIGHLIGHT, "Cannot seek to line number ", linenum + 1, NORMAL);
442 }
443 else if (linenum < (num_flines - height - 2)) {
444 for (i = 0; i < (height - 1); i++) {
445 buffer[i] = flines[linenum + i];
446 }
447 line_pos = linenum;
448 buffer_print();
449 } else { 495 } else {
450 for (i = 0; i < (height - 1); i++) { 496 for (i = 0; i < height - 1; i++) {
451 if (linenum + i < num_flines + 2) 497 if (linenum + i <= num_flines)
452 buffer[i] = flines[linenum + i]; 498 buffer[i] = flines[linenum + i];
453 else 499 else {
454 buffer[i] = (option_mask32 & FLAG_TILDE) ? "" : "~"; 500 buffer[i] = empty_line_marker;
501 }
455 } 502 }
456 line_pos = linenum; 503 line_pos = linenum;
457 /* Set past_eof so buffer_down and buffer_up act differently */
458 option_mask32 |= LESS_STATE_PAST_EOF;
459 buffer_print(); 504 buffer_print();
460 } 505 }
461} 506}
@@ -563,76 +608,37 @@ static void colon_process(void)
563 } 608 }
564} 609}
565 610
566#if ENABLE_FEATURE_LESS_REGEXP 611static int normalize_match_pos(int match)
567/* The below two regular expression handler functions NEED development. */
568
569/* Get a regular expression from the user, and then go through the current
570 file line by line, running a processing regex function on each one. */
571
572static char *process_regex_on_line(char *line, regex_t *pattern, int action)
573{ 612{
574/* UNTESTED. LOOKED BUGGY AND LEAKY AS HELL. */ 613 match_pos = match;
575/* FIXED. NEED TESTING. */ 614 if (match < 0)
576 /* 'line' should be either returned or free()ed */ 615 return (match_pos = 0);
577 616 if (match >= num_matches)
578 /* This function takes the regex and applies it to the line. 617{
579 Each part of the line that matches has the HIGHLIGHT 618 match_pos = num_matches - 1;
580 and NORMAL escape sequences placed around it by 619}
581 insert_highlights if action = 1, or has the escape sequences 620 return match_pos;
582 removed if action = 0, and then the line is returned. */
583 int match_status;
584 char *line2 = line;
585 char *growline = xstrdup("");
586 char *ng;
587 regmatch_t match_structs;
588
589 match_found = 0;
590 match_status = regexec(pattern, line2, 1, &match_structs, 0);
591
592 while (match_status == 0) {
593 match_found = 1;
594 if (action) {
595 ng = xasprintf("%s%.*s%s%.*s%s", growline,
596 match_structs.rm_so, line2, HIGHLIGHT,
597 match_structs.rm_eo - match_structs.rm_so,
598 line2 + match_structs.rm_so, NORMAL);
599 } else {
600 ng = xasprintf("%s%.*s%.*s", growline,
601 match_structs.rm_so - 4, line2,
602 match_structs.rm_eo - match_structs.rm_so,
603 line2 + match_structs.rm_so);
604 }
605 free(growline); growline = ng;
606 line2 += match_structs.rm_eo;
607 match_status = regexec(pattern, line2, 1, &match_structs, REG_NOTBOL);
608 }
609
610 if (match_found) {
611 ng = xasprintf("%s%s", growline, line2);
612 free(line);
613 } else {
614 ng = line;
615 }
616 free(growline);
617 return ng;
618} 621}
619 622
623#if ENABLE_FEATURE_LESS_REGEXP
620static void goto_match(int match) 624static void goto_match(int match)
621{ 625{
622 /* This goes to a specific match - all line positions of matches are 626 buffer_line(match_lines[normalize_match_pos(match)]);
623 stored within the match_lines[] array. */
624 if ((match < num_matches) && (match >= 0)) {
625 buffer_line(match_lines[match]);
626 match_pos = match;
627 }
628} 627}
629 628
630static void regex_process(void) 629static void regex_process(void)
631{ 630{
632 char *uncomp_regex; 631 char *uncomp_regex;
633 int i; 632
634 int j = 0; 633 /* Reset variables */
635 regex_t pattern; 634 match_lines = xrealloc(match_lines, sizeof(int));
635 match_lines[0] = -1;
636 match_pos = 0;
637 num_matches = 0;
638 if (pattern_valid) {
639 regfree(&pattern);
640 pattern_valid = 0;
641 }
636 642
637 /* Get the uncompiled regular expression from the user */ 643 /* Get the uncompiled regular expression from the user */
638 clear_line(); 644 clear_line();
@@ -640,56 +646,33 @@ static void regex_process(void)
640 uncomp_regex = xmalloc_getline(inp); 646 uncomp_regex = xmalloc_getline(inp);
641 if (!uncomp_regex || !uncomp_regex[0]) { 647 if (!uncomp_regex || !uncomp_regex[0]) {
642 free(uncomp_regex); 648 free(uncomp_regex);
643 if (num_matches) 649 buffer_print();
644 goto_match((option_mask32 & LESS_STATE_MATCH_BACKWARDS)
645 ? match_pos - 1 : match_pos + 1);
646 else
647 buffer_print();
648 return; 650 return;
649 } 651 }
650 652
651 /* Compile the regex and check for errors */ 653 /* Compile the regex and check for errors */
652 xregcomp(&pattern, uncomp_regex, 0); 654 xregcomp(&pattern, uncomp_regex, 0);
653 free(uncomp_regex); 655 free(uncomp_regex);
656 pattern_valid = 1;
654 657
655 if (num_matches) { 658 /* Run the regex on each line of the current file */
656 /* Get rid of all the highlights we added previously */ 659 for (match_pos = 0; match_pos <= num_flines; match_pos++) {
657 for (i = 0; i <= num_flines; i++) { 660 if (regexec(&pattern, flines[match_pos], 0, NULL, 0) == 0) {
658 flines[i] = process_regex_on_line(flines[i], &old_pattern, 0); 661 match_lines = xrealloc(match_lines, (num_matches+1) * sizeof(int));
662 match_lines[num_matches++] = match_pos;
659 } 663 }
660 } 664 }
661 old_pattern = pattern;
662 665
663 /* Reset variables */ 666 if (num_matches == 0 || num_flines <= height - 2) {
664 match_lines = xrealloc(match_lines, sizeof(int)); 667 buffer_print();
665 match_lines[0] = -1; 668 return;
666 match_pos = 0;
667 num_matches = 0;
668 match_found = 0;
669 /* Run the regex on each line of the current file here */
670 for (i = 0; i <= num_flines; i++) {
671 flines[i] = process_regex_on_line(flines[i], &pattern, 1);
672 if (match_found) {
673 match_lines = xrealloc(match_lines, (j + 1) * sizeof(int));
674 match_lines[j] = i;
675 j++;
676 }
677 } 669 }
678 670 for (match_pos = 0; match_pos < num_matches; match_pos++) {
679 num_matches = j; 671 if (match_lines[match_pos] > line_pos)
680 if ((match_lines[0] != -1) && (num_flines > height - 2)) { 672 break;
681 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) { 673 }
682 for (i = 0; i < num_matches; i++) { 674 if (option_mask32 & LESS_STATE_MATCH_BACKWARDS) match_pos--;
683 if (match_lines[i] > line_pos) { 675 buffer_line(match_lines[normalize_match_pos(match_pos)]);
684 match_pos = i - 1;
685 buffer_line(match_lines[match_pos]);
686 break;
687 }
688 }
689 } else
690 buffer_line(match_lines[0]);
691 } else
692 buffer_init();
693} 676}
694#endif 677#endif
695 678
@@ -1111,11 +1094,16 @@ int less_main(int argc, char **argv)
1111 inp = xfopen(CURRENT_TTY, "r"); 1094 inp = xfopen(CURRENT_TTY, "r");
1112 1095
1113 get_terminal_width_height(fileno(inp), &width, &height); 1096 get_terminal_width_height(fileno(inp), &width, &height);
1097 if (width < 10 || height < 3)
1098 bb_error_msg_and_die("too narrow here");
1099
1100 if (option_mask32 & FLAG_TILDE) empty_line_marker = "";
1101
1114 data_readlines(); 1102 data_readlines();
1115 1103
1104 tcgetattr(fileno(inp), &term_orig);
1116 signal(SIGTERM, sig_catcher); 1105 signal(SIGTERM, sig_catcher);
1117 signal(SIGINT, sig_catcher); 1106 signal(SIGINT, sig_catcher);
1118 tcgetattr(fileno(inp), &term_orig);
1119 1107
1120 term_vi = term_orig; 1108 term_vi = term_orig;
1121 term_vi.c_lflag &= (~ICANON & ~ECHO); 1109 term_vi.c_lflag &= (~ICANON & ~ECHO);