diff options
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 514 |
1 files changed, 282 insertions, 232 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3757dc6c04..8ec1e51297 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -55,7 +55,7 @@ // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead -#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ +#define DICT_MAXNEST 100 // maximum nesting of lists and dicts static char *e_letunexp = N_("E18: Unexpected characters in :let"); @@ -97,7 +97,7 @@ static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL}; #define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1]) #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) -static int echo_attr = 0; /* attributes used for ":echo" */ +static int echo_attr = 0; // attributes used for ":echo" // The names of packages that once were loaded are remembered. static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; @@ -106,16 +106,16 @@ static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; * Info used by a ":for" loop. */ typedef struct { - int fi_semicolon; /* TRUE if ending in '; var]' */ - int fi_varcount; /* nr of variables in the list */ - listwatch_T fi_lw; /* keep an eye on the item used. */ - list_T *fi_list; /* list being used */ + int fi_semicolon; // TRUE if ending in '; var]' + int fi_varcount; // nr of variables in the list + listwatch_T fi_lw; // keep an eye on the item used. + list_T *fi_list; // list being used } forinfo_T; -/* values for vv_flags: */ -#define VV_COMPAT 1 /* compatible, also used without "v:" */ -#define VV_RO 2 /* read-only */ -#define VV_RO_SBX 4 /* read-only in the sandbox */ +// values for vv_flags: +#define VV_COMPAT 1 // compatible, also used without "v:" +#define VV_RO 2 // read-only +#define VV_RO_SBX 4 // read-only in the sandbox #define VV(idx, name, type, flags) \ [idx] = { \ @@ -232,7 +232,7 @@ static struct vimvar { }; #undef VV -/* shorthand */ +// shorthand #define vv_type vv_di.di_tv.v_type #define vv_nr vv_di.di_tv.vval.v_number #define vv_special vv_di.di_tv.vval.v_special @@ -337,12 +337,14 @@ void eval_init(void) else p->vv_di.di_flags = DI_FLAGS_FIX; - /* add to v: scope dict, unless the value is not always available */ - if (p->vv_type != VAR_UNKNOWN) + // add to v: scope dict, unless the value is not always available + if (p->vv_type != VAR_UNKNOWN) { hash_add(&vimvarht, p->vv_di.di_key); - if (p->vv_flags & VV_COMPAT) - /* add to compat scope dict */ + } + if (p->vv_flags & VV_COMPAT) { + // add to compat scope dict hash_add(&compat_hashtab, p->vv_di.di_key); + } } vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; @@ -416,16 +418,16 @@ void eval_clear(void) } } hash_clear(&vimvarht); - hash_init(&vimvarht); /* garbage_collect() will access it */ + hash_init(&vimvarht); // garbage_collect() will access it hash_clear(&compat_hashtab); free_scriptnames(); free_locales(); - /* global variables */ + // global variables vars_clear(&globvarht); - /* autoloaded script names */ + // autoloaded script names ga_clear_strings(&ga_loaded); /* Script-local variables. First clear all the variables and in a second @@ -472,25 +474,25 @@ static char_u *redir_varname = NULL; int var_redir_start( char_u *name, - int append /* append to an existing variable */ + int append // append to an existing variable ) { int save_emsg; int err; typval_T tv; - /* Catch a bad name early. */ + // Catch a bad name early. if (!eval_isnamec1(*name)) { EMSG(_(e_invarg)); return FAIL; } - /* Make a copy of the name, it is used in redir_lval until redir ends. */ + // Make a copy of the name, it is used in redir_lval until redir ends. redir_varname = vim_strsave(name); redir_lval = xcalloc(1, sizeof(lval_T)); - /* The output is stored in growarray "redir_ga" until redirection ends. */ + // The output is stored in growarray "redir_ga" until redirection ends. ga_init(&redir_ga, (int)sizeof(char), 500); // Parse the variable name (can be a dict or list entry). @@ -499,12 +501,13 @@ var_redir_start( if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL) { clear_lval(redir_lval); - if (redir_endp != NULL && *redir_endp != NUL) - /* Trailing characters are present after the variable name */ + if (redir_endp != NULL && *redir_endp != NUL) { + // Trailing characters are present after the variable name EMSG(_(e_trailing)); - else + } else { EMSG(_(e_invarg)); - redir_endp = NULL; /* don't store a value, only cleanup */ + } + redir_endp = NULL; // don't store a value, only cleanup var_redir_stop(); return FAIL; } @@ -524,7 +527,7 @@ var_redir_start( err = did_emsg; did_emsg |= save_emsg; if (err) { - redir_endp = NULL; /* don't store a value, only cleanup */ + redir_endp = NULL; // don't store a value, only cleanup var_redir_stop(); return FAIL; } @@ -548,10 +551,11 @@ void var_redir_str(char_u *value, int value_len) if (redir_lval == NULL) return; - if (value_len == -1) - len = (int)STRLEN(value); /* Append the entire string */ - else - len = value_len; /* Append only "value_len" characters */ + if (value_len == -1) { + len = (int)STRLEN(value); // Append the entire string + } else { + len = value_len; // Append only "value_len" characters + } ga_grow(&redir_ga, len); memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len); @@ -567,9 +571,9 @@ void var_redir_stop(void) typval_T tv; if (redir_lval != NULL) { - /* If there was no error: assign the text to the variable. */ + // If there was no error: assign the text to the variable. if (redir_endp != NULL) { - ga_append(&redir_ga, NUL); /* Append the trailing NUL. */ + ga_append(&redir_ga, NUL); // Append the trailing NUL. tv.v_type = VAR_STRING; tv.vval.v_string = redir_ga.ga_data; // Call get_lval() again, if it's inside a Dict or List it may @@ -670,7 +674,7 @@ eval_to_bool( char_u *arg, bool *error, char_u **nextcmd, - int skip /* only parse, don't execute */ + int skip // only parse, don't execute ) { typval_T tv; @@ -1125,8 +1129,9 @@ void *call_func_retlist(const char_u *func, int argc, typval_T *argv) * counted for the script/function itself. * Should always be called in pair with prof_child_exit(). */ -void prof_child_enter(proftime_T *tm /* place to store waittime */ - ) +void prof_child_enter( + proftime_T *tm // place to store waittime +) { funccall_T *fc = get_current_funccal(); @@ -1141,8 +1146,9 @@ void prof_child_enter(proftime_T *tm /* place to store waittime */ * Take care of time spent in a child. * Should always be called after prof_child_enter(). */ -void prof_child_exit(proftime_T *tm /* where waittime was stored */ - ) +void prof_child_exit( + proftime_T *tm // where waittime was stored +) { funccall_T *fc = get_current_funccal(); @@ -1167,7 +1173,6 @@ int eval_foldexpr(char_u *arg, int *cp) { typval_T tv; varnumber_T retval; - char_u *s; int use_sandbox = was_set_insecurely((char_u *)"foldexpr", OPT_LOCAL); @@ -1176,20 +1181,21 @@ int eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textlock; *cp = NUL; - if (eval0(arg, &tv, NULL, TRUE) == FAIL) + if (eval0(arg, &tv, NULL, true) == FAIL) { retval = 0; - else { - /* If the result is a number, just return the number. */ - if (tv.v_type == VAR_NUMBER) + } else { + // If the result is a number, just return the number. + if (tv.v_type == VAR_NUMBER) { retval = tv.vval.v_number; - else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) + } else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) { retval = 0; - else { - /* If the result is a string, check if there is a non-digit before - * the number. */ - s = tv.vval.v_string; - if (!ascii_isdigit(*s) && *s != '-') + } else { + // If the result is a string, check if there is a non-digit before + // the number. + char_u *s = tv.vval.v_string; + if (!ascii_isdigit(*s) && *s != '-') { *cp = *s++; + } retval = atol((char *)s); } tv_clear(&tv); @@ -1529,10 +1535,10 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count, const char_u *s; if (*arg == '[') { - /* "[var, var]": find the matching ']'. */ + // "[var, var]": find the matching ']'. p = arg; for (;; ) { - p = skipwhite(p + 1); /* skip whites after '[', ';' or ',' */ + p = skipwhite(p + 1); // skip whites after '[', ';' or ',' s = skip_var_one(p); if (s == p) { EMSG2(_(e_invarg2), p); @@ -1959,7 +1965,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, hashtab_T *ht; int quiet = flags & GLV_QUIET; - /* Clear everything in "lp". */ + // Clear everything in "lp". memset(lp, 0, sizeof(lval_T)); if (skip) { @@ -1977,7 +1983,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, (const char_u **)&expr_end, fne_flags); if (expr_start != NULL) { - /* Don't expand the name when we already know there is an error. */ + // Don't expand the name when we already know there is an error. if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p) && *p != '[' && *p != '.') { EMSG(_(e_trailing)); @@ -2057,7 +2063,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, } p = key + len; } else { - /* Get the index [expr] or the first index [expr: ]. */ + // Get the index [expr] or the first index [expr: ]. p = skipwhite(p + 1); if (*p == ':') { empty1 = true; @@ -2073,7 +2079,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, } } - /* Optionally get the second index [ :expr]. */ + // Optionally get the second index [ :expr]. if (*p == ':') { if (lp->ll_tv->v_type == VAR_DICT) { if (!quiet) { @@ -2119,8 +2125,8 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, return NULL; } - /* Skip to past ']'. */ - ++p; + // Skip to past ']'. + p++; } if (lp->ll_tv->v_type == VAR_DICT) { @@ -2546,7 +2552,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) if (cmdidx == CMD_let || cmdidx == CMD_const) { xp->xp_context = EXPAND_USER_VARS; if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL) { - /* ":let var1 var2 ...": find last space. */ + // ":let var1 var2 ...": find last space. for (p = arg + STRLEN(arg); p >= arg; ) { xp->xp_pattern = p; MB_PTR_BACK(arg, p); @@ -2575,7 +2581,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) } } else if (c == '$') { - /* environment variable */ + // environment variable xp->xp_context = EXPAND_ENV_VARS; } else if (c == '=') { got_eq = TRUE; @@ -2587,18 +2593,20 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) } else if ((c == '<' || c == '#') && xp->xp_context == EXPAND_FUNCTIONS && vim_strchr(xp->xp_pattern, '(') == NULL) { - /* Function name can start with "<SNR>" and contain '#'. */ + // Function name can start with "<SNR>" and contain '#'. break; } else if (cmdidx != CMD_let || got_eq) { - if (c == '"') { /* string */ - while ((c = *++xp->xp_pattern) != NUL && c != '"') - if (c == '\\' && xp->xp_pattern[1] != NUL) - ++xp->xp_pattern; + if (c == '"') { // string + while ((c = *++xp->xp_pattern) != NUL && c != '"') { + if (c == '\\' && xp->xp_pattern[1] != NUL) { + xp->xp_pattern++; + } + } xp->xp_context = EXPAND_NOTHING; - } else if (c == '\'') { /* literal string */ - /* Trick: '' is like stopping and starting a literal string. */ - while ((c = *++xp->xp_pattern) != NUL && c != '\'') - /* skip */; + } else if (c == '\'') { // literal string + // Trick: '' is like stopping and starting a literal string. + while ((c = *++xp->xp_pattern) != NUL && c != '\'') { + } xp->xp_context = EXPAND_NOTHING; } else if (c == '|') { if (xp->xp_pattern[1] == '|') { @@ -2613,15 +2621,14 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) * anyway. */ xp->xp_context = EXPAND_EXPRESSION; arg = xp->xp_pattern; - if (*arg != NUL) - while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) - /* skip */; + if (*arg != NUL) { + while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) { + } + } } xp->xp_pattern = arg; } -// TODO(ZyX-I): move to eval/ex_cmds - /* * ":unlet[!] var1 ... " command. */ @@ -2811,8 +2818,7 @@ int do_unlet(const char *const name, const size_t name_len, const int forceit) if (ht != NULL && *varname != NUL) { dict_T *d = get_current_funccal_dict(ht); - if (d == NULL) - { + if (d == NULL) { if (ht == &globvarht) { d = &globvardict; } else if (ht == &compat_hashtab) { @@ -2905,7 +2911,7 @@ static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, } else if (lp->ll_range) { listitem_T *li = lp->ll_li; - /* (un)lock a range of List items. */ + // (un)lock a range of List items. while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) { tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock); li = TV_LIST_ITEM_NEXT(lp->ll_list, li); @@ -2955,7 +2961,7 @@ static char_u *cat_prefix_varname(int prefix, char_u *name) if (len > varnamebuflen) { xfree(varnamebuf); - len += 10; /* some additional space */ + len += 10; // some additional space varnamebuf = xmalloc(len); varnamebuflen = len; } @@ -2984,7 +2990,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) tdone = 0; } - /* Global variables */ + // Global variables if (gdone < globvarht.ht_used) { if (gdone++ == 0) hi = globvarht.ht_array; @@ -2997,7 +3003,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return hi->hi_key; } - /* b: variables */ + // b: variables ht = &curbuf->b_vars->dv_hashtab; if (bdone < ht->ht_used) { if (bdone++ == 0) @@ -3009,7 +3015,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return cat_prefix_varname('b', hi->hi_key); } - /* w: variables */ + // w: variables ht = &curwin->w_vars->dv_hashtab; if (wdone < ht->ht_used) { if (wdone++ == 0) @@ -3021,7 +3027,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return cat_prefix_varname('w', hi->hi_key); } - /* t: variables */ + // t: variables ht = &curtab->tp_vars->dv_hashtab; if (tdone < ht->ht_used) { if (tdone++ == 0) @@ -3047,7 +3053,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) /// Return TRUE if "pat" matches "text". /// Does not use 'cpo' and always uses 'magic'. -static int pattern_match(char_u *pat, char_u *text, int ic) +static int pattern_match(char_u *pat, char_u *text, bool ic) { int matches = 0; regmatch_T regmatch; @@ -3162,8 +3168,9 @@ int eval1(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, evaluate && result) == FAIL) /* recursive! */ + if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive! return FAIL; + } /* * Check for the ":". @@ -3357,10 +3364,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) char_u *p; int i; exptype_T type = TYPE_UNKNOWN; - int type_is = FALSE; /* TRUE for "is" and "isnot" */ + bool type_is = false; // true for "is" and "isnot" int len = 2; varnumber_T n1, n2; - int ic; + bool ic; /* * Get the first variable. @@ -3398,7 +3405,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) } if (!isalnum(p[len]) && p[len] != '_') { type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL; - type_is = TRUE; + type_is = true; } } break; @@ -3408,23 +3415,18 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) * If there is a comparative operator, use it. */ if (type != TYPE_UNKNOWN) { - /* extra question mark appended: ignore case */ + // extra question mark appended: ignore case if (p[len] == '?') { - ic = TRUE; - ++len; - } - /* extra '#' appended: match case */ - else if (p[len] == '#') { - ic = FALSE; - ++len; - } - /* nothing appended: use 'ignorecase' */ - else + ic = true; + len++; + } else if (p[len] == '#') { // extra '#' appended: match case + ic = false; + len++; + } else { // nothing appended: use 'ignorecase' ic = p_ic; + } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(p + len); if (eval5(arg, &var2, evaluate) == FAIL) { tv_clear(rettv); @@ -3569,7 +3571,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) const char *const s1 = tv_get_string_buf(rettv, buf1); const char *const s2 = tv_get_string_buf(&var2, buf2); if (type != TYPE_MATCH && type != TYPE_NOMATCH) { - i = mb_strcmp_ic((bool)ic, s1, s2); + i = mb_strcmp_ic(ic, s1, s2); } else { i = 0; } @@ -3730,7 +3732,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate) } tv_clear(rettv); - /* If there is a float on either side the result is a float. */ + // If there is a float on either side the result is a float. if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) { if (op == '+') f1 = f1 + f2; @@ -4169,7 +4171,7 @@ eval_index( char_u **arg, typval_T *rettv, int evaluate, - int verbose /* give error messages */ + int verbose // give error messages ) { bool empty1 = false; @@ -4265,7 +4267,7 @@ eval_index( } } - /* Check for the ']'. */ + // Check for the ']'. if (**arg != ']') { if (verbose) { EMSG(_(e_missbrac)); @@ -4276,7 +4278,7 @@ eval_index( } return FAIL; } - *arg = skipwhite(*arg + 1); /* skip the ']' */ + *arg = skipwhite(*arg + 1); // skip the ']' } if (evaluate) { @@ -4468,28 +4470,29 @@ int get_option_tv(const char **const arg, typval_T *const rettv, opt_type = get_option_value((char_u *)(*arg), &numval, rettv == NULL ? NULL : &stringval, opt_flags); - if (opt_type == -3) { /* invalid name */ - if (rettv != NULL) + if (opt_type == -3) { // invalid name + if (rettv != NULL) { EMSG2(_("E113: Unknown option: %s"), *arg); + } ret = FAIL; } else if (rettv != NULL) { - if (opt_type == -2) { /* hidden string option */ + if (opt_type == -2) { // hidden string option rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - } else if (opt_type == -1) { /* hidden number option */ + } else if (opt_type == -1) { // hidden number option rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; - } else if (opt_type == 1) { /* number option */ + } else if (opt_type == 1) { // number option rettv->v_type = VAR_NUMBER; rettv->vval.v_number = numval; - } else { /* string option */ + } else { // string option rettv->v_type = VAR_STRING; rettv->vval.v_string = stringval; } } else if (working && (opt_type == -2 || opt_type == -1)) ret = FAIL; - *option_end = c; /* put back for error messages */ + *option_end = c; // put back for error messages *arg = option_end; return ret; @@ -4523,7 +4526,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) return FAIL; } - /* If only parsing, set *arg and return here */ + // If only parsing, set *arg and return here if (!evaluate) { *arg = p + 1; return OK; @@ -4547,9 +4550,9 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) case 'r': *name++ = CAR; ++p; break; case 't': *name++ = TAB; ++p; break; - case 'X': /* hex: "\x1", "\x12" */ + case 'X': // hex: "\x1", "\x12" case 'x': - case 'u': /* Unicode: "\u0023" */ + case 'u': // Unicode: "\u0023" case 'U': if (ascii_isxdigit(p[1])) { int n, nr; @@ -4578,7 +4581,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) } break; - /* octal: "\1", "\12", "\123" */ + // octal: "\1", "\12", "\123" case '0': case '1': case '2': @@ -4647,7 +4650,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate) return FAIL; } - /* If only parsing return after setting "*arg" */ + // If only parsing return after setting "*arg" if (!evaluate) { *arg = p + 1; return OK; @@ -5346,10 +5349,12 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) * But {} is an empty Dictionary. */ if (*start != '}') { - if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */ + if (eval1(&start, &tv, false) == FAIL) { // recursive! return FAIL; - if (*start == '}') + } + if (*start == '}') { return NOTDONE; + } } if (evaluate) { @@ -5360,8 +5365,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) *arg = skipwhite(*arg + 1); while (**arg != '}' && **arg != NUL) { - if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ + if (eval1(arg, &tvkey, evaluate) == FAIL) { // recursive! goto failret; + } if (**arg != ':') { EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg); tv_clear(&tvkey); @@ -6109,6 +6115,10 @@ void common_function(typval_T *argvars, typval_T *rettv, list = argvars[arg_idx].vval.v_list; if (tv_list_len(list) == 0) { arg_idx = 0; + } else if (tv_list_len(list) > MAX_FUNC_ARGS) { + emsg_funcname((char *)e_toomanyarg, name); + xfree(name); + goto theend; } } } @@ -6312,7 +6322,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) win_T * find_win_by_nr( typval_T *vp, - tabpage_T *tp /* NULL for current tab page */ + tabpage_T *tp // NULL for current tab page ) { int nr = (int)tv_get_number_chk(vp, NULL); @@ -6375,7 +6385,7 @@ void getwinvar( typval_T *argvars, typval_T *rettv, - int off /* 1 for gettabwinvar() */ + int off // 1 for gettabwinvar() ) { win_T *win, *oldcurwin; @@ -7102,10 +7112,16 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool callback_from_typval(Callback *const callback, typval_T *const arg) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { + int r = OK; + if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) { callback->data.partial = arg->vval.v_partial; callback->data.partial->pt_refcount++; callback->type = kCallbackPartial; + } else if (arg->v_type == VAR_STRING + && arg->vval.v_string != NULL + && ascii_isdigit(*arg->vval.v_string)) { + r = FAIL; } else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) { char_u *name = arg->vval.v_string; func_ref(name); @@ -7114,6 +7130,10 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg) } else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) { callback->type = kCallbackNone; } else { + r = FAIL; + } + + if (r == FAIL) { EMSG(_("E921: Invalid callback argument")); return false; } @@ -7592,19 +7612,19 @@ pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum, if (name[0] == 'w' && dollar_lnum) { pos.col = 0; - if (name[1] == '0') { /* "w0": first visible line */ + if (name[1] == '0') { // "w0": first visible line update_topline(); // In silent Ex mode topline is zero, but that's not a valid line // number; use one instead. pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1; return &pos; - } else if (name[1] == '$') { /* "w$": last visible line */ + } else if (name[1] == '$') { // "w$": last visible line validate_botline(); // In silent Ex mode botline is zero, return zero then. pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0; return &pos; } - } else if (name[0] == '$') { /* last column or line */ + } else if (name[0] == '$') { // last column or line if (dollar_lnum) { pos.lnum = curbuf->b_ml.ml_line_count; pos.col = 0; @@ -7744,7 +7764,7 @@ int get_name_len(const char **const arg, { int len; - *alias = NULL; /* default to no alias */ + *alias = NULL; // default to no alias if ((*arg)[0] == (char)K_SPECIAL && (*arg)[1] == (char)KS_EXTRA && (*arg)[2] == (char)KE_SNR) { @@ -7754,7 +7774,7 @@ int get_name_len(const char **const arg, } len = eval_fname_script(*arg); if (len > 0) { - /* literal "<SID>", "s:" or "<SNR>" */ + // literal "<SID>", "s:" or "<SNR>" *arg += len; } @@ -7803,7 +7823,7 @@ int get_name_len(const char **const arg, // Return a pointer to just after the name. Equal to "arg" if there is no // valid name. const char_u *find_name_end(const char_u *arg, const char_u **expr_start, - const char_u **expr_end, int flags) + const char_u **expr_end, int flags) { int mb_nest = 0; int br_nest = 0; @@ -7917,7 +7937,7 @@ static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start, } xfree(temp_result); - *in_end = c1; /* put char back for error messages */ + *in_end = c1; // put char back for error messages *expr_start = '{'; *expr_end = '}'; @@ -7926,7 +7946,7 @@ static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start, (const char_u **)&expr_start, (const char_u **)&expr_end, 0); if (expr_start != NULL) { - /* Further expansion! */ + // Further expansion! temp_result = make_expanded_name(retval, expr_start, expr_end, temp_result); xfree(retval); @@ -8140,10 +8160,7 @@ char_u *v_throwpoint(char_u *oldval) */ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) { - char_u *oldval; - char_u *newval; - - oldval = vimvars[VV_CMDARG].vv_str; + char_u *oldval = vimvars[VV_CMDARG].vv_str; if (eap == NULL) { xfree(oldval); vimvars[VV_CMDARG].vv_str = oldarg; @@ -8159,14 +8176,18 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) if (eap->read_edit) len += 7; - if (eap->force_ff != 0) - len += STRLEN(eap->cmd + eap->force_ff) + 6; - if (eap->force_enc != 0) + if (eap->force_ff != 0) { + len += 10; // " ++ff=unix" + } + if (eap->force_enc != 0) { len += STRLEN(eap->cmd + eap->force_enc) + 7; - if (eap->bad_char != 0) - len += 7 + 4; /* " ++bad=" + "keep" or "drop" */ + } + if (eap->bad_char != 0) { + len += 7 + 4; // " ++bad=" + "keep" or "drop" + } - newval = xmalloc(len + 1); + const size_t newval_len = len + 1; + char_u *newval = xmalloc(newval_len); if (eap->force_bin == FORCE_BIN) sprintf((char *)newval, " ++bin"); @@ -8178,18 +8199,23 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) if (eap->read_edit) STRCAT(newval, " ++edit"); - if (eap->force_ff != 0) - sprintf((char *)newval + STRLEN(newval), " ++ff=%s", - eap->cmd + eap->force_ff); - if (eap->force_enc != 0) - sprintf((char *)newval + STRLEN(newval), " ++enc=%s", - eap->cmd + eap->force_enc); - if (eap->bad_char == BAD_KEEP) + if (eap->force_ff != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++ff=%s", + eap->force_ff == 'u' ? "unix" : + eap->force_ff == 'd' ? "dos" : "mac"); + } + if (eap->force_enc != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++enc=%s", + eap->cmd + eap->force_enc); + } + if (eap->bad_char == BAD_KEEP) { STRCPY(newval + STRLEN(newval), " ++bad=keep"); - else if (eap->bad_char == BAD_DROP) + } else if (eap->bad_char == BAD_DROP) { STRCPY(newval + STRLEN(newval), " ++bad=drop"); - else if (eap->bad_char != 0) - sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char); + } else if (eap->bad_char != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++bad=%c", + eap->bad_char); + } vimvars[VV_CMDARG].vv_str = newval; return oldval; } @@ -8282,8 +8308,8 @@ int handle_subscript( const char **const arg, typval_T *rettv, - int evaluate, /* do more than finding the end */ - int verbose /* give error messages */ + int evaluate, // do more than finding the end + int verbose // give error messages ) { int ret = OK; @@ -8393,6 +8419,27 @@ void set_selfdict(typval_T *const rettv, dict_T *const selfdict) make_partial(selfdict, rettv); } +// Turn a typeval into a string. Similar to tv_get_string_buf() but uses +// string() on Dict, List, etc. +static const char *tv_stringify(typval_T *varp, char *buf) + FUNC_ATTR_NONNULL_ALL +{ + if (varp->v_type == VAR_LIST + || varp->v_type == VAR_DICT + || varp->v_type == VAR_FUNC + || varp->v_type == VAR_PARTIAL + || varp->v_type == VAR_FLOAT) { + typval_T tmp; + + f_string(varp, &tmp, NULL); + const char *const res = tv_get_string_buf(&tmp, buf); + tv_clear(varp); + *varp = tmp; + return res; + } + return tv_get_string_buf(varp, buf); +} + // Find variable "name" in the list of variables. // Return a pointer to it if found, NULL if not found. // Careful: "a:0" variables don't have a name. @@ -8421,7 +8468,8 @@ dictitem_T *find_var(const char *const name, const size_t name_len, return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL); } -/// Find variable in hashtab +/// Find variable in hashtab. +/// When "varname" is empty returns curwin/curtab/etc vars dictionary. /// /// @param[in] ht Hashtab to find variable in. /// @param[in] htname Hashtab name (first character). @@ -9107,10 +9155,10 @@ int var_item_copy(const vimconv_T *const conv, case VAR_DICT: to->v_type = VAR_DICT; to->v_lock = 0; - if (from->vval.v_dict == NULL) + if (from->vval.v_dict == NULL) { to->vval.v_dict = NULL; - else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) { - /* use the copy made earlier */ + } else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) { + // use the copy made earlier to->vval.v_dict = from->vval.v_dict->dv_copydict; ++to->vval.v_dict->dv_refcount; } else { @@ -9243,7 +9291,10 @@ void ex_execute(exarg_T *eap) } if (!eap->skip) { - const char *const argstr = tv_get_string(&rettv); + char buf[NUMBUFLEN]; + const char *const argstr = eap->cmdidx == CMD_execute + ? tv_get_string_buf(&rettv, buf) + : tv_stringify(&rettv, buf); const size_t len = strlen(argstr); ga_grow(&ga, len + 2); if (!GA_EMPTY(&ga)) { @@ -9270,7 +9321,7 @@ void ex_execute(exarg_T *eap) MSG_ATTR(ga.ga_data, echo_attr); ui_flush(); } else if (eap->cmdidx == CMD_echoerr) { - /* We don't want to abort following commands, restore did_emsg. */ + // We don't want to abort following commands, restore did_emsg. save_did_emsg = did_emsg; msg_ext_set_kind("echoerr"); EMSG((char_u *)ga.ga_data); @@ -9325,10 +9376,7 @@ static const char *find_option_end(const char **const arg, int *const opt_flags) return p; } - -/* - * Start profiling function "fp". - */ +/// Start profiling function "fp". void func_do_profile(ufunc_T *fp) { int len = fp->uf_lines.ga_len; @@ -9372,8 +9420,9 @@ void func_dump_profile(FILE *fd) int st_len = 0; todo = (int)func_hashtab.ht_used; - if (todo == 0) - return; /* nothing to dump */ + if (todo == 0) { + return; // nothing to dump + } sorttab = xmalloc(sizeof(ufunc_T *) * todo); @@ -9442,7 +9491,7 @@ prof_sort_list( ufunc_T **sorttab, int st_len, char *title, - int prefer_self /* when equal print only self time */ + int prefer_self // when equal print only self time ) { int i; @@ -9470,8 +9519,8 @@ static void prof_func_line( int count, proftime_T *total, proftime_T *self, - int prefer_self /* when equal print only self time */ - ) + int prefer_self // when equal print only self time +) { if (count > 0) { fprintf(fd, "%5d ", count); @@ -9507,6 +9556,33 @@ static int prof_self_cmp(const void *s1, const void *s2) return profile_cmp(p1->uf_tm_self, p2->uf_tm_self); } +/// Return the autoload script name for a function or variable name +/// Caller must make sure that "name" contains AUTOLOAD_CHAR. +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// +/// @return [allocated] autoload script name. +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 *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; +} /// If name has a package name try autoloading the script for it /// @@ -9516,7 +9592,7 @@ static int prof_self_cmp(const void *s1, const void *s2) /// /// @return true if a package was loaded. bool script_autoload(const char *const name, const size_t name_len, - const bool reload) + const bool reload) { // If there is no '#' after name[0] there is no package name. const char *p = memchr(name, AUTOLOAD_CHAR, name_len); @@ -9555,34 +9631,6 @@ bool script_autoload(const char *const name, const size_t name_len, return ret; } -/// Return the autoload script name for a function or variable name -/// Caller must make sure that "name" contains AUTOLOAD_CHAR. -/// -/// @param[in] name Variable/function name. -/// @param[in] name_len Name length. -/// -/// @return [allocated] autoload script name. -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 *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; -} - /* * Called when starting to read a function line. * "sourcing_lnum" must be correct! @@ -9597,10 +9645,11 @@ void func_line_start(void *cookie) if (fp->uf_profiling && sourcing_lnum >= 1 && sourcing_lnum <= fp->uf_lines.ga_len) { fp->uf_tml_idx = sourcing_lnum - 1; - /* Skip continuation lines. */ - while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) - --fp->uf_tml_idx; - fp->uf_tml_execed = FALSE; + // Skip continuation lines. + while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) { + fp->uf_tml_idx--; + } + fp->uf_tml_execed = false; fp->uf_tml_start = profile_start(); fp->uf_tml_children = profile_zero(); fp->uf_tml_wait = profile_get_wait(); @@ -9822,14 +9871,14 @@ modify_fname( int has_fullname = 0; repeat: - /* ":p" - full path/file_name */ + // ":p" - full path/file_name if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') { has_fullname = 1; valid |= VALID_PATH; *usedlen += 2; - /* Expand "~/path" for all systems and "~user/path" for Unix */ + // Expand "~/path" for all systems and "~user/path" for Unix if ((*fnamep)[0] == '~' #if !defined(UNIX) && ((*fnamep)[1] == '/' @@ -9841,7 +9890,7 @@ repeat: && !(tilde_file && (*fnamep)[1] == NUL) ) { *fnamep = expand_env_save(*fnamep); - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -9859,20 +9908,20 @@ repeat: } } - /* FullName_save() is slow, don't use it when not needed. */ + // FullName_save() is slow, don't use it when not needed. if (*p != NUL || !vim_isAbsName(*fnamep)) { - *fnamep = (char_u *)FullName_save((char *)*fnamep, *p != NUL); - xfree(*bufp); /* free any allocated file name */ + *fnamep = (char_u *)FullName_save((char *)(*fnamep), *p != NUL); + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; } - /* Append a path separator to a directory. */ + // Append a path separator to a directory. if (os_isdir(*fnamep)) { - /* Make room for one or two extra characters. */ + // Make room for one or two extra characters. *fnamep = vim_strnsave(*fnamep, STRLEN(*fnamep) + 2); - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -9880,9 +9929,9 @@ repeat: } } - /* ":." - path relative to the current directory */ - /* ":~" - path relative to the home directory */ - /* ":8" - shortname path - postponed till after */ + // ":." - path relative to the current directory + // ":~" - path relative to the home directory + // ":8" - shortname path - postponed till after while (src[*usedlen] == ':' && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8')) { *usedlen += 2; @@ -9890,7 +9939,7 @@ repeat: continue; } pbuf = NULL; - /* Need full path first (use expand_env() to remove a "~/") */ + // Need full path first (use expand_env() to remove a "~/") if (!has_fullname) { if (c == '.' && **fnamep == '~') p = pbuf = expand_env_save(*fnamep); @@ -9908,14 +9957,14 @@ repeat: if (s != NULL) { *fnamep = s; if (pbuf != NULL) { - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = pbuf; pbuf = NULL; } } } else { - home_replace(NULL, p, dirname, MAXPATHL, TRUE); - /* Only replace it when it starts with '~' */ + home_replace(NULL, p, dirname, MAXPATHL, true); + // Only replace it when it starts with '~' if (*dirname == '~') { s = vim_strsave(dirname); *fnamep = s; @@ -9930,8 +9979,8 @@ repeat: tail = path_tail(*fnamep); *fnamelen = STRLEN(*fnamep); - /* ":h" - head, remove "/file_name", can be repeated */ - /* Don't remove the first "/" or "c:\" */ + // ":h" - head, remove "/file_name", can be repeated + // Don't remove the first "/" or "c:\" while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') { valid |= VALID_HEAD; *usedlen += 2; @@ -9941,7 +9990,7 @@ repeat: } *fnamelen = (size_t)(tail - *fnamep); if (*fnamelen == 0) { - /* Result is empty. Turn it into "." to make ":cd %:h" work. */ + // Result is empty. Turn it into "." to make ":cd %:h" work. xfree(*bufp); *bufp = *fnamep = tail = vim_strsave((char_u *)"."); *fnamelen = 1; @@ -9952,21 +10001,21 @@ repeat: } } - /* ":8" - shortname */ + // ":8" - shortname if (src[*usedlen] == ':' && src[*usedlen + 1] == '8') { *usedlen += 2; } - /* ":t" - tail, just the basename */ + // ":t" - tail, just the basename if (src[*usedlen] == ':' && src[*usedlen + 1] == 't') { *usedlen += 2; *fnamelen -= (size_t)(tail - *fnamep); *fnamep = tail; } - /* ":e" - extension, can be repeated */ - /* ":r" - root, without extension, can be repeated */ + // ":e" - extension, can be repeated + // ":r" - root, without extension, can be repeated while (src[*usedlen] == ':' && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r')) { /* find a '.' in the tail: @@ -10018,8 +10067,8 @@ repeat: *usedlen += 2; } - /* ":s?pat?foo?" - substitute */ - /* ":gs?pat?foo?" - global substitute */ + // ":s?pat?foo?" - substitute + // ":gs?pat?foo?" - global substitute if (src[*usedlen] == ':' && (src[*usedlen + 1] == 's' || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) { @@ -10039,12 +10088,12 @@ repeat: sep = *s++; if (sep) { - /* find end of pattern */ + // find end of pattern p = vim_strchr(s, sep); if (p != NULL) { pat = vim_strnsave(s, (int)(p - s)); s = p + 1; - /* find end of substitution */ + // find end of substitution p = vim_strchr(s, sep); if (p != NULL) { sub = vim_strnsave(s, (int)(p - s)); @@ -10061,9 +10110,10 @@ repeat: } xfree(pat); } - /* after using ":s", repeat all the modifiers */ - if (didit) + // after using ":s", repeat all the modifiers + if (didit) { goto repeat; + } } } @@ -10102,7 +10152,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *save_cpo; char_u *zero_width = NULL; - /* Make 'cpoptions' empty, so that the 'l' flag doesn't work here */ + // Make 'cpoptions' empty, so that the 'l' flag doesn't work here save_cpo = p_cpo; p_cpo = empty_option; @@ -10116,7 +10166,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, tail = str; end = str + STRLEN(str); while (vim_regexec_nl(®match, str, (colnr_T)(tail - str))) { - /* Skip empty match except for first match. */ + // Skip empty match except for first match. if (regmatch.startp[0] == regmatch.endp[0]) { if (zero_width == regmatch.startp[0]) { // avoid getting stuck on a match with an empty string @@ -10138,7 +10188,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, ga_grow(&ga, (int)((end - tail) + sublen - (regmatch.endp[0] - regmatch.startp[0]))); - /* copy the text up to where the match is */ + // copy the text up to where the match is int i = (int)(regmatch.startp[0] - tail); memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i); // add the substituted text |