Mercurial > vim
changeset 36004:1aa3500798a3 v9.1.0685
patch 9.1.0685: too many strlen() calls in usercmd.c
Commit: https://github.com/vim/vim/commit/9e795852f31f1eab52e776bad27f8a169cb15238
Author: John Marriott <basilisk@internode.on.net>
Date: Tue Aug 20 20:57:23 2024 +0200
patch 9.1.0685: too many strlen() calls in usercmd.c
Problem: too many strlen() calls in usercmd.c
Solution: refactor code to reduce the number or strlen() calls
(John Marriott)
closes: #15516
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 20 Aug 2024 21:15:03 +0200 |
parents | 0071ce92bf67 |
children | ea33a537204f |
files | src/testdir/test_usercommands.vim src/usercmd.c src/version.c |
diffstat | 3 files changed, 306 insertions(+), 215 deletions(-) [+] |
line wrap: on
line diff
--- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -133,6 +133,10 @@ function Test_cmdmods() \ 'silent verbose aboveleft belowright botright tab topleft vertical', \ g:mods) + kee keep keepm keepma keepmar keepmarks keepa keepalt keepj keepjumps + \ keepp keeppatterns MyCmd + call assert_equal('keepalt keepjumps keepmarks keeppatterns', g:mods) + let g:mods = '' command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
--- a/src/usercmd.c +++ b/src/usercmd.c @@ -16,6 +16,7 @@ typedef struct ucmd { char_u *uc_name; // The command name + size_t uc_namelen; // The length of the command name (excluding the NUL) long_u uc_argt; // The argument type char_u *uc_rep; // The command's replacement string long uc_def; // The default value for a range/count @@ -39,94 +40,100 @@ static int ucmd_locked = 0; /* * List of names for completion for ":command" with the EXPAND_ flag. - * Must be alphabetical for completion. + * Must be alphabetical on the 'value' field for completion and because + * it is used by bsearch()! */ -static struct -{ - int expand; - char *name; -} command_complete[] = +static keyvalue_T command_complete_tab[] = { - {EXPAND_ARGLIST, "arglist"}, - {EXPAND_AUGROUP, "augroup"}, - {EXPAND_BEHAVE, "behave"}, - {EXPAND_BUFFERS, "buffer"}, - {EXPAND_COLORS, "color"}, - {EXPAND_COMMANDS, "command"}, - {EXPAND_COMPILER, "compiler"}, + KEYVALUE_ENTRY(EXPAND_ARGLIST, "arglist"), + KEYVALUE_ENTRY(EXPAND_AUGROUP, "augroup"), + KEYVALUE_ENTRY(EXPAND_BEHAVE, "behave"), +#if defined(FEAT_EVAL) + KEYVALUE_ENTRY(EXPAND_BREAKPOINT, "breakpoint"), +#endif + KEYVALUE_ENTRY(EXPAND_BUFFERS, "buffer"), + KEYVALUE_ENTRY(EXPAND_COLORS, "color"), + KEYVALUE_ENTRY(EXPAND_COMMANDS, "command"), + KEYVALUE_ENTRY(EXPAND_COMPILER, "compiler"), #if defined(FEAT_CSCOPE) - {EXPAND_CSCOPE, "cscope"}, + KEYVALUE_ENTRY(EXPAND_CSCOPE, "cscope"), #endif #if defined(FEAT_EVAL) - {EXPAND_USER_DEFINED, "custom"}, - {EXPAND_USER_LIST, "customlist"}, + KEYVALUE_ENTRY(EXPAND_USER_DEFINED, "custom"), + KEYVALUE_ENTRY(EXPAND_USER_LIST, "customlist"), #endif - {EXPAND_DIFF_BUFFERS, "diff_buffer"}, - {EXPAND_DIRECTORIES, "dir"}, - {EXPAND_ENV_VARS, "environment"}, - {EXPAND_EVENTS, "event"}, - {EXPAND_EXPRESSION, "expression"}, - {EXPAND_FILES, "file"}, - {EXPAND_FILES_IN_PATH, "file_in_path"}, - {EXPAND_FILETYPE, "filetype"}, - {EXPAND_FUNCTIONS, "function"}, - {EXPAND_HELP, "help"}, - {EXPAND_HIGHLIGHT, "highlight"}, - {EXPAND_HISTORY, "history"}, + KEYVALUE_ENTRY(EXPAND_DIFF_BUFFERS, "diff_buffer"), + KEYVALUE_ENTRY(EXPAND_DIRECTORIES, "dir"), + KEYVALUE_ENTRY(EXPAND_DIRS_IN_CDPATH, "dir_in_path"), + KEYVALUE_ENTRY(EXPAND_ENV_VARS, "environment"), + KEYVALUE_ENTRY(EXPAND_EVENTS, "event"), + KEYVALUE_ENTRY(EXPAND_EXPRESSION, "expression"), + KEYVALUE_ENTRY(EXPAND_FILES, "file"), + KEYVALUE_ENTRY(EXPAND_FILES_IN_PATH, "file_in_path"), + KEYVALUE_ENTRY(EXPAND_FILETYPE, "filetype"), + KEYVALUE_ENTRY(EXPAND_FUNCTIONS, "function"), + KEYVALUE_ENTRY(EXPAND_HELP, "help"), + KEYVALUE_ENTRY(EXPAND_HIGHLIGHT, "highlight"), + KEYVALUE_ENTRY(EXPAND_HISTORY, "history"), #if defined(FEAT_KEYMAP) - {EXPAND_KEYMAP, "keymap"}, + KEYVALUE_ENTRY(EXPAND_KEYMAP, "keymap"), #endif #if defined(HAVE_LOCALE_H) || defined(X_LOCALE) - {EXPAND_LOCALES, "locale"}, + KEYVALUE_ENTRY(EXPAND_LOCALES, "locale"), #endif - {EXPAND_MAPCLEAR, "mapclear"}, - {EXPAND_MAPPINGS, "mapping"}, - {EXPAND_MENUS, "menu"}, - {EXPAND_MESSAGES, "messages"}, - {EXPAND_OWNSYNTAX, "syntax"}, -#if defined(FEAT_PROFILE) - {EXPAND_SYNTIME, "syntime"}, + KEYVALUE_ENTRY(EXPAND_MAPCLEAR, "mapclear"), + KEYVALUE_ENTRY(EXPAND_MAPPINGS, "mapping"), + KEYVALUE_ENTRY(EXPAND_MENUS, "menu"), + KEYVALUE_ENTRY(EXPAND_MESSAGES, "messages"), + KEYVALUE_ENTRY(EXPAND_SETTINGS, "option"), + KEYVALUE_ENTRY(EXPAND_PACKADD, "packadd"), + KEYVALUE_ENTRY(EXPAND_RUNTIME, "runtime"), +#if defined(FEAT_EVAL) + KEYVALUE_ENTRY(EXPAND_SCRIPTNAMES, "scriptnames"), +#endif + KEYVALUE_ENTRY(EXPAND_SHELLCMD, "shellcmd"), +#if defined(FEAT_SIGNS) + KEYVALUE_ENTRY(EXPAND_SIGN, "sign"), #endif - {EXPAND_SETTINGS, "option"}, - {EXPAND_PACKADD, "packadd"}, - {EXPAND_RUNTIME, "runtime"}, - {EXPAND_SHELLCMD, "shellcmd"}, -#if defined(FEAT_SIGNS) - {EXPAND_SIGN, "sign"}, + KEYVALUE_ENTRY(EXPAND_OWNSYNTAX, "syntax"), +#if defined(FEAT_PROFILE) + KEYVALUE_ENTRY(EXPAND_SYNTIME, "syntime"), #endif - {EXPAND_TAGS, "tag"}, - {EXPAND_TAGS_LISTFILES, "tag_listfiles"}, - {EXPAND_USER, "user"}, - {EXPAND_USER_VARS, "var"}, -#if defined(FEAT_EVAL) - {EXPAND_BREAKPOINT, "breakpoint"}, - {EXPAND_SCRIPTNAMES, "scriptnames"}, -#endif - {EXPAND_DIRS_IN_CDPATH, "dir_in_path"}, - {0, NULL} + KEYVALUE_ENTRY(EXPAND_TAGS, "tag"), + KEYVALUE_ENTRY(EXPAND_TAGS_LISTFILES, "tag_listfiles"), + KEYVALUE_ENTRY(EXPAND_USER, "user"), + KEYVALUE_ENTRY(EXPAND_USER_VARS, "var") }; +typedef struct +{ + cmd_addr_T key; + char *fullname; + size_t fullnamelen; + char *shortname; + size_t shortnamelen; +} addrtype_T; + /* * List of names of address types. Must be alphabetical for completion. + * Must be sorted by the 'fullname' field because it is used by bsearch()! */ -static struct -{ - cmd_addr_T expand; - char *name; - char *shortname; -} addr_type_complete[] = +#define ADDRTYPE_ENTRY(k, fn, sn) \ + {(k), (fn), STRLEN_LITERAL(fn), (sn), STRLEN_LITERAL(sn)} +static addrtype_T addr_type_complete_tab[] = { - {ADDR_ARGUMENTS, "arguments", "arg"}, - {ADDR_LINES, "lines", "line"}, - {ADDR_LOADED_BUFFERS, "loaded_buffers", "load"}, - {ADDR_TABS, "tabs", "tab"}, - {ADDR_BUFFERS, "buffers", "buf"}, - {ADDR_WINDOWS, "windows", "win"}, - {ADDR_QUICKFIX, "quickfix", "qf"}, - {ADDR_OTHER, "other", "?"}, - {ADDR_NONE, NULL, NULL} + ADDRTYPE_ENTRY(ADDR_ARGUMENTS, "arguments", "arg"), + ADDRTYPE_ENTRY(ADDR_BUFFERS, "buffers", "buf"), + ADDRTYPE_ENTRY(ADDR_LINES, "lines", "line"), + ADDRTYPE_ENTRY(ADDR_LOADED_BUFFERS, "loaded_buffers", "load"), + ADDRTYPE_ENTRY(ADDR_OTHER, "other", "?"), + ADDRTYPE_ENTRY(ADDR_QUICKFIX, "quickfix", "qf"), + ADDRTYPE_ENTRY(ADDR_TABS, "tabs", "tab"), + ADDRTYPE_ENTRY(ADDR_WINDOWS, "windows", "win") }; +static int cmp_addr_type(const void *a, const void *b); + /* * Search for a user command that matches "eap->cmd". * Return cmdidx in "eap->cmdidx", flags in "eap->argt", idx in "eap->useridx". @@ -272,19 +279,16 @@ set_context_in_user_cmd(expand_T *xp, ch { xp->xp_context = EXPAND_USER_COMPLETE; xp->xp_pattern = p + 1; - return NULL; } else if (STRNICMP(arg, "nargs", p - arg) == 0) { xp->xp_context = EXPAND_USER_NARGS; xp->xp_pattern = p + 1; - return NULL; } else if (STRNICMP(arg, "addr", p - arg) == 0) { xp->xp_context = EXPAND_USER_ADDR_TYPE; xp->xp_pattern = p + 1; - return NULL; } return NULL; } @@ -417,7 +421,9 @@ get_user_command_name(int idx, int cmdid char_u * get_user_cmd_addr_type(expand_T *xp UNUSED, int idx) { - return (char_u *)addr_type_complete[idx].name; + if (idx < 0 || idx >= (int)ARRAY_LENGTH(addr_type_complete_tab)) + return NULL; + return (char_u *)addr_type_complete_tab[idx].fullname; } /* @@ -432,7 +438,7 @@ get_user_cmd_flags(expand_T *xp UNUSED, "count", "nargs", "range", "register", "keepscript" }; - if (idx >= (int)ARRAY_LENGTH(user_cmd_flags)) + if (idx < 0 || idx >= (int)ARRAY_LENGTH(user_cmd_flags)) return NULL; return (char_u *)user_cmd_flags[idx]; } @@ -445,7 +451,7 @@ get_user_cmd_nargs(expand_T *xp UNUSED, { static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"}; - if (idx >= (int)ARRAY_LENGTH(user_cmd_nargs)) + if (idx < 0 || idx >= (int)ARRAY_LENGTH(user_cmd_nargs)) return NULL; return (char_u *)user_cmd_nargs[idx]; } @@ -457,7 +463,24 @@ get_user_cmd_nargs(expand_T *xp UNUSED, char_u * get_user_cmd_complete(expand_T *xp UNUSED, int idx) { - return (char_u *)command_complete[idx].name; + if (idx < 0 || idx >= (int)ARRAY_LENGTH(command_complete_tab)) + return NULL; + return (char_u *)command_complete_tab[idx].value; +} + +/* + * Return the row in the command_complete_tab table that contains the given key. + */ + static keyvalue_T * +get_commandtype(int expand) +{ + int i; + + for (i = 0; i < (int)ARRAY_LENGTH(command_complete_tab); ++i) + if (command_complete_tab[i].key == expand) + return &command_complete_tab[i]; + + return NULL; } #ifdef FEAT_EVAL @@ -467,13 +490,11 @@ get_user_cmd_complete(expand_T *xp UNUSE char_u * cmdcomplete_type_to_str(int expand) { - int i; + keyvalue_T *kv; - for (i = 0; command_complete[i].expand != 0; i++) - if (command_complete[i].expand == expand) - return (char_u *)command_complete[i].name; + kv = get_commandtype(expand); - return NULL; + return (kv == NULL) ? NULL : (char_u *)kv->value; } /* @@ -483,18 +504,35 @@ cmdcomplete_type_to_str(int expand) int cmdcomplete_str_to_type(char_u *complete_str) { - int i; + keyvalue_T target; + keyvalue_T *entry; + static keyvalue_T *last_entry = NULL; // cached result if (STRNCMP(complete_str, "custom,", 7) == 0) return EXPAND_USER_DEFINED; if (STRNCMP(complete_str, "customlist,", 11) == 0) return EXPAND_USER_LIST; - for (i = 0; command_complete[i].expand != 0; ++i) - if (STRCMP(complete_str, command_complete[i].name) == 0) - return command_complete[i].expand; + target.key = 0; + target.value = (char *)complete_str; + target.length = 0; // not used, see cmp_keyvalue_value() - return EXPAND_NOTHING; + if (last_entry != NULL && cmp_keyvalue_value(&target, last_entry) == 0) + entry = last_entry; + else + { + entry = (keyvalue_T *)bsearch(&target, + &command_complete_tab, + ARRAY_LENGTH(command_complete_tab), + sizeof(command_complete_tab[0]), + cmp_keyvalue_value); + if (entry == NULL) + return EXPAND_NOTHING; + + last_entry = entry; + } + + return entry->key; } #endif @@ -511,6 +549,7 @@ uc_list(char_u *name, size_t name_len) int over; long a; garray_T *gap; + keyvalue_T *entry; // don't allow for adding or removing user commands here ++ucmd_locked; @@ -564,7 +603,7 @@ uc_list(char_u *name, size_t name_len) msg_putchar(' '); msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); - len = (int)STRLEN(cmd->uc_name) + 4; + len = (int)cmd->uc_namelen + 4; do { msg_putchar(' '); @@ -596,16 +635,14 @@ uc_list(char_u *name, size_t name_len) if (a & EX_COUNT) { // -count=N - sprintf((char *)IObuff + len, "%ldc", cmd->uc_def); - len += (int)STRLEN(IObuff + len); + len += vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ldc", cmd->uc_def); } else if (a & EX_DFLALL) IObuff[len++] = '%'; else if (cmd->uc_def >= 0) { // -range=N - sprintf((char *)IObuff + len, "%ld", cmd->uc_def); - len += (int)STRLEN(IObuff + len); + len += vim_snprintf((char *)IObuff + len, IOSIZE - len, "%ld", cmd->uc_def); } else IObuff[len++] = '.'; @@ -616,12 +653,12 @@ uc_list(char_u *name, size_t name_len) } while (len < 8 - over); // Address Type - for (j = 0; addr_type_complete[j].expand != ADDR_NONE; ++j) - if (addr_type_complete[j].expand != ADDR_LINES - && addr_type_complete[j].expand == cmd->uc_addr_type) + for (j = 0; j < (int)ARRAY_LENGTH(addr_type_complete_tab); ++j) + if (addr_type_complete_tab[j].key != ADDR_LINES + && addr_type_complete_tab[j].key == cmd->uc_addr_type) { - STRCPY(IObuff + len, addr_type_complete[j].shortname); - len += (int)STRLEN(IObuff + len); + STRCPY(IObuff + len, addr_type_complete_tab[j].shortname); + len += (int)addr_type_complete_tab[j].shortnamelen; break; } @@ -630,28 +667,31 @@ uc_list(char_u *name, size_t name_len) } while (len < 13 - over); // Completion - for (j = 0; command_complete[j].expand != 0; ++j) - if (command_complete[j].expand == cmd->uc_compl) - { - STRCPY(IObuff + len, command_complete[j].name); - len += (int)STRLEN(IObuff + len); + entry = get_commandtype(cmd->uc_compl); + if (entry != NULL) + { + STRCPY(IObuff + len, entry->value); + len += entry->length; #ifdef FEAT_EVAL - if (p_verbose > 0 && cmd->uc_compl_arg != NULL - && STRLEN(cmd->uc_compl_arg) < 200) + if (p_verbose > 0 && cmd->uc_compl_arg != NULL) + { + size_t uc_compl_arglen = STRLEN(cmd->uc_compl_arg); + + if (uc_compl_arglen < 200) { - IObuff[len] = ','; - STRCPY(IObuff + len + 1, cmd->uc_compl_arg); - len += (int)STRLEN(IObuff + len); + IObuff[len++] = ','; + STRCPY(IObuff + len, cmd->uc_compl_arg); + len += uc_compl_arglen; } + } #endif - break; - } + } do { IObuff[len++] = ' '; } while (len < 25 - over); - IObuff[len] = '\0'; + IObuff[len] = NUL; msg_outtrans(IObuff); msg_outtrans_special(cmd->uc_rep, FALSE, @@ -687,7 +727,7 @@ uc_fun_cmd(void) for (i = 0; fcmd[i]; ++i) IObuff[i] = fcmd[i] - 0x40; - IObuff[i] = 0; + IObuff[i] = NUL; return (char *)IObuff; } @@ -700,33 +740,52 @@ parse_addr_type_arg( int vallen, cmd_addr_T *addr_type_arg) { - int i, a, b; + addrtype_T target; + addrtype_T *entry; + static addrtype_T *last_entry; // cached result - for (i = 0; addr_type_complete[i].expand != ADDR_NONE; ++i) + target.key = 0; + target.fullname = (char *)value; + target.fullnamelen = vallen; + + if (last_entry != NULL && cmp_addr_type(&target, last_entry) == 0) + entry = last_entry; + else { - a = (int)STRLEN(addr_type_complete[i].name) == vallen; - b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0; - if (a && b) + entry = (addrtype_T *)bsearch(&target, + &addr_type_complete_tab, + ARRAY_LENGTH(addr_type_complete_tab), + sizeof(addr_type_complete_tab[0]), + cmp_addr_type); + if (entry == NULL) { - *addr_type_arg = addr_type_complete[i].expand; - break; + int i; + char_u *err = value; + + for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) + ; + err[i] = NUL; + semsg(_(e_invalid_address_type_value_str), err); + return FAIL; } + + last_entry = entry; } - if (addr_type_complete[i].expand == ADDR_NONE) - { - char_u *err = value; - - for (i = 0; err[i] != NUL && !VIM_ISWHITE(err[i]); i++) - ; - err[i] = NUL; - semsg(_(e_invalid_address_type_value_str), err); - return FAIL; - } + *addr_type_arg = entry->key; return OK; } + static int +cmp_addr_type(const void *a, const void *b) +{ + addrtype_T *at1 = (addrtype_T *)a; + addrtype_T *at2 = (addrtype_T *)b; + + return STRNCMP(at1->fullname, at2->fullname, MAX(at1->fullnamelen, at2->fullnamelen)); +} + /* * Parse a completion argument "value[vallen]". * The detected completion goes in "*complp", argument type in "*argt". @@ -748,6 +807,9 @@ parse_compl_arg( # endif int i; int valend = vallen; + keyvalue_T target; + keyvalue_T *entry; + static keyvalue_T *last_entry = NULL; // cached result // Look for any argument part - which is the part after any ',' for (i = 0; i < vallen; ++i) @@ -763,33 +825,40 @@ parse_compl_arg( } } - for (i = 0; command_complete[i].expand != 0; ++i) + target.key = 0; + target.value = (char *)value; + target.length = valend; + + if (last_entry != NULL && cmp_keyvalue_value_n(&target, last_entry) == 0) + entry = last_entry; + else { - if ((int)STRLEN(command_complete[i].name) == valend - && STRNCMP(value, command_complete[i].name, valend) == 0) + entry = (keyvalue_T *)bsearch(&target, + &command_complete_tab, + ARRAY_LENGTH(command_complete_tab), + sizeof(command_complete_tab[0]), + cmp_keyvalue_value_n); + if (entry == NULL) { - *complp = command_complete[i].expand; - if (command_complete[i].expand == EXPAND_BUFFERS) - *argt |= EX_BUFNAME; - else if (command_complete[i].expand == EXPAND_DIRECTORIES - || command_complete[i].expand == EXPAND_FILES) - *argt |= EX_XFILE; - break; + semsg(_(e_invalid_complete_value_str), value); + return FAIL; } + + last_entry = entry; } - if (command_complete[i].expand == 0) - { - semsg(_(e_invalid_complete_value_str), value); - return FAIL; - } + *complp = entry->key; + if (*complp == EXPAND_BUFFERS) + *argt |= EX_BUFNAME; + else if (*complp == EXPAND_DIRECTORIES || *complp == EXPAND_FILES) + *argt |= EX_XFILE; + if ( # if defined(FEAT_EVAL) - if (*complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST - && arg != NULL) -# else - if (arg != NULL) + *complp != EXPAND_USER_DEFINED && *complp != EXPAND_USER_LIST + && # endif + arg != NULL) { emsg(_(e_completion_argument_only_allowed_for_custom_completion)); return FAIL; @@ -806,6 +875,7 @@ parse_compl_arg( if (arg != NULL) *compl_arg = vim_strnsave(arg, arglen); # endif + return OK; } @@ -1023,16 +1093,13 @@ uc_add_command( // Search for the command in the already defined commands. for (i = 0; i < gap->ga_len; ++i) { - size_t len; - cmd = USER_CMD_GA(gap, i); - len = STRLEN(cmd->uc_name); cmp = STRNCMP(name, cmd->uc_name, name_len); if (cmp == 0) { - if (name_len < len) + if (name_len < cmd->uc_namelen) cmp = -1; - else if (name_len > len) + else if (name_len > cmd->uc_namelen) cmp = 1; } @@ -1078,6 +1145,7 @@ uc_add_command( ++gap->ga_len; cmd->uc_name = p; + cmd->uc_namelen = name_len; } cmd->uc_rep = rep_buf; @@ -1199,7 +1267,7 @@ ex_command(exarg_T *eap) p = skipwhite(end); if (!has_attr && ends_excmd2(eap->arg, p)) { - uc_list(name, end - name); + uc_list(name, name_len); } else if (!ASCII_ISUPPER(*name)) { @@ -1282,6 +1350,7 @@ uc_clear(garray_T *gap) { cmd = USER_CMD_GA(gap, i); vim_free(cmd->uc_name); + cmd->uc_namelen = 0; vim_free(cmd->uc_rep); # if defined(FEAT_EVAL) vim_free(cmd->uc_compl_arg); @@ -1439,30 +1508,31 @@ uc_split_args(char_u *arg, size_t *lenp) } } *q++ = '"'; - *q = 0; + *q = NUL; *lenp = len; return buf; } static size_t -add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods) +add_cmd_modifier(char_u *buf, size_t buflen, char *mod_str, size_t mod_strlen, int *multi_mods) { - size_t result; - - result = STRLEN(mod_str); - if (*multi_mods) - result += 1; if (buf != NULL) { if (*multi_mods) - STRCAT(buf, " "); - STRCAT(buf, mod_str); + { + STRCPY(buf + buflen, " "); // the separating space + ++buflen; + } + STRCPY(buf + buflen, mod_str); } - *multi_mods = 1; + if (*multi_mods) + ++mod_strlen; // +1 for the separating space + else + *multi_mods = 1; - return result; + return mod_strlen; } /* @@ -1472,17 +1542,17 @@ add_cmd_modifier(char_u *buf, char *mod_ size_t add_win_cmd_modifiers(char_u *buf, cmdmod_T *cmod, int *multi_mods) { - size_t result = 0; + size_t buflen = 0; // :aboveleft and :leftabove if (cmod->cmod_split & WSP_ABOVE) - result += add_cmd_modifier(buf, "aboveleft", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "aboveleft", STRLEN_LITERAL("aboveleft"), multi_mods); // :belowright and :rightbelow if (cmod->cmod_split & WSP_BELOW) - result += add_cmd_modifier(buf, "belowright", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "belowright", STRLEN_LITERAL("belowright"), multi_mods); // :botright if (cmod->cmod_split & WSP_BOT) - result += add_cmd_modifier(buf, "botright", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "botright", STRLEN_LITERAL("botright"), multi_mods); // :tab if (cmod->cmod_tab > 0) @@ -1493,27 +1563,29 @@ add_win_cmd_modifiers(char_u *buf, cmdmo { // For compatibility, don't add a tabpage number if it is the same // as the default number for :tab. - result += add_cmd_modifier(buf, "tab", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "tab", STRLEN_LITERAL("tab"), multi_mods); } else { char tab_buf[NUMBUFLEN + 3]; + size_t tab_buflen; - sprintf(tab_buf, "%dtab", tabnr); - result += add_cmd_modifier(buf, tab_buf, multi_mods); + tab_buflen = vim_snprintf(tab_buf, sizeof(tab_buf), "%dtab", tabnr); + buflen += add_cmd_modifier(buf, buflen, tab_buf, tab_buflen, multi_mods); } } // :topleft if (cmod->cmod_split & WSP_TOP) - result += add_cmd_modifier(buf, "topleft", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "topleft", STRLEN_LITERAL("topleft"), multi_mods); // :vertical if (cmod->cmod_split & WSP_VERT) - result += add_cmd_modifier(buf, "vertical", multi_mods); + buflen += add_cmd_modifier(buf, buflen, "vertical", STRLEN_LITERAL("vertical"), multi_mods); // :horizontal if (cmod->cmod_split & WSP_HOR) - result += add_cmd_modifier(buf, "horizontal", multi_mods); - return result; + buflen += add_cmd_modifier(buf, buflen, "horizontal", STRLEN_LITERAL("horizontal"), multi_mods); + + return buflen; } /* @@ -1523,78 +1595,92 @@ add_win_cmd_modifiers(char_u *buf, cmdmo size_t produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote) { - size_t result = 0; + size_t buflen = 0; int multi_mods = 0; int i; - typedef struct { - int flag; - char *name; - } mod_entry_T; - static mod_entry_T mod_entries[] = { + static keyvalue_T mod_entry_tab[] = + { #ifdef FEAT_BROWSE_CMD - {CMOD_BROWSE, "browse"}, + KEYVALUE_ENTRY(CMOD_BROWSE, "browse"), #endif #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) - {CMOD_CONFIRM, "confirm"}, + KEYVALUE_ENTRY(CMOD_CONFIRM, "confirm"), #endif - {CMOD_HIDE, "hide"}, - {CMOD_KEEPALT, "keepalt"}, - {CMOD_KEEPJUMPS, "keepjumps"}, - {CMOD_KEEPMARKS, "keepmarks"}, - {CMOD_KEEPPATTERNS, "keeppatterns"}, - {CMOD_LOCKMARKS, "lockmarks"}, - {CMOD_NOSWAPFILE, "noswapfile"}, - {CMOD_UNSILENT, "unsilent"}, - {CMOD_NOAUTOCMD, "noautocmd"}, + KEYVALUE_ENTRY(CMOD_HIDE, "hide"), + KEYVALUE_ENTRY(CMOD_KEEPALT, "keepalt"), + KEYVALUE_ENTRY(CMOD_KEEPJUMPS, "keepjumps"), + KEYVALUE_ENTRY(CMOD_KEEPMARKS, "keepmarks"), + KEYVALUE_ENTRY(CMOD_KEEPPATTERNS, "keeppatterns"), + KEYVALUE_ENTRY(CMOD_LOCKMARKS, "lockmarks"), + KEYVALUE_ENTRY(CMOD_NOSWAPFILE, "noswapfile"), + KEYVALUE_ENTRY(CMOD_UNSILENT, "unsilent"), + KEYVALUE_ENTRY(CMOD_NOAUTOCMD, "noautocmd"), #ifdef HAVE_SANDBOX - {CMOD_SANDBOX, "sandbox"}, + KEYVALUE_ENTRY(CMOD_SANDBOX, "sandbox"), #endif - {CMOD_LEGACY, "legacy"}, - {0, NULL} + KEYVALUE_ENTRY(CMOD_LEGACY, "legacy") }; - result = quote ? 2 : 0; - if (buf != NULL) + if (quote) { - if (quote) - *buf++ = '"'; - *buf = '\0'; + ++buflen; + if (buf != NULL) + { + *buf = '"'; + *(buf + buflen) = NUL; + } } + else + if (buf != NULL) + *buf = NUL; // the modifiers that are simple flags - for (i = 0; mod_entries[i].name != NULL; ++i) - if (cmod->cmod_flags & mod_entries[i].flag) - result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods); + for (i = 0; i < (int)ARRAY_LENGTH(mod_entry_tab); ++i) + if (cmod->cmod_flags & mod_entry_tab[i].key) + buflen += add_cmd_modifier(buf, buflen, mod_entry_tab[i].value, mod_entry_tab[i].length, &multi_mods); // :silent if (cmod->cmod_flags & CMOD_SILENT) - result += add_cmd_modifier(buf, - (cmod->cmod_flags & CMOD_ERRSILENT) ? "silent!" - : "silent", &multi_mods); + { + if (cmod->cmod_flags & CMOD_ERRSILENT) + buflen += add_cmd_modifier(buf, buflen, "silent!", STRLEN_LITERAL("silent!"), &multi_mods); + else + buflen += add_cmd_modifier(buf, buflen, "silent", STRLEN_LITERAL("silent"), &multi_mods); + } + // :verbose if (cmod->cmod_verbose > 0) { int verbose_value = cmod->cmod_verbose - 1; if (verbose_value == 1) - result += add_cmd_modifier(buf, "verbose", &multi_mods); + buflen += add_cmd_modifier(buf, buflen, "verbose", STRLEN_LITERAL("verbose"), &multi_mods); else { char verbose_buf[NUMBUFLEN]; + size_t verbose_buflen; - sprintf(verbose_buf, "%dverbose", verbose_value); - result += add_cmd_modifier(buf, verbose_buf, &multi_mods); + verbose_buflen = vim_snprintf(verbose_buf, sizeof(verbose_buf), "%dverbose", verbose_value); + buflen += add_cmd_modifier(buf, buflen, verbose_buf, verbose_buflen, &multi_mods); } } + // flags from cmod->cmod_split - result += add_win_cmd_modifiers(buf, cmod, &multi_mods); + buflen += add_win_cmd_modifiers((buf == NULL) ? NULL : buf + buflen, cmod, &multi_mods); - if (quote && buf != NULL) + if (quote) { - buf += result - 2; - *buf = '"'; + if (buf == NULL) + ++buflen; + else + { + *(buf + buflen) = '"'; + ++buflen; + *(buf + buflen) = NUL; + } } - return result; + + return buflen; } /* @@ -1755,15 +1841,14 @@ uc_check_code( case ct_RANGE: case ct_COUNT: { - char num_buf[20]; + char num_buf[NUMBUFLEN]; long num = (type == ct_LINE1) ? eap->line1 : (type == ct_LINE2) ? eap->line2 : (type == ct_RANGE) ? eap->addr_count : (eap->addr_count > 0) ? eap->line2 : cmd->uc_def; size_t num_len; - sprintf(num_buf, "%ld", num); - num_len = STRLEN(num_buf); + num_len = vim_snprintf(num_buf, sizeof(num_buf), "%ld", num); result = num_len; if (quote)