| To: vim-dev@vim.org |
| Subject: Patch 7.2.080 |
| Fcc: outbox |
| From: Bram Moolenaar <Bram@moolenaar.net> |
| Mime-Version: 1.0 |
| Content-Type: text/plain; charset=ISO-8859-1 |
| Content-Transfer-Encoding: 8bit |
| |
| |
| Patch 7.2.080 |
| Problem: When typing a composing character just after starting completion |
| may access memory before its allocation point. (Dominique Pelle) |
| Solution: Don't delete before the completion start column. Add extra checks |
| for the offset not being negative. |
| Files: src/edit.c |
| |
| |
| |
| |
| |
| *** 147,152 **** |
| --- 147,153 ---- |
| static int ins_compl_bs __ARGS((void)); |
| static void ins_compl_new_leader __ARGS((void)); |
| static void ins_compl_addleader __ARGS((int c)); |
| + static int ins_compl_len __ARGS((void)); |
| static void ins_compl_restart __ARGS((void)); |
| static void ins_compl_set_original_text __ARGS((char_u *str)); |
| static void ins_compl_addfrommatch __ARGS((void)); |
| |
| *** 197,203 **** |
| static void mb_replace_pop_ins __ARGS((int cc)); |
| #endif |
| static void replace_flush __ARGS((void)); |
| ! static void replace_do_bs __ARGS((void)); |
| #ifdef FEAT_CINDENT |
| static int cindent_on __ARGS((void)); |
| #endif |
| --- 198,205 ---- |
| static void mb_replace_pop_ins __ARGS((int cc)); |
| #endif |
| static void replace_flush __ARGS((void)); |
| ! static void replace_do_bs __ARGS((int limit_col)); |
| ! static int del_char_after_col __ARGS((int limit_col)); |
| #ifdef FEAT_CINDENT |
| static int cindent_on __ARGS((void)); |
| #endif |
| |
| *** 1933,1938 **** |
| --- 1935,1942 ---- |
| /* |
| * Backspace the cursor until the given column. Handles REPLACE and VREPLACE |
| * modes correctly. May also be used when not in insert mode at all. |
| + * Will attempt not to go before "col" even when there is a composing |
| + * character. |
| */ |
| void |
| backspace_until_column(col) |
| |
| *** 1942,1954 **** |
| { |
| curwin->w_cursor.col--; |
| if (State & REPLACE_FLAG) |
| ! replace_do_bs(); |
| ! else |
| ! (void)del_char(FALSE); |
| } |
| } |
| #endif |
| |
| #if defined(FEAT_INS_EXPAND) || defined(PROTO) |
| /* |
| * CTRL-X pressed in Insert mode. |
| --- 1946,1994 ---- |
| { |
| curwin->w_cursor.col--; |
| if (State & REPLACE_FLAG) |
| ! replace_do_bs(col); |
| ! else if (!del_char_after_col(col)) |
| ! break; |
| } |
| } |
| #endif |
| |
| + /* |
| + * Like del_char(), but make sure not to go before column "limit_col". |
| + * Only matters when there are composing characters. |
| + * Return TRUE when something was deleted. |
| + */ |
| + static int |
| + del_char_after_col(limit_col) |
| + int limit_col; |
| + { |
| + #ifdef FEAT_MBYTE |
| + if (enc_utf8 && limit_col >= 0) |
| + { |
| + int ecol = curwin->w_cursor.col + 1; |
| + |
| + /* Make sure the cursor is at the start of a character, but |
| + * skip forward again when going too far back because of a |
| + * composing character. */ |
| + mb_adjust_cursor(); |
| + while (curwin->w_cursor.col < limit_col) |
| + { |
| + int l = utf_ptr2len(ml_get_cursor()); |
| + |
| + if (l == 0) /* end of line */ |
| + break; |
| + curwin->w_cursor.col += l; |
| + } |
| + if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol) |
| + return FALSE; |
| + del_bytes((long)(ecol - curwin->w_cursor.col), FALSE, TRUE); |
| + } |
| + else |
| + #endif |
| + (void)del_char(FALSE); |
| + return TRUE; |
| + } |
| + |
| #if defined(FEAT_INS_EXPAND) || defined(PROTO) |
| /* |
| * CTRL-X pressed in Insert mode. |
| |
| *** 2418,2424 **** |
| { |
| had_match = (curwin->w_cursor.col > compl_col); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + curwin->w_cursor.col - compl_col); |
| ins_redraw(FALSE); |
| |
| /* When the match isn't there (to avoid matching itself) remove it |
| --- 2458,2464 ---- |
| { |
| had_match = (curwin->w_cursor.col > compl_col); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + ins_compl_len()); |
| ins_redraw(FALSE); |
| |
| /* When the match isn't there (to avoid matching itself) remove it |
| |
| *** 2470,2476 **** |
| *p = NUL; |
| had_match = (curwin->w_cursor.col > compl_col); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + curwin->w_cursor.col - compl_col); |
| ins_redraw(FALSE); |
| |
| /* When the match isn't there (to avoid matching itself) remove it |
| --- 2510,2516 ---- |
| *p = NUL; |
| had_match = (curwin->w_cursor.col > compl_col); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + ins_compl_len()); |
| ins_redraw(FALSE); |
| |
| /* When the match isn't there (to avoid matching itself) remove it |
| |
| *** 3209,3215 **** |
| { |
| ins_compl_del_pum(); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + curwin->w_cursor.col - compl_col); |
| compl_used_match = FALSE; |
| |
| if (compl_started) |
| --- 3249,3255 ---- |
| { |
| ins_compl_del_pum(); |
| ins_compl_delete(); |
| ! ins_bytes(compl_leader + ins_compl_len()); |
| compl_used_match = FALSE; |
| |
| if (compl_started) |
| |
| *** 3264,3269 **** |
| --- 3304,3323 ---- |
| } |
| |
| /* |
| + * Return the length of the completion, from the completion start column to |
| + * the cursor column. Making sure it never goes below zero. |
| + */ |
| + static int |
| + ins_compl_len() |
| + { |
| + int off = curwin->w_cursor.col - compl_col; |
| + |
| + if (off < 0) |
| + return 0; |
| + return off; |
| + } |
| + |
| + /* |
| * Append one character to the match leader. May reduce the number of |
| * matches. |
| */ |
| |
| *** 3621,3630 **** |
| { |
| ins_compl_delete(); |
| if (compl_leader != NULL) |
| ! ins_bytes(compl_leader + curwin->w_cursor.col - compl_col); |
| else if (compl_first_match != NULL) |
| ! ins_bytes(compl_orig_text |
| ! + curwin->w_cursor.col - compl_col); |
| retval = TRUE; |
| } |
| |
| --- 3675,3683 ---- |
| { |
| ins_compl_delete(); |
| if (compl_leader != NULL) |
| ! ins_bytes(compl_leader + ins_compl_len()); |
| else if (compl_first_match != NULL) |
| ! ins_bytes(compl_orig_text + ins_compl_len()); |
| retval = TRUE; |
| } |
| |
| |
| *** 4256,4262 **** |
| static void |
| ins_compl_insert() |
| { |
| ! ins_bytes(compl_shown_match->cp_str + curwin->w_cursor.col - compl_col); |
| if (compl_shown_match->cp_flags & ORIGINAL_TEXT) |
| compl_used_match = FALSE; |
| else |
| --- 4309,4315 ---- |
| static void |
| ins_compl_insert() |
| { |
| ! ins_bytes(compl_shown_match->cp_str + ins_compl_len()); |
| if (compl_shown_match->cp_flags & ORIGINAL_TEXT) |
| compl_used_match = FALSE; |
| else |
| |
| *** 4425,4431 **** |
| if (!compl_get_longest || compl_used_match) |
| ins_compl_insert(); |
| else |
| ! ins_bytes(compl_leader + curwin->w_cursor.col - compl_col); |
| } |
| else |
| compl_used_match = FALSE; |
| --- 4478,4484 ---- |
| if (!compl_get_longest || compl_used_match) |
| ins_compl_insert(); |
| else |
| ! ins_bytes(compl_leader + ins_compl_len()); |
| } |
| else |
| compl_used_match = FALSE; |
| |
| *** 7123,7131 **** |
| * cc == 0: character was inserted, delete it |
| * cc > 0: character was replaced, put cc (first byte of original char) back |
| * and check for more characters to be put back |
| */ |
| static void |
| ! replace_do_bs() |
| { |
| int cc; |
| #ifdef FEAT_VREPLACE |
| --- 7176,7187 ---- |
| * cc == 0: character was inserted, delete it |
| * cc > 0: character was replaced, put cc (first byte of original char) back |
| * and check for more characters to be put back |
| + * When "limit_col" is >= 0, don't delete before this column. Matters when |
| + * using composing characters, use del_char_after_col() instead of del_char(). |
| */ |
| static void |
| ! replace_do_bs(limit_col) |
| ! int limit_col; |
| { |
| int cc; |
| #ifdef FEAT_VREPLACE |
| |
| *** 7153,7159 **** |
| #ifdef FEAT_MBYTE |
| if (has_mbyte) |
| { |
| ! del_char(FALSE); |
| # ifdef FEAT_VREPLACE |
| if (State & VREPLACE_FLAG) |
| orig_len = (int)STRLEN(ml_get_cursor()); |
| --- 7209,7215 ---- |
| #ifdef FEAT_MBYTE |
| if (has_mbyte) |
| { |
| ! (void)del_char_after_col(limit_col); |
| # ifdef FEAT_VREPLACE |
| if (State & VREPLACE_FLAG) |
| orig_len = (int)STRLEN(ml_get_cursor()); |
| |
| *** 7203,7209 **** |
| changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); |
| } |
| else if (cc == 0) |
| ! (void)del_char(FALSE); |
| } |
| |
| #ifdef FEAT_CINDENT |
| --- 7259,7265 ---- |
| changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); |
| } |
| else if (cc == 0) |
| ! (void)del_char_after_col(limit_col); |
| } |
| |
| #ifdef FEAT_CINDENT |
| |
| *** 8239,8245 **** |
| * Replace mode */ |
| if (curwin->w_cursor.lnum != Insstart.lnum |
| || curwin->w_cursor.col >= Insstart.col) |
| ! replace_do_bs(); |
| } |
| else |
| (void)del_char(FALSE); |
| --- 8295,8301 ---- |
| * Replace mode */ |
| if (curwin->w_cursor.lnum != Insstart.lnum |
| || curwin->w_cursor.col >= Insstart.col) |
| ! replace_do_bs(-1); |
| } |
| else |
| (void)del_char(FALSE); |
| |
| *** 8556,8562 **** |
| break; |
| } |
| if (State & REPLACE_FLAG) |
| ! replace_do_bs(); |
| else |
| { |
| #ifdef FEAT_MBYTE |
| --- 8612,8618 ---- |
| break; |
| } |
| if (State & REPLACE_FLAG) |
| ! replace_do_bs(-1); |
| else |
| { |
| #ifdef FEAT_MBYTE |
| |
| |
| |
| *** 678,679 **** |
| --- 678,681 ---- |
| { /* Add new patch number below this line */ |
| + /**/ |
| + 80, |
| /**/ |
| |
| -- |
| At some point in the project somebody will start whining about the need to |
| determine the project "requirements". This involves interviewing people who |
| don't know what they want but, curiously, know exactly when they need it. |
| (Scott Adams - The Dilbert principle) |
| |
| /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ |
| /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ |
| \\\ download, build and distribute -- http://www.A-A-P.org /// |
| \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |