On Monday 13 October 2008 06:48:22 am Rob Landley wrote:
> If you use the cursor keys in vi, it adds three characters at a time. (The
> ansi "move cursor" sequence for the direction you hit.) If you hold it down
> so it repeats, on a slow system (such as qemu's arm emulation) or one that's
> heavily loaded, you can easily have several of them queue up before VI gets
> scheduled again.
>
> A dozen times 3 characters is 36 characters. If you look at editors/vi.c
> line
> 216 you'll see that the buffer you're reading into (readbuffer) is 32
> characters. I.E. your buffer is not divisible by 3, so it'll read an even 10
> cursor lefts, plus an escape left bracket pair which isn't part of a
> recognized sequence, so is interpreted as separate characters. The escape
> drops you out of insert mode and into edit mode.
>
> Next time it reads a buffer, it starts with the last character of a cursor
> left sequence: capital D. Capital D is "delete to end of line", which it
> does.
>
> So basically, busybox vi is corrupting your data when you cursor around in a
> file on a loaded system. Wheee...
Please try this patch, and let me know whether it helps.
--
vda
diff -d -urpN busybox.1/editors/vi.c busybox.2/editors/vi.c
--- busybox.1/editors/vi.c 2008-09-28 17:02:14.000000000 +0200
+++ busybox.2/editors/vi.c 2008-10-14 11:21:44.000000000 +0200
@@ -293,6 +293,9 @@ struct globals {
last_file_modified = -1; \
} while (0)
+/* We want to have space for guard NUL: */
+#define readbuffer_size ((int)sizeof(readbuffer) - 1)
+
static int init_text_buffer(char *); // init from file or create new
static void edit_file(char *); // edit one file
@@ -2250,39 +2253,41 @@ static char readit(void) // read (maybe
// 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));
+ n = safe_read(STDIN_FILENO, readbuffer, readbuffer_size);
if (n <= 0) {
+ error:
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;
- }
- }
- chars_to_parse = n;
}
c = readbuffer[0];
+ /* elsewhere we can get very confused by NULs */
+ if (c == '\0')
+ c = ' ';
+ if (c == 27) {
+ // This is an ESC char,
+ // is this a whole Fn or cursor key sequence?
+ struct pollfd pfd[1];
+ pfd[0].fd = STDIN_FILENO;
+ pfd[0].events = POLLIN;
+ // Keep reading while there are room in buffer, and input chars
+ while (n < readbuffer_size
+ && safe_poll(pfd, 1, /*timeout:*/ 0) > 0
+ ) {
+ // Read the rest of the ESC string
+ int r = safe_read(STDIN_FILENO, readbuffer + n, readbuffer_size - n);
+ if (r < 0) // (btw, this can't be EAGAIN or EINTR)
+ goto error;
+ n += r;
+ }
+ }
+ // Prevent misdetection of ESC sequences
+ // (NB: potential store to readbuffer[readbuffer_size] is ok)
+ readbuffer[n] = '\0';
+
+ chars_to_parse = n;
if (c == 27 && n > 1) {
// Maybe cursor or function key?
const struct esc_cmds *eindex;
@@ -2294,12 +2299,12 @@ static char readit(void) // read (maybe
if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0)
continue;
c = eindex->val; // magic char value
- n = cnt + 1; // squeeze out the ESC sequence
+ n = 1 + cnt; // remove ESC + the rest of seq
goto found;
}
// defined ESC sequence not found
}
- n = 1;
+ n = 1; // remove 1 char
found:
// remove key sequence from Q
chars_to_parse -= n;
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox