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 busybox@busybox.net http://busybox.net/cgi-bin/mailman/listinfo/busybox