aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-24 22:43:27 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-24 22:43:27 +0000
commit53c80f09723fa5e9bccd6fbab9c11b14ed520404 (patch)
tree1c05b9eb8166124b0ac9fb74587aca6459634755
parentaa2a1c000c360d89c36c9b1138473ab5f57a946f (diff)
downloadbusybox-w32-53c80f09723fa5e9bccd6fbab9c11b14ed520404.tar.gz
busybox-w32-53c80f09723fa5e9bccd6fbab9c11b14ed520404.tar.bz2
busybox-w32-53c80f09723fa5e9bccd6fbab9c11b14ed520404.zip
less: add optional line number toggle and resizing on SIGWINCH.
-rw-r--r--TODO_config_nommu2
-rw-r--r--miscutils/Config.in20
-rw-r--r--miscutils/less.c151
-rw-r--r--scripts/defconfig2
4 files changed, 108 insertions, 67 deletions
diff --git a/TODO_config_nommu b/TODO_config_nommu
index 35546897f..df51dc05a 100644
--- a/TODO_config_nommu
+++ b/TODO_config_nommu
@@ -575,7 +575,7 @@ CONFIG_LESS=y
575CONFIG_FEATURE_LESS_MAXLINES=9999999 575CONFIG_FEATURE_LESS_MAXLINES=9999999
576CONFIG_FEATURE_LESS_BRACKETS=y 576CONFIG_FEATURE_LESS_BRACKETS=y
577CONFIG_FEATURE_LESS_FLAGS=y 577CONFIG_FEATURE_LESS_FLAGS=y
578CONFIG_FEATURE_LESS_FLAGCS=y 578CONFIG_FEATURE_LESS_DASHCMD=y
579CONFIG_FEATURE_LESS_MARKS=y 579CONFIG_FEATURE_LESS_MARKS=y
580CONFIG_FEATURE_LESS_REGEXP=y 580CONFIG_FEATURE_LESS_REGEXP=y
581CONFIG_HDPARM=y 581CONFIG_HDPARM=y
diff --git a/miscutils/Config.in b/miscutils/Config.in
index 15f677a73..40edf23a2 100644
--- a/miscutils/Config.in
+++ b/miscutils/Config.in
@@ -293,13 +293,13 @@ config FEATURE_LESS_FLAGS
293 The -M flag enables a more sophisticated status line. 293 The -M flag enables a more sophisticated status line.
294 The -m flag enables a simpler status line with a percentage. 294 The -m flag enables a simpler status line with a percentage.
295 295
296config FEATURE_LESS_FLAGCS 296config FEATURE_LESS_DASHCMD
297 bool "Enable flag changes" 297 bool "Enable flag changes ('-' command)"
298 default n 298 default n
299 depends on LESS 299 depends on LESS
300 help 300 help
301 This enables the ability to change command-line flags within 301 This enables the ability to change command-line flags within
302 less itself. 302 less itself ('-' keyboard command).
303 303
304config FEATURE_LESS_MARKS 304config FEATURE_LESS_MARKS
305 bool "Enable marks" 305 bool "Enable marks"
@@ -315,6 +315,20 @@ config FEATURE_LESS_REGEXP
315 help 315 help
316 Enable regular expressions, allowing complex file searches. 316 Enable regular expressions, allowing complex file searches.
317 317
318config FEATURE_LESS_LINENUMS
319 bool "Enable dynamic switching of line numbers"
320 default n
321 depends on LESS
322 help
323 Enable "-N" command.
324
325config FEATURE_LESS_WINCH
326 bool "Enable automatic resizing on window size changes"
327 default n
328 depends on LESS
329 help
330 Makes less track window size changes.
331
318config HDPARM 332config HDPARM
319 bool "hdparm" 333 bool "hdparm"
320 default n 334 default n
diff --git a/miscutils/less.c b/miscutils/less.c
index 1af9685bf..f367b0ebc 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -28,13 +28,6 @@
28#include "xregex.h" 28#include "xregex.h"
29#endif 29#endif
30 30
31/* In progress */
32#define ENABLE_FEATURE_LESS_REWRAP 0
33
34/* FIXME: currently doesn't work right */
35#undef ENABLE_FEATURE_LESS_FLAGCS
36#define ENABLE_FEATURE_LESS_FLAGCS 0
37
38/* The escape codes for highlighted and normal text */ 31/* The escape codes for highlighted and normal text */
39#define HIGHLIGHT "\033[7m" 32#define HIGHLIGHT "\033[7m"
40#define NORMAL "\033[0m" 33#define NORMAL "\033[0m"
@@ -77,14 +70,14 @@ enum {
77 70
78/* Command line options */ 71/* Command line options */
79enum { 72enum {
80 FLAG_E = 1, 73 FLAG_E = 1 << 0,
81 FLAG_M = 1 << 1, 74 FLAG_M = 1 << 1,
82 FLAG_m = 1 << 2, 75 FLAG_m = 1 << 2,
83 FLAG_N = 1 << 3, 76 FLAG_N = 1 << 3,
84 FLAG_TILDE = 1 << 4, 77 FLAG_TILDE = 1 << 4,
85 FLAG_I = 1 << 5, 78 FLAG_I = 1 << 5,
79 FLAG_S = (1 << 6) * ENABLE_FEATURE_LESS_DASHCMD,
86/* hijack command line options variable for internal state vars */ 80/* hijack command line options variable for internal state vars */
87 LESS_STATE_NO_WRAP = 1 << 14,
88 LESS_STATE_MATCH_BACKWARDS = 1 << 15, 81 LESS_STATE_MATCH_BACKWARDS = 1 << 15,
89}; 82};
90 83
@@ -98,10 +91,13 @@ struct globals {
98 int less_gets_pos; 91 int less_gets_pos;
99/* last position in last line, taking into account tabs */ 92/* last position in last line, taking into account tabs */
100 size_t linepos; 93 size_t linepos;
101 unsigned max_displayed_line;
102 unsigned max_fline; 94 unsigned max_fline;
103 unsigned max_lineno; /* this one tracks linewrap */ 95 unsigned max_lineno; /* this one tracks linewrap */
96 unsigned max_displayed_line;
104 unsigned width; 97 unsigned width;
98#if ENABLE_FEATURE_LESS_WINCH
99 unsigned winch_counter;
100#endif
105 ssize_t eof_error; /* eof if 0, error if < 0 */ 101 ssize_t eof_error; /* eof if 0, error if < 0 */
106 ssize_t readpos; 102 ssize_t readpos;
107 ssize_t readeof; /* must be signed */ 103 ssize_t readeof; /* must be signed */
@@ -132,10 +128,11 @@ struct globals {
132#define kbd_fd (G.kbd_fd ) 128#define kbd_fd (G.kbd_fd )
133#define less_gets_pos (G.less_gets_pos ) 129#define less_gets_pos (G.less_gets_pos )
134#define linepos (G.linepos ) 130#define linepos (G.linepos )
135#define max_displayed_line (G.max_displayed_line)
136#define max_fline (G.max_fline ) 131#define max_fline (G.max_fline )
137#define max_lineno (G.max_lineno ) 132#define max_lineno (G.max_lineno )
133#define max_displayed_line (G.max_displayed_line)
138#define width (G.width ) 134#define width (G.width )
135#define winch_counter (G.winch_counter )
139#define eof_error (G.eof_error ) 136#define eof_error (G.eof_error )
140#define readpos (G.readpos ) 137#define readpos (G.readpos )
141#define readeof (G.readeof ) 138#define readeof (G.readeof )
@@ -218,7 +215,7 @@ static void less_exit(int code)
218 exit(code); 215 exit(code);
219} 216}
220 217
221#if ENABLE_FEATURE_LESS_REWRAP 218#if ENABLE_FEATURE_LESS_LINENUMS || ENABLE_FEATURE_LESS_WINCH
222static void re_wrap(void) 219static void re_wrap(void)
223{ 220{
224 int w = width; 221 int w = width;
@@ -297,6 +294,7 @@ static void re_wrap(void)
297 linepos = 0; // XXX 294 linepos = 0; // XXX
298 cur_fline = new_cur_fline; 295 cur_fline = new_cur_fline;
299 /* max_lineno is screen-size independent */ 296 /* max_lineno is screen-size independent */
297 pattern_valid = 0;
300} 298}
301#endif 299#endif
302 300
@@ -426,7 +424,11 @@ static void read_lines(void)
426 eof_error = 0; /* Pretend we saw EOF */ 424 eof_error = 0; /* Pretend we saw EOF */
427 break; 425 break;
428 } 426 }
429 if (max_fline > cur_fline + max_displayed_line) { 427 if (!(option_mask32 & FLAG_S)
428 ? (max_fline > cur_fline + max_displayed_line)
429 : (max_fline >= cur_fline
430 && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line)
431 ) {
430#if !ENABLE_FEATURE_LESS_REGEXP 432#if !ENABLE_FEATURE_LESS_REGEXP
431 break; 433 break;
432#else 434#else
@@ -719,18 +721,19 @@ static void buffer_print(void)
719 status_print(); 721 status_print();
720} 722}
721 723
722#if ENABLE_FEATURE_LESS_REWRAP
723static void buffer_fill_and_print(void) 724static void buffer_fill_and_print(void)
724{ 725{
725 unsigned i = 0; 726 unsigned i;
726 int fpos = cur_fline + i; 727#if ENABLE_FEATURE_LESS_DASHCMD
728 int fpos = cur_fline;
727 729
728 if (option_mask32 & LESS_STATE_NO_WRAP) { 730 if (option_mask32 & FLAG_S) {
729 /* Go back to the beginning of this line */ 731 /* Go back to the beginning of this line */
730 while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1])) 732 while (fpos && LINENO(flines[fpos]) == LINENO(flines[fpos-1]))
731 fpos--; 733 fpos--;
732 } 734 }
733 735
736 i = 0;
734 while (i <= max_displayed_line && fpos <= max_fline) { 737 while (i <= max_displayed_line && fpos <= max_fline) {
735 int lineno = LINENO(flines[fpos]); 738 int lineno = LINENO(flines[fpos]);
736 buffer[i] = flines[fpos]; 739 buffer[i] = flines[fpos];
@@ -738,28 +741,20 @@ static void buffer_fill_and_print(void)
738 do { 741 do {
739 fpos++; 742 fpos++;
740 } while ((fpos <= max_fline) 743 } while ((fpos <= max_fline)
741 && (option_mask32 & LESS_STATE_NO_WRAP) 744 && (option_mask32 & FLAG_S)
742 && lineno == LINENO(flines[fpos]) 745 && lineno == LINENO(flines[fpos])
743 ); 746 );
744 } 747 }
745 for (; i <= max_displayed_line; i++) {
746 buffer[i] = empty_line_marker;
747 }
748 buffer_print();
749}
750#else 748#else
751static void buffer_fill_and_print(void)
752{
753 unsigned i;
754 for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) { 749 for (i = 0; i <= max_displayed_line && cur_fline + i <= max_fline; i++) {
755 buffer[i] = flines[cur_fline + i]; 750 buffer[i] = flines[cur_fline + i];
756 } 751 }
752#endif
757 for (; i <= max_displayed_line; i++) { 753 for (; i <= max_displayed_line; i++) {
758 buffer[i] = empty_line_marker; 754 buffer[i] = empty_line_marker;
759 } 755 }
760 buffer_print(); 756 buffer_print();
761} 757}
762#endif
763 758
764/* Move the buffer up and down in the file in order to scroll */ 759/* Move the buffer up and down in the file in order to scroll */
765static void buffer_down(int nlines) 760static void buffer_down(int nlines)
@@ -857,7 +852,19 @@ static ssize_t getch_nowait(char* input, int sz)
857 if (less_gets_pos >= 0) 852 if (less_gets_pos >= 0)
858 move_cursor(max_displayed_line + 2, less_gets_pos + 1); 853 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
859 fflush(stdout); 854 fflush(stdout);
855#if ENABLE_FEATURE_LESS_WINCH
856 while (1) {
857 int r;
858 r = poll(pfd + rd, 2 - rd, -1);
859 if (/*r < 0 && errno == EINTR &&*/ winch_counter) {
860 input[0] = '\\'; /* anything which has no defined function */
861 return 1;
862 }
863 if (r) break;
864 }
865#else
860 safe_poll(pfd + rd, 2 - rd, -1); 866 safe_poll(pfd + rd, 2 - rd, -1);
867#endif
861 868
862 input[0] = '\0'; 869 input[0] = '\0';
863 rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */ 870 rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */
@@ -1114,7 +1121,7 @@ static void regex_process(void)
1114 1121
1115 /* Compile the regex and check for errors */ 1122 /* Compile the regex and check for errors */
1116 err = regcomp_or_errmsg(&pattern, uncomp_regex, 1123 err = regcomp_or_errmsg(&pattern, uncomp_regex,
1117 option_mask32 & FLAG_I ? REG_ICASE : 0); 1124 (option_mask32 & FLAG_I) ? REG_ICASE : 0);
1118 free(uncomp_regex); 1125 free(uncomp_regex);
1119 if (err) { 1126 if (err) {
1120 print_statusline(err); 1127 print_statusline(err);
@@ -1208,7 +1215,7 @@ static void number_process(int first_digit)
1208 } 1215 }
1209} 1216}
1210 1217
1211#if ENABLE_FEATURE_LESS_FLAGCS 1218#if ENABLE_FEATURE_LESS_DASHCMD
1212static void flag_change(void) 1219static void flag_change(void)
1213{ 1220{
1214 int keypress; 1221 int keypress;
@@ -1230,6 +1237,17 @@ static void flag_change(void)
1230 case '~': 1237 case '~':
1231 option_mask32 ^= FLAG_TILDE; 1238 option_mask32 ^= FLAG_TILDE;
1232 break; 1239 break;
1240 case 'S':
1241 option_mask32 ^= FLAG_S;
1242 buffer_fill_and_print();
1243 break;
1244#if ENABLE_FEATURE_LESS_LINENUMS
1245 case 'N':
1246 option_mask32 ^= FLAG_N;
1247 re_wrap();
1248 buffer_fill_and_print();
1249 break;
1250#endif
1233 } 1251 }
1234} 1252}
1235 1253
@@ -1467,7 +1485,7 @@ static void keypress_process(int keypress)
1467 regex_process(); 1485 regex_process();
1468 break; 1486 break;
1469#endif 1487#endif
1470#if ENABLE_FEATURE_LESS_FLAGCS 1488#if ENABLE_FEATURE_LESS_DASHCMD
1471 case '-': 1489 case '-':
1472 flag_change(); 1490 flag_change();
1473 buffer_print(); 1491 buffer_print();
@@ -1487,25 +1505,6 @@ static void keypress_process(int keypress)
1487 case ':': 1505 case ':':
1488 colon_process(); 1506 colon_process();
1489 break; 1507 break;
1490#if ENABLE_FEATURE_LESS_REWRAP
1491 case '*': /* Should be -N command / option */
1492 option_mask32 ^= FLAG_N;
1493 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1494 if (width < 20) /* 20: two tabstops + 4 */
1495 width = 20;
1496 if (max_displayed_line < 3)
1497 max_displayed_line = 3;
1498 max_displayed_line -= 2;
1499 free(buffer);
1500 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1501 re_wrap();
1502 buffer_fill_and_print();
1503 break;
1504 case '&': /* Should be -S command / option */
1505 option_mask32 ^= LESS_STATE_NO_WRAP;
1506 buffer_fill_and_print();
1507 break;
1508#endif
1509 } 1508 }
1510 1509
1511 if (isdigit(keypress)) 1510 if (isdigit(keypress))
@@ -1517,6 +1516,13 @@ static void sig_catcher(int sig)
1517 less_exit(- sig); 1516 less_exit(- sig);
1518} 1517}
1519 1518
1519#if ENABLE_FEATURE_LESS_WINCH
1520static void sigwinch_handler(int sig UNUSED_PARAM)
1521{
1522 winch_counter++;
1523}
1524#endif
1525
1520int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1526int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1521int less_main(int argc, char **argv) 1527int less_main(int argc, char **argv)
1522{ 1528{
@@ -1527,7 +1533,7 @@ int less_main(int argc, char **argv)
1527 /* TODO: -x: do not interpret backspace, -xx: tab also */ 1533 /* TODO: -x: do not interpret backspace, -xx: tab also */
1528 /* -xxx: newline also */ 1534 /* -xxx: newline also */
1529 /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */ 1535 /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */
1530 getopt32(argv, "EMmN~I"); 1536 getopt32(argv, "EMmN~I" USE_FEATURE_LESS_DASHCMD("S"));
1531 argc -= optind; 1537 argc -= optind;
1532 argv += optind; 1538 argv += optind;
1533 num_files = argc; 1539 num_files = argc;
@@ -1537,10 +1543,6 @@ int less_main(int argc, char **argv)
1537 * is not a tty and turns into cat. This makes sense. */ 1543 * is not a tty and turns into cat. This makes sense. */
1538 if (!isatty(STDOUT_FILENO)) 1544 if (!isatty(STDOUT_FILENO))
1539 return bb_cat(argv); 1545 return bb_cat(argv);
1540 kbd_fd = open(CURRENT_TTY, O_RDONLY);
1541 if (kbd_fd < 0)
1542 return bb_cat(argv);
1543 ndelay_on(kbd_fd);
1544 1546
1545 if (!num_files) { 1547 if (!num_files) {
1546 if (isatty(STDIN_FILENO)) { 1548 if (isatty(STDIN_FILENO)) {
@@ -1548,19 +1550,18 @@ int less_main(int argc, char **argv)
1548 bb_error_msg("missing filename"); 1550 bb_error_msg("missing filename");
1549 bb_show_usage(); 1551 bb_show_usage();
1550 } 1552 }
1551 } else 1553 } else {
1552 filename = xstrdup(files[0]); 1554 filename = xstrdup(files[0]);
1555 }
1553 1556
1554 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1555 /* 20: two tabstops + 4 */
1556 if (width < 20 || max_displayed_line < 3)
1557 return bb_cat(argv);
1558 max_displayed_line -= 2;
1559
1560 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1561 if (option_mask32 & FLAG_TILDE) 1557 if (option_mask32 & FLAG_TILDE)
1562 empty_line_marker = ""; 1558 empty_line_marker = "";
1563 1559
1560 kbd_fd = open(CURRENT_TTY, O_RDONLY);
1561 if (kbd_fd < 0)
1562 return bb_cat(argv);
1563 ndelay_on(kbd_fd);
1564
1564 tcgetattr(kbd_fd, &term_orig); 1565 tcgetattr(kbd_fd, &term_orig);
1565 term_less = term_orig; 1566 term_less = term_orig;
1566 term_less.c_lflag &= ~(ICANON | ECHO); 1567 term_less.c_lflag &= ~(ICANON | ECHO);
@@ -1569,11 +1570,37 @@ int less_main(int argc, char **argv)
1569 term_less.c_cc[VMIN] = 1; 1570 term_less.c_cc[VMIN] = 1;
1570 term_less.c_cc[VTIME] = 0; 1571 term_less.c_cc[VTIME] = 0;
1571 1572
1573 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1574 /* 20: two tabstops + 4 */
1575 if (width < 20 || max_displayed_line < 3)
1576 return bb_cat(argv);
1577 max_displayed_line -= 2;
1578
1572 /* We want to restore term_orig on exit */ 1579 /* We want to restore term_orig on exit */
1573 bb_signals(BB_FATAL_SIGS, sig_catcher); 1580 bb_signals(BB_FATAL_SIGS, sig_catcher);
1581#if ENABLE_FEATURE_LESS_WINCH
1582 signal(SIGWINCH, sigwinch_handler);
1583#endif
1574 1584
1585 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1575 reinitialize(); 1586 reinitialize();
1576 while (1) { 1587 while (1) {
1588#if ENABLE_FEATURE_LESS_WINCH
1589 if (winch_counter) {
1590 winch_counter--;
1591 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1592 /* 20: two tabstops + 4 */
1593 if (width < 20)
1594 width = 20;
1595 if (max_displayed_line < 3)
1596 max_displayed_line = 3;
1597 max_displayed_line -= 2;
1598 free(buffer);
1599 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1600 re_wrap();
1601 buffer_fill_and_print();
1602 }
1603#endif
1577 keypress = less_getch(-1); /* -1: do not position cursor */ 1604 keypress = less_getch(-1); /* -1: do not position cursor */
1578 keypress_process(keypress); 1605 keypress_process(keypress);
1579 } 1606 }
diff --git a/scripts/defconfig b/scripts/defconfig
index dc926c8e0..5a5a23fb6 100644
--- a/scripts/defconfig
+++ b/scripts/defconfig
@@ -573,7 +573,7 @@ CONFIG_LESS=y
573CONFIG_FEATURE_LESS_MAXLINES=9999999 573CONFIG_FEATURE_LESS_MAXLINES=9999999
574CONFIG_FEATURE_LESS_BRACKETS=y 574CONFIG_FEATURE_LESS_BRACKETS=y
575CONFIG_FEATURE_LESS_FLAGS=y 575CONFIG_FEATURE_LESS_FLAGS=y
576CONFIG_FEATURE_LESS_FLAGCS=y 576CONFIG_FEATURE_LESS_DASHCMD=y
577CONFIG_FEATURE_LESS_MARKS=y 577CONFIG_FEATURE_LESS_MARKS=y
578CONFIG_FEATURE_LESS_REGEXP=y 578CONFIG_FEATURE_LESS_REGEXP=y
579CONFIG_HDPARM=y 579CONFIG_HDPARM=y