Clean up editors/vi.c:readit() so it only does readahead when actually

parsing an escape sequence.  (This mitigates but doesn't fully fix the
the "cursoring around the file deletes data under qemu" bug, presumably due
to "\033[D" being treated as three separate characters.)
This commit is contained in:
Rob Landley 2008-10-14 01:42:33 +00:00
parent f886fd2bc7
commit 988dd5549b

View File

@ -210,11 +210,7 @@ struct globals {
#endif #endif
// Should be just enough to hold a key sequence, // Should be just enough to hold a key sequence,
// but CRASME mode uses it as generated command buffer too // but CRASME mode uses it as generated command buffer too
#if ENABLE_FEATURE_VI_CRASHME char readbuffer[8];
char readbuffer[128];
#else
char readbuffer[32];
#endif
#define STATUS_BUFFER_LEN 200 #define STATUS_BUFFER_LEN 200
char status_buffer[STATUS_BUFFER_LEN]; // messages to the user char status_buffer[STATUS_BUFFER_LEN]; // messages to the user
#if ENABLE_FEATURE_VI_DOT_CMD #if ENABLE_FEATURE_VI_DOT_CMD
@ -2201,18 +2197,23 @@ static char readit(void) // read (maybe cursor) key from stdin
{ {
char c; char c;
int n; int n;
struct esc_cmds {
// Known escape sequences for cursor and function keys.
static const struct esc_cmds {
const char seq[4]; const char seq[4];
char val; char val;
}; } esccmds[] = {
static const struct esc_cmds esccmds[] = {
{"OA" , VI_K_UP }, // cursor key Up {"OA" , VI_K_UP }, // cursor key Up
{"OB" , VI_K_DOWN }, // cursor key Down {"OB" , VI_K_DOWN }, // cursor key Down
{"OC" , VI_K_RIGHT }, // Cursor Key Right {"OC" , VI_K_RIGHT }, // Cursor Key Right
{"OD" , VI_K_LEFT }, // cursor key Left {"OD" , VI_K_LEFT }, // cursor key Left
{"OH" , VI_K_HOME }, // Cursor Key Home {"OH" , VI_K_HOME }, // Cursor Key Home
{"OF" , VI_K_END }, // Cursor Key End {"OF" , VI_K_END }, // Cursor Key End
{"OP" , VI_K_FUN1 }, // Function Key F1
{"OQ" , VI_K_FUN2 }, // Function Key F2
{"OR" , VI_K_FUN3 }, // Function Key F3
{"OS" , VI_K_FUN4 }, // Function Key F4
{"[A" , VI_K_UP }, // cursor key Up {"[A" , VI_K_UP }, // cursor key Up
{"[B" , VI_K_DOWN }, // cursor key Down {"[B" , VI_K_DOWN }, // cursor key Down
{"[C" , VI_K_RIGHT }, // Cursor Key Right {"[C" , VI_K_RIGHT }, // Cursor Key Right
@ -2225,10 +2226,6 @@ static char readit(void) // read (maybe cursor) key from stdin
{"[4~" , VI_K_END }, // Cursor Key End {"[4~" , VI_K_END }, // Cursor Key End
{"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up {"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up
{"[6~" , VI_K_PAGEDOWN}, // Cursor Key Page Down {"[6~" , VI_K_PAGEDOWN}, // Cursor Key Page Down
{"OP" , VI_K_FUN1 }, // Function Key F1
{"OQ" , VI_K_FUN2 }, // Function Key F2
{"OR" , VI_K_FUN3 }, // Function Key F3
{"OS" , VI_K_FUN4 }, // Function Key F4
// careful: these have no terminating NUL! // careful: these have no terminating NUL!
{"[11~", VI_K_FUN1 }, // Function Key F1 {"[11~", VI_K_FUN1 }, // Function Key F1
{"[12~", VI_K_FUN2 }, // Function Key F2 {"[12~", VI_K_FUN2 }, // Function Key F2
@ -2243,67 +2240,67 @@ static char readit(void) // read (maybe cursor) key from stdin
{"[23~", VI_K_FUN11 }, // Function Key F11 {"[23~", VI_K_FUN11 }, // Function Key F11
{"[24~", VI_K_FUN12 }, // Function Key F12 {"[24~", VI_K_FUN12 }, // Function Key F12
}; };
enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) };
fflush(stdout); fflush(stdout);
// If no data, block waiting for input.
n = chars_to_parse; n = chars_to_parse;
// get input from User - are there already input chars in Q? while (!n) {
if (n <= 0) { n = safe_read(0, readbuffer, 1);
// the Q is empty, wait for a typed char
again:
n = safe_read(STDIN_FILENO, readbuffer, sizeof(readbuffer));
if (n <= 0) { if (n <= 0) {
place_cursor(rows - 1, 0, FALSE); // go to bottom of screen place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
clear_to_eol(); // erase to end of line clear_to_eol(); // erase to end of line
cookmode(); // terminal to "cooked" cookmode(); // terminal to "cooked"
bb_error_msg_and_die("can't read user input"); bb_error_msg_and_die("can't read user input");
} }
/* elsewhere we can get very confused by NULs */ // Returning NUL from this routine would be bad.
if (readbuffer[0] == '\0') if (*readbuffer) break;
goto again;
if (readbuffer[0] == 27) {
// This is an ESC char. Is this Esc sequence?
// Could be bare Esc key. See if there are any
// more chars to read after the ESC. This would
// be a Function or Cursor Key sequence.
struct pollfd pfd[1];
pfd[0].fd = 0;
pfd[0].events = POLLIN;
// keep reading while there are input chars, and room in buffer
// for a complete ESC sequence (assuming 8 chars is enough)
while ((safe_poll(pfd, 1, 0) > 0)
&& ((size_t)n <= (sizeof(readbuffer) - 8))
) {
// read the rest of the ESC string
int r = safe_read(STDIN_FILENO, readbuffer + n, sizeof(readbuffer) - n);
if (r > 0)
n += r;
} }
}
chars_to_parse = n; // Grab character to return from buffer
} c = *readbuffer;
c = readbuffer[0]; n--;
if (c == 27 && n > 1) { if (n) memmove(readbuffer, readbuffer+1, n);
// Maybe cursor or function key?
// If it's an escape sequence, loop through known matches.
if (c == 27) {
const struct esc_cmds *eindex; const struct esc_cmds *eindex;
for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) { for (eindex = esccmds; eindex < esccmds+ARRAY_SIZE(esccmds); eindex++) {
int cnt = strnlen(eindex->seq, 4); int i=0, cnt = strnlen(eindex->seq, 4);
if (n <= cnt)
continue; // Loop through chars in this sequence.
if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0) for (;;) {
continue;
c = eindex->val; // magic char value // If we've matched this escape sequence so far but need more
n = cnt + 1; // squeeze out the ESC sequence // chars, read another as long as it wouldn't block. (Note that
goto found; // escape sequences come in as a unit, so if we would block
// it's not really an escape sequence.)
if (n <= i) {
struct pollfd pfd;
pfd.fd = 0;
pfd.events = POLLIN;
if (0 < safe_poll(&pfd, 1, 0)
&& 0 < safe_read(0, readbuffer + n, 1))
n++;
// Since the array is sorted from shortest to longest, if
// we needed more data we can't match anything later, so
// break out of both loops.
else goto loop_out;
} }
// defined ESC sequence not found if (readbuffer[i] != eindex->seq[i]) break;
if (++i == cnt) {
c = eindex->val;
n = 0;
goto loop_out;
} }
n = 1; }
found: }
// remove key sequence from Q }
chars_to_parse -= n; loop_out:
memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n);
chars_to_parse = n;
return c; return c;
} }