Patch 8.2.3689
Problem: ex_let_one() is too long.
Solution: Split into multiple functions.
Files: src/evalvars.c
*** ../vim-8.2.3688/src/evalvars.c 2021-11-26 17:36:48.008799188 +0000
--- src/evalvars.c 2021-11-28 19:53:13.786295854 +0000
***************
*** 1289,1525 ****
}
/*
! * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
! * Returns a pointer to the char just after the var name.
! * Returns NULL if there is an error.
*/
static char_u *
! ex_let_one(
! char_u *arg, // points to variable name
! typval_T *tv, // value to assign to variable
! int copy, // copy value from "tv"
! int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
! char_u *endchars, // valid chars after variable name or NULL
! char_u *op, // "+", "-", "." or NULL
! int var_idx) // variable index for "let [a, b] = list"
{
- int c1;
- char_u *name;
- char_u *p;
char_u *arg_end = NULL;
int len;
- int opt_flags;
- char_u *tofree = NULL;
! if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
! && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
! && vim_strchr((char_u *)"$@&", *arg) != NULL)
{
! vim9_declare_error(arg);
return NULL;
}
! // ":let $VAR = expr": Set environment variable.
! if (*arg == '$')
{
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
{
! emsg(_("E996: Cannot lock an environment variable"));
! return NULL;
! }
! // Find the end of the name.
! ++arg;
! name = arg;
! len = get_env_len(&arg);
! if (len == 0)
! semsg(_(e_invarg2), name - 1);
! else
! {
! if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
! semsg(_(e_letwrong), op);
! else if (endchars != NULL
! && vim_strchr(endchars, *skipwhite(arg)) == NULL)
! emsg(_(e_unexpected_characters_in_let));
! else if (!check_secure())
{
! c1 = name[len];
! name[len] = NUL;
! p = tv_get_string_chk(tv);
! if (p != NULL && op != NULL && *op == '.')
! {
! int mustfree = FALSE;
! char_u *s = vim_getenv(name, &mustfree);
! if (s != NULL)
! {
! p = tofree = concat_str(s, p);
! if (mustfree)
! vim_free(s);
! }
! }
! if (p != NULL)
{
! vim_setenv_ext(name, p);
! arg_end = arg;
}
- name[len] = c1;
- vim_free(tofree);
}
}
}
! // ":let &option = expr": Set option value.
! // ":let &l:option = expr": Set local option value.
! // ":let &g:option = expr": Set global option value.
! // ":for &ts in range(8)": Set option value for for loop
! else if (*arg == '&')
{
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
{
! emsg(_(e_const_option));
! return NULL;
}
! // Find the end of the name.
! p = find_option_end(&arg, &opt_flags);
! if (p == NULL || (endchars != NULL
! && vim_strchr(endchars, *skipwhite(p)) == NULL))
! emsg(_(e_unexpected_characters_in_let));
! else
{
! long n = 0;
! getoption_T opt_type;
! long numval;
! char_u *stringval = NULL;
! char_u *s = NULL;
! int failed = FALSE;
!
! c1 = *p;
! *p = NUL;
!
! opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
! if ((opt_type == gov_bool
! || opt_type == gov_number
! || opt_type == gov_hidden_bool
! || opt_type == gov_hidden_number)
! && (tv->v_type != VAR_STRING || !in_vim9script()))
! {
! if (opt_type == gov_bool || opt_type == gov_hidden_bool)
! // bool, possibly hidden
! n = (long)tv_get_bool(tv);
! else
! // number, possibly hidden
! n = (long)tv_get_number(tv);
! }
!
! // Avoid setting a string option to the text "v:false" or similar.
! // In Vim9 script also don't convert a number to string.
! if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
! && (!in_vim9script() || tv->v_type != VAR_NUMBER))
! s = tv_get_string_chk(tv);
!
! if (op != NULL && *op != '=')
! {
! if (((opt_type == gov_bool || opt_type == gov_number)
! && *op == '.')
! || (opt_type == gov_string && *op != '.'))
! {
! semsg(_(e_letwrong), op);
! failed = TRUE; // don't set the value
! }
! else
{
! // number, in legacy script also bool
! if (opt_type == gov_number
! || (opt_type == gov_bool && !in_vim9script()))
{
! switch (*op)
! {
! case '+': n = numval + n; break;
! case '-': n = numval - n; break;
! case '*': n = numval * n; break;
! case '/': n = (long)num_divide(numval, n,
&failed); break;
! case '%': n = (long)num_modulus(numval, n,
&failed); break;
- }
- s = NULL;
- }
- else if (opt_type == gov_string
- && stringval != NULL && s != NULL)
- {
- // string
- s = concat_str(stringval, s);
- vim_free(stringval);
- stringval = s;
}
}
}
! if (!failed)
{
! if (opt_type != gov_string || s != NULL)
! {
! set_option_value(arg, n, s, opt_flags);
! arg_end = p;
! }
! else
! emsg(_(e_stringreq));
}
! *p = c1;
! vim_free(stringval);
}
}
! // ":let @r = expr": Set register contents.
! else if (*arg == '@')
{
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
! {
! emsg(_("E996: Cannot lock a register"));
! return NULL;
! }
! ++arg;
! if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
! semsg(_(e_letwrong), op);
! else if (endchars != NULL
! && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
! emsg(_(e_unexpected_characters_in_let));
! else
{
! char_u *ptofree = NULL;
! char_u *s;
! p = tv_get_string_chk(tv);
! if (p != NULL && op != NULL && *op == '.')
{
! s = get_reg_contents(*arg == '@' ? '"' : *arg, GREG_EXPR_SRC);
! if (s != NULL)
! {
! p = ptofree = concat_str(s, p);
! vim_free(s);
! }
}
- if (p != NULL)
- {
- write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
- arg_end = arg + 1;
- }
- vim_free(ptofree);
}
}
! // ":let var = expr": Set internal variable.
! // ":let var: type = expr": Set internal variable with type.
! // ":let {expr} = expr": Idem, name made with curly braces
else if (eval_isnamec1(*arg) || *arg == '{')
{
lval_T lv;
p = get_lval(arg, tv, &lv, FALSE, FALSE,
(flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
? GLV_NO_DECL : 0, FNE_CHECK_START);
--- 1289,1578 ----
}
/*
! * Set an environment variable, part of ex_let_one().
*/
static char_u *
! ex_let_env(
! char_u *arg,
! typval_T *tv,
! int flags,
! char_u *endchars,
! char_u *op)
{
char_u *arg_end = NULL;
+ char_u *name;
int len;
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
{
! emsg(_("E996: Cannot lock an environment variable"));
return NULL;
}
! // Find the end of the name.
! ++arg;
! name = arg;
! len = get_env_len(&arg);
! if (len == 0)
! semsg(_(e_invarg2), name - 1);
! else
{
! if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
! semsg(_(e_letwrong), op);
! else if (endchars != NULL
! && vim_strchr(endchars, *skipwhite(arg)) == NULL)
! emsg(_(e_unexpected_characters_in_let));
! else if (!check_secure())
{
! char_u *tofree = NULL;
! int c1 = name[len];
! char_u *p;
! name[len] = NUL;
! p = tv_get_string_chk(tv);
! if (p != NULL && op != NULL && *op == '.')
{
! int mustfree = FALSE;
! char_u *s = vim_getenv(name, &mustfree);
! if (s != NULL)
{
! p = tofree = concat_str(s, p);
! if (mustfree)
! vim_free(s);
}
}
+ if (p != NULL)
+ {
+ vim_setenv_ext(name, p);
+ arg_end = arg;
+ }
+ name[len] = c1;
+ vim_free(tofree);
}
}
+ return arg_end;
+ }
! /*
! * Set an option, part of ex_let_one().
! */
! static char_u *
! ex_let_option(
! char_u *arg,
! typval_T *tv,
! int flags,
! char_u *endchars,
! char_u *op)
! {
! char_u *p;
! int opt_flags;
! char_u *arg_end = NULL;
!
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
! {
! emsg(_(e_const_option));
! return NULL;
! }
!
! // Find the end of the name.
! p = find_option_end(&arg, &opt_flags);
! if (p == NULL || (endchars != NULL
! && vim_strchr(endchars, *skipwhite(p)) == NULL))
! emsg(_(e_unexpected_characters_in_let));
! else
{
! int c1;
! long n = 0;
! getoption_T opt_type;
! long numval;
! char_u *stringval = NULL;
! char_u *s = NULL;
! int failed = FALSE;
!
! c1 = *p;
! *p = NUL;
!
! opt_type = get_option_value(arg, &numval, &stringval, opt_flags);
! if ((opt_type == gov_bool
! || opt_type == gov_number
! || opt_type == gov_hidden_bool
! || opt_type == gov_hidden_number)
! && (tv->v_type != VAR_STRING || !in_vim9script()))
{
! if (opt_type == gov_bool || opt_type == gov_hidden_bool)
! // bool, possibly hidden
! n = (long)tv_get_bool(tv);
! else
! // number, possibly hidden
! n = (long)tv_get_number(tv);
}
!
! // Avoid setting a string option to the text "v:false" or similar.
! // In Vim9 script also don't convert a number to string.
! if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL
! && (!in_vim9script() || tv->v_type != VAR_NUMBER))
! s = tv_get_string_chk(tv);
!
! if (op != NULL && *op != '=')
{
! if (((opt_type == gov_bool || opt_type == gov_number) && *op == '.')
! || (opt_type == gov_string && *op != '.'))
! {
! semsg(_(e_letwrong), op);
! failed = TRUE; // don't set the value
! }
! else
! {
! // number, in legacy script also bool
! if (opt_type == gov_number
! || (opt_type == gov_bool && !in_vim9script()))
{
! switch (*op)
{
! case '+': n = numval + n; break;
! case '-': n = numval - n; break;
! case '*': n = numval * n; break;
! case '/': n = (long)num_divide(numval, n,
&failed); break;
! case '%': n = (long)num_modulus(numval, n,
&failed); break;
}
+ s = NULL;
+ }
+ else if (opt_type == gov_string
+ && stringval != NULL && s != NULL)
+ {
+ // string
+ s = concat_str(stringval, s);
+ vim_free(stringval);
+ stringval = s;
}
}
+ }
! if (!failed)
! {
! if (opt_type != gov_string || s != NULL)
{
! set_option_value(arg, n, s, opt_flags);
! arg_end = p;
}
! else
! emsg(_(e_stringreq));
}
+ *p = c1;
+ vim_free(stringval);
}
+ return arg_end;
+ }
! /*
! * Set a register, part of ex_let_one().
! */
! static char_u *
! ex_let_register(
! char_u *arg,
! typval_T *tv,
! int flags,
! char_u *endchars,
! char_u *op)
! {
! char_u *arg_end = NULL;
!
! if ((flags & (ASSIGN_CONST | ASSIGN_FINAL))
! && (flags & ASSIGN_FOR_LOOP) == 0)
{
! emsg(_("E996: Cannot lock a register"));
! return NULL;
! }
! ++arg;
! if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
! semsg(_(e_letwrong), op);
! else if (endchars != NULL
! && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
! emsg(_(e_unexpected_characters_in_let));
! else
! {
! char_u *ptofree = NULL;
! char_u *p;
!
! p = tv_get_string_chk(tv);
! if (p != NULL && op != NULL && *op == '.')
{
! char_u *s = get_reg_contents(*arg == '@'
! ? '"' : *arg, GREG_EXPR_SRC);
! if (s != NULL)
{
! p = ptofree = concat_str(s, p);
! vim_free(s);
}
}
+ if (p != NULL)
+ {
+ write_reg_contents(*arg == '@' ? '"' : *arg, p, -1, FALSE);
+ arg_end = arg + 1;
+ }
+ vim_free(ptofree);
+ }
+ return arg_end;
+ }
+
+ /*
+ * Set one item of ":let var = expr" or ":let [v1, v2] = list" to its value.
+ * Returns a pointer to the char just after the var name.
+ * Returns NULL if there is an error.
+ */
+ static char_u *
+ ex_let_one(
+ char_u *arg, // points to variable name
+ typval_T *tv, // value to assign to variable
+ int copy, // copy value from "tv"
+ int flags, // ASSIGN_CONST, ASSIGN_FINAL, etc.
+ char_u *endchars, // valid chars after variable name or NULL
+ char_u *op, // "+", "-", "." or NULL
+ int var_idx) // variable index for "let [a, b] = list"
+ {
+ char_u *arg_end = NULL;
+
+ if (in_vim9script() && (flags & (ASSIGN_NO_DECL | ASSIGN_DECL)) == 0
+ && (flags & (ASSIGN_CONST | ASSIGN_FINAL)) == 0
+ && vim_strchr((char_u *)"$@&", *arg) != NULL)
+ {
+ vim9_declare_error(arg);
+ return NULL;
}
! if (*arg == '$')
! {
! // ":let $VAR = expr": Set environment variable.
! return ex_let_env(arg, tv, flags, endchars, op);
! }
! else if (*arg == '&')
! {
! // ":let &option = expr": Set option value.
! // ":let &l:option = expr": Set local option value.
! // ":let &g:option = expr": Set global option value.
! // ":for &ts in range(8)": Set option value for for loop
! return ex_let_option(arg, tv, flags, endchars, op);
! }
! else if (*arg == '@')
! {
! // ":let @r = expr": Set register contents.
! return ex_let_register(arg, tv, flags, endchars, op);
! }
else if (eval_isnamec1(*arg) || *arg == '{')
{
lval_T lv;
+ char_u *p;
+ // ":let var = expr": Set internal variable.
+ // ":let var: type = expr": Set internal variable with type.
+ // ":let {expr} = expr": Idem, name made with curly braces
p = get_lval(arg, tv, &lv, FALSE, FALSE,
(flags & (ASSIGN_NO_DECL | ASSIGN_DECL))
? GLV_NO_DECL : 0, FNE_CHECK_START);
***************
*** 1527,1533 ****
--- 1580,1588 ----
{
if (endchars != NULL && vim_strchr(endchars,
*skipwhite(lv.ll_name_end)) == NULL)
+ {
emsg(_(e_unexpected_characters_in_let));
+ }
else
{
set_var_lval(&lv, p, tv, copy, flags, op, var_idx);
***************
*** 1536,1542 ****
}
clear_lval(&lv);
}
-
else
semsg(_(e_invarg2), arg);
--- 1591,1596 ----
*** ../vim-8.2.3688/src/version.c 2021-11-28 18:41:00.548752971 +0000
--- src/version.c 2021-11-28 19:41:34.991966618 +0000
***************
*** 759,760 ****
--- 759,762 ----
{ /* Add new patch number below this line */
+ /**/
+ 3689,
/**/
--
FATAL ERROR! SYSTEM HALTED! - Press any key to continue doing nothing.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///