summaryrefslogtreecommitdiff
path: root/editors/vi.c
diff options
context:
space:
mode:
authorRob Landley2008-10-14 01:42:33 +0000
committerRob Landley2008-10-14 01:42:33 +0000
commit988dd5549bc7e6c455bd16929eff7d9566822be1 (patch)
tree2a30f76659669b2f16f54e59e6d25c355bc2d077 /editors/vi.c
parentf886fd2bc7b313d5616e88822387cc6fd6898f34 (diff)
downloadbusybox-988dd5549bc7e6c455bd16929eff7d9566822be1.zip
busybox-988dd5549bc7e6c455bd16929eff7d9566822be1.tar.gz
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.)
Diffstat (limited to 'editors/vi.c')
-rw-r--r--editors/vi.c119
1 files changed, 58 insertions, 61 deletions
diff --git a/editors/vi.c b/editors/vi.c
index 02bdbb3..6902b76 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -210,11 +210,7 @@ struct globals {
#endif
// Should be just enough to hold a key sequence,
// but CRASME mode uses it as generated command buffer too
-#if ENABLE_FEATURE_VI_CRASHME
- char readbuffer[128];
-#else
- char readbuffer[32];
-#endif
+ char readbuffer[8];
#define STATUS_BUFFER_LEN 200
char status_buffer[STATUS_BUFFER_LEN]; // messages to the user
#if ENABLE_FEATURE_VI_DOT_CMD
@@ -2201,18 +2197,23 @@ static char readit(void) // read (maybe cursor) key from stdin
{
char c;
int n;
- struct esc_cmds {
+
+ // Known escape sequences for cursor and function keys.
+ static const struct esc_cmds {
const char seq[4];
char val;
- };
-
- static const struct esc_cmds esccmds[] = {
+ } esccmds[] = {
{"OA" , VI_K_UP }, // cursor key Up
{"OB" , VI_K_DOWN }, // cursor key Down
{"OC" , VI_K_RIGHT }, // Cursor Key Right
{"OD" , VI_K_LEFT }, // cursor key Left
{"OH" , VI_K_HOME }, // Cursor Key Home
{"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
{"[B" , VI_K_DOWN }, // cursor key Down
{"[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
{"[5~" , VI_K_PAGEUP }, // Cursor Key Page Up
{"[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!
{"[11~", VI_K_FUN1 }, // Function Key F1
{"[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
{"[24~", VI_K_FUN12 }, // Function Key F12
};
- enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) };
fflush(stdout);
+
+ // If no data, block waiting for input.
n = chars_to_parse;
- // get input from User - are there already input chars in Q?
- if (n <= 0) {
- // the Q is empty, wait for a typed char
- again:
- n = safe_read(STDIN_FILENO, readbuffer, sizeof(readbuffer));
+ while (!n) {
+ n = safe_read(0, readbuffer, 1);
if (n <= 0) {
place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
clear_to_eol(); // erase to end of line
cookmode(); // terminal to "cooked"
bb_error_msg_and_die("can't read user input");
}
- /* elsewhere we can get very confused by NULs */
- if (readbuffer[0] == '\0')
- 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;
+ // Returning NUL from this routine would be bad.
+ if (*readbuffer) break;
+ }
+
+ // Grab character to return from buffer
+ c = *readbuffer;
+ n--;
+ if (n) memmove(readbuffer, readbuffer+1, n);
+
+ // If it's an escape sequence, loop through known matches.
+ if (c == 27) {
+ const struct esc_cmds *eindex;
+
+ for (eindex = esccmds; eindex < esccmds+ARRAY_SIZE(esccmds); eindex++) {
+ int i=0, cnt = strnlen(eindex->seq, 4);
+
+ // Loop through chars in this sequence.
+ for (;;) {
+
+ // If we've matched this escape sequence so far but need more
+ // chars, read another as long as it wouldn't block. (Note that
+ // 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;
+ }
+ if (readbuffer[i] != eindex->seq[i]) break;
+ if (++i == cnt) {
+ c = eindex->val;
+ n = 0;
+ goto loop_out;
+ }
}
}
- chars_to_parse = n;
}
- c = readbuffer[0];
- if (c == 27 && n > 1) {
- // Maybe cursor or function key?
- const struct esc_cmds *eindex;
+loop_out:
- for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) {
- int cnt = strnlen(eindex->seq, 4);
- if (n <= cnt)
- continue;
- if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0)
- continue;
- c = eindex->val; // magic char value
- n = cnt + 1; // squeeze out the ESC sequence
- goto found;
- }
- // defined ESC sequence not found
- }
- n = 1;
- found:
- // remove key sequence from Q
- chars_to_parse -= n;
- memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n);
+ chars_to_parse = n;
return c;
}