From: John Marriott Date: Sat, 23 Nov 2024 13:01:57 +0000 (+0100) Subject: patch 9.1.0882: too many strlen() calls in insexpand.c X-Git-Tag: v9.1.0882^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e6ea92b2c58cbfc642d7e35bd717f99aa2e1e53;p=thirdparty%2Fvim.git patch 9.1.0882: too many strlen() calls in insexpand.c Problem: too many strlen() calls in insexpand.c Solution: Refactor insexpand.c and reduce number of calls to STRLEN(), fix a warning get_next_filename_completion(), add new function ins_compl_leader_len() (John Marriott) closes: #16095 Signed-off-by: John Marriott Signed-off-by: Christian Brabandt --- diff --git a/src/insexpand.c b/src/insexpand.c index 9fe9fc5c56..6bc5075cbd 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -95,7 +95,7 @@ struct compl_S { compl_T *cp_next; compl_T *cp_prev; - char_u *cp_str; // matched text + string_T cp_str; // matched text char_u *(cp_text[CPT_COUNT]); // text for the menu #ifdef FEAT_EVAL typval_T cp_user_data; @@ -136,7 +136,7 @@ static int compl_enter_selects = FALSE; // When "compl_leader" is not NULL only matches that start with this string // are used. -static char_u *compl_leader = NULL; +static string_T compl_leader = {NULL, 0}; static int compl_get_longest = FALSE; // put longest common string // in compl_leader @@ -162,8 +162,7 @@ static int compl_started = FALSE; static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; // number of completion matches -static char_u *compl_pattern = NULL; -static size_t compl_patternlen = 0; +static string_T compl_pattern = {NULL, 0}; static int compl_direction = FORWARD; static int compl_shows_dir = FORWARD; static int compl_pending = 0; // > 1 for postponed CTRL-N @@ -173,7 +172,7 @@ static pos_T compl_startpos; static int compl_length = 0; static colnr_T compl_col = 0; // column where the text starts // that is being completed -static char_u *compl_orig_text = NULL; // text as it was before +static string_T compl_orig_text = {NULL, 0}; // text as it was before // completion started static int compl_cont_mode = 0; static expand_T compl_xp; @@ -208,7 +207,7 @@ static int ins_compl_need_restart(void); static void ins_compl_new_leader(void); static int get_compl_len(void); static void ins_compl_restart(void); -static void ins_compl_set_original_text(char_u *str); +static void ins_compl_set_original_text(char_u *str, size_t len); static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg); # if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) static void ins_compl_add_list(list_T *list); @@ -560,7 +559,7 @@ ins_compl_infercase_gettext( wca[i] = *(p++); // Rule 1: Were any chars converted to lower? - p = compl_orig_text; + p = compl_orig_text.string; for (i = 0; i < min_len; ++i) { if (has_mbyte) @@ -584,7 +583,7 @@ ins_compl_infercase_gettext( // upper case. if (!has_lower) { - p = compl_orig_text; + p = compl_orig_text.string; for (i = 0; i < min_len; ++i) { if (has_mbyte) @@ -603,7 +602,7 @@ ins_compl_infercase_gettext( } // Copy the original case of the part we typed. - p = compl_orig_text; + p = compl_orig_text.string; for (i = 0; i < min_len; ++i) { if (has_mbyte) @@ -651,7 +650,7 @@ ins_compl_infercase_gettext( } *p = NUL; STRCPY(gap.ga_data, IObuff); - gap.ga_len = (int)STRLEN(IObuff); + gap.ga_len = (int)(p - IObuff); } else if (has_mbyte) p += (*mb_char2bytes)(wca[i++], p); @@ -715,7 +714,7 @@ ins_compl_add_infercase( // Find actual length of original text. if (has_mbyte) { - p = compl_orig_text; + p = compl_orig_text.string; compl_char_len = 0; while (*p != NUL) { @@ -795,9 +794,9 @@ ins_compl_add( do { if (!match_at_original_text(match) - && STRNCMP(match->cp_str, str, len) == 0 - && ((int)STRLEN(match->cp_str) <= len - || match->cp_str[len] == NUL)) + && STRNCMP(match->cp_str.string, str, len) == 0 + && ((int)match->cp_str.length <= len + || match->cp_str.string[len] == NUL)) return NOTDONE; match = match->cp_next; } while (match != NULL && !is_first_match(match)); @@ -814,12 +813,14 @@ ins_compl_add( match->cp_number = -1; if (flags & CP_ORIGINAL_TEXT) match->cp_number = 0; - if ((match->cp_str = vim_strnsave(str, len)) == NULL) + if ((match->cp_str.string = vim_strnsave(str, len)) == NULL) { vim_free(match); return FAIL; } + match->cp_str.length = len; + // match-fname is: // - compl_curr_match->cp_fname if it is a string equal to fname. // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem. @@ -892,8 +893,8 @@ ins_compl_equal(compl_T *match, char_u *str, int len) if (match->cp_flags & CP_EQUAL) return TRUE; if (match->cp_flags & CP_ICASE) - return STRNICMP(match->cp_str, str, (size_t)len) == 0; - return STRNCMP(match->cp_str, str, (size_t)len) == 0; + return STRNICMP(match->cp_str.string, str, (size_t)len) == 0; + return STRNCMP(match->cp_str.string, str, (size_t)len) == 0; } /* @@ -906,16 +907,17 @@ ins_compl_longest_match(compl_T *match) int c1, c2; int had_match; - if (compl_leader == NULL) + if (compl_leader.string == NULL) { // First match, use it as a whole. - compl_leader = vim_strsave(match->cp_str); - if (compl_leader == NULL) + compl_leader.string = vim_strnsave(match->cp_str.string, match->cp_str.length); + if (compl_leader.string == NULL) return; + compl_leader.length = match->cp_str.length; had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(); - ins_bytes(compl_leader + get_compl_len()); + ins_bytes(compl_leader.string + get_compl_len()); ins_redraw(FALSE); // When the match isn't there (to avoid matching itself) remove it @@ -928,8 +930,8 @@ ins_compl_longest_match(compl_T *match) } // Reduce the text if this match differs from compl_leader. - p = compl_leader; - s = match->cp_str; + p = compl_leader.string; + s = match->cp_str.string; while (*p != NUL) { if (has_mbyte) @@ -961,9 +963,11 @@ ins_compl_longest_match(compl_T *match) { // Leader was shortened, need to change the inserted text. *p = NUL; + compl_leader.length = (size_t)(p - compl_leader.string); + had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(); - ins_bytes(compl_leader + get_compl_len()); + ins_bytes(compl_leader.string + get_compl_len()); ins_redraw(FALSE); // When the match isn't there (to avoid matching itself) remove it @@ -1040,7 +1044,7 @@ ins_compl_has_shown_match(void) int ins_compl_long_shown_match(void) { - return (int)STRLEN(compl_shown_match->cp_str) + return (int)compl_shown_match->cp_str.length > curwin->w_cursor.col - compl_col; } @@ -1149,7 +1153,7 @@ ins_compl_dict_alloc(compl_T *match) if (dict == NULL) return NULL; - dict_add_string(dict, "word", match->cp_str); + dict_add_string(dict, "word", match->cp_str.string); dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]); dict_add_string(dict, "menu", match->cp_text[CPT_MENU]); dict_add_string(dict, "kind", match->cp_text[CPT_KIND]); @@ -1225,7 +1229,6 @@ ins_compl_build_pum(void) int shown_match_ok = FALSE; int i; int cur = -1; - int lead_len = 0; int max_fuzzy_score = 0; unsigned int cur_cot_flags = get_cot_flags(); int compl_no_select = (cur_cot_flags & COT_NOSELECT) != 0; @@ -1234,19 +1237,17 @@ ins_compl_build_pum(void) // Need to build the popup menu list. compl_match_arraysize = 0; compl = compl_first_match; - if (compl_leader != NULL) - lead_len = (int)STRLEN(compl_leader); do { // When 'completeopt' contains "fuzzy" and leader is not NULL or empty, // set the cp_score for later comparisons. - if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) - compl->cp_score = fuzzy_match_str(compl->cp_str, compl_leader); + if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0) + compl->cp_score = fuzzy_match_str(compl->cp_str.string, compl_leader.string); if (!match_at_original_text(compl) - && (compl_leader == NULL - || ins_compl_equal(compl, compl_leader, lead_len) + && (compl_leader.string == NULL + || ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length) || (compl_fuzzy_match && compl->cp_score > 0))) ++compl_match_arraysize; compl = compl->cp_next; @@ -1264,8 +1265,8 @@ ins_compl_build_pum(void) if (match_at_original_text(compl_shown_match)) shown_match_ok = TRUE; - if (compl_leader != NULL - && STRCMP(compl_leader, compl_orig_text) == 0 + if (compl_leader.string != NULL + && STRCMP(compl_leader.string, compl_orig_text.string) == 0 && shown_match_ok == FALSE) compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; @@ -1275,8 +1276,8 @@ ins_compl_build_pum(void) do { if (!match_at_original_text(compl) - && (compl_leader == NULL - || ins_compl_equal(compl, compl_leader, lead_len) + && (compl_leader.string == NULL + || ins_compl_equal(compl, compl_leader.string, (int)compl_leader.length) || (compl_fuzzy_match && compl->cp_score > 0))) { if (!shown_match_ok && !compl_fuzzy_match) @@ -1321,7 +1322,7 @@ ins_compl_build_pum(void) // reset the current index. if (!compl_no_select && (max_fuzzy_score > 0 - || (compl_leader == NULL || lead_len == 0))) + || (compl_leader.string == NULL || compl_leader.length == 0))) { if (match_at_original_text(compl_shown_match)) compl_shown_match = shown_compl; @@ -1331,7 +1332,7 @@ ins_compl_build_pum(void) if (compl->cp_text[CPT_ABBR] != NULL) compl_match_array[i].pum_text = compl->cp_text[CPT_ABBR]; else - compl_match_array[i].pum_text = compl->cp_str; + compl_match_array[i].pum_text = compl->cp_str.string; compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND]; compl_match_array[i].pum_info = compl->cp_text[CPT_INFO]; compl_match_array[i].pum_score = compl->cp_score; @@ -1364,7 +1365,7 @@ ins_compl_build_pum(void) compl = compl->cp_next; } while (compl != NULL && !is_first_match(compl)); - if (compl_fuzzy_match && compl_leader != NULL && lead_len > 0) + if (compl_fuzzy_match && compl_leader.string != NULL && compl_leader.length > 0) { for (i = 0; i < compl_match_arraysize; i++) compl_match_array[i].pum_idx = i; @@ -1404,7 +1405,7 @@ ins_compl_show_pum(void) { // popup menu already exists, only need to find the current item. for (i = 0; i < compl_match_arraysize; ++i) - if (compl_match_array[i].pum_text == compl_shown_match->cp_str + if (compl_match_array[i].pum_text == compl_shown_match->cp_str.string || compl_match_array[i].pum_text == compl_shown_match->cp_text[CPT_ABBR]) { @@ -1453,7 +1454,16 @@ ins_compl_show_pum(void) char_u * ins_compl_leader(void) { - return compl_leader != NULL ? compl_leader : compl_orig_text; + return compl_leader.string != NULL ? compl_leader.string : compl_orig_text.string; +} + +/* + * Get current completion leader length + */ + size_t +ins_compl_leader_len(void) +{ + return compl_leader.string != NULL ? compl_leader.length : compl_orig_text.length; } /* @@ -1778,9 +1788,8 @@ ins_compl_free(void) compl_T *match; int i; - VIM_CLEAR(compl_pattern); - compl_patternlen = 0; - VIM_CLEAR(compl_leader); + VIM_CLEAR_STRING(compl_pattern); + VIM_CLEAR_STRING(compl_leader); if (compl_first_match == NULL) return; @@ -1793,7 +1802,7 @@ ins_compl_free(void) { match = compl_curr_match; compl_curr_match = compl_curr_match->cp_next; - vim_free(match->cp_str); + VIM_CLEAR_STRING(match->cp_str); // several entries may use the same fname, free it just once. if (match->cp_flags & CP_FREE_FNAME) vim_free(match->cp_fname); @@ -1818,11 +1827,10 @@ ins_compl_clear(void) compl_cont_status = 0; compl_started = FALSE; compl_matches = 0; - VIM_CLEAR(compl_pattern); - compl_patternlen = 0; - VIM_CLEAR(compl_leader); + VIM_CLEAR_STRING(compl_pattern); + VIM_CLEAR_STRING(compl_leader); edit_submode_extra = NULL; - VIM_CLEAR(compl_orig_text); + VIM_CLEAR_STRING(compl_orig_text); compl_enter_selects = FALSE; #ifdef FEAT_EVAL // clear v:completed_item @@ -1927,10 +1935,14 @@ ins_compl_bs(void) || ins_compl_need_restart()) ins_compl_restart(); - vim_free(compl_leader); - compl_leader = vim_strnsave(line + compl_col, (p - line) - compl_col); - if (compl_leader == NULL) + VIM_CLEAR_STRING(compl_leader); + compl_leader.length = (size_t)((p - line) - compl_col); + compl_leader.string = vim_strnsave(line + compl_col, compl_leader.length); + if (compl_leader.string == NULL) + { + compl_leader.length = 0; return K_BS; + } ins_compl_new_leader(); if (compl_shown_match != NULL) @@ -1963,11 +1975,11 @@ ins_compl_new_leader(void) { ins_compl_del_pum(); ins_compl_delete(); - ins_bytes(compl_leader + get_compl_len()); + ins_bytes(compl_leader.string + get_compl_len()); compl_used_match = FALSE; if (compl_started) - ins_compl_set_original_text(compl_leader); + ins_compl_set_original_text(compl_leader.string, compl_leader.length); else { #ifdef FEAT_SPELL @@ -2052,11 +2064,17 @@ ins_compl_addleader(int c) // break redo. if (!compl_opt_refresh_always) { - vim_free(compl_leader); - compl_leader = vim_strnsave(ml_get_curline() + compl_col, - curwin->w_cursor.col - compl_col); - if (compl_leader != NULL) - ins_compl_new_leader(); + VIM_CLEAR_STRING(compl_leader); + compl_leader.length = (size_t)(curwin->w_cursor.col - compl_col); + compl_leader.string = vim_strnsave(ml_get_curline() + compl_col, + compl_leader.length); + if (compl_leader.string == NULL) + { + compl_leader.length = 0; + return; + } + + ins_compl_new_leader(); } } @@ -2078,31 +2096,31 @@ ins_compl_restart(void) * Set the first match, the original text. */ static void -ins_compl_set_original_text(char_u *str) +ins_compl_set_original_text(char_u *str, size_t len) { - char_u *p; - // Replace the original text entry. // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly // be at the last item for backward completion if (match_at_original_text(compl_first_match)) // safety check { - p = vim_strsave(str); + char_u *p = vim_strnsave(str, len); if (p != NULL) { - vim_free(compl_first_match->cp_str); - compl_first_match->cp_str = p; + VIM_CLEAR_STRING(compl_first_match->cp_str); + compl_first_match->cp_str.string = p; + compl_first_match->cp_str.length = len; } } else if (compl_first_match->cp_prev != NULL && match_at_original_text(compl_first_match->cp_prev)) { - p = vim_strsave(str); - if (p != NULL) - { - vim_free(compl_first_match->cp_prev->cp_str); - compl_first_match->cp_prev->cp_str = p; - } + char_u *p = vim_strnsave(str, len); + if (p != NULL) + { + VIM_CLEAR_STRING(compl_first_match->cp_prev->cp_str); + compl_first_match->cp_prev->cp_str.string = p; + compl_first_match->cp_prev->cp_str.length = len; + } } } @@ -2116,29 +2134,33 @@ ins_compl_addfrommatch(void) char_u *p; int len = (int)curwin->w_cursor.col - (int)compl_col; int c; - compl_T *cp; - p = compl_shown_match->cp_str; - if ((int)STRLEN(p) <= len) // the match is too short + p = compl_shown_match->cp_str.string; + if ((int)compl_shown_match->cp_str.length <= len) // the match is too short { + size_t plen; + compl_T *cp; + // When still at the original match use the first entry that matches // the leader. if (!match_at_original_text(compl_shown_match)) return; p = NULL; + plen = 0; for (cp = compl_shown_match->cp_next; cp != NULL && !is_first_match(cp); cp = cp->cp_next) { - if (compl_leader == NULL - || ins_compl_equal(cp, compl_leader, - (int)STRLEN(compl_leader))) + if (compl_leader.string == NULL + || ins_compl_equal(cp, compl_leader.string, + (int)compl_leader.length)) { - p = cp->cp_str; + p = cp->cp_str.string; + plen = cp->cp_str.length; break; } } - if (p == NULL || (int)STRLEN(p) <= len) + if (p == NULL || (int)plen <= len) return; } p += len; @@ -2284,14 +2306,15 @@ set_ctrl_x_mode(int c) static int ins_compl_stop(int c, int prev_mode, int retval) { - char_u *ptr; int want_cindent; // Get here when we have finished typing a sequence of ^N and // ^P or other completion characters in CTRL-X mode. Free up // memory that was used, and make sure we can redo the insert. - if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) + if (compl_curr_match != NULL || compl_leader.string != NULL || c == Ctrl_E) { + char_u *ptr; + // If any of the original typed text has been changed, eg when // ignorecase is set, we must add back-spaces to the redo // buffer. We add as few as necessary to delete just the part @@ -2299,7 +2322,7 @@ ins_compl_stop(int c, int prev_mode, int retval) // When using the longest match, edited the match or used // CTRL-E then don't use the current match. if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) - ptr = compl_curr_match->cp_str; + ptr = compl_curr_match->cp_str.string; else ptr = NULL; ins_compl_fixRedoBufForLeader(ptr); @@ -2346,19 +2369,25 @@ ins_compl_stop(int c, int prev_mode, int retval) if (c == Ctrl_E) { char_u *p = NULL; + size_t plen = 0; ins_compl_delete(); - if (compl_leader != NULL) - p = compl_leader; + if (compl_leader.string != NULL) + { + p = compl_leader.string; + plen = compl_leader.length; + } else if (compl_first_match != NULL) - p = compl_orig_text; + { + p = compl_orig_text.string; + plen = compl_orig_text.length; + } if (p != NULL) { int compl_len = get_compl_len(); - int len = (int)STRLEN(p); - if (len > compl_len) - ins_bytes_len(p + compl_len, len - compl_len); + if ((int)plen > compl_len) + ins_bytes_len(p + compl_len, (int)(plen - compl_len)); } retval = TRUE; } @@ -2536,20 +2565,20 @@ ins_compl_prep(int c) static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg) { - int len; + int len = 0; char_u *p; char_u *ptr = ptr_arg; if (ptr == NULL) { - if (compl_leader != NULL) - ptr = compl_leader; + if (compl_leader.string != NULL) + ptr = compl_leader.string; else return; // nothing to do } - if (compl_orig_text != NULL) + if (compl_orig_text.string != NULL) { - p = compl_orig_text; + p = compl_orig_text.string; for (len = 0; p[len] != NUL && p[len] == ptr[len]; ++len) ; if (len > 0) @@ -2557,8 +2586,6 @@ ins_compl_fixRedoBufForLeader(char_u *ptr_arg) for (p += len; *p != NUL; MB_PTR_ADV(p)) AppendCharToRedobuff(K_BS); } - else - len = 0; if (ptr != NULL) AppendToRedobuffLit(ptr + len, -1); } @@ -2988,12 +3015,18 @@ set_completion(colnr_T startcol, list_T *list) compl_col = startcol; compl_length = (int)curwin->w_cursor.col - (int)startcol; // compl_pattern doesn't need to be set - compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length); + compl_orig_text.string = vim_strnsave(ml_get_curline() + compl_col, (size_t)compl_length); if (p_ic) flags |= CP_ICASE; - if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, - -1, NULL, NULL, NULL, 0, - flags | CP_FAST, FALSE, NULL) != OK) + if (compl_orig_text.string == NULL) + { + compl_orig_text.length = 0; + return; + } + compl_orig_text.length = (size_t)compl_length; + if (ins_compl_add(compl_orig_text.string, + (int)compl_orig_text.length, NULL, NULL, NULL, 0, + flags | CP_FAST, FALSE, NULL) != OK) return; ctrl_x_mode = CTRL_X_EVAL; @@ -3223,7 +3256,7 @@ get_complete_info(list_T *what_list, dict_T *retdict) ret = list_append_dict(li, di); if (ret != OK) return; - dict_add_string(di, "word", match->cp_str); + dict_add_string(di, "word", match->cp_str.string); dict_add_string(di, "abbr", match->cp_text[CPT_ABBR]); dict_add_string(di, "menu", match->cp_text[CPT_MENU]); dict_add_string(di, "kind", match->cp_text[CPT_KIND]); @@ -3470,8 +3503,8 @@ done: static void get_next_include_file_completion(int compl_type) { - find_pattern_in_path(compl_pattern, compl_direction, - (int)compl_patternlen, FALSE, FALSE, + find_pattern_in_path(compl_pattern.string, compl_direction, + (int)compl_pattern.length, FALSE, FALSE, (compl_type == CTRL_X_PATH_DEFINES && !(compl_cont_status & CONT_SOL)) ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND, @@ -3488,7 +3521,7 @@ get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f) { #ifdef FEAT_COMPL_FUNC if (thesaurus_func_complete(compl_type)) - expand_by_function(compl_type, compl_pattern); + expand_by_function(compl_type, compl_pattern.string); else #endif ins_compl_dictionaries( @@ -3496,7 +3529,7 @@ get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f) : (compl_type == CTRL_X_THESAURUS ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr) : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)), - compl_pattern, + compl_pattern.string, dict != NULL ? dict_f : 0, compl_type == CTRL_X_THESAURUS); } @@ -3513,12 +3546,12 @@ get_next_tag_completion(void) // set p_ic according to p_ic, p_scs and pat for find_tags(). save_p_ic = p_ic; - p_ic = ignorecase(compl_pattern); + p_ic = ignorecase(compl_pattern.string); // Find up to TAG_MANY matches. Avoids that an enormous number // of matches is found when compl_pattern is empty g_tag_at_cursor = TRUE; - if (find_tags(compl_pattern, &num_matches, &matches, + if (find_tags(compl_pattern.string, &num_matches, &matches, TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0), TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) @@ -3553,13 +3586,11 @@ get_next_filename_completion(void) int i; int score; char_u *leader = ins_compl_leader(); - size_t leader_len = STRLEN(leader); + size_t leader_len = ins_compl_leader_len();; int in_fuzzy = ((get_cot_flags() & COT_FUZZY) != 0 && leader_len > 0); char_u **sorted_matches; int *fuzzy_indices_data; char_u *last_sep = NULL; - size_t path_with_wildcard_len; - char_u *path_with_wildcard; #ifdef BACKSLASH_IN_FILENAME char pathsep = (curbuf->b_p_csl[0] == 's') ? @@ -3573,7 +3604,7 @@ get_next_filename_completion(void) #ifdef BACKSLASH_IN_FILENAME if (curbuf->b_p_csl[0] == 's') { - for (i = 0; i < leader_len; i++) + for (i = 0; i < (int)leader_len; i++) { if (leader[i] == '\\') leader[i] = '/'; @@ -3581,7 +3612,7 @@ get_next_filename_completion(void) } else if (curbuf->b_p_csl[0] == 'b') { - for (i = 0; i < leader_len; i++) + for (i = 0; i < (int)leader_len; i++) { if (leader[i] == '/') leader[i] = '\\'; @@ -3593,9 +3624,11 @@ get_next_filename_completion(void) { // No path separator or separator is the last character, // fuzzy match the whole leader - vim_free(compl_pattern); - compl_pattern = vim_strsave((char_u *)"*"); - compl_patternlen = STRLEN(compl_pattern); + VIM_CLEAR_STRING(compl_pattern); + compl_pattern.string = vim_strnsave((char_u *)"*", 1); + if (compl_pattern.string == NULL) + return; + compl_pattern.length = 1; } else if (*(last_sep + 1) == '\0') in_fuzzy = FALSE; @@ -3603,29 +3636,29 @@ get_next_filename_completion(void) { // Split leader into path and file parts int path_len = last_sep - leader + 1; - path_with_wildcard_len = path_len + 2; - path_with_wildcard = alloc(path_with_wildcard_len); + char_u *path_with_wildcard; + + path_with_wildcard = alloc(path_len + 2); if (path_with_wildcard != NULL) { - vim_strncpy(path_with_wildcard, leader, path_len); - vim_strcat(path_with_wildcard, (char_u *)"*", path_with_wildcard_len); - vim_free(compl_pattern); - compl_pattern = path_with_wildcard; - compl_patternlen = STRLEN(compl_pattern); + vim_snprintf((char *)path_with_wildcard, path_len + 2, "%*.*s*", path_len, path_len, leader); + VIM_CLEAR_STRING(compl_pattern); + compl_pattern.string = path_with_wildcard; + compl_pattern.length = path_len + 1; // Move leader to the file part leader = last_sep + 1; - leader_len = STRLEN(leader); + leader_len -= path_len; } } } - if (expand_wildcards(1, &compl_pattern, &num_matches, &matches, + if (expand_wildcards(1, &compl_pattern.string, &num_matches, &matches, EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) return; // May change home directory back to "~". - tilde_replace(compl_pattern, num_matches, matches); + tilde_replace(compl_pattern.string, num_matches, matches); #ifdef BACKSLASH_IN_FILENAME if (curbuf->b_p_csl[0] != NUL) { @@ -3701,8 +3734,8 @@ get_next_cmdline_completion(void) char_u **matches; int num_matches; - if (expand_cmdline(&compl_xp, compl_pattern, - (int)compl_patternlen, &num_matches, &matches) == EXPAND_OK) + if (expand_cmdline(&compl_xp, compl_pattern.string, + (int)compl_pattern.length, &num_matches, &matches) == EXPAND_OK) ins_compl_add_matches(num_matches, matches, FALSE); } @@ -3716,7 +3749,7 @@ get_next_spell_completion(linenr_T lnum UNUSED) char_u **matches; int num_matches; - num_matches = expand_spelling(lnum, compl_pattern, &matches); + num_matches = expand_spelling(lnum, compl_pattern.string, &matches); if (num_matches > 0) ins_compl_add_matches(num_matches, matches, p_ic); else @@ -3741,6 +3774,7 @@ ins_compl_get_next_word_or_line( *match_len = 0; ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, FALSE) + cur_match_pos->col; + len = (int)ml_get_buf_len(ins_buf, cur_match_pos->lnum) - cur_match_pos->col; if (ctrl_x_mode_line_or_eval()) { if (compl_status_adding()) @@ -3748,16 +3782,21 @@ ins_compl_get_next_word_or_line( if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) return NULL; ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE); + len = ml_get_buf_len(ins_buf, cur_match_pos->lnum + 1); if (!p_paste) - ptr = skipwhite(ptr); + { + char_u *tmp_ptr = ptr; + + ptr = skipwhite(tmp_ptr); + len -= (int)(ptr - tmp_ptr); + } } - len = (int)STRLEN(ptr); } else { char_u *tmp_ptr = ptr; - if (compl_status_adding() && compl_length <= (int)STRLEN(tmp_ptr)) + if (compl_status_adding() && compl_length <= len) { tmp_ptr += compl_length; // Skip if already inside a word. @@ -3866,14 +3905,14 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos) // has added a word that was at the beginning of the line if ((ctrl_x_mode_whole_line() && !in_fuzzy) || ctrl_x_mode_eval() || (compl_cont_status & CONT_SOL)) found_new_match = search_for_exact_line(st->ins_buf, - st->cur_match_pos, compl_direction, compl_pattern); + st->cur_match_pos, compl_direction, compl_pattern.string); else if (in_fuzzy) found_new_match = search_for_fuzzy_match(st->ins_buf, st->cur_match_pos, leader, compl_direction, start_pos, &len, &ptr, ctrl_x_mode_whole_line()); else found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, - NULL, compl_direction, compl_pattern, compl_patternlen, + NULL, compl_direction, compl_pattern.string, (int)compl_pattern.length, 1L, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); --msg_silent; if (!compl_started || st->set_match_pos) @@ -3981,7 +4020,7 @@ get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini) #ifdef FEAT_COMPL_FUNC case CTRL_X_FUNCTION: case CTRL_X_OMNI: - expand_by_function(type, compl_pattern); + expand_by_function(type, compl_pattern.string); break; #endif @@ -4071,7 +4110,7 @@ ins_compl_get_exp(pos_T *ini) // If complete() was called then compl_pattern has been reset. The // following won't work then, bail out. - if (compl_pattern == NULL) + if (compl_pattern.string == NULL) break; // get the next set of completion matches @@ -4137,7 +4176,7 @@ ins_compl_get_exp(pos_T *ini) ins_compl_update_shown_match(void) { while (!ins_compl_equal(compl_shown_match, - compl_leader, (int)STRLEN(compl_leader)) + compl_leader.string, (int)compl_leader.length) && compl_shown_match->cp_next != NULL && !is_first_match(compl_shown_match->cp_next)) compl_shown_match = compl_shown_match->cp_next; @@ -4146,12 +4185,12 @@ ins_compl_update_shown_match(void) // backward, find the last match. if (compl_shows_dir_backward() && !ins_compl_equal(compl_shown_match, - compl_leader, (int)STRLEN(compl_leader)) + compl_leader.string, (int)compl_leader.length) && (compl_shown_match->cp_next == NULL || is_first_match(compl_shown_match->cp_next))) { while (!ins_compl_equal(compl_shown_match, - compl_leader, (int)STRLEN(compl_leader)) + compl_leader.string, (int)compl_leader.length) && compl_shown_match->cp_prev != NULL && !is_first_match(compl_shown_match->cp_prev)) compl_shown_match = compl_shown_match->cp_prev; @@ -4196,8 +4235,8 @@ ins_compl_insert(int in_compl_func) // Make sure we don't go over the end of the string, this can happen with // illegal bytes. - if (compl_len < (int)STRLEN(compl_shown_match->cp_str)) - ins_bytes(compl_shown_match->cp_str + compl_len); + if (compl_len < (int)compl_shown_match->cp_str.length) + ins_bytes(compl_shown_match->cp_str.string + compl_len); if (match_at_original_text(compl_shown_match)) compl_used_match = FALSE; else @@ -4277,7 +4316,7 @@ find_comp_when_fuzzy(void) comp = compl_first_match; do { - if (comp->cp_score == score && (str == comp->cp_str || str == comp->cp_text[CPT_ABBR])) + if (comp->cp_score == score && (str == comp->cp_str.string || str == comp->cp_text[CPT_ABBR])) return comp; comp = comp->cp_next; } while (comp != NULL && !is_first_match(comp)); @@ -4374,9 +4413,9 @@ find_next_completion_match( found_end = FALSE; } if (!match_at_original_text(compl_shown_match) - && compl_leader != NULL + && compl_leader.string != NULL && !ins_compl_equal(compl_shown_match, - compl_leader, (int)STRLEN(compl_leader)) + compl_leader.string, (int)compl_leader.length) && !(compl_fuzzy_match && compl_shown_match->cp_score > 0)) ++todo; else @@ -4436,7 +4475,7 @@ ins_compl_next( if (compl_shown_match == NULL) return -1; - if (compl_leader != NULL + if (compl_leader.string != NULL && !match_at_original_text(compl_shown_match) && !compl_fuzzy_match) // Update "compl_shown_match" to the actually shown match @@ -4474,7 +4513,7 @@ ins_compl_next( // Insert the text of the new completion, or the compl_leader. if (compl_no_insert && !started) { - ins_bytes(compl_orig_text + get_compl_len()); + ins_bytes(compl_orig_text.string + get_compl_len()); compl_used_match = FALSE; } else if (insert_match) @@ -4482,7 +4521,7 @@ ins_compl_next( if (!compl_get_longest || compl_used_match) ins_compl_insert(in_compl_func); else - ins_bytes(compl_leader + get_compl_len()); + ins_bytes(compl_leader.string + get_compl_len()); } else compl_used_match = FALSE; @@ -4662,8 +4701,7 @@ ins_compl_use_match(int c) /* * Get the pattern, column and length for normal completion (CTRL-N CTRL-P * completion) - * Sets the global variables: compl_col, compl_length, compl_pattern and - * compl_patternlen. + * Sets the global variables: compl_col, compl_length and compl_pattern. * Uses the global variables: compl_cont_status and ctrl_x_mode */ static int @@ -4679,29 +4717,33 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) compl_length = curs_col - startcol; } if (p_ic) - compl_pattern = str_foldcase(line + compl_col, + { + compl_pattern.string = str_foldcase(line + compl_col, compl_length, NULL, 0); + if (compl_pattern.string == NULL) + { + compl_pattern.length = 0; + return FAIL; + } + compl_pattern.length = STRLEN(compl_pattern.string); + } else - compl_pattern = vim_strnsave(line + compl_col, compl_length); - if (compl_pattern == NULL) { - compl_patternlen = 0; - return FAIL; + compl_pattern.string = vim_strnsave(line + compl_col, (size_t)compl_length); + if (compl_pattern.string == NULL) + { + compl_pattern.length = 0; + return FAIL; + } + compl_pattern.length = (size_t)compl_length; } } else if (compl_status_adding()) { char_u *prefix = (char_u *)"\\<"; size_t prefixlen = STRLEN_LITERAL("\\<"); + size_t n; - // we need up to 2 extra chars for the prefix - compl_pattern = alloc(quote_meta(NULL, line + compl_col, - compl_length) + prefixlen); - if (compl_pattern == NULL) - { - compl_patternlen = 0; - return FAIL; - } if (!vim_iswordp(line + compl_col) || (compl_col > 0 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) @@ -4709,20 +4751,33 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) prefix = (char_u *)""; prefixlen = 0; } - STRCPY((char *)compl_pattern, prefix); - (void)quote_meta(compl_pattern + prefixlen, + + // we need up to 2 extra chars for the prefix + n = quote_meta(NULL, line + compl_col, compl_length) + prefixlen; + compl_pattern.string = alloc(n); + if (compl_pattern.string == NULL) + { + compl_pattern.length = 0; + return FAIL; + } + STRCPY((char *)compl_pattern.string, prefix); + (void)quote_meta(compl_pattern.string + prefixlen, line + compl_col, compl_length); + compl_pattern.length = n - 1; } else if (--startcol < 0 || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { + size_t len = STRLEN_LITERAL("\\<\\k\\k"); + // Match any word of at least two chars - compl_pattern = vim_strnsave((char_u *)"\\<\\k\\k", STRLEN_LITERAL("\\<\\k\\k")); - if (compl_pattern == NULL) + compl_pattern.string = vim_strnsave((char_u *)"\\<\\k\\k", len); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } + compl_pattern.length = len; compl_col += curs_col; compl_length = 0; } @@ -4756,32 +4811,34 @@ get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col) // Only match word with at least two chars -- webb // there's no need to call quote_meta, // alloc(7) is enough -- Acevedo - compl_pattern = alloc(7); - if (compl_pattern == NULL) + compl_pattern.string = alloc(7); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - STRCPY((char *)compl_pattern, "\\<"); - (void)quote_meta(compl_pattern + 2, line + compl_col, 1); - STRCAT((char *)compl_pattern, "\\k"); + STRCPY((char *)compl_pattern.string, "\\<"); + (void)quote_meta(compl_pattern.string + 2, line + compl_col, 1); + STRCAT((char *)compl_pattern.string, "\\k"); + compl_pattern.length = STRLEN(compl_pattern.string); } else { - compl_pattern = alloc(quote_meta(NULL, line + compl_col, - compl_length) + 2); - if (compl_pattern == NULL) + size_t n = quote_meta(NULL, line + compl_col, compl_length) + 2; + + compl_pattern.string = alloc(n); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - STRCPY((char *)compl_pattern, "\\<"); - (void)quote_meta(compl_pattern + 2, line + compl_col, + STRCPY((char *)compl_pattern.string, "\\<"); + (void)quote_meta(compl_pattern.string + 2, line + compl_col, compl_length); + compl_pattern.length = n - 1; } } - compl_patternlen = STRLEN(compl_pattern); return OK; } @@ -4798,18 +4855,27 @@ get_wholeline_compl_info(char_u *line, colnr_T curs_col) if (compl_length < 0) // cursor in indent: empty pattern compl_length = 0; if (p_ic) - compl_pattern = str_foldcase(line + compl_col, compl_length, + { + compl_pattern.string = str_foldcase(line + compl_col, compl_length, NULL, 0); + if (compl_pattern.string == NULL) + { + compl_pattern.length = 0; + return FAIL; + } + compl_pattern.length = STRLEN(compl_pattern.string); + } else - compl_pattern = vim_strnsave(line + compl_col, compl_length); - if (compl_pattern == NULL) { - compl_patternlen = 0; - return FAIL; + compl_pattern.string = vim_strnsave(line + compl_col, (size_t)compl_length); + if (compl_pattern.string == NULL) + { + compl_pattern.length = 0; + return FAIL; + } + compl_pattern.length = (size_t)compl_length; } - compl_patternlen = STRLEN(compl_pattern); - return OK; } @@ -4836,14 +4902,14 @@ get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col) compl_col += startcol; compl_length = (int)curs_col - startcol; - compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES); - if (compl_pattern == NULL) + compl_pattern.string = addstar(line + compl_col, compl_length, EXPAND_FILES); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - compl_patternlen = STRLEN(compl_pattern); + compl_pattern.length = STRLEN(compl_pattern.string); return OK; } @@ -4855,22 +4921,22 @@ get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col) static int get_cmdline_compl_info(char_u *line, colnr_T curs_col) { - compl_pattern = vim_strnsave(line, curs_col); - if (compl_pattern == NULL) + compl_pattern.string = vim_strnsave(line, curs_col); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - compl_patternlen = curs_col; - set_cmd_context(&compl_xp, compl_pattern, - (int)compl_patternlen, curs_col, FALSE); + compl_pattern.length = curs_col; + set_cmd_context(&compl_xp, compl_pattern.string, + (int)compl_pattern.length, curs_col, FALSE); if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL || compl_xp.xp_context == EXPAND_NOTHING) // No completion possible, use an empty pattern to get a // "pattern not found" message. compl_col = curs_col; else - compl_col = (int)(compl_xp.xp_pattern - compl_pattern); + compl_col = (int)(compl_xp.xp_pattern - compl_pattern.string); compl_length = curs_col - compl_col; return OK; @@ -4959,14 +5025,14 @@ get_userdefined_compl_info(colnr_T curs_col UNUSED) // it may have become invalid. line = ml_get(curwin->w_cursor.lnum); compl_length = curs_col - compl_col; - compl_pattern = vim_strnsave(line + compl_col, compl_length); - if (compl_pattern == NULL) + compl_pattern.string = vim_strnsave(line + compl_col, (size_t)compl_length); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - compl_patternlen = compl_length; + compl_pattern.length = (size_t)compl_length; ret = OK; #endif @@ -5001,14 +5067,14 @@ get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED) } // Need to obtain "line" again, it may have become invalid. line = ml_get(curwin->w_cursor.lnum); - compl_pattern = vim_strnsave(line + compl_col, compl_length); - if (compl_pattern == NULL) + compl_pattern.string = vim_strnsave(line + compl_col, (size_t)compl_length); + if (compl_pattern.string == NULL) { - compl_patternlen = 0; + compl_pattern.length = 0; return FAIL; } - compl_patternlen = compl_length; + compl_pattern.length = (size_t)compl_length; ret = OK; #endif @@ -5227,16 +5293,16 @@ ins_compl_start(void) ins_compl_fixRedoBufForLeader(NULL); // Always add completion for the original text. - vim_free(compl_orig_text); - compl_orig_text = vim_strnsave(line + compl_col, compl_length); + VIM_CLEAR_STRING(compl_orig_text); + compl_orig_text.length = (size_t)compl_length; + compl_orig_text.string = vim_strnsave(line + compl_col, (size_t)compl_length); if (p_ic) flags |= CP_ICASE; - if (compl_orig_text == NULL || ins_compl_add(compl_orig_text, - -1, NULL, NULL, NULL, 0, flags, FALSE, NULL) != OK) + if (compl_orig_text.string == NULL || ins_compl_add(compl_orig_text.string, + (int)compl_orig_text.length, NULL, NULL, NULL, 0, flags, FALSE, NULL) != OK) { - VIM_CLEAR(compl_pattern); - compl_patternlen = 0; - VIM_CLEAR(compl_orig_text); + VIM_CLEAR_STRING(compl_pattern); + VIM_CLEAR_STRING(compl_orig_text); return FAIL; } @@ -5505,7 +5571,7 @@ quote_meta(char_u *dest, char_u *src, int len) void free_insexpand_stuff(void) { - VIM_CLEAR(compl_orig_text); + VIM_CLEAR_STRING(compl_orig_text); # ifdef FEAT_EVAL free_callback(&cfu_cb); free_callback(&ofu_cb); diff --git a/src/proto/insexpand.pro b/src/proto/insexpand.pro index dbd5ef7efa..4feab85854 100644 --- a/src/proto/insexpand.pro +++ b/src/proto/insexpand.pro @@ -31,6 +31,7 @@ unsigned int get_cot_flags(void); int pum_wanted(void); void ins_compl_show_pum(void); char_u *ins_compl_leader(void); +size_t ins_compl_leader_len(void); char_u *find_word_start(char_u *ptr); char_u *find_word_end(char_u *ptr); void ins_compl_clear(void); diff --git a/src/version.c b/src/version.c index 4eea94afc3..9adbf9ba80 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 882, /**/ 881, /**/