aboutsummaryrefslogtreecommitdiff
path: root/miscutils
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-25 23:27:29 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-25 23:27:29 +0000
commit5f6aaf39cff31f5f679fe07449a9e363dd474216 (patch)
tree16dbc935b47dd2f5ebc817a7c36705566c39eb55 /miscutils
parent39b0135c59555203a568bd9fb4fc4126dbdde992 (diff)
downloadbusybox-w32-5f6aaf39cff31f5f679fe07449a9e363dd474216.tar.gz
busybox-w32-5f6aaf39cff31f5f679fe07449a9e363dd474216.tar.bz2
busybox-w32-5f6aaf39cff31f5f679fe07449a9e363dd474216.zip
less: reuse former vi's key reading code. Improve SIGWINCH handling.
function old new delta less_main 2056 2097 +41 getch_nowait 248 273 +25 read_key 310 321 +11 static.esccmds 61 69 +8 count_lines 72 74 +2 less_gets 166 142 -24 less_getch 172 43 -129 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/5 up/down: 91/-170) Total: -79 bytes text data bss dec hex filename
Diffstat (limited to 'miscutils')
-rw-r--r--miscutils/less.c137
1 files changed, 53 insertions, 84 deletions
diff --git a/miscutils/less.c b/miscutils/less.c
index f367b0ebc..d9ada619a 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -36,34 +36,9 @@
36/* The escape code to clear to end of line */ 36/* The escape code to clear to end of line */
37#define CLEAR_2_EOL "\033[K" 37#define CLEAR_2_EOL "\033[K"
38 38
39/* These are the escape sequences corresponding to special keys */
40enum { 39enum {
41 REAL_KEY_UP = 'A',
42 REAL_KEY_DOWN = 'B',
43 REAL_KEY_RIGHT = 'C',
44 REAL_KEY_LEFT = 'D',
45 REAL_PAGE_UP = '5',
46 REAL_PAGE_DOWN = '6',
47 REAL_KEY_HOME = '7', // vt100? linux vt? or what?
48 REAL_KEY_END = '8',
49 REAL_KEY_HOME_ALT = '1', // ESC [1~ (vt100? linux vt? or what?)
50 REAL_KEY_END_ALT = '4', // ESC [4~
51 REAL_KEY_HOME_XTERM = 'H',
52 REAL_KEY_END_XTERM = 'F',
53
54/* These are the special codes assigned by this program to the special keys */
55 KEY_UP = 20,
56 KEY_DOWN = 21,
57 KEY_RIGHT = 22,
58 KEY_LEFT = 23,
59 PAGE_UP = 24,
60 PAGE_DOWN = 25,
61 KEY_HOME = 26,
62 KEY_END = 27,
63
64/* Absolute max of lines eaten */ 40/* Absolute max of lines eaten */
65 MAXLINES = CONFIG_FEATURE_LESS_MAXLINES, 41 MAXLINES = CONFIG_FEATURE_LESS_MAXLINES,
66
67/* This many "after the end" lines we will show (at max) */ 42/* This many "after the end" lines we will show (at max) */
68 TILDES = 1, 43 TILDES = 1,
69}; 44};
@@ -133,6 +108,8 @@ struct globals {
133#define max_displayed_line (G.max_displayed_line) 108#define max_displayed_line (G.max_displayed_line)
134#define width (G.width ) 109#define width (G.width )
135#define winch_counter (G.winch_counter ) 110#define winch_counter (G.winch_counter )
111/* This one is 100% not cached by compiler on read access */
112#define WINCH_COUNTER (*(volatile unsigned *)&winch_counter)
136#define eof_error (G.eof_error ) 113#define eof_error (G.eof_error )
137#define readpos (G.readpos ) 114#define readpos (G.readpos )
138#define readeof (G.readeof ) 115#define readeof (G.readeof )
@@ -824,9 +801,10 @@ static void reinitialize(void)
824 buffer_fill_and_print(); 801 buffer_fill_and_print();
825} 802}
826 803
827static ssize_t getch_nowait(char* input, int sz) 804static ssize_t getch_nowait(void)
828{ 805{
829 ssize_t rd; 806 char input[KEYCODE_BUFFER_SIZE];
807 int rd;
830 struct pollfd pfd[2]; 808 struct pollfd pfd[2];
831 809
832 pfd[0].fd = STDIN_FILENO; 810 pfd[0].fd = STDIN_FILENO;
@@ -842,34 +820,39 @@ static ssize_t getch_nowait(char* input, int sz)
842 * (switch fd into O_NONBLOCK'ed mode to avoid it) 820 * (switch fd into O_NONBLOCK'ed mode to avoid it)
843 */ 821 */
844 rd = 1; 822 rd = 1;
845 if (max_fline <= cur_fline + max_displayed_line 823 /* Are we interested in stdin? */
846 && eof_error > 0 /* did NOT reach eof yet */ 824//TODO: reuse code for determining this
825 if (!(option_mask32 & FLAG_S)
826 ? !(max_fline > cur_fline + max_displayed_line)
827 : !(max_fline >= cur_fline
828 && max_lineno > LINENO(flines[cur_fline]) + max_displayed_line)
847 ) { 829 ) {
848 /* We are interested in stdin */ 830 if (eof_error > 0) /* did NOT reach eof yet */
849 rd = 0; 831 rd = 0; /* yes, we are interested in stdin */
850 } 832 }
851 /* position cursor if line input is done */ 833 /* Position cursor if line input is done */
852 if (less_gets_pos >= 0) 834 if (less_gets_pos >= 0)
853 move_cursor(max_displayed_line + 2, less_gets_pos + 1); 835 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
854 fflush(stdout); 836 fflush(stdout);
855#if ENABLE_FEATURE_LESS_WINCH 837#if ENABLE_FEATURE_LESS_WINCH
856 while (1) { 838 while (1) {
857 int r; 839 int r;
840 /* NB: SIGWINCH interrupts poll() */
858 r = poll(pfd + rd, 2 - rd, -1); 841 r = poll(pfd + rd, 2 - rd, -1);
859 if (/*r < 0 && errno == EINTR &&*/ winch_counter) { 842 if (/*r < 0 && errno == EINTR &&*/ winch_counter)
860 input[0] = '\\'; /* anything which has no defined function */ 843 return '\\'; /* anything which has no defined function */
861 return 1;
862 }
863 if (r) break; 844 if (r) break;
864 } 845 }
865#else 846#else
866 safe_poll(pfd + rd, 2 - rd, -1); 847 safe_poll(pfd + rd, 2 - rd, -1);
867#endif 848#endif
868 849
869 input[0] = '\0'; 850 /* We have kbd_fd in O_NONBLOCK mode, read inside read_key()
870 rd = safe_read(kbd_fd, input, sz); /* NB: kbd_fd is in O_NONBLOCK mode */ 851 * would not block even if there is no input available */
871 if (rd < 0 && errno == EAGAIN) { 852 rd = read_key(kbd_fd, NULL, input);
872 /* No keyboard input -> we have input on stdin! */ 853 if (rd == -1 && errno == EAGAIN) {
854 /* No keyboard input available. Since poll() did return,
855 * we should have input on stdin */
873 read_lines(); 856 read_lines();
874 buffer_fill_and_print(); 857 buffer_fill_and_print();
875 goto again; 858 goto again;
@@ -883,51 +866,29 @@ static ssize_t getch_nowait(char* input, int sz)
883 * special return codes. Note that this function works best with raw input. */ 866 * special return codes. Note that this function works best with raw input. */
884static int less_getch(int pos) 867static int less_getch(int pos)
885{ 868{
886 unsigned char input[16]; 869 int i;
887 unsigned i;
888 870
889 again: 871 again:
890 less_gets_pos = pos; 872 less_gets_pos = pos;
891 memset(input, 0, sizeof(input)); 873 i = getch_nowait();
892 getch_nowait((char *)input, sizeof(input));
893 less_gets_pos = -1; 874 less_gets_pos = -1;
894 875
895 /* Detect escape sequences (i.e. arrow keys) and handle 876 /* Discard Ctrl-something chars */
896 * them accordingly */ 877 if (i >= 0 && i < ' ' && i != 0x0d && i != 8)
897 if (input[0] == '\033' && input[1] == '[') {
898 i = input[2] - REAL_KEY_UP;
899 if (i < 4)
900 return 20 + i;
901 i = input[2] - REAL_PAGE_UP;
902 if (i < 4)
903 return 24 + i;
904 if (input[2] == REAL_KEY_HOME_XTERM)
905 return KEY_HOME;
906 if (input[2] == REAL_KEY_HOME_ALT)
907 return KEY_HOME;
908 if (input[2] == REAL_KEY_END_XTERM)
909 return KEY_END;
910 if (input[2] == REAL_KEY_END_ALT)
911 return KEY_END;
912 return 0;
913 }
914 /* Reject almost all control chars */
915 i = input[0];
916 if (i < ' ' && i != 0x0d && i != 8)
917 goto again; 878 goto again;
918 return i; 879 return i;
919} 880}
920 881
921static char* less_gets(int sz) 882static char* less_gets(int sz)
922{ 883{
923 char c; 884 int c;
924 unsigned i = 0; 885 unsigned i = 0;
925 char *result = xzalloc(1); 886 char *result = xzalloc(1);
926 887
927 while (1) { 888 while (1) {
928 c = '\0'; 889 c = '\0';
929 less_gets_pos = sz + i; 890 less_gets_pos = sz + i;
930 getch_nowait(&c, 1); 891 c = getch_nowait();
931 if (c == 0x0d) { 892 if (c == 0x0d) {
932 result[i] = '\0'; 893 result[i] = '\0';
933 less_gets_pos = -1; 894 less_gets_pos = -1;
@@ -939,7 +900,7 @@ static char* less_gets(int sz)
939 printf("\x8 \x8"); 900 printf("\x8 \x8");
940 i--; 901 i--;
941 } 902 }
942 if (c < ' ') 903 if (c < ' ') /* filters out KEYCODE_xxx too (<0) */
943 continue; 904 continue;
944 if (i >= width - sz - 1) 905 if (i >= width - sz - 1)
945 continue; /* len limit */ 906 continue; /* len limit */
@@ -1151,8 +1112,8 @@ static void number_process(int first_digit)
1151{ 1112{
1152 unsigned i; 1113 unsigned i;
1153 int num; 1114 int num;
1115 int keypress;
1154 char num_input[sizeof(int)*4]; /* more than enough */ 1116 char num_input[sizeof(int)*4]; /* more than enough */
1155 char keypress;
1156 1117
1157 num_input[0] = first_digit; 1118 num_input[0] = first_digit;
1158 1119
@@ -1163,15 +1124,14 @@ static void number_process(int first_digit)
1163 /* Receive input until a letter is given */ 1124 /* Receive input until a letter is given */
1164 i = 1; 1125 i = 1;
1165 while (i < sizeof(num_input)-1) { 1126 while (i < sizeof(num_input)-1) {
1166 num_input[i] = less_getch(i + 1); 1127 keypress = less_getch(i + 1);
1167 if (!num_input[i] || !isdigit(num_input[i])) 1128 if ((unsigned)keypress > 255 || !isdigit(num_input[i]))
1168 break; 1129 break;
1169 bb_putchar(num_input[i]); 1130 num_input[i] = keypress;
1131 bb_putchar(keypress);
1170 i++; 1132 i++;
1171 } 1133 }
1172 1134
1173 /* Take the final letter out of the digits string */
1174 keypress = num_input[i];
1175 num_input[i] = '\0'; 1135 num_input[i] = '\0';
1176 num = bb_strtou(num_input, NULL, 10); 1136 num = bb_strtou(num_input, NULL, 10);
1177 /* on format error, num == -1 */ 1137 /* on format error, num == -1 */
@@ -1182,10 +1142,10 @@ static void number_process(int first_digit)
1182 1142
1183 /* We now know the number and the letter entered, so we process them */ 1143 /* We now know the number and the letter entered, so we process them */
1184 switch (keypress) { 1144 switch (keypress) {
1185 case KEY_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015': 1145 case KEYCODE_DOWN: case 'z': case 'd': case 'e': case ' ': case '\015':
1186 buffer_down(num); 1146 buffer_down(num);
1187 break; 1147 break;
1188 case KEY_UP: case 'b': case 'w': case 'y': case 'u': 1148 case KEYCODE_UP: case 'b': case 'w': case 'y': case 'u':
1189 buffer_up(num); 1149 buffer_up(num);
1190 break; 1150 break;
1191 case 'g': case '<': case 'G': case '>': 1151 case 'g': case '<': case 'G': case '>':
@@ -1413,16 +1373,16 @@ static void match_left_bracket(char bracket)
1413static void keypress_process(int keypress) 1373static void keypress_process(int keypress)
1414{ 1374{
1415 switch (keypress) { 1375 switch (keypress) {
1416 case KEY_DOWN: case 'e': case 'j': case 0x0d: 1376 case KEYCODE_DOWN: case 'e': case 'j': case 0x0d:
1417 buffer_down(1); 1377 buffer_down(1);
1418 break; 1378 break;
1419 case KEY_UP: case 'y': case 'k': 1379 case KEYCODE_UP: case 'y': case 'k':
1420 buffer_up(1); 1380 buffer_up(1);
1421 break; 1381 break;
1422 case PAGE_DOWN: case ' ': case 'z': case 'f': 1382 case KEYCODE_PAGEDOWN: case ' ': case 'z': case 'f':
1423 buffer_down(max_displayed_line + 1); 1383 buffer_down(max_displayed_line + 1);
1424 break; 1384 break;
1425 case PAGE_UP: case 'w': case 'b': 1385 case KEYCODE_PAGEUP: case 'w': case 'b':
1426 buffer_up(max_displayed_line + 1); 1386 buffer_up(max_displayed_line + 1);
1427 break; 1387 break;
1428 case 'd': 1388 case 'd':
@@ -1431,10 +1391,10 @@ static void keypress_process(int keypress)
1431 case 'u': 1391 case 'u':
1432 buffer_up((max_displayed_line + 1) / 2); 1392 buffer_up((max_displayed_line + 1) / 2);
1433 break; 1393 break;
1434 case KEY_HOME: case 'g': case 'p': case '<': case '%': 1394 case KEYCODE_HOME: case 'g': case 'p': case '<': case '%':
1435 buffer_line(0); 1395 buffer_line(0);
1436 break; 1396 break;
1437 case KEY_END: case 'G': case '>': 1397 case KEYCODE_END: case 'G': case '>':
1438 cur_fline = MAXLINES; 1398 cur_fline = MAXLINES;
1439 read_lines(); 1399 read_lines();
1440 buffer_line(cur_fline); 1400 buffer_line(cur_fline);
@@ -1586,7 +1546,8 @@ int less_main(int argc, char **argv)
1586 reinitialize(); 1546 reinitialize();
1587 while (1) { 1547 while (1) {
1588#if ENABLE_FEATURE_LESS_WINCH 1548#if ENABLE_FEATURE_LESS_WINCH
1589 if (winch_counter) { 1549 while (WINCH_COUNTER) {
1550 again:
1590 winch_counter--; 1551 winch_counter--;
1591 get_terminal_width_height(kbd_fd, &width, &max_displayed_line); 1552 get_terminal_width_height(kbd_fd, &width, &max_displayed_line);
1592 /* 20: two tabstops + 4 */ 1553 /* 20: two tabstops + 4 */
@@ -1597,8 +1558,16 @@ int less_main(int argc, char **argv)
1597 max_displayed_line -= 2; 1558 max_displayed_line -= 2;
1598 free(buffer); 1559 free(buffer);
1599 buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); 1560 buffer = xmalloc((max_displayed_line+1) * sizeof(char *));
1561 /* Avoid re-wrap and/or redraw if we already know
1562 * we need to do it again. These ops are expensive */
1563 if (WINCH_COUNTER)
1564 goto again;
1600 re_wrap(); 1565 re_wrap();
1566 if (WINCH_COUNTER)
1567 goto again;
1601 buffer_fill_and_print(); 1568 buffer_fill_and_print();
1569 /* This took some time. Loop back and check,
1570 * were there another SIGWINCH? */
1602 } 1571 }
1603#endif 1572#endif
1604 keypress = less_getch(-1); /* -1: do not position cursor */ 1573 keypress = less_getch(-1); /* -1: do not position cursor */