aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editors/vi.c13
-rw-r--r--include/libbb.h13
-rw-r--r--libbb/Config.in12
-rw-r--r--libbb/lineedit.c42
-rw-r--r--libbb/read_key.c57
-rw-r--r--miscutils/less.c14
6 files changed, 116 insertions, 35 deletions
diff --git a/editors/vi.c b/editors/vi.c
index ccc53fb58..ee5b5d98a 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -151,7 +151,6 @@ struct globals {
151 char erase_char; // the users erase character 151 char erase_char; // the users erase character
152 char last_input_char; // last char read from user 152 char last_input_char; // last char read from user
153 153
154 smalluint chars_to_parse;
155#if ENABLE_FEATURE_VI_DOT_CMD 154#if ENABLE_FEATURE_VI_DOT_CMD
156 smallint adding2q; // are we currently adding user input to q 155 smallint adding2q; // are we currently adding user input to q
157 int lmc_len; // length of last_modifying_cmd 156 int lmc_len; // length of last_modifying_cmd
@@ -235,7 +234,6 @@ struct globals {
235#define last_forward_char (G.last_forward_char ) 234#define last_forward_char (G.last_forward_char )
236#define erase_char (G.erase_char ) 235#define erase_char (G.erase_char )
237#define last_input_char (G.last_input_char ) 236#define last_input_char (G.last_input_char )
238#define chars_to_parse (G.chars_to_parse )
239#if ENABLE_FEATURE_VI_READONLY 237#if ENABLE_FEATURE_VI_READONLY
240#define readonly_mode (G.readonly_mode ) 238#define readonly_mode (G.readonly_mode )
241#else 239#else
@@ -620,7 +618,7 @@ static void edit_file(char *fn)
620 // poll to see if there is input already waiting. if we are 618 // poll to see if there is input already waiting. if we are
621 // not able to display output fast enough to keep up, skip 619 // not able to display output fast enough to keep up, skip
622 // the display update until we catch up with input. 620 // the display update until we catch up with input.
623 if (!chars_to_parse && mysleep(0) == 0) { 621 if (!readbuffer[0] && mysleep(0) == 0) {
624 // no input pending - so update output 622 // no input pending - so update output
625 refresh(FALSE); 623 refresh(FALSE);
626 show_status_line(); 624 show_status_line();
@@ -2206,7 +2204,7 @@ static int readit(void) // read (maybe cursor) key from stdin
2206 int c; 2204 int c;
2207 2205
2208 fflush(stdout); 2206 fflush(stdout);
2209 c = read_key(STDIN_FILENO, &chars_to_parse, readbuffer); 2207 c = read_key(STDIN_FILENO, readbuffer);
2210 if (c == -1) { // EOF/error 2208 if (c == -1) { // EOF/error
2211 go_bottom_and_clear_to_eol(); 2209 go_bottom_and_clear_to_eol();
2212 cookmode(); // terminal to "cooked" 2210 cookmode(); // terminal to "cooked"
@@ -3851,10 +3849,11 @@ static void crash_dummy()
3851 cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL"; 3849 cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL";
3852 3850
3853 // is there already a command running? 3851 // is there already a command running?
3854 if (chars_to_parse > 0) 3852 if (readbuffer[0] > 0)
3855 goto cd1; 3853 goto cd1;
3856 cd0: 3854 cd0:
3857 startrbi = rbi = 0; 3855 readbuffer[0] = 'X';
3856 startrbi = rbi = 1;
3858 sleeptime = 0; // how long to pause between commands 3857 sleeptime = 0; // how long to pause between commands
3859 memset(readbuffer, '\0', sizeof(readbuffer)); 3858 memset(readbuffer, '\0', sizeof(readbuffer));
3860 // generate a command by percentages 3859 // generate a command by percentages
@@ -3928,7 +3927,7 @@ static void crash_dummy()
3928 } 3927 }
3929 strcat(readbuffer, "\033"); 3928 strcat(readbuffer, "\033");
3930 } 3929 }
3931 chars_to_parse = strlen(readbuffer); 3930 readbuffer[0] = strlen(readbuffer + 1);
3932 cd1: 3931 cd1:
3933 totalcmds++; 3932 totalcmds++;
3934 if (sleeptime > 0) 3933 if (sleeptime > 0)
diff --git a/include/libbb.h b/include/libbb.h
index bae7efb00..788140d14 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -962,16 +962,23 @@ enum {
962 KEYCODE_FUN11 = -22, 962 KEYCODE_FUN11 = -22,
963 KEYCODE_FUN12 = -23, 963 KEYCODE_FUN12 = -23,
964#endif 964#endif
965 /* How long the longest ESC sequence we know? */ 965 KEYCODE_CURSOR_POS = -0x100,
966 KEYCODE_BUFFER_SIZE = 4 966 /* How long is the longest ESC sequence we know?
967 * We want it big enough to be able to contain
968 * cursor position sequence "ESC [ 9999 ; 9999 R"
969 */
970 KEYCODE_BUFFER_SIZE = 16
967}; 971};
968/* Note: fd may be in blocking or non-blocking mode, both make sense. 972/* Note: fd may be in blocking or non-blocking mode, both make sense.
969 * For one, less uses non-blocking mode. 973 * For one, less uses non-blocking mode.
970 * Only the first read syscall inside read_key may block indefinitely 974 * Only the first read syscall inside read_key may block indefinitely
971 * (unless fd is in non-blocking mode), 975 * (unless fd is in non-blocking mode),
972 * subsequent reads will time out after a few milliseconds. 976 * subsequent reads will time out after a few milliseconds.
977 * Return of -1 means EOF or error (errno == 0 on EOF).
978 * buffer[0] is used as a counter of buffered chars and must be 0
979 * on first call.
973 */ 980 */
974int read_key(int fd, smalluint *nbuffered, char *buffer) FAST_FUNC; 981int64_t read_key(int fd, char *buffer) FAST_FUNC;
975 982
976 983
977/* Networking */ 984/* Networking */
diff --git a/libbb/Config.in b/libbb/Config.in
index f5b804ff8..7ced387a9 100644
--- a/libbb/Config.in
+++ b/libbb/Config.in
@@ -102,6 +102,18 @@ config FEATURE_EDITING_FANCY_PROMPT
102 Setting this option allows for prompts to use things like \w and 102 Setting this option allows for prompts to use things like \w and
103 \$ and escape codes. 103 \$ and escape codes.
104 104
105config FEATURE_EDITING_ASK_TERMINAL
106 bool "Query cursor position from terminal"
107 default n
108 depends on FEATURE_EDITING
109 help
110 Allow usage of "ESC [ 6 n" sequence. Terminal answers back with
111 current cursor position. This information is used to make line
112 editing more robust in some cases.
113 If you are not sure whether your terminals respond to this code
114 correctly, or want to save on code size (about 300 bytes),
115 then do not turn this option on.
116
105config FEATURE_VERBOSE_CP_MESSAGE 117config FEATURE_VERBOSE_CP_MESSAGE
106 bool "Give more precise messages when copy fails (cp, mv etc)" 118 bool "Give more precise messages when copy fails (cp, mv etc)"
107 default n 119 default n
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index ccf3e0dc8..e1404fb68 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -86,8 +86,8 @@ struct lineedit_statics {
86 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ 86 volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */
87 sighandler_t previous_SIGWINCH_handler; 87 sighandler_t previous_SIGWINCH_handler;
88 88
89 unsigned cmdedit_x; /* real x terminal position */ 89 unsigned cmdedit_x; /* real x (col) terminal position */
90 unsigned cmdedit_y; /* pseudoreal y terminal position */ 90 unsigned cmdedit_y; /* pseudoreal y (row) terminal position */
91 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */ 91 unsigned cmdedit_prmt_len; /* length of prompt (without colors etc) */
92 92
93 unsigned cursor; 93 unsigned cursor;
@@ -299,6 +299,16 @@ static void input_backward(unsigned num)
299 299
300static void put_prompt(void) 300static void put_prompt(void)
301{ 301{
302#if ENABLE_FEATURE_EDITING_ASK_TERMINAL
303 /* Ask terminal where is cursor now.
304 * lineedit_read_key handles response and corrects
305 * our idea of current cursor position.
306 * Testcase: run "echo -n long_line_long_line_long_line",
307 * then type in a long, wrapping command and try to
308 * delete it using backspace key.
309 */
310 out1str("\033" "[6n");
311#endif
302 out1str(cmdedit_prompt); 312 out1str(cmdedit_prompt);
303 cursor = 0; 313 cursor = 0;
304 { 314 {
@@ -1430,18 +1440,33 @@ static void win_changed(int nsig)
1430 signal(SIGWINCH, win_changed); /* rearm ourself */ 1440 signal(SIGWINCH, win_changed); /* rearm ourself */
1431} 1441}
1432 1442
1433static int lineedit_read_key(smalluint *read_key_bufsize, char *read_key_buffer) 1443static int lineedit_read_key(char *read_key_buffer)
1434{ 1444{
1435 int ic; 1445 int64_t ic;
1436 struct pollfd pfd; 1446 struct pollfd pfd;
1447
1437 pfd.fd = STDIN_FILENO; 1448 pfd.fd = STDIN_FILENO;
1438 pfd.events = POLLIN; 1449 pfd.events = POLLIN;
1439 do { 1450 do {
1451 poll_again:
1440 /* Wait for input. Can't just call read_key, it will return 1452 /* Wait for input. Can't just call read_key, it will return
1441 * at once if stdin is in non-blocking mode. */ 1453 * at once if stdin is in non-blocking mode. */
1442 safe_poll(&pfd, 1, -1); 1454 safe_poll(&pfd, 1, -1);
1443 /* note: read_key sets errno to 0 on success: */ 1455 /* note: read_key sets errno to 0 on success: */
1444 ic = read_key(STDIN_FILENO, read_key_bufsize, read_key_buffer); 1456 ic = read_key(STDIN_FILENO, read_key_buffer);
1457 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
1458 && (int32_t)ic == KEYCODE_CURSOR_POS
1459 ) {
1460 int col = ((ic >> 32) & 0x7fff) - 1;
1461 if (col > 0) {
1462 cmdedit_x += col;
1463 while (cmdedit_x >= cmdedit_termw) {
1464 cmdedit_x -= cmdedit_termw;
1465 cmdedit_y++;
1466 }
1467 }
1468 goto poll_again;
1469 }
1445 } while (errno == EAGAIN); 1470 } while (errno == EAGAIN);
1446 return ic; 1471 return ic;
1447} 1472}
@@ -1482,7 +1507,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1482#endif 1507#endif
1483 struct termios initial_settings; 1508 struct termios initial_settings;
1484 struct termios new_settings; 1509 struct termios new_settings;
1485 smalluint read_key_bufsize;
1486 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 1510 char read_key_buffer[KEYCODE_BUFFER_SIZE];
1487 1511
1488 INIT_S(); 1512 INIT_S();
@@ -1561,7 +1585,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1561 1585
1562 while (1) { 1586 while (1) {
1563 fflush(NULL); 1587 fflush(NULL);
1564 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1588 ic = lineedit_read_key(read_key_buffer);
1565 1589
1566#if ENABLE_FEATURE_EDITING_VI 1590#if ENABLE_FEATURE_EDITING_VI
1567 newdelflag = 1; 1591 newdelflag = 1;
@@ -1738,7 +1762,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1738 sc = cursor; 1762 sc = cursor;
1739 prev_ic = ic; 1763 prev_ic = ic;
1740 1764
1741 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1765 ic = lineedit_read_key(read_key_buffer);
1742 if (errno) /* error */ 1766 if (errno) /* error */
1743 goto prepare_to_die; 1767 goto prepare_to_die;
1744 1768
@@ -1801,7 +1825,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1801 put(); 1825 put();
1802 break; 1826 break;
1803 case 'r'|VI_CMDMODE_BIT: 1827 case 'r'|VI_CMDMODE_BIT:
1804 ic = lineedit_read_key(&read_key_bufsize, read_key_buffer); 1828 ic = lineedit_read_key(read_key_buffer);
1805 if (errno) /* error */ 1829 if (errno) /* error */
1806 goto prepare_to_die; 1830 goto prepare_to_die;
1807 if (ic < ' ' || ic > 255) { 1831 if (ic < ' ' || ic > 255) {
diff --git a/libbb/read_key.c b/libbb/read_key.c
index fd100b0ec..3771045d2 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -9,7 +9,7 @@
9 */ 9 */
10#include "libbb.h" 10#include "libbb.h"
11 11
12int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer) 12int64_t FAST_FUNC read_key(int fd, char *buffer)
13{ 13{
14 struct pollfd pfd; 14 struct pollfd pfd;
15 const char *seq; 15 const char *seq;
@@ -67,9 +67,7 @@ int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
67 }; 67 };
68 68
69 errno = 0; 69 errno = 0;
70 n = 0; 70 n = (unsigned char) *buffer++;
71 if (nbuffered)
72 n = *nbuffered;
73 if (n == 0) { 71 if (n == 0) {
74 /* If no data, block waiting for input. If we read more 72 /* If no data, block waiting for input. If we read more
75 * than the minimal ESC sequence size, the "n=0" below 73 * than the minimal ESC sequence size, the "n=0" below
@@ -148,11 +146,54 @@ int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer)
148 } 146 }
149 } 147 }
150 /* We did not find matching sequence, it was a bare ESC. 148 /* We did not find matching sequence, it was a bare ESC.
151 * We possibly read and stored more input in buffer[] 149 * We possibly read and stored more input in buffer[] by now. */
152 * by now. */ 150
151 /* Try to decipher "ESC [ NNN ; NNN R" sequence */
152 if (ENABLE_FEATURE_EDITING_ASK_TERMINAL
153 && n != 0
154 && buffer[0] == '['
155 ) {
156 char *end;
157 unsigned long row, col;
158
159 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for cnt */
160 if (safe_poll(&pfd, 1, 50) == 0) {
161 /* No more data! */
162 break;
163 }
164 errno = 0;
165 if (safe_read(fd, buffer + n, 1) <= 0) {
166 /* If EAGAIN, then fd is O_NONBLOCK and poll lied:
167 * in fact, there is no data. */
168 if (errno != EAGAIN)
169 c = -1; /* otherwise it's EOF/error */
170 goto ret;
171 }
172 if (buffer[n++] == 'R')
173 goto got_R;
174 }
175 goto ret;
176 got_R:
177 if (!isdigit(buffer[1]))
178 goto ret;
179 row = strtoul(buffer + 1, &end, 10);
180 if (*end != ';' || !isdigit(end[1]))
181 goto ret;
182 col = strtoul(end + 1, &end, 10);
183 if (*end != 'R')
184 goto ret;
185 if (row < 1 || col < 1 || (row | col) > 0x7fff)
186 goto ret;
187
188 buffer[-1] = 0;
189
190 /* Pack into "1 <row15bits> <col16bits>" 32-bit sequence */
191 c = (((-1 << 15) | row) << 16) | col;
192 /* Return it in high-order word */
193 return ((int64_t) c << 32) | (uint32_t)KEYCODE_CURSOR_POS;
194 }
153 195
154 ret: 196 ret:
155 if (nbuffered) 197 buffer[-1] = n;
156 *nbuffered = n;
157 return c; 198 return c;
158} 199}
diff --git a/miscutils/less.c b/miscutils/less.c
index 702c4a891..bd855066f 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -96,7 +96,6 @@ struct globals {
96 smallint pattern_valid; 96 smallint pattern_valid;
97#endif 97#endif
98 smallint terminated; 98 smallint terminated;
99 smalluint kbd_input_size;
100 struct termios term_orig, term_less; 99 struct termios term_orig, term_less;
101 char kbd_input[KEYCODE_BUFFER_SIZE]; 100 char kbd_input[KEYCODE_BUFFER_SIZE];
102}; 101};
@@ -135,7 +134,6 @@ struct globals {
135#define terminated (G.terminated ) 134#define terminated (G.terminated )
136#define term_orig (G.term_orig ) 135#define term_orig (G.term_orig )
137#define term_less (G.term_less ) 136#define term_less (G.term_less )
138#define kbd_input_size (G.kbd_input_size )
139#define kbd_input (G.kbd_input ) 137#define kbd_input (G.kbd_input )
140#define INIT_G() do { \ 138#define INIT_G() do { \
141 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 139 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
@@ -806,7 +804,7 @@ static void reinitialize(void)
806 buffer_fill_and_print(); 804 buffer_fill_and_print();
807} 805}
808 806
809static ssize_t getch_nowait(void) 807static int getch_nowait(void)
810{ 808{
811 int rd; 809 int rd;
812 struct pollfd pfd[2]; 810 struct pollfd pfd[2];
@@ -839,7 +837,7 @@ static ssize_t getch_nowait(void)
839 move_cursor(max_displayed_line + 2, less_gets_pos + 1); 837 move_cursor(max_displayed_line + 2, less_gets_pos + 1);
840 fflush(stdout); 838 fflush(stdout);
841 839
842 if (kbd_input_size == 0) { 840 if (kbd_input[0] == 0) { /* if nothing is buffered */
843#if ENABLE_FEATURE_LESS_WINCH 841#if ENABLE_FEATURE_LESS_WINCH
844 while (1) { 842 while (1) {
845 int r; 843 int r;
@@ -856,7 +854,7 @@ static ssize_t getch_nowait(void)
856 854
857 /* We have kbd_fd in O_NONBLOCK mode, read inside read_key() 855 /* We have kbd_fd in O_NONBLOCK mode, read inside read_key()
858 * would not block even if there is no input available */ 856 * would not block even if there is no input available */
859 rd = read_key(kbd_fd, &kbd_input_size, kbd_input); 857 rd = read_key(kbd_fd, kbd_input);
860 if (rd == -1) { 858 if (rd == -1) {
861 if (errno == EAGAIN) { 859 if (errno == EAGAIN) {
862 /* No keyboard input available. Since poll() did return, 860 /* No keyboard input available. Since poll() did return,
@@ -872,9 +870,9 @@ static ssize_t getch_nowait(void)
872 return rd; 870 return rd;
873} 871}
874 872
875/* Grab a character from input without requiring the return key. If the 873/* Grab a character from input without requiring the return key.
876 * character is ASCII \033, get more characters and assign certain sequences 874 * May return KEYCODE_xxx values.
877 * special return codes. Note that this function works best with raw input. */ 875 * Note that this function works best with raw input. */
878static int less_getch(int pos) 876static int less_getch(int pos)
879{ 877{
880 int i; 878 int i;