diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 1356 |
1 files changed, 739 insertions, 617 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 49ce9f3144..57c2368523 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1422,13 +1422,13 @@ void ex_let(exarg_T *eap) if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL && expr[1] == '=')) { // ":let" without "=": list variables - if (*arg == '[') + if (*arg == '[') { EMSG(_(e_invarg)); - else if (!ends_excmd(*arg)) - /* ":let var1 var2" */ - arg = list_arg_vars(eap, arg, &first); - else if (!eap->skip) { - /* ":let" */ + } else if (!ends_excmd(*arg)) { + // ":let var1 var2" + arg = (char_u *)list_arg_vars(eap, (const char *)arg, &first); + } else if (!eap->skip) { + // ":let" list_glob_vars(&first); list_buf_vars(&first); list_win_vars(&first); @@ -1612,7 +1612,8 @@ static char_u *skip_var_one(char_u *arg) * List variables for hashtab "ht" with prefix "prefix". * If "empty" is TRUE also list NULL strings as empty strings. */ -static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first) +static void list_hashtable_vars(hashtab_T *ht, const char *prefix, int empty, + int *first) { hashitem_T *hi; dictitem_T *di; @@ -1621,11 +1622,12 @@ static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *f todo = (int)ht->ht_used; for (hi = ht->ht_array; todo > 0 && !got_int; ++hi) { if (!HASHITEM_EMPTY(hi)) { - --todo; + todo--; di = HI2DI(hi); if (empty || di->di_tv.v_type != VAR_STRING - || di->di_tv.vval.v_string != NULL) + || di->di_tv.vval.v_string != NULL) { list_one_var(di, prefix, first); + } } } } @@ -1635,7 +1637,7 @@ static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *f */ static void list_glob_vars(int *first) { - list_hashtable_vars(&globvarht, (char_u *)"", TRUE, first); + list_hashtable_vars(&globvarht, "", true, first); } /* @@ -1643,14 +1645,13 @@ static void list_glob_vars(int *first) */ static void list_buf_vars(int *first) { - char_u numbuf[NUMBUFLEN]; + char numbuf[NUMBUFLEN]; - list_hashtable_vars(&curbuf->b_vars->dv_hashtab, (char_u *)"b:", - TRUE, first); + list_hashtable_vars(&curbuf->b_vars->dv_hashtab, "b:", true, first); - sprintf((char *)numbuf, "%" PRId64, (int64_t)curbuf->b_changedtick); - list_one_var_a((char_u *)"b:", (char_u *)"changedtick", VAR_NUMBER, - numbuf, first); + snprintf(numbuf, sizeof(numbuf), "%d", curbuf->b_changedtick); + list_one_var_a("b:", "changedtick", sizeof("changedtick") - 1, VAR_NUMBER, + numbuf, first); } /* @@ -1658,8 +1659,7 @@ static void list_buf_vars(int *first) */ static void list_win_vars(int *first) { - list_hashtable_vars(&curwin->w_vars->dv_hashtab, - (char_u *)"w:", TRUE, first); + list_hashtable_vars(&curwin->w_vars->dv_hashtab, "w:", true, first); } /* @@ -1667,8 +1667,7 @@ static void list_win_vars(int *first) */ static void list_tab_vars(int *first) { - list_hashtable_vars(&curtab->tp_vars->dv_hashtab, - (char_u *)"t:", TRUE, first); + list_hashtable_vars(&curtab->tp_vars->dv_hashtab, "t:", true, first); } /* @@ -1676,7 +1675,7 @@ static void list_tab_vars(int *first) */ static void list_vim_vars(int *first) { - list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE, first); + list_hashtable_vars(&vimvarht, "v:", false, first); } /* @@ -1684,9 +1683,9 @@ static void list_vim_vars(int *first) */ static void list_script_vars(int *first) { - if (current_SID > 0 && current_SID <= ga_scripts.ga_len) - list_hashtable_vars(&SCRIPT_VARS(current_SID), - (char_u *)"s:", FALSE, first); + if (current_SID > 0 && current_SID <= ga_scripts.ga_len) { + list_hashtable_vars(&SCRIPT_VARS(current_SID), "s:", false, first); + } } /* @@ -1694,36 +1693,37 @@ static void list_script_vars(int *first) */ static void list_func_vars(int *first) { - if (current_funccal != NULL) - list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, - (char_u *)"l:", FALSE, first); + if (current_funccal != NULL) { + list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, "l:", false, + first); + } } /* * List variables in "arg". */ -static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) +static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first) { int error = FALSE; int len; - char_u *name; - char_u *name_start; - char_u *arg_subsc; - char_u *tofree; + const char *name; + const char *name_start; typval_T tv; while (!ends_excmd(*arg) && !got_int) { if (error || eap->skip) { - arg = find_name_end(arg, NULL, NULL, FNE_INCL_BR | FNE_CHECK_START); + arg = (const char *)find_name_end((char_u *)arg, NULL, NULL, + FNE_INCL_BR | FNE_CHECK_START); if (!ascii_iswhite(*arg) && !ends_excmd(*arg)) { emsg_severe = TRUE; EMSG(_(e_trailing)); break; } } else { - /* get_name_len() takes care of expanding curly braces */ + // get_name_len() takes care of expanding curly braces name_start = name = arg; - len = get_name_len(&arg, &tofree, TRUE, TRUE); + char *tofree; + len = get_name_len(&arg, &tofree, true, true); if (len <= 0) { /* This is mainly to keep test 49 working: when expanding * curly braces fails overrule the exception error message. */ @@ -1737,14 +1737,15 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) if (tofree != NULL) { name = tofree; } - if (get_var_tv(name, len, &tv, NULL, true, false) == FAIL) { + if (get_var_tv((const char *)name, len, &tv, NULL, true, false) + == FAIL) { error = true; } else { // handle d.key, l[idx], f(expr) - arg_subsc = arg; - if (handle_subscript(&arg, &tv, TRUE, TRUE) == FAIL) - error = TRUE; - else { + const char *const arg_subsc = arg; + if (handle_subscript(&arg, &tv, true, true) == FAIL) { + error = true; + } else { if (arg == arg_subsc && len == 2 && name[1] == ':') { switch (*name) { case 'g': list_glob_vars(first); break; @@ -1758,17 +1759,15 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) EMSG2(_("E738: Can't list variables for %s"), name); } } else { - int c; - - char_u *s = (char_u *) encode_tv2echo(&tv, NULL); - c = *arg; - *arg = NUL; - list_one_var_a((char_u *)"", - arg == arg_subsc ? name : name_start, - tv.v_type, - s == NULL ? (char_u *)"" : s, - first); - *arg = c; + char *const s = encode_tv2echo(&tv, NULL); + const char *const used_name = (arg == arg_subsc + ? name + : name_start); + const ptrdiff_t name_size = (used_name == tofree + ? (ptrdiff_t)strlen(used_name) + : (arg - used_name)); + list_one_var_a("", used_name, name_size, + tv.v_type, s == NULL ? "" : s, first); xfree(s); } clear_tv(&tv); @@ -1779,7 +1778,7 @@ static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first) xfree(tofree); } - arg = skipwhite(arg); + arg = (const char *)skipwhite((const char_u *)arg); } return arg; @@ -1799,9 +1798,7 @@ ex_let_one ( char_u *op /* "+", "-", "." or NULL*/ ) { - int c1; char_u *name; - char_u *p; char_u *arg_end = NULL; int len; int opt_flags; @@ -1815,18 +1812,18 @@ ex_let_one ( ++arg; name = arg; len = get_env_len(&arg); - if (len == 0) + if (len == 0) { EMSG2(_(e_invarg2), name - 1); - else { - if (op != NULL && (*op == '+' || *op == '-')) + } else { + if (op != NULL && (*op == '+' || *op == '-')) { EMSG2(_(e_letwrong), op); - else if (endchars != NULL - && vim_strchr(endchars, *skipwhite(arg)) == NULL) + } else if (endchars != NULL + && vim_strchr(endchars, *skipwhite(arg)) == NULL) { EMSG(_(e_letunexp)); - else if (!check_secure()) { - c1 = name[len]; + } else if (!check_secure()) { + const char_u c1 = name[len]; name[len] = NUL; - p = get_tv_string_chk(tv); + char_u *p = get_tv_string_chk(tv); if (p != NULL && op != NULL && *op == '.') { char *s = vim_getenv((char *)name); @@ -1850,43 +1847,41 @@ ex_let_one ( xfree(tofree); } } - } - /* - * ":let &option = expr": Set option value. - * ":let &l:option = expr": Set local option value. - * ":let &g:option = expr": Set global option value. - */ - else if (*arg == '&') { - /* Find the end of the name. */ - p = find_option_end(&arg, &opt_flags); - if (p == NULL || (endchars != NULL - && vim_strchr(endchars, *skipwhite(p)) == NULL)) + // ":let &option = expr": Set option value. + // ":let &l:option = expr": Set local option value. + // ":let &g:option = expr": Set global option value. + } else if (*arg == '&') { + // Find the end of the name. + char *const p = (char *)find_option_end((const char **)&arg, &opt_flags); + if (p == NULL + || (endchars != NULL + && vim_strchr(endchars, *skipwhite((const char_u *)p)) == NULL)) { EMSG(_(e_letunexp)); - else { + } else { long n; int opt_type; long numval; - char_u *stringval = NULL; - char_u *s; + char_u *stringval = NULL; + char_u *s; - c1 = *p; + const char c1 = *p; *p = NUL; n = get_tv_number(tv); s = get_tv_string_chk(tv); /* != NULL if number or string */ if (s != NULL && op != NULL && *op != '=') { - opt_type = get_option_value(arg, &numval, - &stringval, opt_flags); + opt_type = get_option_value(arg, &numval, &stringval, opt_flags); if ((opt_type == 1 && *op == '.') - || (opt_type == 0 && *op != '.')) + || (opt_type == 0 && *op != '.')) { EMSG2(_(e_letwrong), op); - else { - if (opt_type == 1) { /* number */ - if (*op == '+') + } else { + if (opt_type == 1) { // number + if (*op == '+') { n = numval + n; - else + } else { n = numval - n; - } else if (opt_type == 0 && stringval != NULL) { /* string */ + } + } else if (opt_type == 0 && stringval != NULL) { // string s = concat_str(stringval, s); xfree(stringval); stringval = s; @@ -1895,7 +1890,7 @@ ex_let_one ( } if (s != NULL) { set_option_value(arg, n, s, opt_flags); - arg_end = p; + arg_end = (char_u *)p; } *p = c1; xfree(stringval); @@ -1915,7 +1910,7 @@ ex_let_one ( char_u *ptofree = NULL; char_u *s; - p = get_tv_string_chk(tv); + char_u *p = get_tv_string_chk(tv); if (p != NULL && op != NULL && *op == '.') { s = get_reg_contents(*arg == '@' ? '"' : *arg, kGRegExprSrc); if (s != NULL) { @@ -1937,7 +1932,7 @@ ex_let_one ( else if (eval_isnamec1(*arg) || *arg == '{') { lval_T lv; - p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); + char_u *const p = get_lval(arg, tv, &lv, false, false, 0, FNE_CHECK_START); if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(p)) == NULL) EMSG(_(e_letunexp)); @@ -2047,9 +2042,11 @@ get_lval ( cc = *p; *p = NUL; - v = find_var(lp->ll_name, &ht, flags & GLV_NO_AUTOLOAD); - if (v == NULL && !quiet) + v = find_var((const char *)lp->ll_name, STRLEN(lp->ll_name), &ht, + flags & GLV_NO_AUTOLOAD); + if (v == NULL && !quiet) { EMSG2(_(e_undefvar), lp->ll_name); + } *p = cc; if (v == NULL) return NULL; @@ -2309,7 +2306,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, ch // handle +=, -= and .= di = NULL; - if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), + if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name), &tv, &di, true, false) == OK) { if ((di == NULL || (!var_check_ro(di->di_flags, lp->ll_name, false) @@ -2785,7 +2782,7 @@ void ex_call(exarg_T *eap) // contents. For VAR_PARTIAL get its partial, unless we already have one // from trans_function_name(). len = (int)STRLEN(tofree); - name = deref_func_name(tofree, &len, + name = deref_func_name((const char *)tofree, &len, partial != NULL ? NULL : &partial, false); /* Skip white space to allow ":call func ()". Not good, but required for @@ -2823,9 +2820,10 @@ void ex_call(exarg_T *eap) break; } - /* Handle a function returning a Funcref, Dictionary or List. */ - if (handle_subscript(&arg, &rettv, !eap->skip, TRUE) == FAIL) { - failed = TRUE; + // Handle a function returning a Funcref, Dictionary or List. + if (handle_subscript((const char **)&arg, &rettv, !eap->skip, true) + == FAIL) { + failed = true; break; } @@ -3014,7 +3012,8 @@ int do_unlet(char_u *name, int forceit) dict_T *d; dictitem_T *di; dict_T *dict; - ht = find_var_ht_dict(name, &varname, &dict); + ht = find_var_ht_dict((const char *)name, STRLEN(name), + (const char **)&varname, &dict); if (ht != NULL && *varname != NUL) { if (ht == &globvarht) { @@ -3025,7 +3024,7 @@ int do_unlet(char_u *name, int forceit) } else if (ht == &compat_hashtab) { d = &vimvardict; } else { - di = find_var_in_ht(ht, *name, (char_u *)"", false); + di = find_var_in_ht(ht, *name, "", 0, false); d = di->di_tv.vval.v_dict; } if (d == NULL) { @@ -3034,7 +3033,7 @@ int do_unlet(char_u *name, int forceit) } hi = hash_find(ht, varname); if (HASHITEM_EMPTY(hi)) { - hi = find_hi_in_scoped_ht(name, &ht); + hi = find_hi_in_scoped_ht((const char *)name, &ht); } if (hi != NULL && !HASHITEM_EMPTY(hi)) { di = HI2DI(hi); @@ -3088,18 +3087,19 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock) cc = *name_end; *name_end = NUL; - /* Normal name or expanded name. */ - if (check_changedtick(lp->ll_name)) + // Normal name or expanded name. + if (check_changedtick(lp->ll_name)) { ret = FAIL; - else { - di = find_var(lp->ll_name, NULL, TRUE); - if (di == NULL) + } else { + di = find_var((const char *)lp->ll_name, STRLEN(lp->ll_name), NULL, true); + if (di == NULL) { ret = FAIL; - else { - if (lock) + } else { + if (lock) { di->di_flags |= DI_FLAGS_LOCK; - else + } else { di->di_flags &= ~DI_FLAGS_LOCK; + } item_lock(&di->di_tv, deep, lock); } } @@ -4280,9 +4280,10 @@ static int eval7( break; // Option value: &name - case '&': ret = get_option_tv(arg, rettv, evaluate); + case '&': { + ret = get_option_tv((const char **)arg, rettv, evaluate); break; - + } // Environment variable: $VAR. case '$': ret = get_env_tv(arg, rettv, evaluate); break; @@ -4318,7 +4319,7 @@ static int eval7( // Must be a variable or function name. // Can also be a curly-braces kind of name: {expr}. s = *arg; - len = get_name_len(arg, &alias, evaluate, true); + len = get_name_len((const char **)arg, (char **)&alias, evaluate, true); if (alias != NULL) { s = alias; } @@ -4330,12 +4331,12 @@ static int eval7( partial_T *partial; if (!evaluate) { - check_vars(s, len); + check_vars((const char *)s, len); } // If "s" is the name of a variable of type VAR_FUNC // use its contents. - s = deref_func_name(s, &len, &partial, !evaluate); + s = deref_func_name((const char *)s, &len, &partial, !evaluate); // Invoke the function. ret = get_func_tv(s, len, rettv, arg, @@ -4360,9 +4361,9 @@ static int eval7( ret = FAIL; } } else if (evaluate) { - ret = get_var_tv(s, len, rettv, NULL, true, false); + ret = get_var_tv((const char *)s, len, rettv, NULL, true, false); } else { - check_vars(s, len); + check_vars((const char *)s, len); ret = OK; } } @@ -4374,7 +4375,7 @@ static int eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr). if (ret == OK) { - ret = handle_subscript(arg, rettv, evaluate, true); + ret = handle_subscript((const char **)arg, rettv, evaluate, true); } // Apply logical NOT and unary '-', from right to left, ignore '+'. @@ -4675,35 +4676,32 @@ eval_index ( return OK; } -/* - * Get an option value. - * "arg" points to the '&' or '+' before the option name. - * "arg" is advanced to character after the option name. - * Return OK or FAIL. - */ -static int -get_option_tv ( - char_u **arg, - typval_T *rettv, /* when NULL, only check if option exists */ - int evaluate -) +/// Get an option value +/// +/// @param[in,out] arg Points to the '&' or '+' before the option name. Is +/// advanced to the character after the option name. +/// @param[out] rettv Location where result is saved. +/// @param[in] evaluate If not true, rettv is not populated. +/// +/// @return OK or FAIL. +static int get_option_tv(const char **const arg, typval_T *const rettv, + const bool evaluate) + FUNC_ATTR_NONNULL_ARG(1) { - char_u *option_end; long numval; char_u *stringval; int opt_type; int c; - int working = (**arg == '+'); /* has("+option") */ + bool working = (**arg == '+'); // has("+option") int ret = OK; int opt_flags; - /* - * Isolate the option name and find its value. - */ - option_end = find_option_end(arg, &opt_flags); + // Isolate the option name and find its value. + char *option_end = (char *)find_option_end(arg, &opt_flags); if (option_end == NULL) { - if (rettv != NULL) + if (rettv != NULL) { EMSG2(_("E112: Option name missing: %s"), *arg); + } return FAIL; } @@ -4714,8 +4712,8 @@ get_option_tv ( c = *option_end; *option_end = NUL; - opt_type = get_option_value(*arg, &numval, - rettv == NULL ? NULL : &stringval, opt_flags); + opt_type = get_option_value((char_u *)(*arg), &numval, + rettv == NULL ? NULL : &stringval, opt_flags); if (opt_type == -3) { /* invalid name */ if (rettv != NULL) @@ -7266,53 +7264,55 @@ static VimLFuncDef *find_internal_func(const char *const name) return find_internal_func_gperf(name, len); } -/// Check if "name" is a variable of type VAR_FUNC. If so, return the function -/// name it contains, otherwise return "name". -/// If "partialp" is not NULL, and "name" is of type VAR_PARTIAL also set -/// "partialp". -static char_u *deref_func_name( - char_u *name, int *lenp, - partial_T **partialp, bool no_autoload -) +/// Return name of the function corresponding to `name` +/// +/// If `name` points to variable that is either a function or partial then +/// corresponding function name is returned. Otherwise it returns `name` itself. +/// +/// @param[in] name Function name to check. +/// @param[in,out] lenp Location where length of the returned name is stored. +/// Must be set to the length of the `name` argument. +/// @param[out] partialp Location where partial will be stored if found +/// function appears to be a partial. May be NULL if this +/// is not needed. +/// @param[in] no_autoload If true, do not source autoload scripts if function +/// was not found. +/// +/// @return name of the function. +static char_u *deref_func_name(const char *name, int *lenp, + partial_T **const partialp, bool no_autoload) + FUNC_ATTR_NONNULL_ARG(1, 2) { - dictitem_T *v; - int cc; - char_u *s; - if (partialp != NULL) { *partialp = NULL; } - cc = name[*lenp]; - name[*lenp] = NUL; - v = find_var(name, NULL, no_autoload); - name[*lenp] = cc; + dictitem_T *const v = find_var(name, (size_t)(*lenp), NULL, no_autoload); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { - if (v->di_tv.vval.v_string == NULL) { + if (v->di_tv.vval.v_string == NULL) { // just in case *lenp = 0; - return (char_u *)""; /* just in case */ + return (char_u *)""; } - s = v->di_tv.vval.v_string; - *lenp = (int)STRLEN(s); - return s; + *lenp = (int)STRLEN(v->di_tv.vval.v_string); + return v->di_tv.vval.v_string; } if (v != NULL && v->di_tv.v_type == VAR_PARTIAL) { - partial_T *pt = v->di_tv.vval.v_partial; + partial_T *const pt = v->di_tv.vval.v_partial; - if (pt == NULL) { + if (pt == NULL) { // just in case *lenp = 0; - return (char_u *)""; // just in case + return (char_u *)""; } if (partialp != NULL) { *partialp = pt; } - s = partial_name(pt); + char_u *s = partial_name(pt); *lenp = (int)STRLEN(s); return s; } - return name; + return (char_u *)name; } /* @@ -7394,34 +7394,49 @@ get_func_tv ( return ret; } -#define ERROR_UNKNOWN 0 -#define ERROR_TOOMANY 1 -#define ERROR_TOOFEW 2 -#define ERROR_SCRIPT 3 -#define ERROR_DICT 4 -#define ERROR_NONE 5 -#define ERROR_OTHER 6 -#define ERROR_BOTH 7 -#define ERROR_DELETED 8 +typedef enum { + ERROR_UNKNOWN = 0, + ERROR_TOOMANY, + ERROR_TOOFEW, + ERROR_SCRIPT, + ERROR_DICT, + ERROR_NONE, + ERROR_OTHER, + ERROR_BOTH, + ERROR_DELETED, +} FnameTransError; + #define FLEN_FIXED 40 -/// In a script change <SID>name() and s:name() to K_SNR 123_name(). -/// Change <SNR>123_name() to K_SNR 123_name(). -/// Use "fname_buf[FLEN_FIXED + 1]" when it fits, otherwise allocate memory -/// (slow). -static char_u * -fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { - int llen; +/// In a script transform script-local names into actually used names +/// +/// Transforms "<SID>" and "s:" prefixes to `K_SNR {N}` (e.g. K_SNR "123") and +/// "<SNR>" prefix to `K_SNR`. Uses `fname_buf` buffer that is supposed to have +/// #FLEN_FIXED + 1 length when it fits, otherwise it allocates memory. +/// +/// @param[in] name Name to transform. +/// @param fname_buf Buffer to save resulting function name to, if it fits. +/// Must have at least #FLEN_FIXED + 1 length. +/// @param[out] tofree Location where pointer to an allocated memory is saved +/// in case result does not fit into fname_buf. +/// @param[out] error Location where error type is saved, @see +/// FnameTransError. +/// +/// @return transformed name: either `fname_buf` or a pointer to an allocated +/// memory. +static char_u *fname_trans_sid(const char_u *const name, + char_u *const fname_buf, + char_u **const tofree, int *const error) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ char_u *fname; - int i; - - llen = eval_fname_script(name); + const int llen = eval_fname_script((const char *)name); if (llen > 0) { fname_buf[0] = K_SPECIAL; fname_buf[1] = KS_EXTRA; fname_buf[2] = (int)KE_SNR; - i = 3; - if (eval_fname_sid(name)) { // "<SID>" or "s:" + int i = 3; + if (eval_fname_sid((const char *)name)) { // "<SID>" or "s:" if (current_SID <= 0) { *error = ERROR_SCRIPT; } else { @@ -7444,7 +7459,7 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error) { } } } else { - fname = name; + fname = (char_u *)name; } return fname; @@ -7564,7 +7579,7 @@ call_func( rettv->vval.v_number = 0; error = ERROR_UNKNOWN; - if (!builtin_function(rfname, -1)) { + if (!builtin_function((const char *)rfname, -1)) { // User defined function. if (partial != NULL && partial->pt_func != NULL) { fp = partial->pt_func; @@ -7579,9 +7594,10 @@ call_func( /* executed an autocommand, search for the function again */ fp = find_func(rfname); } - /* Try loading a package. */ - if (fp == NULL && script_autoload(rfname, TRUE) && !aborting()) { - /* loaded a package, search for the function again */ + // Try loading a package. + if (fp == NULL && script_autoload((const char *)rfname, STRLEN(rfname), + true) && !aborting()) { + // Loaded a package, search for the function again. fp = find_func(rfname); } @@ -7609,7 +7625,7 @@ call_func( } } else { // Find the function name in the table, call its implementation. - VimLFuncDef *const fdef = find_internal_func((char *)fname); + VimLFuncDef *const fdef = find_internal_func((const char *)fname); if (fdef != NULL) { if (argcount < fdef->min_argc) { error = ERROR_TOOFEW; @@ -8292,17 +8308,17 @@ static buf_T *get_buf_tv(typval_T *tv, int curtab_only) */ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - buf_T *buf; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); rettv->v_type = VAR_STRING; - if (buf != NULL && buf->b_fname != NULL) - rettv->vval.v_string = vim_strsave(buf->b_fname); - else - rettv->vval.v_string = NULL; - --emsg_off; + rettv->vval.v_string = NULL; + if (!tv_check_str_or_nr(&argvars[0])) { + return; + } + emsg_off++; + const buf_T *const buf = get_buf_tv(&argvars[0], false); + emsg_off--; + if (buf != NULL && buf->b_fname != NULL) { + rettv->vval.v_string = (char_u *)xstrdup((char *)buf->b_fname); + } } /* @@ -8310,36 +8326,36 @@ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - buf_T *buf; - int error = FALSE; - char_u *name; + int error = false; + char_u *name; - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - --emsg_off; + rettv->vval.v_number = -1; + if (!tv_check_str_or_nr(&argvars[0])) { + return; + } + emsg_off++; + const buf_T *buf = get_buf_tv(&argvars[0], false); + emsg_off--; - /* If the buffer isn't found and the second argument is not zero create a - * new buffer. */ + // If the buffer isn't found and the second argument is not zero create a + // new buffer. if (buf == NULL && argvars[1].v_type != VAR_UNKNOWN && get_tv_number_chk(&argvars[1], &error) != 0 && !error && (name = get_tv_string_chk(&argvars[0])) != NULL - && !error) + && !error) { buf = buflist_new(name, NULL, (linenr_T)1, 0); + } - if (buf != NULL) + if (buf != NULL) { rettv->vval.v_number = buf->b_fnum; - else - rettv->vval.v_number = -1; + } } static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr) { - int error = false; - (void)get_tv_number_chk(&argvars[0], &error); // issue errmsg if type error - if (error) { // the argument has an invalid type + if (!tv_check_str_or_nr(&argvars[0])) { rettv->vval.v_number = -1; return; } @@ -8383,14 +8399,13 @@ static void f_bufwinnr(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_byte2line(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - long boff = 0; - - boff = get_tv_number(&argvars[0]) - 1; /* boff gets -1 on type error */ - if (boff < 0) + long boff = get_tv_number(&argvars[0]) - 1; + if (boff < 0) { rettv->vval.v_number = -1; - else - rettv->vval.v_number = ml_find_line_or_offset(curbuf, - (linenr_T)0, &boff); + } else { + rettv->vval.v_number = (varnumber_T)ml_find_line_or_offset(curbuf, 0, + &boff); + } } static void byteidx(typval_T *argvars, typval_T *rettv, int comp) @@ -9250,54 +9265,55 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - char_u *p; - char_u *name; - int n = FALSE; + int n = false; int len = 0; - p = get_tv_string(&argvars[0]); - if (*p == '$') { /* environment variable */ - /* first try "normal" environment variables (fast) */ - if (os_getenv((char *)(p + 1)) != NULL) - n = TRUE; - else { - /* try expanding things like $VIM and ${HOME} */ - p = expand_env_save(p); - if (p != NULL && *p != '$') - n = TRUE; + char *p = (char *)get_tv_string(&argvars[0]); + if (*p == '$') { // Environment variable. + // First try "normal" environment variables (fast). + if (os_getenv(p + 1) != NULL) { + n = true; + } else { + // Try expanding things like $VIM and ${HOME}. + p = (char *)expand_env_save((char_u *)p); + if (p != NULL && *p != '$') { + n = true; + } xfree(p); } - } else if (*p == '&' || *p == '+') { // option - n = (get_option_tv(&p, NULL, true) == OK); - if (*skipwhite(p) != NUL) { - n = false; // trailing garbage + } else if (*p == '&' || *p == '+') { // Option. + n = (get_option_tv((const char **)&p, NULL, true) == OK); + if (*skipwhite((const char_u *)p) != NUL) { + n = false; // Trailing garbage. } - } else if (*p == '*') { // internal or user defined function + } else if (*p == '*') { // Internal or user defined function. n = function_exists(p + 1, false); } else if (*p == ':') { n = cmd_exists(p + 1); } else if (*p == '#') { - if (p[1] == '#') + if (p[1] == '#') { n = autocmd_supported(p + 2); - else + } else { n = au_exists(p + 1); - } else { /* internal variable */ - char_u *tofree; + } + } else { // Internal variable. typval_T tv; - /* get_name_len() takes care of expanding curly braces */ - name = p; - len = get_name_len(&p, &tofree, TRUE, FALSE); + // get_name_len() takes care of expanding curly braces + const char *name = p; + char *tofree; + len = get_name_len((const char **)&p, &tofree, true, false); if (len > 0) { if (tofree != NULL) { name = tofree; } n = (get_var_tv(name, len, &tv, NULL, false, true) == OK); if (n) { - /* handle d.key, l[idx], f(expr) */ - n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK); - if (n) + // Handle d.key, l[idx], f(expr). + n = (handle_subscript((const char **)&p, &tv, true, false) == OK); + if (n) { clear_tv(&tv); + } } } if (*p != NUL) @@ -10055,7 +10071,7 @@ static void common_function(typval_T *argvars, typval_T *rettv, // Don't check an autoload name for existence here. } else if (trans_name != NULL && (is_funcref ? find_func(trans_name) == NULL - : !translated_function_exists(trans_name))) { + : !translated_function_exists((const char *)trans_name))) { EMSG2(_("E700: Unknown function: %s"), s); } else { int dict_idx = 0; @@ -10451,20 +10467,22 @@ static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) { linenr_T lnum; linenr_T end; - buf_T *buf; + buf_T *buf = NULL; - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); - --emsg_off; + if (tv_check_str_or_nr(&argvars[0])) { + emsg_off++; + buf = get_buf_tv(&argvars[0], false); + emsg_off--; + } lnum = get_tv_lnum_buf(&argvars[1], buf); - if (argvars[2].v_type == VAR_UNKNOWN) + if (argvars[2].v_type == VAR_UNKNOWN) { end = lnum; - else + } else { end = get_tv_lnum_buf(&argvars[2], buf); + } - get_buffer_lines(buf, lnum, end, TRUE, rettv); + get_buffer_lines(buf, lnum, end, true, rettv); } /* @@ -10472,26 +10490,25 @@ static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - buf_T *buf; - buf_T *save_curbuf; - char_u *varname; - dictitem_T *v; - int done = FALSE; - - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - varname = get_tv_string_chk(&argvars[1]); - ++emsg_off; - buf = get_buf_tv(&argvars[0], FALSE); + bool done = false; rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + if (!tv_check_str_or_nr(&argvars[0])) { + goto f_getbufvar_end; + } + + const char *varname = (const char *)get_tv_string_chk(&argvars[1]); + emsg_off++; + buf_T *const buf = get_buf_tv(&argvars[0], false); + if (buf != NULL && varname != NULL) { - /* set curbuf to be our buf, temporarily */ - save_curbuf = curbuf; + // set curbuf to be our buf, temporarily + buf_T *const save_curbuf = curbuf; curbuf = buf; - if (*varname == '&') { // buffer-local-option + if (*varname == '&') { // buffer-local-option if (varname[1] == NUL) { // get all buffer-local options in a dict dict_T *opts = get_winbuf_options(true); @@ -10511,25 +10528,26 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = curbuf->b_changedtick; done = true; } else { - /* Look up the variable. */ - /* Let getbufvar({nr}, "") return the "b:" dictionary. */ - v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, - 'b', varname, FALSE); + // Look up the variable. + // Let getbufvar({nr}, "") return the "b:" dictionary. + dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b', + varname, strlen(varname), false); if (v != NULL) { copy_tv(&v->di_tv, rettv); - done = TRUE; + done = true; } } - /* restore previous notion of curbuf */ + // restore previous notion of curbuf curbuf = save_curbuf; } + emsg_off--; - if (!done && argvars[2].v_type != VAR_UNKNOWN) - /* use the default value */ +f_getbufvar_end: + if (!done && argvars[2].v_type != VAR_UNKNOWN) { + // use the default value copy_tv(&argvars[2], rettv); - - --emsg_off; + } } /* @@ -11297,13 +11315,12 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) win_T *oldcurwin; tabpage_T *tp, *oldtabpage; dictitem_T *v; - char_u *varname; bool done = false; rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - varname = get_tv_string_chk(&argvars[1]); + const char *const varname = (const char *)get_tv_string_chk(&argvars[1]); tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL)); if (tp != NULL && varname != NULL) { // Set tp to be our tabpage, temporarily. Also set the window to the @@ -11312,7 +11329,8 @@ static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (switch_win(&oldcurwin, &oldtabpage, window, tp, true) == OK) { // look up the variable // Let gettabvar({nr}, "") return the "t:" dictionary. - v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE); + v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', + varname, strlen(varname), false); if (v != NULL) { copy_tv(&v->di_tv, rettv); done = true; @@ -11491,7 +11509,6 @@ getwinvar ( ) { win_T *win, *oldcurwin; - char_u *varname; dictitem_T *v; tabpage_T *tp = NULL; tabpage_T *oldtabpage = NULL; @@ -11502,12 +11519,13 @@ getwinvar ( else tp = curtab; win = find_win_by_nr(&argvars[off], tp); - varname = get_tv_string_chk(&argvars[off + 1]); - ++emsg_off; + const char *varname = (const char *)get_tv_string_chk( + &argvars[off + 1]); rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + emsg_off++; if (win != NULL && varname != NULL) { // Set curwin to be our win, temporarily. Also set the tabpage, // otherwise the window is not valid. Only do this when needed, @@ -11533,7 +11551,8 @@ getwinvar ( } else { // Look up the variable. // Let getwinvar({nr}, "") return the "w:" dictionary. - v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname, FALSE); + v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w', varname, + strlen(varname), false); if (v != NULL) { copy_tv(&v->di_tv, rettv); done = true; @@ -11546,12 +11565,12 @@ getwinvar ( restore_win(oldcurwin, oldtabpage, true); } } + emsg_off--; - if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) - /* use the default return value */ + if (!done && argvars[off + 2].v_type != VAR_UNKNOWN) { + // use the default return value copy_tv(&argvars[off + 2], rettv); - - --emsg_off; + } } /* @@ -11821,6 +11840,10 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) #endif } else if (STRICMP(name, "syntax_items") == 0) { n = syntax_present(curwin); +#ifdef UNIX + } else if (STRICMP(name, "unnamedplus") == 0) { + n = eval_has_provider("clipboard"); +#endif } } @@ -12217,8 +12240,8 @@ static void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog) *p = NUL; msg_start(); msg_clr_eos(); - msg_puts_attr(prompt, echo_attr); - msg_didout = FALSE; + msg_puts_attr((const char *)prompt, echo_attr); + msg_didout = false; msg_starthere(); *p = c; } @@ -12310,7 +12333,7 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) msg_clr_eos(); for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next) { - msg_puts(get_tv_string(&li->li_tv)); + msg_puts((const char *)get_tv_string(&li->li_tv)); msg_putchar('\n'); } @@ -12435,10 +12458,11 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr) EMSG(_(e_trailing)); else { if (lv.ll_tv == NULL) { - if (check_changedtick(lv.ll_name)) - rettv->vval.v_number = 1; /* always locked */ - else { - di = find_var(lv.ll_name, NULL, TRUE); + if (check_changedtick(lv.ll_name)) { + rettv->vval.v_number = 1; // Always locked. + } else { + di = find_var((const char *)lv.ll_name, STRLEN(lv.ll_name), NULL, + true); if (di != NULL) { /* Consider a variable locked when: * 1. the variable itself is locked @@ -13279,9 +13303,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) rettv_dict_alloc(rettv); if (rhs != NULL) { // Return a dictionary. - char_u *lhs = str2special_save(mp->m_keys, TRUE); - char_u *mapmode = map_mode_to_chars(mp->m_mode); - dict_T *dict = rettv->vval.v_dict; + char_u *lhs = str2special_save(mp->m_keys, true); + char *const mapmode = map_mode_to_chars(mp->m_mode); + dict_T *dict = rettv->vval.v_dict; dict_add_nr_str(dict, "lhs", 0L, lhs); dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); @@ -13291,7 +13315,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_add_nr_str(dict, "sid", (long)mp->m_script_ID, NULL); dict_add_nr_str(dict, "buffer", (long)buffer_local, NULL); dict_add_nr_str(dict, "nowait", mp->m_nowait ? 1L : 0L, NULL); - dict_add_nr_str(dict, "mode", 0L, mapmode); + dict_add_nr_str(dict, "mode", 0L, (char_u *)mapmode); xfree(lhs); xfree(mapmode); @@ -15508,44 +15532,45 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - buf_T *buf; - char_u *varname, *bufvarname; - typval_T *varp; char_u nbuf[NUMBUFLEN]; - if (check_restricted() || check_secure()) + if (check_restricted() + || check_secure() + || !tv_check_str_or_nr(&argvars[0])) { return; - (void)get_tv_number(&argvars[0]); /* issue errmsg if type error */ - varname = get_tv_string_chk(&argvars[1]); - buf = get_buf_tv(&argvars[0], FALSE); - varp = &argvars[2]; + } + const char *varname = (const char *)get_tv_string_chk(&argvars[1]); + buf_T *const buf = get_buf_tv(&argvars[0], false); + typval_T *varp = &argvars[2]; if (buf != NULL && varname != NULL && varp != NULL) { if (*varname == '&') { long numval; - char_u *strval; + char_u *strval; int error = false; - aco_save_T aco; + aco_save_T aco; // set curbuf to be our buf, temporarily aucmd_prepbuf(&aco, buf); - ++varname; + varname++; numval = get_tv_number_chk(varp, &error); strval = get_tv_string_buf_chk(varp, nbuf); - if (!error && strval != NULL) - set_option_value(varname, numval, strval, OPT_LOCAL); + if (!error && strval != NULL) { + set_option_value((char_u *)varname, numval, strval, OPT_LOCAL); + } // reset notion of buffer aucmd_restbuf(&aco); } else { buf_T *save_curbuf = curbuf; - bufvarname = xmalloc(STRLEN(varname) + 3); + const size_t varname_len = STRLEN(varname); + char_u *const bufvarname = xmalloc(STRLEN(varname) + 3); curbuf = buf; - STRCPY(bufvarname, "b:"); - STRCPY(bufvarname + 2, varname); - set_var(bufvarname, varp, TRUE); + memcpy(bufvarname, "b:", 2); + memcpy(bufvarname + 2, varname, varname_len + 1); + set_var(bufvarname, varp, true); xfree(bufvarname); curbuf = save_curbuf; } @@ -17232,8 +17257,8 @@ static void f_synIDattr(typval_T *argvars, typval_T *rettv, FunPtr fptr) p = highlight_has_attr(id, HL_ITALIC, modec); break; - case 'n': /* name */ - p = get_highlight_name(NULL, id - 1); + case 'n': // name + p = (char_u *)get_highlight_name(NULL, id - 1); break; case 'r': /* reverse */ @@ -18802,11 +18827,12 @@ static int get_env_len(char_u **arg) // Get the length of the name of a function or internal variable. // "arg" is advanced to the first non-white character after the name. // Return 0 if something is wrong. -static int get_id_len(char_u **arg) { - char_u *p; +static int get_id_len(const char **const arg) +{ int len; // Find the end of the name. + const char *p; for (p = *arg; eval_isnamec(*p); p++) { if (*p == ':') { // "s:" is start of "s:var", but "n:" is not and can be used in @@ -18823,7 +18849,7 @@ static int get_id_len(char_u **arg) { } len = (int)(p - *arg); - *arg = skipwhite(p); + *arg = (const char *)skipwhite((const char_u *)p); return len; } @@ -18837,18 +18863,20 @@ static int get_id_len(char_u **arg) { * If the name contains 'magic' {}'s, expand them and return the * expanded name in an allocated string via 'alias' - caller must free. */ -static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose) +static int get_name_len(const char **const arg, + char **alias, + int evaluate, + int verbose) { int len; - char_u *p; char_u *expr_start; char_u *expr_end; *alias = NULL; /* default to no alias */ - if ((*arg)[0] == K_SPECIAL && (*arg)[1] == KS_EXTRA - && (*arg)[2] == (int)KE_SNR) { - /* hard coded <SNR>, already translated */ + if ((*arg)[0] == (char)K_SPECIAL && (*arg)[1] == (char)KS_EXTRA + && (*arg)[2] == (char)KE_SNR) { + // Hard coded <SNR>, already translated. *arg += 3; return get_id_len(arg) + 3; } @@ -18861,14 +18889,14 @@ static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose) /* * Find the end of the name; check for {} construction. */ - p = find_name_end(*arg, &expr_start, &expr_end, - len > 0 ? 0 : FNE_CHECK_START); + const char *p = (const char *)find_name_end((char_u *)(*arg), + &expr_start, + &expr_end, + len > 0 ? 0 : FNE_CHECK_START); if (expr_start != NULL) { - char_u *temp_string; - if (!evaluate) { len += (int)(p - *arg); - *arg = skipwhite(p); + *arg = (const char *)skipwhite((const char_u *)p); return len; } @@ -18876,11 +18904,13 @@ static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose) * Include any <SID> etc in the expanded string: * Thus the -len here. */ - temp_string = make_expanded_name(*arg - len, expr_start, expr_end, p); - if (temp_string == NULL) + char_u *temp_string = make_expanded_name((char_u *)(*arg) - len, expr_start, + expr_end, (char_u *)p); + if (temp_string == NULL) { return -1; - *alias = temp_string; - *arg = skipwhite(p); + } + *alias = (char *)temp_string; + *arg = (const char *)skipwhite((const char_u *)p); return (int)STRLEN(temp_string); } @@ -19294,9 +19324,8 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) * Get the value of internal variable "name". * Return OK or FAIL. */ -static int -get_var_tv ( - char_u *name, +static int get_var_tv( + const char *name, int len, // length of "name" typval_T *rettv, // NULL when only checking existence dictitem_T **dip, // non-NULL when typval's dict item is needed @@ -19308,25 +19337,16 @@ get_var_tv ( typval_T *tv = NULL; typval_T atv; dictitem_T *v; - int cc; - /* truncate the name, so that we can use strcmp() */ - cc = name[len]; - name[len] = NUL; - - /* - * Check for "b:changedtick". - */ - if (STRCMP(name, "b:changedtick") == 0) { + // Check for "b:changedtick". + if (sizeof("b:changedtick") - 1 == len + && STRNCMP(name, "b:changedtick", len) == 0) { atv.v_type = VAR_NUMBER; atv.vval.v_number = curbuf->b_changedtick; tv = &atv; - } - /* - * Check for user-defined variables. - */ - else { - v = find_var(name, NULL, no_autoload); + } else { + // Check for user-defined variables. + v = find_var(name, (size_t)len, NULL, no_autoload); if (v != NULL) { tv = &v->di_tv; if (dip != NULL) { @@ -19336,41 +19356,33 @@ get_var_tv ( } if (tv == NULL) { - if (rettv != NULL && verbose) - EMSG2(_(e_undefvar), name); + if (rettv != NULL && verbose) { + emsgf(_("E121: Undefined variable: %.*s"), len, name); + } ret = FAIL; - } else if (rettv != NULL) + } else if (rettv != NULL) { copy_tv(tv, rettv); - - name[len] = cc; + } return ret; } /// Check if variable "name[len]" is a local variable or an argument. /// If so, "*eval_lavars_used" is set to TRUE. -static void check_vars(char_u *name, int len) +static void check_vars(const char *name, size_t len) { - int cc; - char_u *varname; - hashtab_T *ht; - if (eval_lavars_used == NULL) { return; } - // truncate the name, so that we can use strcmp() - cc = name[len]; - name[len] = NUL; + const char *varname; + hashtab_T *ht = find_var_ht(name, len, &varname); - ht = find_var_ht(name, &varname); if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht()) { - if (find_var(name, NULL, true) != NULL) { + if (find_var(name, len, NULL, true) != NULL) { *eval_lavars_used = true; } } - - name[len] = cc; } /// Handle expr[expr], expr[expr:expr] subscript and .name lookup. @@ -19378,7 +19390,7 @@ static void check_vars(char_u *name, int len) /// Can all be combined: dict.func(expr)[idx]['func'](expr) static int handle_subscript( - char_u **arg, + const char **const arg, typval_T *rettv, int evaluate, /* do more than finding the end */ int verbose /* give error messages */ @@ -19413,7 +19425,7 @@ handle_subscript( } else { s = (char_u *)""; } - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg, + ret = get_func_tv(s, (int)STRLEN(s), rettv, (char_u **)arg, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &len, evaluate, pt, selfdict); @@ -19440,7 +19452,7 @@ handle_subscript( ++selfdict->dv_refcount; } else selfdict = NULL; - if (eval_index(arg, rettv, evaluate, verbose) == FAIL) { + if (eval_index((char_u **)arg, rettv, evaluate, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; } @@ -19813,6 +19825,53 @@ static void init_tv(typval_T *varp) memset(varp, 0, sizeof(typval_T)); } +/// Check that given value is a number or string +/// +/// Error messages are compatible with get_tv_number() previously used for the +/// same purpose in buf*() functions. Special values are not accepted (previous +/// behaviour: silently fail to find buffer). +/// +/// @param[in] tv Value to check. +/// +/// @return true if everything is OK, false otherwise. +bool tv_check_str_or_nr(const typval_T *const tv) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +{ + switch (tv->v_type) { + case VAR_NUMBER: + case VAR_STRING: { + return true; + } + case VAR_FLOAT: { + EMSG(_("E805: Expected a Number or a String, Float found")); + return false; + } + case VAR_PARTIAL: + case VAR_FUNC: { + EMSG(_("E703: Expected a Number or a String, Funcref found")); + return false; + } + case VAR_LIST: { + EMSG(_("E745: Expected a Number or a String, List found")); + return false; + } + case VAR_DICT: { + EMSG(_("E728: Expected a Number or a String, Dictionary found")); + return false; + } + case VAR_SPECIAL: { + EMSG(_("E5300: Expected a Number or a String")); + return false; + } + case VAR_UNKNOWN: { + EMSG2(_(e_intern2), "tv_check_str_or_nr(UNKNOWN)"); + return false; + } + } + assert(false); + return false; +} + /* * Get the number value of a variable. * If it is a String variable, uses vim_str2nr(). @@ -20017,67 +20076,82 @@ char_u *get_tv_string_buf_chk(const typval_T *varp, char_u *buf) * When "htp" is not NULL we are writing to the variable, set "htp" to the * hashtab_T used. */ -static dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload) +static dictitem_T *find_var(const char *const name, const size_t name_len, + hashtab_T **htp, int no_autoload) { - char_u *varname; - hashtab_T *ht; - dictitem_T *ret = NULL; - - ht = find_var_ht(name, &varname); + const char *varname; + hashtab_T *ht = find_var_ht(name, name_len, &varname); if (htp != NULL) { *htp = ht; } if (ht == NULL) { return NULL; } - ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL); + dictitem_T *ret = find_var_in_ht(ht, *name, + varname, name_len - (size_t)(varname - name), + no_autoload || htp != NULL); if (ret != NULL) { return ret; } // Search in parent scope for lambda - return find_var_in_scoped_ht(name, no_autoload || htp != NULL); + return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL); } -/// Find variable "varname" in hashtab "ht" with name "htname". -/// Returns NULL if not found. -dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, - char_u *varname, bool no_autoload) +/// Find variable in hashtab +/// +/// @param[in] ht Hashtab to find variable in. +/// @param[in] htname Hashtab name (first character). +/// @param[in] varname Variable name. +/// @param[in] varname_len Variable name length. +/// @param[in] no_autoload If true then autoload scripts will not be sourced +/// if autoload variable was not found. +/// +/// @return pointer to the dictionary item with the found variable or NULL if it +/// was not found. +static dictitem_T *find_var_in_ht(hashtab_T *const ht, + int htname, + const char *const varname, + const size_t varname_len, + int no_autoload) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { hashitem_T *hi; - if (*varname == NUL) { - /* Must be something like "s:", otherwise "ht" would be NULL. */ + if (varname_len == 0) { + // Must be something like "s:", otherwise "ht" would be NULL. switch (htname) { - case 's': return &SCRIPT_SV(current_SID)->sv_var; - case 'g': return &globvars_var; - case 'v': return &vimvars_var; - case 'b': return &curbuf->b_bufvar; - case 'w': return &curwin->w_winvar; - case 't': return &curtab->tp_winvar; - case 'l': return current_funccal == NULL - ? NULL : ¤t_funccal->l_vars_var; - case 'a': return current_funccal == NULL - ? NULL : ¤t_funccal->l_avars_var; + case 's': return (dictitem_T *)&SCRIPT_SV(current_SID)->sv_var; + case 'g': return (dictitem_T *)&globvars_var; + case 'v': return (dictitem_T *)&vimvars_var; + case 'b': return (dictitem_T *)&curbuf->b_bufvar; + case 'w': return (dictitem_T *)&curwin->w_winvar; + case 't': return (dictitem_T *)&curtab->tp_winvar; + case 'l': return (current_funccal == NULL + ? NULL : (dictitem_T *)¤t_funccal->l_vars_var); + case 'a': return (current_funccal == NULL + ? NULL : (dictitem_T *)¤t_funccal->l_avars_var); } return NULL; } - hi = hash_find(ht, varname); + hi = hash_find_len(ht, varname, varname_len); if (HASHITEM_EMPTY(hi)) { - /* For global variables we may try auto-loading the script. If it - * worked find the variable again. Don't auto-load a script if it was - * loaded already, otherwise it would be loaded every time when - * checking if a function name is a Funcref variable. */ + // For global variables we may try auto-loading the script. If it + // worked find the variable again. Don't auto-load a script if it was + // loaded already, otherwise it would be loaded every time when + // checking if a function name is a Funcref variable. if (ht == &globvarht && !no_autoload) { - /* Note: script_autoload() may make "hi" invalid. It must either - * be obtained again or not used. */ - if (!script_autoload(varname, FALSE) || aborting()) + // Note: script_autoload() may make "hi" invalid. It must either + // be obtained again or not used. + if (!script_autoload(varname, varname_len, false) || aborting()) { return NULL; - hi = hash_find(ht, varname); + } + hi = hash_find_len(ht, varname, varname_len); } - if (HASHITEM_EMPTY(hi)) + if (HASHITEM_EMPTY(hi)) { return NULL; + } } return HI2DI(hi); } @@ -20103,7 +20177,7 @@ static funccall_T *get_funccal(void) /// Return the hashtable used for argument in the current funccal. /// Return NULL if there is no current funccal. -hashtab_T *get_funccal_args_ht(void) +static hashtab_T *get_funccal_args_ht(void) { if (current_funccal == NULL) { return NULL; @@ -20113,7 +20187,7 @@ hashtab_T *get_funccal_args_ht(void) /// Return the hashtable used for local variables in the current funccal. /// Return NULL if there is no current funccal. -hashtab_T *get_funccal_local_ht(void) +static hashtab_T *get_funccal_local_ht(void) { if (current_funccal == NULL) { return NULL; @@ -20121,17 +20195,25 @@ hashtab_T *get_funccal_local_ht(void) return &get_funccal()->l_vars.dv_hashtab; } -// Find the dict and hashtable used for a variable name. Set "varname" to the -// start of name without ':'. -static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) +/// Find the dict and hashtable used for a variable +/// +/// @param[in] name Variable name, possibly with scope prefix. +/// @param[in] name_len Variable name length. +/// @param[out] varname Will be set to the start of the name without scope +/// prefix. +/// @param[out] d Scope dictionary. +/// +/// @return Scope hashtab, NULL if name is not valid. +static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, + const char **varname, dict_T **d) { - hashitem_T *hi; + hashitem_T *hi; *d = NULL; - if (name[0] == NUL) { + if (name_len == 0) { return NULL; } - if (name[1] != ':') { + if (name_len == 1 || (name_len >= 2 && name[1] != ':')) { // name has implicit scope if (name[0] == ':' || name[0] == AUTOLOAD_CHAR) { // The name must not start with a colon or #. @@ -20140,7 +20222,7 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) *varname = name; // "version" is "v:version" in all scopes - hi = hash_find(&compat_hashtab, name); + hi = hash_find_len(&compat_hashtab, name, name_len); if (!HASHITEM_EMPTY(hi)) { return &compat_hashtab; } @@ -20156,26 +20238,27 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) *varname = name + 2; if (*name == 'g') { // global variable *d = &globvardict; - } else if (vim_strchr(name + 2, ':') != NULL - || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL) { + } else if (name_len > 2 + && (memchr(name + 2, ':', name_len - 2) != NULL + || memchr(name + 2, AUTOLOAD_CHAR, name_len - 2) != NULL)) { // There must be no ':' or '#' in the rest of the name if g: was not used return NULL; } - if (*name == 'b') { // buffer variable + if (*name == 'b') { // buffer variable *d = curbuf->b_vars; - } else if (*name == 'w') { // window variable + } else if (*name == 'w') { // window variable *d = curwin->w_vars; - } else if (*name == 't') { // tab page variable + } else if (*name == 't') { // tab page variable *d = curtab->tp_vars; - } else if (*name == 'v') { // v: variable + } else if (*name == 'v') { // v: variable *d = &vimvardict; } else if (*name == 'a' && current_funccal != NULL) { // function argument *d = &get_funccal()->l_avars; } else if (*name == 'l' && current_funccal != NULL) { // local variable *d = &get_funccal()->l_vars; - } else if (*name == 's' // script variable - && current_SID > 0 && current_SID <= ga_scripts.ga_len) { + } else if (*name == 's' // script variable + && current_SID > 0 && current_SID <= ga_scripts.ga_len) { *d = &SCRIPT_SV(current_SID)->sv_dict; } @@ -20183,13 +20266,19 @@ end: return *d ? &(*d)->dv_hashtab : NULL; } -// Find the hashtab used for a variable name. -// Return NULL if the name is not valid. -// Set "varname" to the start of name without ':'. -static hashtab_T *find_var_ht(uint8_t *name, uint8_t **varname) +/// Find the hashtable used for a variable +/// +/// @param[in] name Variable name, possibly with scope prefix. +/// @param[in] name_len Variable name length. +/// @param[out] varname Will be set to the start of the name without scope +/// prefix. +/// +/// @return Scope hashtab, NULL if name is not valid. +static hashtab_T *find_var_ht(const char *name, const size_t name_len, + const char **varname) { dict_T *d; - return find_var_ht_dict(name, varname, &d); + return find_var_ht_dict(name, name_len, varname, &d); } /* @@ -20197,13 +20286,14 @@ static hashtab_T *find_var_ht(uint8_t *name, uint8_t **varname) * Note: see get_tv_string() for how long the pointer remains valid. * Returns NULL when it doesn't exist. */ -char_u *get_var_value(char_u *name) +char_u *get_var_value(const char *const name) { dictitem_T *v; - v = find_var(name, NULL, FALSE); - if (v == NULL) + v = find_var(name, strlen(name), NULL, false); + if (v == NULL) { return NULL; + } return get_tv_string(&v->di_tv); } @@ -20324,28 +20414,27 @@ static void delete_var(hashtab_T *ht, hashitem_T *hi) /* * List the value of one internal variable. */ -static void list_one_var(dictitem_T *v, char_u *prefix, int *first) +static void list_one_var(dictitem_T *v, const char *prefix, int *first) { - char_u *s = (char_u *) encode_tv2echo(&v->di_tv, NULL); - list_one_var_a(prefix, v->di_key, v->di_tv.v_type, - s == NULL ? (char_u *)"" : s, first); + char *const s = encode_tv2echo(&v->di_tv, NULL); + list_one_var_a(prefix, (const char *)v->di_key, STRLEN(v->di_key), + v->di_tv.v_type, (s == NULL ? "" : s), first); xfree(s); } -static void -list_one_var_a ( - char_u *prefix, - char_u *name, - int type, - char_u *string, - int *first /* when TRUE clear rest of screen and set to FALSE */ -) +/// @param[in] name_len Length of the name. May be -1, in this case strlen() +/// will be used. +/// @param[in,out] first When true clear rest of screen and set to false. +static void list_one_var_a(const char *prefix, const char *name, + const ptrdiff_t name_len, const int type, + const char *string, int *first) { - /* don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" */ + // don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" msg_start(); msg_puts(prefix); - if (name != NULL) /* "a:" vars don't have a name stored */ - msg_puts(name); + if (name != NULL) { // "a:" vars don't have a name stored + msg_puts_attr_len(name, name_len, 0); + } msg_putchar(' '); msg_advance(22); if (type == VAR_NUMBER) { @@ -20363,10 +20452,10 @@ list_one_var_a ( } else msg_putchar(' '); - msg_outtrans(string); + msg_outtrans((char_u *)string); if (type == VAR_FUNC || type == VAR_PARTIAL) { - msg_puts((char_u *)"()"); + msg_puts("()"); } if (*first) { msg_clr_eos(); @@ -20387,12 +20476,14 @@ set_var ( ) { dictitem_T *v; - char_u *varname; hashtab_T *ht; typval_T oldtv; dict_T *dict; - ht = find_var_ht_dict(name, &varname, &dict); + const size_t name_len = STRLEN(name); + char_u *varname; + ht = find_var_ht_dict((const char *)name, name_len, (const char **)&varname, + &dict); bool watched = is_watched(dict); if (watched) { @@ -20403,11 +20494,13 @@ set_var ( EMSG2(_(e_illvar), name); return; } - v = find_var_in_ht(ht, 0, varname, true); + v = find_var_in_ht(ht, 0, + (const char *)varname, name_len - (size_t)(varname - name), + true); // Search in parent scope which is possible to reference from lambda if (v == NULL) { - v = find_var_in_scoped_ht(name, true); + v = find_var_in_scoped_ht((const char *)name, name_len, true); } if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL) @@ -20538,12 +20631,12 @@ var_check_func_name ( // Don't allow hiding a function. When "v" is not NULL we might be // assigning another function to the same var, the type is checked // below. - if (new_var && function_exists(name, false)) { + if (new_var && function_exists((const char *)name, false)) { EMSG2(_("E705: Variable name conflicts with existing function: %s"), - name); - return TRUE; + name); + return true; } - return FALSE; + return false; } /* @@ -20738,7 +20831,6 @@ void ex_echo(exarg_T *eap) { char_u *arg = eap->arg; typval_T rettv; - char_u *p; bool needclr = true; bool atstart = true; @@ -20749,19 +20841,20 @@ void ex_echo(exarg_T *eap) * still need to be cleared. E.g., "echo 22,44". */ need_clr_eos = needclr; - p = arg; - if (eval1(&arg, &rettv, !eap->skip) == FAIL) { - /* - * Report the invalid expression unless the expression evaluation - * has been cancelled due to an aborting error, an interrupt, or an - * exception. - */ - if (!aborting()) - EMSG2(_(e_invexpr2), p); - need_clr_eos = FALSE; - break; + { + char_u *p = arg; + if (eval1(&arg, &rettv, !eap->skip) == FAIL) { + // Report the invalid expression unless the expression evaluation + // has been cancelled due to an aborting error, an interrupt, or an + // exception. + if (!aborting()) { + EMSG2(_(e_invexpr2), p); + } + need_clr_eos = false; + break; + } + need_clr_eos = false; } - need_clr_eos = FALSE; if (!eap->skip) { if (atstart) { @@ -20775,9 +20868,11 @@ void ex_echo(exarg_T *eap) msg_sb_eol(); msg_start(); } - } else if (eap->cmdidx == CMD_echo) - msg_puts_attr((char_u *)" ", echo_attr); - char_u *tofree = p = (char_u *) encode_tv2echo(&rettv, NULL); + } else if (eap->cmdidx == CMD_echo) { + msg_puts_attr(" ", echo_attr); + } + char *tofree = encode_tv2echo(&rettv, NULL); + const char *p = tofree; if (p != NULL) { for (; *p != NUL && !got_int; ++p) { if (*p == '\n' || *p == '\r' || *p == TAB) { @@ -20786,15 +20881,16 @@ void ex_echo(exarg_T *eap) msg_clr_eos(); needclr = false; } - msg_putchar_attr(*p, echo_attr); + msg_putchar_attr((uint8_t)(*p), echo_attr); } else { if (has_mbyte) { - int i = (*mb_ptr2len)(p); + int i = (*mb_ptr2len)((const char_u *)p); - (void)msg_outtrans_len_attr(p, i, echo_attr); + (void)msg_outtrans_len_attr((char_u *)p, i, echo_attr); p += i - 1; - } else - (void)msg_outtrans_len_attr(p, 1, echo_attr); + } else { + (void)msg_outtrans_len_attr((char_u *)p, 1, echo_attr); + } } } } @@ -20908,9 +21004,9 @@ void ex_execute(exarg_T *eap) * Returns NULL when no option name found. Otherwise pointer to the char * after the option name. */ -static char_u *find_option_end(char_u **arg, int *opt_flags) +static const char *find_option_end(const char **const arg, int *const opt_flags) { - char_u *p = *arg; + const char *p = *arg; ++p; if (*p == 'g' && p[1] == ':') { @@ -21086,7 +21182,7 @@ void ex_function(exarg_T *eap) } if (!got_int) { msg_putchar('\n'); - msg_puts((char_u *)" endfunction"); + msg_puts(" endfunction"); } } else emsg_funcname(N_("E123: Undefined function: %s"), name); @@ -21263,7 +21359,7 @@ void ex_function(exarg_T *eap) if (*p == '!') { p = skipwhite(p + 1); } - p += eval_fname_script(p); + p += eval_fname_script((const char *)p); xfree(trans_function_name(&p, true, 0, NULL, NULL)); if (*skipwhite(p) == '(') { nesting++; @@ -21338,7 +21434,7 @@ void ex_function(exarg_T *eap) * If there are no errors, add the function */ if (fudi.fd_dict == NULL) { - v = find_var(name, &ht, FALSE); + v = find_var((const char *)name, STRLEN(name), &ht, false); if (v != NULL && v->di_tv.v_type == VAR_FUNC) { emsg_funcname(N_("E707: Function name conflicts with variable: %s"), name); @@ -21404,7 +21500,7 @@ void ex_function(exarg_T *eap) /* Check that the autoload name matches the script name. */ int j = FAIL; if (sourcing_name != NULL) { - scriptname = autoload_name(name); + scriptname = (char_u *)autoload_name((const char *)name, STRLEN(name)); p = vim_strchr(scriptname, '/'); plen = (int)STRLEN(p); slen = (int)STRLEN(sourcing_name); @@ -21521,15 +21617,16 @@ trans_function_name( if ((*pp)[0] == K_SPECIAL && (*pp)[1] == KS_EXTRA && (*pp)[2] == (int)KE_SNR) { *pp += 3; - len = get_id_len(pp) + 3; - return vim_strnsave(start, len); + len = get_id_len((const char **)pp) + 3; + return (char_u *)xmemdupz(start, len); } /* A name starting with "<SID>" or "<SNR>" is local to a script. But * don't skip over "s:", get_lval() needs it for "s:dict.func". */ - lead = eval_fname_script(start); - if (lead > 2) + lead = eval_fname_script((const char *)start); + if (lead > 2) { start += lead; + } /* Note that TFN_ flags use the same values as GLV_ flags. */ end = get_lval(start, NULL, &lv, FALSE, skip, flags, @@ -21592,14 +21689,15 @@ trans_function_name( /* Check if the name is a Funcref. If so, use the value. */ if (lv.ll_exp_name != NULL) { len = (int)STRLEN(lv.ll_exp_name); - name = deref_func_name(lv.ll_exp_name, &len, partial, + name = deref_func_name((const char *)lv.ll_exp_name, &len, partial, flags & TFN_NO_AUTOLOAD); if (name == lv.ll_exp_name) { name = NULL; } } else if (!(flags & TFN_NO_DEREF)) { len = (int)(end - *pp); - name = deref_func_name(*pp, &len, partial, flags & TFN_NO_AUTOLOAD); + name = deref_func_name((const char *)(*pp), &len, partial, + flags & TFN_NO_AUTOLOAD); if (name == *pp) { name = NULL; } @@ -21644,9 +21742,9 @@ trans_function_name( lead = 0; /* do nothing */ else if (lead > 0) { lead = 3; - if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name)) - || eval_fname_sid(*pp)) { - /* It's "s:" or "<SID>" */ + if ((lv.ll_exp_name != NULL && eval_fname_sid((const char *)lv.ll_exp_name)) + || eval_fname_sid((const char *)(*pp))) { + // It's "s:" or "<SID>". if (current_SID <= 0) { EMSG(_(e_usingsid)); goto theend; @@ -21654,7 +21752,8 @@ trans_function_name( sprintf((char *)sid_buf, "%" PRId64 "_", (int64_t)current_SID); lead += (int)STRLEN(sid_buf); } - } else if (!(flags & TFN_INT) && builtin_function(lv.ll_name, len)) { + } else if (!(flags & TFN_INT) + && builtin_function((const char *)lv.ll_name, len)) { EMSG2(_("E128: Function name must start with a capital or \"s:\": %s"), start); goto theend; @@ -21691,12 +21790,13 @@ theend: * Return 2 if "p" starts with "s:". * Return 0 otherwise. */ -static int eval_fname_script(char_u *p) +static int eval_fname_script(const char *const p) { // Use mb_stricmp() because in Turkish comparing the "I" may not work with // the standard library function. - if (p[0] == '<' && (mb_strnicmp(p + 1, (char_u *)"SID>", 4) == 0 - || mb_strnicmp(p + 1, (char_u *)"SNR>", 4) == 0)) { + if (p[0] == '<' + && (mb_strnicmp((char_u *)p + 1, (char_u *)"SID>", 4) == 0 + || mb_strnicmp((char_u *)p + 1, (char_u *)"SNR>", 4) == 0)) { return 5; } if (p[0] == 's' && p[1] == ':') { @@ -21705,13 +21805,19 @@ static int eval_fname_script(char_u *p) return 0; } -/* - * Return TRUE if "p" starts with "<SID>" or "s:". - * Only works if eval_fname_script() returned non-zero for "p"! - */ -static int eval_fname_sid(char_u *p) +/// Check whether function name starts with <SID> or s: +/// +/// Only works for names previously checked by eval_fname_script(), if it +/// returned non-zero. +/// +/// @param[in] name Name to check. +/// +/// @return true if it starts with <SID> or s:, false otherwise. +static inline bool eval_fname_sid(const char *const name) + FUNC_ATTR_PURE FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_WARN_UNUSED_RESULT + FUNC_ATTR_NONNULL_ALL { - return *p == 's' || TOUPPER_ASC(p[2]) == 'I'; + return *name == 's' || TOUPPER_ASC(name[2]) == 'I'; } /* @@ -21725,33 +21831,36 @@ static void list_func_head(ufunc_T *fp, int indent) MSG_PUTS("function "); if (fp->uf_name[0] == K_SPECIAL) { MSG_PUTS_ATTR("<SNR>", hl_attr(HLF_8)); - msg_puts(fp->uf_name + 3); - } else - msg_puts(fp->uf_name); + msg_puts((const char *)fp->uf_name + 3); + } else { + msg_puts((const char *)fp->uf_name); + } msg_putchar('('); int j; - for (j = 0; j < fp->uf_args.ga_len; ++j) { - if (j) - MSG_PUTS(", "); - msg_puts(FUNCARG(fp, j)); + for (j = 0; j < fp->uf_args.ga_len; j++) { + if (j) { + msg_puts(", "); + } + msg_puts((const char *)FUNCARG(fp, j)); } if (fp->uf_varargs) { - if (j) - MSG_PUTS(", "); - MSG_PUTS("..."); + if (j) { + msg_puts(", "); + } + msg_puts("..."); } msg_putchar(')'); if (fp->uf_flags & FC_ABORT) { - MSG_PUTS(" abort"); + msg_puts(" abort"); } if (fp->uf_flags & FC_RANGE) { - MSG_PUTS(" range"); + msg_puts(" range"); } if (fp->uf_flags & FC_DICT) { - MSG_PUTS(" dict"); + msg_puts(" dict"); } if (fp->uf_flags & FC_CLOSURE) { - MSG_PUTS(" closure"); + msg_puts(" closure"); } msg_clr_eos(); if (p_verbose > 0) @@ -21760,7 +21869,7 @@ static void list_func_head(ufunc_T *fp, int indent) /// Find a function by name, return pointer to it in ufuncs. /// @return NULL for unknown function. -ufunc_T *find_func(char_u *name) +static ufunc_T *find_func(const char_u *name) { hashitem_T *hi; @@ -21832,58 +21941,59 @@ void free_all_functions(void) #endif -int translated_function_exists(char_u *name) +bool translated_function_exists(const char *name) { if (builtin_function(name, -1)) { return find_internal_func((char *)name) != NULL; } - return find_func(name) != NULL; + return find_func((const char_u *)name) != NULL; } -/// Check if a function exists by name +/// Check whether function with the given name exists /// -/// @param[in] name The name of the function to check. -/// @param[in] no_deref If true, do not dereference a Funcref. +/// @param[in] name Function name. +/// @param[in] no_deref Whether to dereference a Funcref. /// -/// @return true if a function "name" exists. -static int function_exists(char_u *name, bool no_deref) +/// @return True if it exists, false otherwise. +static bool function_exists(const char *const name, bool no_deref) { - char_u *nm = name; - char_u *p; - int n = false; + char_u *nm = (char_u *)name; + bool n = false; int flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; if (no_deref) { flag |= TFN_NO_DEREF; } - p = trans_function_name(&nm, false, flag, NULL, NULL); + char *const p = (char *)trans_function_name(&nm, false, flag, NULL, NULL); nm = skipwhite(nm); /* Only accept "funcname", "funcname ", "funcname (..." and * "funcname(...", not "funcname!...". */ - if (p != NULL && (*nm == NUL || *nm == '(')) + if (p != NULL && (*nm == NUL || *nm == '(')) { n = translated_function_exists(p); + } xfree(p); return n; } /// Checks if a builtin function with the given name exists. /// -/// @param[in] name The name of the builtin function to check. -/// @param[in] len The length of "name", or -1 for NUL terminated. +/// @param[in] name name of the builtin function to check. +/// @param[in] len length of "name", or -1 for NUL terminated. /// /// @return true if "name" looks like a builtin function name: starts with a /// lower case letter and doesn't contain AUTOLOAD_CHAR. -static bool builtin_function(char_u *name, int len) +static bool builtin_function(const char *name, int len) { if (!ASCII_ISLOWER(name[0])) { - return FALSE; + return false; } - char_u *p = vim_strchr(name, AUTOLOAD_CHAR); + const char *p = (len == -1 + ? strchr(name, AUTOLOAD_CHAR) + : memchr(name, AUTOLOAD_CHAR, (size_t)len)); - return p == NULL - || (len > 0 && p > name + len); + return p == NULL; } /* @@ -22049,44 +22159,45 @@ static int prof_self_cmp(const void *s1, const void *s2) } -/* - * If "name" has a package name try autoloading the script for it. - * Return TRUE if a package was loaded. - */ -static int -script_autoload ( - char_u *name, - int reload /* load script again when already loaded */ -) +/// If name has a package name try autoloading the script for it +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// @param[in] reload If true, load script again when already loaded. +/// +/// @return true if a package was loaded. +static bool script_autoload(const char *const name, const size_t name_len, + const bool reload) { - char_u *p; - char_u *scriptname, *tofree; - int ret = FALSE; - int i; - - /* If there is no '#' after name[0] there is no package name. */ - p = vim_strchr(name, AUTOLOAD_CHAR); - if (p == NULL || p == name) - return FALSE; + // If there is no '#' after name[0] there is no package name. + const char *p = memchr(name, AUTOLOAD_CHAR, name_len); + if (p == NULL || p == name) { + return false; + } - tofree = scriptname = autoload_name(name); + bool ret = false; + char *tofree = autoload_name(name, name_len); + char *scriptname = tofree; - /* Find the name in the list of previously loaded package names. Skip - * "autoload/", it's always the same. */ - for (i = 0; i < ga_loaded.ga_len; ++i) - if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) + // Find the name in the list of previously loaded package names. Skip + // "autoload/", it's always the same. + int i = 0; + for (; i < ga_loaded.ga_len; i++) { + if (STRCMP(((char **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0) { break; - if (!reload && i < ga_loaded.ga_len) - ret = FALSE; /* was loaded already */ - else { - /* Remember the name if it wasn't loaded already. */ + } + } + if (!reload && i < ga_loaded.ga_len) { + ret = false; // Was loaded already. + } else { + // Remember the name if it wasn't loaded already. if (i == ga_loaded.ga_len) { - GA_APPEND(char_u *, &ga_loaded, scriptname); + GA_APPEND(char *, &ga_loaded, scriptname); tofree = NULL; } // Try loading the package from $VIMRUNTIME/autoload/<name>.vim - if (source_runtime(scriptname, 0) == OK) { + if (source_runtime((char_u *)scriptname, 0) == OK) { ret = true; } } @@ -22095,21 +22206,29 @@ script_autoload ( return ret; } -/* - * Return the autoload script name for a function or variable name. - */ -static char_u *autoload_name(char_u *name) +/// Return the autoload script name for a function or variable name +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// +/// @return [allocated] autoload script name. +static char *autoload_name(const char *const name, const size_t name_len) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT { - /* Get the script file name: replace '#' with '/', append ".vim". */ - char_u *scriptname = xmalloc(STRLEN(name) + 14); - STRCPY(scriptname, "autoload/"); - STRCAT(scriptname, name); - *vim_strrchr(scriptname, AUTOLOAD_CHAR) = NUL; - STRCAT(scriptname, ".vim"); - - char_u *p; - while ((p = vim_strchr(scriptname, AUTOLOAD_CHAR)) != NULL) - *p = '/'; + // Get the script file name: replace '#' with '/', append ".vim". + char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); + memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); + memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); + size_t auchar_idx = 0; + for (size_t i = sizeof("autoload/") - 1; + i - sizeof("autoload/") + 1 < name_len; + i++) { + if (scriptname[i] == AUTOLOAD_CHAR) { + scriptname[i] = '/'; + auchar_idx = i; + } + } + memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); return scriptname; } @@ -22582,24 +22701,24 @@ call_user_func( smsg(_("calling %s"), sourcing_name); if (p_verbose >= 14) { - char_u buf[MSG_BUF_LEN]; - - msg_puts((char_u *)"("); - for (int i = 0; i < argcount; ++i) { + msg_puts("("); + for (int i = 0; i < argcount; i++) { if (i > 0) { - msg_puts((char_u *)", "); + msg_puts(", "); } if (argvars[i].v_type == VAR_NUMBER) { msg_outnum((long)argvars[i].vval.v_number); } else { // Do not want errors such as E724 here. emsg_off++; - char_u *s = (char_u *) encode_tv2string(&argvars[i], NULL); - char_u *tofree = s; + char *tofree = encode_tv2string(&argvars[i], NULL); + char *s = tofree; emsg_off--; if (s != NULL) { - if (vim_strsize(s) > MSG_BUF_CLEN) { - trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN); + if (vim_strsize((char_u *)s) > MSG_BUF_CLEN) { + char buf[MSG_BUF_LEN]; + trunc_string((char_u *)s, (char_u *)buf, MSG_BUF_CLEN, + sizeof(buf)); s = buf; } msg_puts(s); @@ -22607,9 +22726,9 @@ call_user_func( } } } - msg_puts((char_u *)")"); + msg_puts(")"); } - msg_puts((char_u *)"\n"); /* don't overwrite this either */ + msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); --no_wait_return; @@ -22700,7 +22819,7 @@ call_user_func( xfree(tofree); } } - msg_puts((char_u *)"\n"); /* don't overwrite this either */ + msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); --no_wait_return; @@ -22718,7 +22837,7 @@ call_user_func( verbose_enter_scroll(); smsg(_("continuing in %s"), sourcing_name); - msg_puts((char_u *)"\n"); /* don't overwrite this either */ + msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); --no_wait_return; @@ -23172,23 +23291,23 @@ static var_flavour_T var_flavour(char_u *varname) } /// Search hashitem in parent scope. -hashitem_T *find_hi_in_scoped_ht(char_u *name, hashtab_T **pht) +hashitem_T *find_hi_in_scoped_ht(const char *name, hashtab_T **pht) { - funccall_T *old_current_funccal = current_funccal; - hashtab_T *ht; - hashitem_T *hi = NULL; - char_u *varname; - if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) { return NULL; } + funccall_T *old_current_funccal = current_funccal; + hashitem_T *hi = NULL; + const size_t namelen = strlen(name); + const char *varname; + // Search in parent scope which is possible to reference from lambda current_funccal = current_funccal->func->uf_scoped; while (current_funccal != NULL) { - ht = find_var_ht(name, &varname); + hashtab_T *ht = find_var_ht(name, namelen, &varname); if (ht != NULL && *varname != NUL) { - hi = hash_find(ht, varname); + hi = hash_find_len(ht, varname, namelen - (varname - name)); if (!HASHITEM_EMPTY(hi)) { *pht = ht; break; @@ -23205,23 +23324,24 @@ hashitem_T *find_hi_in_scoped_ht(char_u *name, hashtab_T **pht) } /// Search variable in parent scope. -dictitem_T *find_var_in_scoped_ht(char_u *name, int no_autoload) +dictitem_T *find_var_in_scoped_ht(const char *name, const size_t namelen, + int no_autoload) { - dictitem_T *v = NULL; - funccall_T *old_current_funccal = current_funccal; - hashtab_T *ht; - char_u *varname; - if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) { return NULL; } + dictitem_T *v = NULL; + funccall_T *old_current_funccal = current_funccal; + const char *varname; + // Search in parent scope which is possible to reference from lambda current_funccal = current_funccal->func->uf_scoped; while (current_funccal) { - ht = find_var_ht(name, &varname); + hashtab_T *ht = find_var_ht(name, namelen, &varname); if (ht != NULL && *varname != NUL) { - v = find_var_in_ht(ht, *name, varname, no_autoload); + v = find_var_in_ht(ht, *name, varname, + namelen - (size_t)(varname - name), no_autoload); if (v != NULL) { break; } @@ -23230,7 +23350,7 @@ dictitem_T *find_var_in_scoped_ht(char_u *name, int no_autoload) break; } current_funccal = current_funccal->func->uf_scoped; - } + } current_funccal = old_current_funccal; return v; @@ -24137,10 +24257,12 @@ bool eval_has_provider(char *name) { #define check_provider(name) \ if (has_##name == -1) { \ - has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \ if (!has_##name) { \ - script_autoload((uint8_t *)"provider#" #name "#Call", false); \ - has_##name = !!find_func((uint8_t *)"provider#" #name "#Call"); \ + script_autoload("provider#" #name "#Call", \ + sizeof("provider#" #name "#Call") - 1, \ + false); \ + has_##name = !!find_func((char_u *)"provider#" #name "#Call"); \ } \ } |