# HG changeset patch # User Bram Moolenaar # Date 1328475948 -3600 # Node ID a27fac494e709a3cb78399f5dbc5d807a1dc7a46 # Parent 6a032c66c972d50f2fd1b0ae3658ec2eab333fdb updated for version 7.3.431 Problem: Fetching a key at a prompt may be confused by escape sequences. Especially when getting a prompt at a VimEnter autocommand. (Alex Efros) Solution: Properly handle escape sequences deleted by check_termcode(). diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -2282,7 +2282,8 @@ vgetorpeek(advance) typebuf.tb_off] == RM_YES)) && !timedout) { - keylen = check_termcode(max_mlen + 1, NULL, 0); + keylen = check_termcode(max_mlen + 1, + NULL, 0, NULL); /* If no termcode matched but 'pastetoggle' * matched partially it's like an incomplete key diff --git a/src/misc1.c b/src/misc1.c --- a/src/misc1.c +++ b/src/misc1.c @@ -3105,8 +3105,9 @@ ask_yesno(str, direct) int get_keystroke() { -#define CBUFLEN 151 - char_u buf[CBUFLEN]; + char_u *buf = NULL; + int buflen = 150; + int maxlen; int len = 0; int n; int save_mapped_ctrl_c = mapped_ctrl_c; @@ -3118,12 +3119,29 @@ get_keystroke() cursor_on(); out_flush(); + /* Leave some room for check_termcode() to insert a key code into (max + * 5 chars plus NUL). And fix_input_buffer() can triple the number of + * bytes. */ + maxlen = (buflen - 6 - len) / 3; + if (buf == NULL) + buf = alloc(buflen); + else if (maxlen < 10) + { + /* Need some more space. This migth happen when receiving a long + * escape sequence. */ + buflen += 100; + buf = vim_realloc(buf, buflen); + maxlen = (buflen - 6 - len) / 3; + } + if (buf == NULL) + { + do_outofmem_msg((long_u)buflen); + return ESC; /* panic! */ + } + /* First time: blocking wait. Second time: wait up to 100ms for a - * terminal code to complete. Leave some room for check_termcode() to - * insert a key code into (max 5 chars plus NUL). And - * fix_input_buffer() can triple the number of bytes. */ - n = ui_inchar(buf + len, (CBUFLEN - 6 - len) / 3, - len == 0 ? -1L : 100L, 0); + * terminal code to complete. */ + n = ui_inchar(buf + len, maxlen, len == 0 ? -1L : 100L, 0); if (n > 0) { /* Replace zero and CSI by a special key code. */ @@ -3135,7 +3153,7 @@ get_keystroke() ++waited; /* keep track of the waiting time */ /* Incomplete termcode and not timed out yet: get more characters */ - if ((n = check_termcode(1, buf, len)) < 0 + if ((n = check_termcode(1, buf, buflen, &len)) < 0 && (!p_ttimeout || waited * 100L < (p_ttm < 0 ? p_tm : p_ttm))) continue; @@ -3203,7 +3221,7 @@ get_keystroke() { if (MB_BYTE2LEN(n) > len) continue; /* more bytes to get */ - buf[len >= CBUFLEN ? CBUFLEN - 1 : len] = NUL; + buf[len >= buflen ? buflen - 1 : len] = NUL; n = (*mb_ptr2char)(buf); } #endif @@ -3213,6 +3231,7 @@ get_keystroke() #endif break; } + vim_free(buf); mapped_ctrl_c = save_mapped_ctrl_c; return n; diff --git a/src/proto/term.pro b/src/proto/term.pro --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -50,7 +50,7 @@ char_u *find_termcode __ARGS((char_u *na char_u *get_termcode __ARGS((int i)); void del_termcode __ARGS((char_u *name)); void set_mouse_topline __ARGS((win_T *wp)); -int check_termcode __ARGS((int max_offset, char_u *buf, int buflen)); +int check_termcode __ARGS((int max_offset, char_u *buf, int bufsize, int *buflen)); char_u *replace_termcodes __ARGS((char_u *from, char_u **bufp, int from_part, int do_lt, int special)); int find_term_bykeys __ARGS((char_u *src)); void show_termcodes __ARGS((void)); diff --git a/src/term.c b/src/term.c --- a/src/term.c +++ b/src/term.c @@ -3785,14 +3785,16 @@ set_mouse_topline(wp) * With a match, the match is removed, the replacement code is inserted in * typebuf.tb_buf[] and the number of characters in typebuf.tb_buf[] is * returned. - * When "buf" is not NULL, it is used instead of typebuf.tb_buf[]. "buflen" is - * then the length of the string in buf[]. + * When "buf" is not NULL, buf[bufsize] is used instead of typebuf.tb_buf[]. + * "buflen" is then the length of the string in buf[] and is updated for + * inserts and deletes. */ int -check_termcode(max_offset, buf, buflen) +check_termcode(max_offset, buf, bufsize, buflen) int max_offset; char_u *buf; - int buflen; + int bufsize; + int *buflen; { char_u *tp; char_u *p; @@ -3864,10 +3866,10 @@ check_termcode(max_offset, buf, buflen) } else { - if (offset >= buflen) + if (offset >= *buflen) break; tp = buf + offset; - len = buflen - offset; + len = *buflen - offset; } /* @@ -5002,12 +5004,18 @@ check_termcode(max_offset, buf, buflen) if (extra < 0) /* remove matched characters */ mch_memmove(buf + offset, buf + offset - extra, - (size_t)(buflen + offset + extra)); + (size_t)(*buflen + offset + extra)); else if (extra > 0) - /* insert the extra space we need */ + { + /* Insert the extra space we need. If there is insufficient + * space return -1. */ + if (*buflen + extra + new_slen >= bufsize) + return -1; mch_memmove(buf + offset + extra, buf + offset, - (size_t)(buflen - offset)); + (size_t)(*buflen - offset)); + } mch_memmove(buf + offset, string, (size_t)new_slen); + *buflen = *buflen + extra + new_slen; } return retval == 0 ? (len + extra + offset) : retval; } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -715,6 +715,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 431, +/**/ 430, /**/ 429,