aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbb/xregcomp.c7
-rw-r--r--miscutils/less.c484
2 files changed, 238 insertions, 253 deletions
diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c
index 4bcb9aedf..6e9a29f49 100644
--- a/libbb/xregcomp.c
+++ b/libbb/xregcomp.c
@@ -8,16 +8,13 @@
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */ 9 */
10 10
11#include <stdio.h>
12#include "libbb.h" 11#include "libbb.h"
13#include "xregex.h" 12#include "xregex.h"
14 13
15
16
17void xregcomp(regex_t *preg, const char *regex, int cflags) 14void xregcomp(regex_t *preg, const char *regex, int cflags)
18{ 15{
19 int ret; 16 int ret = regcomp(preg, regex, cflags);
20 if ((ret = regcomp(preg, regex, cflags)) != 0) { 17 if (ret) {
21 int errmsgsz = regerror(ret, preg, NULL, 0); 18 int errmsgsz = regerror(ret, preg, NULL, 0);
22 char *errmsg = xmalloc(errmsgsz); 19 char *errmsg = xmalloc(errmsgsz);
23 regerror(ret, preg, errmsg, errmsgsz); 20 regerror(ret, preg, errmsg, errmsgsz);
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);