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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20211128195414.46AFD1C45E4%40moolenaar.net.

Raspunde prin e-mail lui