diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2022-08-30 23:29:44 -0600 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2022-08-30 23:29:44 -0600 |
commit | 442d4e54c30b8e193e3f6e4d32b43e96815bccd7 (patch) | |
tree | b52e341e7db3d2428d8762a7ecf9b58dd84ff6c4 /src/nvim/eval.c | |
parent | 8436383af96dc7afa3596fc22c012d68e76f47f8 (diff) | |
parent | f4274d0f62625683486d3912dcd6e8e45877c6a4 (diff) | |
download | rneovim-442d4e54c30b8e193e3f6e4d32b43e96815bccd7.tar.gz rneovim-442d4e54c30b8e193e3f6e4d32b43e96815bccd7.tar.bz2 rneovim-442d4e54c30b8e193e3f6e4d32b43e96815bccd7.zip |
Merge remote-tracking branch 'upstream/master' into usermarks
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 1054 |
1 files changed, 330 insertions, 724 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5911a93099..2dbaa2f8ac 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1,24 +1,18 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * eval.c: Expression evaluation. - */ +// eval.c: Expression evaluation. #include <math.h> #include <stdlib.h> -#include "auto/config.h" - -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif - #include "nvim/ascii.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/change.h" #include "nvim/channel.h" #include "nvim/charset.h" +#include "nvim/cmdhist.h" #include "nvim/cursor.h" #include "nvim/edit.h" #include "nvim/eval.h" @@ -28,23 +22,29 @@ #include "nvim/eval/typval.h" #include "nvim/eval/userfunc.h" #include "nvim/eval/vars.h" +#include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" +#include "nvim/ex_docmd.h" +#include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/ex_session.h" -#include "nvim/fileio.h" #include "nvim/getchar.h" #include "nvim/highlight_group.h" +#include "nvim/locale.h" #include "nvim/lua/executor.h" #include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/move.h" #include "nvim/ops.h" #include "nvim/option.h" +#include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/shell.h" #include "nvim/path.h" +#include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/sign.h" @@ -71,19 +71,15 @@ static char * const namespace_char = "abglstvw"; /// Variable used for g: static ScopeDictDictItem globvars_var; -/* - * Old Vim variables such as "v:version" are also available without the "v:". - * Also in functions. We need a special hashtable for them. - */ +/// Old Vim variables such as "v:version" are also available without the "v:". +/// Also in functions. We need a special hashtable for them. static hashtab_T compat_hashtab; /// Used for checking if local variables or arguments used in a lambda. bool *eval_lavars_used = NULL; -/* - * Array to hold the hashtab with variables local to each sourced script. - * Each item holds a variable (nameless) that points to the dict_T. - */ +/// Array to hold the hashtab with variables local to each sourced script. +/// Each item holds a variable (nameless) that points to the dict_T. typedef struct { ScopeDictDictItem sv_var; dict_T sv_dict; @@ -98,11 +94,9 @@ 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 *), 4, NULL }; -/* - * Info used by a ":for" loop. - */ +/// Info used by a ":for" loop. typedef struct { - int fi_semicolon; // TRUE if ending in '; var]' + 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 @@ -356,8 +350,6 @@ void eval_init(void) { vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; - struct vimvar *p; - init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE); init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE); vimvardict.dv_lock = VAR_FIXED; @@ -365,7 +357,7 @@ void eval_init(void) func_init(); for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { - p = &vimvars[i]; + struct vimvar *p = &vimvars[i]; assert(STRLEN(p->vv_name) <= VIMVAR_KEY_LEN); STRCPY(p->vv_di.di_key, p->vv_name); if (p->vv_flags & VV_RO) { @@ -447,10 +439,8 @@ void eval_init(void) #if defined(EXITFREE) void eval_clear(void) { - struct vimvar *p; - for (size_t i = 0; i < ARRAY_SIZE(vimvars); i++) { - p = &vimvars[i]; + struct vimvar *p = &vimvars[i]; if (p->vv_di.di_tv.v_type == VAR_STRING) { XFREE_CLEAR(p->vv_str); } else if (p->vv_di.di_tv.v_type == VAR_LIST) { @@ -473,13 +463,13 @@ void eval_clear(void) // autoloaded script names ga_clear_strings(&ga_loaded); - /* Script-local variables. First clear all the variables and in a second - * loop free the scriptvar_T, because a variable in one script might hold - * a reference to the whole scope of another script. */ - for (int i = 1; i <= ga_scripts.ga_len; ++i) { + // Script-local variables. First clear all the variables and in a second + // loop free the scriptvar_T, because a variable in one script might hold + // a reference to the whole scope of another script. + for (int i = 1; i <= ga_scripts.ga_len; i++) { vars_clear(&SCRIPT_VARS(i)); } - for (int i = 1; i <= ga_scripts.ga_len; ++i) { + for (int i = 1; i <= ga_scripts.ga_len; i++) { xfree(SCRIPT_SV(i)); } ga_clear(&ga_scripts); @@ -518,10 +508,6 @@ static char *redir_varname = NULL; /// @return OK if successfully completed the setup. FAIL otherwise. int var_redir_start(char *name, int append) { - int save_emsg; - int err; - typval_T tv; - // Catch a bad name early. if (!eval_isnamec1(*name)) { emsg(_(e_invarg)); @@ -553,10 +539,11 @@ int var_redir_start(char *name, int append) return FAIL; } - /* check if we can write to the variable: set it to or append an empty - * string */ - save_emsg = did_emsg; - did_emsg = FALSE; + // check if we can write to the variable: set it to or append an empty + // string + int save_emsg = did_emsg; + did_emsg = false; + typval_T tv; tv.v_type = VAR_STRING; tv.vval.v_string = ""; if (append) { @@ -565,7 +552,7 @@ int var_redir_start(char *name, int append) set_var_lval(redir_lval, redir_endp, &tv, true, false, "="); } clear_lval(redir_lval); - err = did_emsg; + int err = did_emsg; did_emsg |= save_emsg; if (err) { redir_endp = NULL; // don't store a value, only cleanup @@ -585,12 +572,11 @@ int var_redir_start(char *name, int append) /// :redir END void var_redir_str(char *value, int value_len) { - int len; - if (redir_lval == NULL) { return; } + int len; if (value_len == -1) { len = (int)STRLEN(value); // Append the entire string } else { @@ -606,12 +592,11 @@ void var_redir_str(char *value, int value_len) /// Frees the allocated memory. void var_redir_stop(void) { - typval_T tv; - if (redir_lval != NULL) { // If there was no error: assign the text to the variable. if (redir_endp != NULL) { ga_append(&redir_ga, NUL); // Append the trailing NUL. + typval_T tv; 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 @@ -641,7 +626,7 @@ int eval_charconvert(const char *const enc_from, const char *const enc_to, set_vim_var_string(VV_CC_TO, enc_to, -1); set_vim_var_string(VV_FNAME_IN, fname_from, -1); set_vim_var_string(VV_FNAME_OUT, fname_to, -1); - if (eval_to_bool((char *)p_ccv, &err, NULL, false)) { + if (eval_to_bool(p_ccv, &err, NULL, false)) { err = true; } set_vim_var_string(VV_CC_FROM, NULL, -1); @@ -661,7 +646,7 @@ int eval_printexpr(const char *const fname, const char *const args) set_vim_var_string(VV_FNAME_IN, fname, -1); set_vim_var_string(VV_CMDARG, args, -1); - if (eval_to_bool((char *)p_pexpr, &err, NULL, false)) { + if (eval_to_bool(p_pexpr, &err, NULL, false)) { err = true; } set_vim_var_string(VV_FNAME_IN, NULL, -1); @@ -681,7 +666,7 @@ void eval_diff(const char *const origfile, const char *const newfile, const char set_vim_var_string(VV_FNAME_IN, origfile, -1); set_vim_var_string(VV_FNAME_NEW, newfile, -1); set_vim_var_string(VV_FNAME_OUT, outfile, -1); - (void)eval_to_bool((char *)p_dex, &err, NULL, false); + (void)eval_to_bool(p_dex, &err, NULL, false); set_vim_var_string(VV_FNAME_IN, NULL, -1); set_vim_var_string(VV_FNAME_NEW, NULL, -1); set_vim_var_string(VV_FNAME_OUT, NULL, -1); @@ -701,11 +686,11 @@ void eval_patch(const char *const origfile, const char *const difffile, const ch } /// Top level evaluation function, returning a boolean. -/// Sets "error" to TRUE if there was an error. +/// Sets "error" to true if there was an error. /// /// @param skip only parse, don't execute /// -/// @return TRUE or FALSE. +/// @return true or false. int eval_to_bool(char *arg, bool *error, char **nextcmd, int skip) { typval_T tv; @@ -905,7 +890,7 @@ char *eval_to_string(char *arg, char **nextcmd, bool convert) /// Call eval_to_string() without using current local variables and using /// textlock. /// -/// @param use_sandbox when TRUE, use the sandbox. +/// @param use_sandbox when true, use the sandbox. char *eval_to_string_safe(char *arg, char **nextcmd, int use_sandbox) { char *retval; @@ -935,7 +920,7 @@ varnumber_T eval_to_number(char *expr) varnumber_T retval; char *p = skipwhite(expr); - ++emsg_off; + emsg_off++; if (eval1(&p, &rettv, true) == FAIL) { retval = -1; @@ -943,7 +928,7 @@ varnumber_T eval_to_number(char *expr) retval = tv_get_number_chk(&rettv, NULL); tv_clear(&rettv); } - --emsg_off; + emsg_off--; return retval; } @@ -1000,11 +985,9 @@ void prepare_vimvar(int idx, typval_T *save_tv) /// When no longer defined, remove the variable from the v: hashtable. void restore_vimvar(int idx, typval_T *save_tv) { - hashitem_T *hi; - vimvars[idx].vv_tv = *save_tv; if (vimvars[idx].vv_type == VAR_UNKNOWN) { - hi = hash_find(&vimvarht, (char *)vimvars[idx].vv_di.di_key); + hashitem_T *hi = hash_find(&vimvarht, (char *)vimvars[idx].vv_di.di_key); if (HASHITEM_EMPTY(hi)) { internal_error("restore_vimvar()"); } else { @@ -1040,7 +1023,7 @@ list_T *eval_spell_expr(char *badword, char *expr) vimvars[VV_VAL].vv_type = VAR_STRING; vimvars[VV_VAL].vv_str = badword; if (p_verbose == 0) { - ++emsg_off; + emsg_off++; } if (eval1(&p, &rettv, true) == OK) { @@ -1052,7 +1035,7 @@ list_T *eval_spell_expr(char *badword, char *expr) } if (p_verbose == 0) { - --emsg_off; + emsg_off--; } restore_vimvar(VV_VAL, &save_val); @@ -1134,12 +1117,11 @@ varnumber_T call_func_retnr(const char *func, int argc, typval_T *argv) FUNC_ATTR_NONNULL_ALL { typval_T rettv; - varnumber_T retval; if (call_vim_function((char *)func, argc, argv, &rettv) == FAIL) { return -1; } - retval = tv_get_number_chk(&rettv, NULL); + varnumber_T retval = tv_get_number_chk(&rettv, NULL); tv_clear(&rettv); return retval; } @@ -1191,42 +1173,6 @@ void *call_func_retlist(const char *func, int argc, typval_T *argv) return rettv.vval.v_list; } -/// Prepare profiling for entering a child or something else that is not -/// counted for the script/function itself. -/// Should always be called in pair with prof_child_exit(). -/// -/// @param tm place to store waittime -void prof_child_enter(proftime_T *tm) -{ - funccall_T *fc = get_current_funccal(); - - if (fc != NULL && fc->func->uf_profiling) { - fc->prof_child = profile_start(); - } - - script_prof_save(tm); -} - -/// Take care of time spent in a child. -/// Should always be called after prof_child_enter(). -/// -/// @param tm where waittime was stored -void prof_child_exit(proftime_T *tm) -{ - funccall_T *fc = get_current_funccal(); - - if (fc != NULL && fc->func->uf_profiling) { - fc->prof_child = profile_end(fc->prof_child); - // don't count waiting time - fc->prof_child = profile_sub_wait(*tm, fc->prof_child); - fc->func->uf_tm_children = - profile_add(fc->func->uf_tm_children, fc->prof_child); - fc->func->uf_tml_children = - profile_add(fc->func->uf_tml_children, fc->prof_child); - } - script_prof_restore(tm); -} - /// Evaluate 'foldexpr'. Returns the foldlevel, and any character preceding /// it in "*cp". Doesn't give error messages. int eval_foldexpr(char *arg, int *cp) @@ -1235,11 +1181,11 @@ int eval_foldexpr(char *arg, int *cp) varnumber_T retval; int use_sandbox = was_set_insecurely(curwin, "foldexpr", OPT_LOCAL); - ++emsg_off; + emsg_off++; if (use_sandbox) { - ++sandbox; + sandbox++; } - ++textlock; + textlock++; *cp = NUL; if (eval0(arg, &tv, NULL, true) == FAIL) { retval = 0; @@ -1260,11 +1206,11 @@ int eval_foldexpr(char *arg, int *cp) } tv_clear(&tv); } - --emsg_off; + emsg_off--; if (use_sandbox) { - --sandbox; + sandbox--; } - --textlock; + textlock--; return (int)retval; } @@ -1298,16 +1244,11 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const const bool skip, const int flags, const int fne_flags) FUNC_ATTR_NONNULL_ARG(1, 3) { - dictitem_T *v; - typval_T var1; - typval_T var2; - int empty1 = FALSE; - listitem_T *ni; - hashtab_T *ht = NULL; + bool empty1 = false; int quiet = flags & GLV_QUIET; // Clear everything in "lp". - memset(lp, 0, sizeof(lval_T)); + CLEAR_POINTER(lp); if (skip) { // When skipping just find the end of the name. @@ -1355,11 +1296,13 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const return p; } + hashtab_T *ht = NULL; + // Only pass &ht when we would write to the variable, it prevents autoload // as well. - v = find_var(lp->ll_name, lp->ll_name_len, - (flags & GLV_READ_ONLY) ? NULL : &ht, - flags & GLV_NO_AUTOLOAD); + dictitem_T *v = find_var(lp->ll_name, lp->ll_name_len, + (flags & GLV_READ_ONLY) ? NULL : &ht, + flags & GLV_NO_AUTOLOAD); if (v == NULL && !quiet) { semsg(_("E121: Undefined variable: %.*s"), (int)lp->ll_name_len, lp->ll_name); @@ -1370,7 +1313,9 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const // Loop until no more [idx] or .key is following. lp->ll_tv = &v->di_tv; + typval_T var1; var1.v_type = VAR_UNKNOWN; + typval_T var2; var2.v_type = VAR_UNKNOWN; while (*p == '[' || (*p == '.' && lp->ll_tv->v_type == VAR_DICT)) { if (!(lp->ll_tv->v_type == VAR_LIST && lp->ll_tv->vval.v_list != NULL) @@ -1612,7 +1557,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const lp->ll_n2 = (long)tv_get_number(&var2); // Is number or string. tv_clear(&var2); if (lp->ll_n2 < 0) { - ni = tv_list_find(lp->ll_list, (int)lp->ll_n2); + listitem_T *ni = tv_list_find(lp->ll_list, (int)lp->ll_n2); if (ni == NULL) { if (!quiet) { semsg(_(e_listidx), (int64_t)lp->ll_n2); @@ -1765,9 +1710,7 @@ void set_var_lval(lval_T *lp, char *endp, typval_T *rettv, int copy, const bool ll_n1++; } - /* - * Assign the List values to the list items. - */ + // Assign the List values to the list items. for (ri = tv_list_first(rettv->vval.v_list); ri != NULL;) { if (op != NULL && *op != '=') { eexe_mod_op(TV_LIST_ITEM_TV(lp->ll_li), TV_LIST_ITEM_TV(ri), op); @@ -1864,7 +1807,7 @@ notify: /// Evaluate the expression used in a ":for var in expr" command. /// "arg" points to "var". /// -/// @param[out] *errp set to TRUE for an error, FALSE otherwise; +/// @param[out] *errp set to true for an error, false otherwise; /// /// @return a pointer that holds the info. Null when there is an error. void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) @@ -1888,7 +1831,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) } if (skip) { - ++emsg_skip; + emsg_skip++; } if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) { *errp = false; @@ -1930,7 +1873,7 @@ void *eval_for_line(const char *arg, bool *errp, char **nextcmdp, int skip) } } if (skip) { - --emsg_skip; + emsg_skip--; } return fi; @@ -2009,7 +1952,7 @@ void free_for_info(void *fi_void) void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) FUNC_ATTR_NONNULL_ALL { - int got_eq = FALSE; + bool got_eq = false; int c; char *p; @@ -2035,7 +1978,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) if (c == '&') { c = (uint8_t)xp->xp_pattern[1]; if (c == '&') { - ++xp->xp_pattern; + xp->xp_pattern++; xp->xp_context = cmdidx != CMD_let || got_eq ? EXPAND_EXPRESSION : EXPAND_NOTHING; } else if (c != ' ') { @@ -2048,7 +1991,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) // environment variable xp->xp_context = EXPAND_ENV_VARS; } else if (c == '=') { - got_eq = TRUE; + got_eq = true; xp->xp_context = EXPAND_EXPRESSION; } else if (c == '#' && xp->xp_context == EXPAND_EXPRESSION) { @@ -2073,7 +2016,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) xp->xp_context = EXPAND_NOTHING; } else if (c == '|') { if (xp->xp_pattern[1] == '|') { - ++xp->xp_pattern; + xp->xp_pattern++; xp->xp_context = EXPAND_EXPRESSION; } else { xp->xp_context = EXPAND_COMMANDS; @@ -2099,7 +2042,7 @@ void set_context_for_expression(expand_T *xp, char *arg, cmdidx_T cmdidx) || cmdidx == CMD_echomsg) && xp->xp_context == EXPAND_EXPRESSION) { for (;;) { - char *const n = (char *)skiptowhite((char_u *)arg); + char *const n = skiptowhite(arg); if (n == arg || ascii_iswhite_or_nul(*skipwhite(n))) { break; @@ -2123,11 +2066,9 @@ void del_menutrans_vars(void) hash_unlock(&globvarht); } -/* - * Local string buffer for the next two functions to store a variable name - * with its prefix. Allocated in cat_prefix_varname(), freed later in - * get_user_var_name(). - */ +/// Local string buffer for the next two functions to store a variable name +/// with its prefix. Allocated in cat_prefix_varname(), freed later in +/// get_user_var_name(). static char *varnamebuf = NULL; static size_t varnamebuflen = 0; @@ -2171,10 +2112,10 @@ char *get_user_var_name(expand_T *xp, int idx) if (gdone++ == 0) { hi = globvarht.ht_array; } else { - ++hi; + hi++; } while (HASHITEM_EMPTY(hi)) { - ++hi; + hi++; } if (STRNCMP("g:", xp->xp_pattern, 2) == 0) { return cat_prefix_varname('g', (char *)hi->hi_key); @@ -2188,10 +2129,10 @@ char *get_user_var_name(expand_T *xp, int idx) if (bdone++ == 0) { hi = ht->ht_array; } else { - ++hi; + hi++; } while (HASHITEM_EMPTY(hi)) { - ++hi; + hi++; } return cat_prefix_varname('b', (char *)hi->hi_key); } @@ -2202,10 +2143,10 @@ char *get_user_var_name(expand_T *xp, int idx) if (wdone++ == 0) { hi = ht->ht_array; } else { - ++hi; + hi++; } while (HASHITEM_EMPTY(hi)) { - ++hi; + hi++; } return cat_prefix_varname('w', (char *)hi->hi_key); } @@ -2216,10 +2157,10 @@ char *get_user_var_name(expand_T *xp, int idx) if (tdone++ == 0) { hi = ht->ht_array; } else { - ++hi; + hi++; } while (HASHITEM_EMPTY(hi)) { - ++hi; + hi++; } return cat_prefix_varname('t', (char *)hi->hi_key); } @@ -2238,7 +2179,7 @@ char *get_user_var_name(expand_T *xp, int idx) /// Does not use 'cpo' and always uses 'magic'. /// -/// @return TRUE if "pat" matches "text". +/// @return true if "pat" matches "text". int pattern_match(char *pat, char *text, bool ic) { int matches = 0; @@ -2246,7 +2187,7 @@ int pattern_match(char *pat, char *text, bool ic) // avoid 'l' flag in 'cpoptions' char *save_cpo = p_cpo; - p_cpo = ""; + p_cpo = empty_option; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { regmatch.rm_ic = ic; @@ -2291,7 +2232,7 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ funcexe.evaluate = evaluate; funcexe.partial = partial; funcexe.basetv = basetv; - int ret = get_func_tv((char_u *)s, len, rettv, (char_u **)arg, &funcexe); + int ret = get_func_tv((char_u *)s, len, rettv, arg, &funcexe); xfree(s); @@ -2317,15 +2258,13 @@ static int eval_func(char **const arg, char *const name, const int name_len, typ // TODO(ZyX-I): move to eval/expressions -/* - * The "evaluate" argument: When FALSE, the argument is only parsed but not - * executed. The function may return OK, but the rettv will be of type - * VAR_UNKNOWN. The function still returns FAIL for a syntax error. - */ +/// The "evaluate" argument: When false, the argument is only parsed but not +/// executed. The function may return OK, but the rettv will be of type +/// VAR_UNKNOWN. The function still returns FAIL for a syntax error. /// Handle zero level expression. /// This calls eval1() and handles error message and nextcmd. -/// Put the result in "rettv" when returning OK and "evaluate" is TRUE. +/// Put the result in "rettv" when returning OK and "evaluate" is true. /// Note: "rettv.v_lock" is not set. /// /// @return OK or FAIL. @@ -2372,18 +2311,16 @@ int eval0(char *arg, typval_T *rettv, char **nextcmd, int evaluate) /// @return OK or FAIL. int eval1(char **arg, typval_T *rettv, int evaluate) { - int result; + bool result; typval_T var2; - /* - * Get the first variable. - */ + // Get the first variable. if (eval2(arg, rettv, evaluate) == FAIL) { return FAIL; } if ((*arg)[0] == '?') { - result = FALSE; + result = false; if (evaluate) { bool error = false; @@ -2396,17 +2333,13 @@ int eval1(char **arg, typval_T *rettv, int evaluate) } } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(*arg + 1); if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive! return FAIL; } - /* - * Check for the ":". - */ + // Check for the ":". if ((*arg)[0] != ':') { emsg(_("E109: Missing ':' after '?'")); if (evaluate && result) { @@ -2415,9 +2348,7 @@ int eval1(char **arg, typval_T *rettv, int evaluate) return FAIL; } - /* - * Get the third variable. - */ + // Get the third variable. *arg = skipwhite(*arg + 1); if (eval1(arg, &var2, evaluate && !result) == FAIL) { // Recursive! if (evaluate && result) { @@ -2445,22 +2376,16 @@ int eval1(char **arg, typval_T *rettv, int evaluate) static int eval2(char **arg, typval_T *rettv, int evaluate) { typval_T var2; - long result; - int first; bool error = false; - /* - * Get the first variable. - */ + // Get the first variable. if (eval3(arg, rettv, evaluate) == FAIL) { return FAIL; } - /* - * Repeat until there is no following "||". - */ - first = TRUE; - result = FALSE; + // Repeat until there is no following "||". + bool first = true; + bool result = false; while ((*arg)[0] == '|' && (*arg)[1] == '|') { if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) { @@ -2473,17 +2398,13 @@ static int eval2(char **arg, typval_T *rettv, int evaluate) first = false; } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(*arg + 2); if (eval3(arg, &var2, evaluate && !result) == FAIL) { return FAIL; } - /* - * Compute the result. - */ + // Compute the result. if (evaluate && !result) { if (tv_get_number_chk(&var2, &error) != 0) { result = true; @@ -2514,22 +2435,16 @@ static int eval2(char **arg, typval_T *rettv, int evaluate) static int eval3(char **arg, typval_T *rettv, int evaluate) { typval_T var2; - long result; - int first; bool error = false; - /* - * Get the first variable. - */ + // Get the first variable. if (eval4(arg, rettv, evaluate) == FAIL) { return FAIL; } - /* - * Repeat until there is no following "&&". - */ - first = TRUE; - result = TRUE; + // Repeat until there is no following "&&". + bool first = true; + bool result = true; while ((*arg)[0] == '&' && (*arg)[1] == '&') { if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) { @@ -2542,17 +2457,13 @@ static int eval3(char **arg, typval_T *rettv, int evaluate) first = false; } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(*arg + 2); if (eval4(arg, &var2, evaluate && result) == FAIL) { return FAIL; } - /* - * Compute the result. - */ + // Compute the result. if (evaluate && result) { if (tv_get_number_chk(&var2, &error) == 0) { result = false; @@ -2597,9 +2508,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) int len = 2; bool ic; - /* - * Get the first variable. - */ + // Get the first variable. if (eval5(arg, rettv, evaluate) == FAIL) { return FAIL; } @@ -2648,9 +2557,7 @@ static int eval4(char **arg, typval_T *rettv, int evaluate) break; } - /* - * If there is a comparative operator, use it. - */ + // If there is a comparative operator, use it. if (type != EXPR_UNKNOWN) { // extra question mark appended: ignore case if (p[len] == '?') { @@ -2701,16 +2608,12 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) float_T f1 = 0, f2 = 0; char *p; - /* - * Get the first variable. - */ - if (eval6(arg, rettv, evaluate, FALSE) == FAIL) { + // Get the first variable. + if (eval6(arg, rettv, evaluate, false) == FAIL) { return FAIL; } - /* - * Repeat computing, until no '+', '-' or '.' is following. - */ + // Repeat computing, until no '+', '-' or '.' is following. for (;;) { op = (char_u)(**arg); if (op != '+' && op != '-' && op != '.') { @@ -2732,9 +2635,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) } } - /* - * Get the second variable. - */ + // Get the second variable. if (op == '.' && *(*arg + 1) == '.') { // ..string concatenation (*arg)++; } @@ -2745,9 +2646,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) } if (evaluate) { - /* - * Compute the result. - */ + // Compute the result. if (op == '.') { char buf1[NUMBUFLEN]; char buf2[NUMBUFLEN]; @@ -2759,7 +2658,7 @@ static int eval5(char **arg, typval_T *rettv, int evaluate) tv_clear(&var2); return FAIL; } - p = (char *)concat_str((const char_u *)s1, (const char_u *)s2); + p = concat_str(s1, s2); tv_clear(rettv); rettv->v_type = VAR_STRING; rettv->vval.v_string = p; @@ -2876,16 +2775,12 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) float_T f1 = 0, f2 = 0; bool error = false; - /* - * Get the first variable. - */ + // Get the first variable. if (eval7(arg, rettv, evaluate, want_string) == FAIL) { return FAIL; } - /* - * Repeat computing, until no '*', '/' or '%' is following. - */ + // Repeat computing, until no '*', '/' or '%' is following. for (;;) { op = (char_u)(**arg); if (op != '*' && op != '/' && op != '%') { @@ -2908,9 +2803,7 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) n1 = 0; } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(*arg + 1); if (eval7(arg, &var2, evaluate, false) == FAIL) { return FAIL; @@ -2935,10 +2828,8 @@ static int eval6(char **arg, typval_T *rettv, int evaluate, int want_string) } } - /* - * Compute the result. - * When either side is a float the result is a float. - */ + // Compute the result. + // When either side is a float the result is a float. if (use_float) { if (op == '*') { f1 = f1 * f2; @@ -3051,9 +2942,9 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) get_float = true; p = skipdigits(p + 2); if (*p == 'e' || *p == 'E') { - ++p; + p++; if (*p == '-' || *p == '+') { - ++p; + p++; } if (!ascii_isdigit(*p)) { get_float = false; @@ -3147,7 +3038,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) // Lambda: {arg, arg -> expr} // Dictionary: {'key': val, 'key': val} case '{': - ret = get_lambda_tv((char_u **)arg, rettv, evaluate); + ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) { ret = dict_get_tv(arg, rettv, evaluate, false); } @@ -3164,13 +3055,13 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) // Register contents: @r. case '@': - ++*arg; + (*arg)++; if (evaluate) { rettv->v_type = VAR_STRING; rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc); } if (**arg != NUL) { - ++*arg; + (*arg)++; } break; @@ -3179,7 +3070,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string) *arg = skipwhite(*arg + 1); ret = eval1(arg, rettv, evaluate); // recursive! if (**arg == ')') { - ++*arg; + (*arg)++; } else if (ret == OK) { emsg(_("E110: Missing ')'")); tv_clear(rettv); @@ -3325,7 +3216,7 @@ static int call_func_rettv(char **const arg, typval_T *const rettv, const bool e funcexe.selfdict = selfdict; funcexe.basetv = basetv; const int ret = get_func_tv((char_u *)funcname, is_lua ? (int)(*arg - funcname) : -1, rettv, - (char_u **)arg, &funcexe); + arg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -3353,7 +3244,7 @@ static int eval_lambda(char **const arg, typval_T *const rettv, const bool evalu typval_T base = *rettv; rettv->v_type = VAR_UNKNOWN; - int ret = get_lambda_tv((char_u **)arg, rettv, evaluate); + int ret = get_lambda_tv(arg, rettv, evaluate); if (ret != OK) { return FAIL; } else if (**arg != '(') { @@ -3503,9 +3394,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) typval_T var1 = TV_INITIAL_VALUE; typval_T var2 = TV_INITIAL_VALUE; if (**arg == '.') { - /* - * dict.name - */ + // dict.name key = *arg + 1; for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {} if (len == 0) { @@ -3513,11 +3402,9 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) } *arg = skipwhite(key + len); } else { - /* - * something[idx] - * - * Get the (first) variable from inside the []. - */ + // something[idx] + // + // Get the (first) variable from inside the []. *arg = skipwhite(*arg + 1); if (**arg == ':') { empty1 = true; @@ -3529,9 +3416,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) return FAIL; } - /* - * Get the second variable from inside the [:]. - */ + // Get the second variable from inside the [:]. if (**arg == ':') { range = true; *arg = skipwhite(*arg + 1); @@ -3772,11 +3657,7 @@ static int eval_index(char **arg, typval_T *rettv, int evaluate, int verbose) int get_option_tv(const char **const arg, typval_T *const rettv, const bool evaluate) FUNC_ATTR_NONNULL_ARG(1) { - long numval; - char *stringval; - getoption_T opt_type; bool working = (**arg == '+'); // has("+option") - int ret = OK; int opt_flags; // Isolate the option name and find its value. @@ -3793,10 +3674,14 @@ int get_option_tv(const char **const arg, typval_T *const rettv, const bool eval return OK; } + long numval; + char *stringval; + int ret = OK; + char c = *option_end; *option_end = NUL; - opt_type = get_option_value(*arg, &numval, - rettv == NULL ? NULL : &stringval, opt_flags); + getoption_T opt_type = get_option_value(*arg, &numval, + rettv == NULL ? NULL : &stringval, opt_flags); if (opt_type == gov_unknown) { if (rettv != NULL) { @@ -3837,9 +3722,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) char *p; unsigned int extra = 0; - /* - * Find the end of the string, skipping backslashed characters. - */ + // Find the end of the string, skipping backslashed characters. for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) { if (*p == '\\' && p[1] != NUL) { p++; @@ -3863,10 +3746,8 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) return OK; } - /* - * Copy the string into allocated memory, handling backslashed - * characters. - */ + // Copy the string into allocated memory, handling backslashed + // characters. const int len = (int)(p - *arg + extra); char *name = xmalloc((size_t)len); rettv->v_type = VAR_STRING; @@ -3905,7 +3786,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) } nr = 0; while (--n >= 0 && ascii_isxdigit(p[1])) { - ++p; + p++; nr = (nr << 4) + hex2nr(*p); } p++; @@ -3935,7 +3816,7 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) *name = (char)((*name << 3) + *p++ - '0'); } } - ++name; + name++; break; // Special key, e.g.: "\<C-W>" @@ -3957,11 +3838,11 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) FALLTHROUGH; default: - mb_copy_char((const char_u **)&p, (char_u **)&name); + mb_copy_char((const char **)&p, &name); break; } } else { - mb_copy_char((const char_u **)&p, (char_u **)&name); + mb_copy_char((const char **)&p, &name); } } *name = NUL; @@ -3979,19 +3860,16 @@ static int get_string_tv(char **arg, typval_T *rettv, int evaluate) static int get_lit_string_tv(char **arg, typval_T *rettv, int evaluate) { char *p; - char *str; int reduce = 0; - /* - * Find the end of the string, skipping ''. - */ + // Find the end of the string, skipping ''. for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p)) { if (*p == '\'') { if (p[1] != '\'') { break; } - ++reduce; - ++p; + reduce++; + p++; } } @@ -4006,10 +3884,8 @@ static int get_lit_string_tv(char **arg, typval_T *rettv, int evaluate) return OK; } - /* - * Copy the string into allocated memory, handling '' to ' reduction. - */ - str = xmalloc((size_t)((p - *arg) - reduce)); + // Copy the string into allocated memory, handling '' to ' reduction. + char *str = xmalloc((size_t)((p - *arg) - reduce)); rettv->v_type = VAR_STRING; rettv->vval.v_string = str; @@ -4018,9 +3894,9 @@ static int get_lit_string_tv(char **arg, typval_T *rettv, int evaluate) if (p[1] != '\'') { break; } - ++p; + p++; } - mb_copy_char((const char_u **)&p, (char_u **)&str); + mb_copy_char((const char **)&p, &str); } *str = NUL; *arg = p + 1; @@ -4119,16 +3995,14 @@ failret: /// @param ic ignore case bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) { - char_u *s1, *s2; - dict_T *d1, *d2; - int a1, a2; - // empty and NULL function name considered the same - s1 = (char_u *)(tv1->v_type == VAR_FUNC ? tv1->vval.v_string : partial_name(tv1->vval.v_partial)); + char_u *s1 = + (char_u *)(tv1->v_type == VAR_FUNC ? tv1->vval.v_string : partial_name(tv1->vval.v_partial)); if (s1 != NULL && *s1 == NUL) { s1 = NULL; } - s2 = (char_u *)(tv2->v_type == VAR_FUNC ? tv2->vval.v_string : partial_name(tv2->vval.v_partial)); + char_u *s2 = + (char_u *)(tv2->v_type == VAR_FUNC ? tv2->vval.v_string : partial_name(tv2->vval.v_partial)); if (s2 != NULL && *s2 == NUL) { s2 = NULL; } @@ -4141,8 +4015,8 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) } // empty dict and NULL dict is different - d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict; - d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict; + dict_T *d1 = tv1->v_type == VAR_FUNC ? NULL : tv1->vval.v_partial->pt_dict; + dict_T *d2 = tv2->v_type == VAR_FUNC ? NULL : tv2->vval.v_partial->pt_dict; if (d1 == NULL || d2 == NULL) { if (d1 != d2) { return false; @@ -4152,8 +4026,8 @@ bool func_equal(typval_T *tv1, typval_T *tv2, bool ic) } // empty list and no list considered the same - a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc; - a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc; + int a1 = tv1->v_type == VAR_FUNC ? 0 : tv1->vval.v_partial->pt_argc; + int a2 = tv2->v_type == VAR_FUNC ? 0 : tv2->vval.v_partial->pt_argc; if (a1 != a2) { return false; } @@ -4182,25 +4056,23 @@ int get_copyID(void) return current_copyID; } -/* - * Garbage collection for lists and dictionaries. - * - * We use reference counts to be able to free most items right away when they - * are no longer used. But for composite items it's possible that it becomes - * unused while the reference count is > 0: When there is a recursive - * reference. Example: - * :let l = [1, 2, 3] - * :let d = {9: l} - * :let l[1] = d - * - * Since this is quite unusual we handle this with garbage collection: every - * once in a while find out which lists and dicts are not referenced from any - * variable. - * - * Here is a good reference text about garbage collection (refers to Python - * but it applies to all reference-counting mechanisms): - * http://python.ca/nas/python/gc/ - */ +/// Garbage collection for lists and dictionaries. +/// +/// We use reference counts to be able to free most items right away when they +/// are no longer used. But for composite items it's possible that it becomes +/// unused while the reference count is > 0: When there is a recursive +/// reference. Example: +/// :let l = [1, 2, 3] +/// :let d = {9: l} +/// :let l[1] = d +/// +/// Since this is quite unusual we handle this with garbage collection: every +/// once in a while find out which lists and dicts are not referenced from any +/// variable. +/// +/// Here is a good reference text about garbage collection (refers to Python +/// but it applies to all reference-counting mechanisms): +/// http://python.ca/nas/python/gc/ /// Do garbage collection for lists and dicts. /// @@ -4219,6 +4091,23 @@ bool garbage_collect(bool testing) garbage_collect_at_exit = false; } + // The execution stack can grow big, limit the size. + if (exestack.ga_maxlen - exestack.ga_len > 500) { + // Keep 150% of the current size, with a minimum of the growth size. + int n = exestack.ga_len / 2; + if (n < exestack.ga_growsize) { + n = exestack.ga_growsize; + } + + // Don't make it bigger though. + if (exestack.ga_len + n < exestack.ga_maxlen) { + size_t new_len = (size_t)exestack.ga_itemsize * (size_t)(exestack.ga_len + n); + char *pp = xrealloc(exestack.ga_data, new_len); + exestack.ga_maxlen = exestack.ga_len + n; + exestack.ga_data = pp; + } + } + // We advance by two (COPYID_INC) because we add one for items referenced // through previous_funccal. const int copyID = get_copyID(); @@ -4232,7 +4121,7 @@ bool garbage_collect(bool testing) ABORTING(set_ref_in_previous_funccal)(copyID); // script-local variables - for (int i = 1; i <= ga_scripts.ga_len; ++i) { + for (int i = 1; i <= ga_scripts.ga_len; i++) { ABORTING(set_ref_in_ht)(&SCRIPT_VARS(i), copyID, NULL); } @@ -4691,21 +4580,16 @@ static int get_literal_key(char **arg, typval_T *tv) /// @return OK or FAIL. Returns NOTDONE for {expr}. static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal) { - dict_T *d = NULL; - typval_T tvkey; typval_T tv; char *key = NULL; - dictitem_T *item; char *start = skipwhite(*arg + 1); char buf[NUMBUFLEN]; - /* - * First check if it's not a curly-braces thing: {expr}. - * Must do this without evaluating, otherwise a function may be called - * twice. Unfortunately this means we need to call eval1() twice for the - * first item. - * But {} is an empty Dictionary. - */ + // First check if it's not a curly-braces thing: {expr}. + // Must do this without evaluating, otherwise a function may be called + // twice. Unfortunately this means we need to call eval1() twice for the + // first item. + // But {} is an empty Dictionary. if (*start != '}') { if (eval1(&start, &tv, false) == FAIL) { // recursive! return FAIL; @@ -4715,9 +4599,11 @@ static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal) } } + dict_T *d = NULL; if (evaluate) { d = tv_dict_alloc(); } + typval_T tvkey; tvkey.v_type = VAR_UNKNOWN; tv.v_type = VAR_UNKNOWN; @@ -4750,7 +4636,7 @@ static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal) goto failret; } if (evaluate) { - item = tv_dict_find(d, (const char *)key, -1); + dictitem_T *item = tv_dict_find(d, (const char *)key, -1); if (item != NULL) { semsg(_("E721: Duplicate key in Dictionary: \"%s\""), key); tv_clear(&tvkey); @@ -4805,8 +4691,6 @@ failret: size_t string2float(const char *const text, float_T *const ret_value) FUNC_ATTR_NONNULL_ALL { - char *s = NULL; - // MS-Windows does not deal with "inf" and "nan" properly if (STRNICMP(text, "inf", 3) == 0) { *ret_value = (float_T)INFINITY; @@ -4820,6 +4704,7 @@ size_t string2float(const char *const text, float_T *const ret_value) *ret_value = (float_T)NAN; return 3; } + char *s = NULL; *ret_value = strtod(text, &s); return (size_t)(s - text); } @@ -4833,23 +4718,18 @@ size_t string2float(const char *const text, float_T *const ret_value) /// @return FAIL if the name is invalid. static int get_env_tv(char **arg, typval_T *rettv, int evaluate) { - char *name; - char *string = NULL; - int len; - int cc; - - ++*arg; - name = *arg; - len = get_env_len((const char **)arg); + (*arg)++; + char *name = *arg; + int len = get_env_len((const char **)arg); if (evaluate) { if (len == 0) { return FAIL; // Invalid empty name. } - cc = (char_u)name[len]; + int cc = (int)name[len]; name[len] = NUL; // First try vim_getenv(), fast for normal environment vars. - string = vim_getenv(name); + char *string = vim_getenv(name); if (string == NULL || *string == NUL) { xfree(string); @@ -4867,18 +4747,6 @@ static int get_env_tv(char **arg, typval_T *rettv, int evaluate) return OK; } -/// Get the argument list for a given window -void get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv) -{ - tv_list_alloc_ret(rettv, argcount); - if (arglist != NULL) { - for (int idx = 0; idx < argcount; idx++) { - tv_list_append_string(rettv->vval.v_list, - (const char *)alist_name(&arglist[idx]), -1); - } - } -} - /// Add an assert error to v:errors. void assert_error(garray_T *gap) { @@ -4908,17 +4776,10 @@ win_T *find_win_by_nr_or_id(typval_T *vp) /// Implementation of map() and filter(). void filter_map(typval_T *argvars, typval_T *rettv, int map) { - typval_T *expr; list_T *l = NULL; - dictitem_T *di; - hashtab_T *ht; - hashitem_T *hi; dict_T *d = NULL; - typval_T save_val; - typval_T save_key; blob_T *b = NULL; int rem = false; - int todo; char *ermsg = map ? "map()" : "filter()"; const char *const arg_errmsg = (map ? N_("map() argument") @@ -4949,18 +4810,20 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) return; } - expr = &argvars[1]; + typval_T *expr = &argvars[1]; // On type errors, the preceding call has already displayed an error // message. Avoid a misleading error message for an empty string that // was not passed as argument. if (expr->v_type != VAR_UNKNOWN) { + typval_T save_val; prepare_vimvar(VV_VAL, &save_val); // We reset "did_emsg" to be able to detect whether an error // occurred during evaluation of the expression. save_did_emsg = did_emsg; - did_emsg = FALSE; + did_emsg = false; + typval_T save_key; prepare_vimvar(VV_KEY, &save_key); if (argvars[0].v_type == VAR_DICT) { vimvars[VV_KEY].vv_type = VAR_STRING; @@ -4969,14 +4832,14 @@ void filter_map(typval_T *argvars, typval_T *rettv, int map) if (map && d->dv_lock == VAR_UNLOCKED) { d->dv_lock = VAR_LOCKED; } - ht = &d->dv_hashtab; + hashtab_T *ht = &d->dv_hashtab; hash_lock(ht); - todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) { + int todo = (int)ht->ht_used; + for (hashitem_T *hi = ht->ht_array; todo > 0; hi++) { if (!HASHITEM_EMPTY(hi)) { - --todo; + todo--; - di = TV_DICT_HI2DI(hi); + dictitem_T *di = TV_DICT_HI2DI(hi); if (map && (var_check_lock(di->di_tv.v_lock, arg_errmsg, TV_TRANSLATE) || var_check_ro(di->di_flags, arg_errmsg, TV_TRANSLATE))) { @@ -5100,7 +4963,7 @@ theend: return retval; } -void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr fptr) +void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref) { char *s; char *name; @@ -5125,7 +4988,7 @@ void common_function(typval_T *argvars, typval_T *rettv, bool is_funcref, FunPtr if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; - trans_name = (char *)trans_function_name((char_u **)&name, false, + trans_name = (char *)trans_function_name(&name, false, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (*name != NUL) { @@ -5329,29 +5192,6 @@ linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf) return (linenr_T)tv_get_number_chk(tv, NULL); } -void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv) -{ - if (what_arg->v_type == VAR_UNKNOWN) { - tv_list_alloc_ret(rettv, kListLenMayKnow); - if (is_qf || wp != NULL) { - (void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list); - } - } else { - tv_dict_alloc_ret(rettv); - if (is_qf || wp != NULL) { - if (what_arg->v_type == VAR_DICT) { - dict_T *d = what_arg->vval.v_dict; - - if (d != NULL) { - qf_get_properties(wp, d, rettv->vval.v_dict); - } - } else { - emsg(_(e_dictreq)); - } - } - } -} - /// @return information (variables, options, etc.) about a tab page /// as a dictionary. dict_T *get_tabpage_info(tabpage_T *tp, int tp_idx) @@ -5383,12 +5223,12 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) tv_dict_add_nr(dict, S_LEN("tabnr"), tpnr); tv_dict_add_nr(dict, S_LEN("winnr"), winnr); tv_dict_add_nr(dict, S_LEN("winid"), wp->handle); - tv_dict_add_nr(dict, S_LEN("height"), wp->w_height); + tv_dict_add_nr(dict, S_LEN("height"), wp->w_height_inner); tv_dict_add_nr(dict, S_LEN("winrow"), wp->w_winrow + 1); tv_dict_add_nr(dict, S_LEN("topline"), wp->w_topline); tv_dict_add_nr(dict, S_LEN("botline"), wp->w_botline - 1); tv_dict_add_nr(dict, S_LEN("winbar"), wp->w_winbar_height); - tv_dict_add_nr(dict, S_LEN("width"), wp->w_width); + tv_dict_add_nr(dict, S_LEN("width"), wp->w_width_inner); tv_dict_add_nr(dict, S_LEN("bufnr"), wp->w_buffer->b_fnum); tv_dict_add_nr(dict, S_LEN("wincol"), wp->w_wincol + 1); tv_dict_add_nr(dict, S_LEN("textoff"), win_col_off(wp)); @@ -5688,11 +5528,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T FUNC_ATTR_NONNULL_ARG(4, 5) { linenr_T lnum = lnum_arg + (append ? 1 : 0); - const char *line = NULL; - list_T *l = NULL; - listitem_T *li = NULL; long added = 0; - linenr_T append_lnum; buf_T *curbuf_save = NULL; win_T *curwin_save = NULL; const bool is_curbuf = buf == curbuf; @@ -5714,6 +5550,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T find_win_for_curbuf(); } + linenr_T append_lnum; if (append) { // appendbufline() uses the line number below which we insert append_lnum = lnum - 1; @@ -5723,6 +5560,9 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T append_lnum = curbuf->b_ml.ml_line_count; } + list_T *l = NULL; + listitem_T *li = NULL; + const char *line = NULL; if (lines->v_type == VAR_LIST) { l = lines->vval.v_list; li = tv_list_first(l); @@ -5806,7 +5646,6 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv) FUNC_ATTR_NONNULL_ALL { - const void *iter = NULL; list_T *const list = tv_list_alloc(kListLenShouldKnow); rettv->v_type = VAR_LIST; rettv->vval.v_list = list; @@ -5815,6 +5654,7 @@ void get_xdg_var_list(const XDGVarType xdg, typval_T *rettv) if (dirs == NULL) { return; } + const void *iter = NULL; do { size_t dir_len; const char *dir; @@ -5924,9 +5764,9 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool retlist #ifdef USE_CRNL // translate <CR><NL> into <NL> char *d = res; - for (char *s = res; *s; ++s) { + for (char *s = res; *s; s++) { if (s[0] == CAR && s[1] == NL) { - ++s; + s++; } *d++ = *s; @@ -5999,7 +5839,17 @@ bool callback_call(Callback *const callback, const int argcount_in, typval_T *co switch (callback->type) { case kCallbackFuncref: name = callback->data.funcref; - partial = NULL; + int len = (int)STRLEN(name); + if (len >= 6 && !memcmp(name, "v:lua.", 6)) { + name += 6; + len = check_luafunc_name(name, false); + if (len == 0) { + return false; + } + partial = vvlua_partial; + } else { + partial = NULL; + } break; case kCallbackPartial: @@ -6135,7 +5985,7 @@ void timer_due_cb(TimeWatcher *tw, void *data) // Handle error message if (called_emsg > called_emsg_before && did_emsg) { timer->emsg_count++; - if (current_exception != NULL) { + if (did_throw) { discard_current_exception(); } } @@ -6498,12 +6348,9 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret // Argument can be [lnum, col, coladd]. if (tv->v_type == VAR_LIST) { - list_T *l; - int len; bool error = false; - listitem_T *li; - l = tv->vval.v_list; + list_T *l = tv->vval.v_list; if (l == NULL) { return NULL; } @@ -6520,6 +6367,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (error) { return NULL; } + int len; if (charcol) { len = mb_charlen(ml_get(pos.lnum)); } else { @@ -6527,7 +6375,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret } // We accept "$" for the column number: last column. - li = tv_list_find(l, 1L); + listitem_T *li = tv_list_find(l, 1L); if (li != NULL && TV_LIST_ITEM_TV(li)->v_type == VAR_STRING && TV_LIST_ITEM_TV(li)->vval.v_string != NULL && STRCMP(TV_LIST_ITEM_TV(li)->vval.v_string, "$") == 0) { @@ -6627,8 +6475,6 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool charcol) { list_T *l; - int i = 0; - long n; // List must be: [fnum, lnum, col, coladd, curswant], where "fnum" is only // there when "fnump" isn't NULL; "coladd" and "curswant" are optional. @@ -6639,6 +6485,8 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c return FAIL; } + int i = 0; + long n; if (fnump != NULL) { n = tv_list_find_nr(l, i++, NULL); // fnum if (n < 0) { @@ -6691,15 +6539,13 @@ int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp, bool c /// @return 0 for error. int get_env_len(const char **arg) { - int len; - const char *p; for (p = *arg; vim_isIDc(*p); p++) {} if (p == *arg) { // No name found. return 0; } - len = (int)(p - *arg); + int len = (int)(p - *arg); *arg = p; return len; } @@ -6747,8 +6593,6 @@ int get_id_len(const char **const arg) /// 0 if something else is wrong. int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbose) { - int len; - *alias = NULL; // default to no alias if ((*arg)[0] == (char)K_SPECIAL && (*arg)[1] == (char)KS_EXTRA @@ -6757,7 +6601,7 @@ int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbo *arg += 3; return get_id_len(arg) + 3; } - len = eval_fname_script(*arg); + int len = eval_fname_script(*arg); if (len > 0) { // literal "<SID>", "s:" or "<SNR>" *arg += len; @@ -6775,10 +6619,8 @@ int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbo return len; } - /* - * Include any <SID> etc in the expanded string: - * Thus the -len here. - */ + // Include any <SID> etc in the expanded string: + // Thus the -len here. char *temp_string = make_expanded_name(*arg - len, expr_start, expr_end, (char *)p); if (temp_string == NULL) { return -1; @@ -6810,10 +6652,6 @@ int get_name_len(const char **const arg, char **alias, bool evaluate, bool verbo const char *find_name_end(const char *arg, const char **expr_start, const char **expr_end, int flags) { - int mb_nest = 0; - int br_nest = 0; - int len; - if (expr_start != NULL) { *expr_start = NULL; *expr_end = NULL; @@ -6824,6 +6662,10 @@ const char *find_name_end(const char *arg, const char **expr_start, const char * return arg; } + int mb_nest = 0; + int br_nest = 0; + int len; + const char *p; for (p = arg; *p != NUL && (eval_isnamec(*p) @@ -6841,7 +6683,7 @@ const char *find_name_end(const char *arg, const char **expr_start, const char * // skip over "str\"ing" to avoid counting [ and ] inside it. for (p = p + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) { if (*p == '\\' && p[1] != NUL) { - ++p; + p++; } } if (*p == NUL) { @@ -6859,9 +6701,9 @@ const char *find_name_end(const char *arg, const char **expr_start, const char * if (mb_nest == 0) { if (*p == '[') { - ++br_nest; + br_nest++; } else if (*p == ']') { - --br_nest; + br_nest--; } } @@ -6897,20 +6739,19 @@ const char *find_name_end(const char *arg, const char **expr_start, const char * static char *make_expanded_name(const char *in_start, char *expr_start, char *expr_end, char *in_end) { - char c1; - char *retval = NULL; - char *temp_result; - char *nextcmd = NULL; - if (expr_end == NULL || in_end == NULL) { return NULL; } + + char *retval = NULL; + char *nextcmd = NULL; + *expr_start = NUL; *expr_end = NUL; - c1 = *in_end; + char c1 = *in_end; *in_end = NUL; - temp_result = eval_to_string(expr_start + 1, &nextcmd, false); + char *temp_result = eval_to_string(expr_start + 1, &nextcmd, false); if (temp_result != NULL && nextcmd == NULL) { retval = xmalloc(STRLEN(temp_result) + (size_t)(expr_start - in_start) + (size_t)(in_end - expr_end) + 1); @@ -6940,14 +6781,14 @@ static char *make_expanded_name(const char *in_start, char *expr_start, char *ex return retval; } -/// @return TRUE if character "c" can be used in a variable or function name. +/// @return true if character "c" can be used in a variable or function name. /// Does not include '{' or '}' for magic braces. int eval_isnamec(int c) { return ASCII_ISALNUM(c) || c == '_' || c == ':' || c == AUTOLOAD_CHAR; } -/// @return TRUE if character "c" can be used as the first character in a +/// @return true if character "c" can be used as the first character in a /// variable or function name (excluding '{' and '}'). int eval_isnamec1(int c) { @@ -7000,7 +6841,7 @@ void set_vim_var_char(int c) /// Set v:count to "count" and v:count1 to "count1". /// -/// @param set_prevcount if TRUE, first set v:prevcount from v:count. +/// @param set_prevcount if true, first set v:prevcount from v:count. void set_vcount(long count, long count1, int set_prevcount) { if (set_prevcount) { @@ -7353,7 +7194,7 @@ int handle_subscript(const char **const arg, typval_T *rettv, int evaluate, int if (rettv->v_type == VAR_DICT) { selfdict = rettv->vval.v_dict; if (selfdict != NULL) { - ++selfdict->dv_refcount; + selfdict->dv_refcount++; } } else { selfdict = NULL; @@ -7430,8 +7271,6 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va const size_t varname_len, int no_autoload) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - hashitem_T *hi; - if (varname_len == 0) { // Must be something like "s:", otherwise "ht" would be NULL. switch (htname) { @@ -7455,7 +7294,7 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va return NULL; } - hi = hash_find_len(ht, varname, varname_len); + hashitem_T *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 @@ -7490,7 +7329,6 @@ dictitem_T *find_var_in_ht(hashtab_T *const ht, int htname, const char *const va hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char **varname, dict_T **d) { - hashitem_T *hi; funccall_T *funccal = get_funccal(); *d = NULL; @@ -7506,7 +7344,7 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char *varname = name; // "version" is "v:version" in all scopes - hi = hash_find_len(&compat_hashtab, name, name_len); + hashitem_T *hi = hash_find_len(&compat_hashtab, name, name_len); if (!HASHITEM_EMPTY(hi)) { return &compat_hashtab; } @@ -7562,7 +7400,7 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char bool should_free; // should_free is ignored as script_sctx will be resolved to a fnmae // & new_script_item will consume it. - char *sc_name = (char *)get_scriptname(last_set, &should_free); + char *sc_name = get_scriptname(last_set, &should_free); new_script_item(sc_name, ¤t_sctx.sc_sid); } } @@ -7595,28 +7433,26 @@ hashtab_T *find_var_ht(const char *name, const size_t name_len, const char **var /// sourcing this script and when executing functions defined in the script. void new_script_vars(scid_T id) { - hashtab_T *ht; scriptvar_T *sv; ga_grow(&ga_scripts, id - ga_scripts.ga_len); - { - /* Re-allocating ga_data means that an ht_array pointing to - * ht_smallarray becomes invalid. We can recognize this: ht_mask is - * at its init value. Also reset "v_dict", it's always the same. */ - for (int i = 1; i <= ga_scripts.ga_len; ++i) { - ht = &SCRIPT_VARS(i); - if (ht->ht_mask == HT_INIT_SIZE - 1) { - ht->ht_array = ht->ht_smallarray; - } - sv = SCRIPT_SV(i); - sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict; - } - while (ga_scripts.ga_len < id) { - sv = SCRIPT_SV(ga_scripts.ga_len + 1) = xcalloc(1, sizeof(scriptvar_T)); - init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); - ++ga_scripts.ga_len; + // Re-allocating ga_data means that an ht_array pointing to + // ht_smallarray becomes invalid. We can recognize this: ht_mask is + // at its init value. Also reset "v_dict", it's always the same. + for (int i = 1; i <= ga_scripts.ga_len; i++) { + hashtab_T *ht = &SCRIPT_VARS(i); + if (ht->ht_mask == HT_INIT_SIZE - 1) { + ht->ht_array = ht->ht_smallarray; } + sv = SCRIPT_SV(i); + sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict; + } + + while (ga_scripts.ga_len < id) { + sv = SCRIPT_SV(ga_scripts.ga_len + 1) = xcalloc(1, sizeof(scriptvar_T)); + init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE); + ga_scripts.ga_len++; } } @@ -7640,8 +7476,8 @@ void init_var_dict(dict_T *dict, ScopeDictDictItem *dict_var, ScopeType scope) /// Unreference a dictionary initialized by init_var_dict(). void unref_var_dict(dict_T *dict) { - /* Now the dict needs to be freed if no one else is using it, go back to - * normal reference counting. */ + // Now the dict needs to be freed if no one else is using it, go back to + // normal reference counting. dict->dv_refcount -= DO_NOT_FREE_CNT - 1; tv_dict_unref(dict); } @@ -7673,7 +7509,7 @@ int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *c emsg(_("E698: variable nested too deep for making a copy")); return FAIL; } - ++recurse; + recurse++; switch (from->v_type) { case VAR_NUMBER: @@ -7691,9 +7527,9 @@ int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *c } else { to->v_type = VAR_STRING; to->v_lock = VAR_UNLOCKED; - if ((to->vval.v_string = (char *)string_convert((vimconv_T *)conv, - (char_u *)from->vval.v_string, - NULL)) + if ((to->vval.v_string = string_convert((vimconv_T *)conv, + from->vval.v_string, + NULL)) == NULL) { to->vval.v_string = xstrdup(from->vval.v_string); } @@ -7726,7 +7562,7 @@ int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *c } 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; + to->vval.v_dict->dv_refcount++; } else { to->vval.v_dict = tv_dict_copy(conv, from->vval.v_dict, deep, copyID); } @@ -7738,7 +7574,7 @@ int var_item_copy(const vimconv_T *const conv, typval_T *const from, typval_T *c internal_error("var_item_copy(UNKNOWN)"); ret = FAIL; } - --recurse; + recurse--; return ret; } @@ -7755,7 +7591,7 @@ void ex_echo(exarg_T *eap) const int called_emsg_before = called_emsg; if (eap->skip) { - ++emsg_skip; + emsg_skip++; } while (*arg != NUL && *arg != '|' && *arg != '\n' && !got_int) { // If eval1() causes an error message the text from the command may @@ -7835,12 +7671,11 @@ void ex_execute(exarg_T *eap) typval_T rettv; int ret = OK; garray_T ga; - int save_did_emsg; ga_init(&ga, 1, 80); if (eap->skip) { - ++emsg_skip; + emsg_skip++; } while (*arg != NUL && *arg != '|' && *arg != '\n') { ret = eval1_emsg(&arg, &rettv, !eap->skip); @@ -7884,7 +7719,7 @@ void ex_execute(exarg_T *eap) ui_flush(); } else if (eap->cmdidx == CMD_echoerr) { // We don't want to abort following commands, restore did_emsg. - save_did_emsg = did_emsg; + int save_did_emsg = did_emsg; msg_ext_set_kind("echoerr"); emsg(ga.ga_data); if (!force_abort) { @@ -7898,7 +7733,7 @@ void ex_execute(exarg_T *eap) ga_clear(&ga); if (eap->skip) { - --emsg_skip; + emsg_skip--; } eap->nextcmd = (char *)check_nextcmd((char_u *)arg); @@ -7914,7 +7749,7 @@ const char *find_option_end(const char **const arg, int *const opt_flags) { const char *p = *arg; - ++p; + p++; if (*p == 'g' && p[1] == ':') { *opt_flags = OPT_GLOBAL; p += 2; @@ -7940,174 +7775,6 @@ const char *find_option_end(const char **const arg, int *const opt_flags) return p; } -/// Start profiling function "fp". -void func_do_profile(ufunc_T *fp) -{ - int len = fp->uf_lines.ga_len; - - if (!fp->uf_prof_initialized) { - if (len == 0) { - len = 1; // avoid getting error for allocating zero bytes - } - fp->uf_tm_count = 0; - fp->uf_tm_self = profile_zero(); - fp->uf_tm_total = profile_zero(); - - if (fp->uf_tml_count == NULL) { - fp->uf_tml_count = xcalloc((size_t)len, sizeof(int)); - } - - if (fp->uf_tml_total == NULL) { - fp->uf_tml_total = xcalloc((size_t)len, sizeof(proftime_T)); - } - - if (fp->uf_tml_self == NULL) { - fp->uf_tml_self = xcalloc((size_t)len, sizeof(proftime_T)); - } - - fp->uf_tml_idx = -1; - fp->uf_prof_initialized = true; - } - - fp->uf_profiling = TRUE; -} - -/// Dump the profiling results for all functions in file "fd". -void func_dump_profile(FILE *fd) -{ - hashitem_T *hi; - int todo; - ufunc_T *fp; - ufunc_T **sorttab; - int st_len = 0; - - todo = (int)func_hashtab.ht_used; - if (todo == 0) { - return; // nothing to dump - } - - sorttab = xmalloc(sizeof(ufunc_T *) * (size_t)todo); - - for (hi = func_hashtab.ht_array; todo > 0; ++hi) { - if (!HASHITEM_EMPTY(hi)) { - --todo; - fp = HI2UF(hi); - if (fp->uf_prof_initialized) { - sorttab[st_len++] = fp; - - if (fp->uf_name[0] == K_SPECIAL) { - fprintf(fd, "FUNCTION <SNR>%s()\n", fp->uf_name + 3); - } else { - fprintf(fd, "FUNCTION %s()\n", fp->uf_name); - } - if (fp->uf_script_ctx.sc_sid != 0) { - bool should_free; - const LastSet last_set = (LastSet){ - .script_ctx = fp->uf_script_ctx, - .channel_id = 0, - }; - char *p = (char *)get_scriptname(last_set, &should_free); - fprintf(fd, " Defined: %s:%" PRIdLINENR "\n", - p, fp->uf_script_ctx.sc_lnum); - if (should_free) { - xfree(p); - } - } - if (fp->uf_tm_count == 1) { - fprintf(fd, "Called 1 time\n"); - } else { - fprintf(fd, "Called %d times\n", fp->uf_tm_count); - } - fprintf(fd, "Total time: %s\n", profile_msg(fp->uf_tm_total)); - fprintf(fd, " Self time: %s\n", profile_msg(fp->uf_tm_self)); - fprintf(fd, "\n"); - fprintf(fd, "count total (s) self (s)\n"); - - for (int i = 0; i < fp->uf_lines.ga_len; ++i) { - if (FUNCLINE(fp, i) == NULL) { - continue; - } - prof_func_line(fd, fp->uf_tml_count[i], - &fp->uf_tml_total[i], &fp->uf_tml_self[i], TRUE); - fprintf(fd, "%s\n", FUNCLINE(fp, i)); - } - fprintf(fd, "\n"); - } - } - } - - if (st_len > 0) { - qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *), - prof_total_cmp); - prof_sort_list(fd, sorttab, st_len, "TOTAL", FALSE); - qsort((void *)sorttab, (size_t)st_len, sizeof(ufunc_T *), - prof_self_cmp); - prof_sort_list(fd, sorttab, st_len, "SELF", TRUE); - } - - xfree(sorttab); -} - -/// @param prefer_self when equal print only self time -static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self) -{ - int i; - ufunc_T *fp; - - fprintf(fd, "FUNCTIONS SORTED ON %s TIME\n", title); - fprintf(fd, "count total (s) self (s) function\n"); - for (i = 0; i < 20 && i < st_len; ++i) { - fp = sorttab[i]; - prof_func_line(fd, fp->uf_tm_count, &fp->uf_tm_total, &fp->uf_tm_self, - prefer_self); - if (fp->uf_name[0] == K_SPECIAL) { - fprintf(fd, " <SNR>%s()\n", fp->uf_name + 3); - } else { - fprintf(fd, " %s()\n", fp->uf_name); - } - } - fprintf(fd, "\n"); -} - -/// Print the count and times for one function or function line. -/// -/// @param prefer_self when equal print only self time -static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self, - int prefer_self) -{ - if (count > 0) { - fprintf(fd, "%5d ", count); - if (prefer_self && profile_equal(*total, *self)) { - fprintf(fd, " "); - } else { - fprintf(fd, "%s ", profile_msg(*total)); - } - if (!prefer_self && profile_equal(*total, *self)) { - fprintf(fd, " "); - } else { - fprintf(fd, "%s ", profile_msg(*self)); - } - } else { - fprintf(fd, " "); - } -} - -/// Compare function for total time sorting. -static int prof_total_cmp(const void *s1, const void *s2) -{ - ufunc_T *p1 = *(ufunc_T **)s1; - ufunc_T *p2 = *(ufunc_T **)s2; - return profile_cmp(p1->uf_tm_total, p2->uf_tm_total); -} - -/// Compare function for self time sorting. -static int prof_self_cmp(const void *s1, const void *s2) -{ - ufunc_T *p1 = *(ufunc_T **)s1; - ufunc_T *p2 = *(ufunc_T **)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. /// @@ -8182,61 +7849,6 @@ bool script_autoload(const char *const name, const size_t name_len, const bool r return ret; } -/// Called when starting to read a function line. -/// "sourcing_lnum" must be correct! -/// When skipping lines it may not actually be executed, but we won't find out -/// until later and we need to store the time now. -void func_line_start(void *cookie) -{ - funccall_T *fcp = (funccall_T *)cookie; - ufunc_T *fp = fcp->func; - - 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; - fp->uf_tml_start = profile_start(); - fp->uf_tml_children = profile_zero(); - fp->uf_tml_wait = profile_get_wait(); - } -} - -/// Called when actually executing a function line. -void func_line_exec(void *cookie) -{ - funccall_T *fcp = (funccall_T *)cookie; - ufunc_T *fp = fcp->func; - - if (fp->uf_profiling && fp->uf_tml_idx >= 0) { - fp->uf_tml_execed = TRUE; - } -} - -/// Called when done with a function line. -void func_line_end(void *cookie) -{ - funccall_T *fcp = (funccall_T *)cookie; - ufunc_T *fp = fcp->func; - - if (fp->uf_profiling && fp->uf_tml_idx >= 0) { - if (fp->uf_tml_execed) { - ++fp->uf_tml_count[fp->uf_tml_idx]; - fp->uf_tml_start = profile_end(fp->uf_tml_start); - fp->uf_tml_start = profile_sub_wait(fp->uf_tml_wait, fp->uf_tml_start); - fp->uf_tml_total[fp->uf_tml_idx] = - profile_add(fp->uf_tml_total[fp->uf_tml_idx], fp->uf_tml_start); - fp->uf_tml_self[fp->uf_tml_idx] = - profile_self(fp->uf_tml_self[fp->uf_tml_idx], fp->uf_tml_start, - fp->uf_tml_children); - } - fp->uf_tml_idx = -1; - } -} - static var_flavour_T var_flavour(char *varname) FUNC_ATTR_PURE { @@ -8324,11 +7936,9 @@ int store_session_globals(FILE *fd) } if ((fprintf(fd, "let %s = %c%s%c", this_var->di_key, - ((this_var->di_tv.v_type == VAR_STRING) ? '"' - : ' '), + ((this_var->di_tv.v_type == VAR_STRING) ? '"' : ' '), p, - ((this_var->di_tv.v_type == VAR_STRING) ? '"' - : ' ')) < 0) + ((this_var->di_tv.v_type == VAR_STRING) ? '"' : ' ')) < 0) || put_eol(fd) == FAIL) { xfree(p); return FAIL; @@ -8370,7 +7980,7 @@ void option_last_set_msg(LastSet last_set) { if (last_set.script_ctx.sc_sid != 0) { bool should_free; - char *p = (char *)get_scriptname(last_set, &should_free); + char *p = get_scriptname(last_set, &should_free); verbose_enter(); msg_puts(_("\n\tLast set from ")); msg_puts(p); @@ -8413,10 +8023,8 @@ int modify_fname(char *src, bool tilde_file, size_t *usedlen, char **fnamep, cha size_t *fnamelen) { int valid = 0; - char *tail; char *s, *p, *pbuf; char dirname[MAXPATHL]; - int c; bool has_fullname = false; bool has_homerelative = false; @@ -8469,7 +8077,7 @@ repeat: } // Append a path separator to a directory. - if (os_isdir((char_u *)(*fnamep))) { + if (os_isdir(*fnamep)) { // Make room for one or two extra characters. *fnamep = xstrnsave(*fnamep, STRLEN(*fnamep) + 2); xfree(*bufp); // free any allocated file name @@ -8478,6 +8086,8 @@ repeat: } } + int c; + // ":." - path relative to the current directory // ":~" - path relative to the home directory // ":8" - shortname path - postponed till after @@ -8533,6 +8143,7 @@ repeat: // Only replace it when it starts with '~' if (*dirname == '~') { s = xstrdup(dirname); + assert(s != NULL); // suppress clang "Argument with 'nonnull' attribute passed null" *fnamep = s; xfree(*bufp); *bufp = s; @@ -8543,7 +8154,7 @@ repeat: } } - tail = path_tail(*fnamep); + char *tail = path_tail(*fnamep); *fnamelen = STRLEN(*fnamep); // ":h" - head, remove "/file_name", can be repeated @@ -8551,7 +8162,7 @@ repeat: while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') { valid |= VALID_HEAD; *usedlen += 2; - s = (char *)get_past_head((char_u *)(*fnamep)); + s = get_past_head(*fnamep); while (tail > s && after_pathsep(s, tail)) { MB_PTR_BACK(*fnamep, tail); } @@ -8584,10 +8195,9 @@ repeat: // ":r" - root, without extension, can be repeated while (src[*usedlen] == ':' && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r')) { - /* find a '.' in the tail: - * - for second :e: before the current fname - * - otherwise: The last '.' - */ + // find a '.' in the tail: + // - for second :e: before the current fname + // - otherwise: The last '.' const bool is_second_e = *fnamep > tail; if (src[*usedlen + 1] == 'e' && is_second_e) { s = (*fnamep) - 2; @@ -8638,18 +8248,16 @@ repeat: if (src[*usedlen] == ':' && (src[*usedlen + 1] == 's' || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) { - int sep; - char *flags; - int didit = false; + bool didit = false; - flags = ""; + char *flags = ""; s = src + *usedlen + 2; if (src[*usedlen + 1] == 'g') { flags = "g"; s++; } - sep = (char_u)(*s++); + int sep = (char_u)(*s++); if (sep) { // find end of pattern p = vim_strchr(s, sep); @@ -8667,7 +8275,7 @@ repeat: *fnamelen = STRLEN(s); xfree(*bufp); *bufp = s; - didit = TRUE; + didit = true; xfree(sub); xfree(str); } @@ -8708,26 +8316,22 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags { int sublen; regmatch_T regmatch; - int do_all; - char *tail; - char *end; garray_T ga; - char *save_cpo; char *zero_width = NULL; // Make 'cpoptions' empty, so that the 'l' flag doesn't work here - save_cpo = p_cpo; - p_cpo = (char *)empty_option; + char *save_cpo = p_cpo; + p_cpo = empty_option; ga_init(&ga, 1, 200); - do_all = (flags[0] == 'g'); + int do_all = (flags[0] == 'g'); regmatch.rm_ic = p_ic; regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); if (regmatch.regprog != NULL) { - tail = str; - end = str + STRLEN(str); + char *tail = str; + char *end = str + STRLEN(str); while (vim_regexec_nl(®match, (char_u *)str, (colnr_T)(tail - str))) { // Skip empty match except for first match. if (regmatch.startp[0] == regmatch.endp[0]) { @@ -8777,11 +8381,16 @@ char *do_string_sub(char *str, char *pat, char *sub, typval_T *expr, char *flags char *ret = xstrdup(ga.ga_data == NULL ? str : ga.ga_data); ga_clear(&ga); - if ((char_u *)p_cpo == empty_option) { + if (p_cpo == empty_option) { p_cpo = save_cpo; } else { // Darn, evaluating {sub} expression or {expr} changed the value. - free_string_option((char_u *)save_cpo); + // If it's still empty it was changed and restored, need to restore in + // the complicated way. + if (*p_cpo == NUL) { + set_option_value_give_err("cpo", 0L, save_cpo, 0); + } + free_string_option(save_cpo); } return ret; @@ -8868,8 +8477,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments, boo struct caller_scope saved_provider_caller_scope = provider_caller_scope; provider_caller_scope = (struct caller_scope) { .script_ctx = current_sctx, - .sourcing_name = sourcing_name, - .sourcing_lnum = sourcing_lnum, + .es_entry = ((estack_T *)exestack.ga_data)[exestack.ga_len - 1], .autocmd_fname = autocmd_fname, .autocmd_match = autocmd_match, .autocmd_bufnr = autocmd_bufnr, @@ -8968,8 +8576,8 @@ bool eval_has_provider(const char *feat) /// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`. void eval_fmt_source_name_line(char *buf, size_t bufsize) { - if (sourcing_name) { - snprintf(buf, bufsize, "%s:%" PRIdLINENR, sourcing_name, sourcing_lnum); + if (SOURCING_NAME) { + snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM); } else { snprintf(buf, bufsize, "?"); } @@ -8988,7 +8596,7 @@ void ex_checkhealth(exarg_T *eap) if (vimruntime_env == NULL) { emsg(_("E5009: $VIMRUNTIME is empty or unset")); } else { - bool rtp_ok = NULL != strstr((char *)p_rtp, vimruntime_env); + bool rtp_ok = NULL != strstr(p_rtp, vimruntime_env); if (rtp_ok) { semsg(_("E5009: Invalid $VIMRUNTIME: %s"), vimruntime_env); } else { @@ -9011,8 +8619,6 @@ void invoke_prompt_callback(void) { typval_T rettv; typval_T argv[2]; - char *text; - char *prompt; linenr_T lnum = curbuf->b_ml.ml_line_count; // Add a new line for the prompt before invoking the callback, so that @@ -9024,8 +8630,8 @@ void invoke_prompt_callback(void) if (curbuf->b_prompt_callback.type == kCallbackNone) { return; } - text = (char *)ml_get(lnum); - prompt = (char *)prompt_text(); + char *text = (char *)ml_get(lnum); + char *prompt = (char *)prompt_text(); if (STRLEN(text) >= STRLEN(prompt)) { text += STRLEN(prompt); } |