Patch 9.0.1380
Problem:    CTRL-X on 2**64 subtracts two. (James McCoy)
Solution:   Correct computation for large number. (closes #12103)
Files:      src/charset.c, src/proto/charset.pro, src/ex_cmds.c,
            src/ex_getln.c, src/json.c, src/misc2.c, src/ops.c, src/option.c,
            src/strings.c, src/typval.c, src/testdir/test_increment.vim


*** ../vim-9.0.1379/src/charset.c       2023-02-21 14:27:34.512360384 +0000
--- src/charset.c       2023-03-04 20:39:35.476205644 +0000
***************
*** 2138,2144 ****
      varnumber_T               *nptr,      // return: signed result
      uvarnumber_T      *unptr,     // return: unsigned result
      int                       maxlen,     // max length of string to check
!     int                       strict)     // check strictly
  {
      char_u        *ptr = start;
      int                   pre = 0;            // default is decimal
--- 2138,2145 ----
      varnumber_T               *nptr,      // return: signed result
      uvarnumber_T      *unptr,     // return: unsigned result
      int                       maxlen,     // max length of string to check
!     int                       strict,     // check strictly
!     int                       *overflow)  // when not NULL set to TRUE for 
overflow
  {
      char_u        *ptr = start;
      int                   pre = 0;            // default is decimal
***************
*** 2209,2215 ****
--- 2210,2220 ----
            if (un <= UVARNUM_MAX / 2)
                un = 2 * un + (uvarnumber_T)(*ptr - '0');
            else
+           {
                un = UVARNUM_MAX;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            ++ptr;
            if (n++ == maxlen)
                break;
***************
*** 2234,2240 ****
--- 2239,2249 ----
            if (un <= UVARNUM_MAX / 8)
                un = 8 * un + (uvarnumber_T)(*ptr - '0');
            else
+           {
                un = UVARNUM_MAX;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            ++ptr;
            if (n++ == maxlen)
                break;
***************
*** 2258,2264 ****
--- 2267,2277 ----
            if (un <= UVARNUM_MAX / 16)
                un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
            else
+           {
                un = UVARNUM_MAX;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            ++ptr;
            if (n++ == maxlen)
                break;
***************
*** 2282,2288 ****
--- 2295,2305 ----
                    || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10))
                un = 10 * un + digit;
            else
+           {
                un = UVARNUM_MAX;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            ++ptr;
            if (n++ == maxlen)
                break;
***************
*** 2310,2316 ****
--- 2327,2337 ----
        {
            // avoid ubsan error for overflow
            if (un > VARNUM_MAX)
+           {
                *nptr = VARNUM_MIN;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            else
                *nptr = -(varnumber_T)un;
        }
***************
*** 2318,2324 ****
--- 2339,2349 ----
        {
            // prevent a large unsigned number to become negative
            if (un > VARNUM_MAX)
+           {
                un = VARNUM_MAX;
+               if (overflow != NULL)
+                   *overflow = TRUE;
+           }
            *nptr = (varnumber_T)un;
        }
      }
*** ../vim-9.0.1379/src/proto/charset.pro       2023-02-16 15:03:08.501667452 
+0000
--- src/proto/charset.pro       2023-03-04 20:44:54.984494997 +0000
***************
*** 64,70 ****
  long getdigits(char_u **pp);
  long getdigits_quoted(char_u **pp);
  int vim_isblankline(char_u *lbuf);
! void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T 
*nptr, uvarnumber_T *unptr, int maxlen, int strict);
  int hex2nr(int c);
  int hexhex2nr(char_u *p);
  int rem_backslash(char_u *str);
--- 64,70 ----
  long getdigits(char_u **pp);
  long getdigits_quoted(char_u **pp);
  int vim_isblankline(char_u *lbuf);
! void vim_str2nr(char_u *start, int *prep, int *len, int what, varnumber_T 
*nptr, uvarnumber_T *unptr, int maxlen, int strict, int *overflow);
  int hex2nr(int c);
  int hexhex2nr(char_u *p);
  int rem_backslash(char_u *str);
*** ../vim-9.0.1379/src/ex_cmds.c       2023-02-20 12:16:33.328269404 +0000
--- src/ex_cmds.c       2023-03-04 20:40:53.824282930 +0000
***************
*** 511,517 ****
  
        if (sort_nr || sort_flt)
        {
!           // Make sure vim_str2nr doesn't read any digits past the end
            // of the match, by temporarily terminating the string there
            s2 = s + end_col;
            c = *s2;
--- 511,517 ----
  
        if (sort_nr || sort_flt)
        {
!           // Make sure vim_str2nr() doesn't read any digits past the end
            // of the match, by temporarily terminating the string there
            s2 = s + end_col;
            c = *s2;
***************
*** 539,545 ****
                    nrs[lnum - eap->line1].st_u.num.is_number = TRUE;
                    vim_str2nr(s, NULL, NULL, sort_what,
                        &nrs[lnum - eap->line1].st_u.num.value,
!                       NULL, 0, FALSE);
                }
            }
            else
--- 539,545 ----
                    nrs[lnum - eap->line1].st_u.num.is_number = TRUE;
                    vim_str2nr(s, NULL, NULL, sort_what,
                        &nrs[lnum - eap->line1].st_u.num.value,
!                       NULL, 0, FALSE, NULL);
                }
            }
            else
*** ../vim-9.0.1379/src/ex_getln.c      2023-02-20 12:16:33.328269404 +0000
--- src/ex_getln.c      2023-03-04 20:41:05.688294226 +0000
***************
*** 4338,4344 ****
      *str = skipwhite(*str);
      if (**str == '-' || vim_isdigit(**str))  // parse "from" part of range
      {
!       vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
        *str += len;
        *num1 = (int)num;
        first = TRUE;
--- 4338,4344 ----
      *str = skipwhite(*str);
      if (**str == '-' || vim_isdigit(**str))  // parse "from" part of range
      {
!       vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL);
        *str += len;
        *num1 = (int)num;
        first = TRUE;
***************
*** 4347,4353 ****
      if (**str == ',')                 // parse "to" part of range
      {
        *str = skipwhite(*str + 1);
!       vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE);
        if (len > 0)
        {
            *num2 = (int)num;
--- 4347,4353 ----
      if (**str == ',')                 // parse "to" part of range
      {
        *str = skipwhite(*str + 1);
!       vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0, FALSE, NULL);
        if (len > 0)
        {
            *num2 = (int)num;
*** ../vim-9.0.1379/src/json.c  2022-12-08 15:32:11.083034191 +0000
--- src/json.c  2023-03-04 20:41:39.344325712 +0000
***************
*** 540,546 ****
                    nr = 0;
                    len = 0;
                    vim_str2nr(p + 2, NULL, &len,
!                            STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE);
                    if (len == 0)
                    {
                        if (res != NULL)
--- 540,546 ----
                    nr = 0;
                    len = 0;
                    vim_str2nr(p + 2, NULL, &len,
!                            STR2NR_HEX + STR2NR_FORCE, &nr, NULL, 4, TRUE, 
NULL);
                    if (len == 0)
                    {
                        if (res != NULL)
***************
*** 556,563 ****
  
                        // decode surrogate pair: \ud812\u3456
                        len = 0;
!                       vim_str2nr(p + 2, NULL, &len,
!                            STR2NR_HEX + STR2NR_FORCE, &nr2, NULL, 4, TRUE);
                        if (len == 0)
                        {
                            if (res != NULL)
--- 556,563 ----
  
                        // decode surrogate pair: \ud812\u3456
                        len = 0;
!                       vim_str2nr(p + 2, NULL, &len, STR2NR_HEX + STR2NR_FORCE,
!                                                   &nr2, NULL, 4, TRUE, NULL);
                        if (len == 0)
                        {
                            if (res != NULL)
***************
*** 882,888 ****
  
                            vim_str2nr(reader->js_buf + reader->js_used,
                                    NULL, &len, 0, // what
!                                   &nr, NULL, 0, TRUE);
                            if (len == 0)
                            {
                                semsg(_(e_json_decode_error_at_str), p);
--- 882,888 ----
  
                            vim_str2nr(reader->js_buf + reader->js_used,
                                    NULL, &len, 0, // what
!                                   &nr, NULL, 0, TRUE, NULL);
                            if (len == 0)
                            {
                                semsg(_(e_json_decode_error_at_str), p);
*** ../vim-9.0.1379/src/misc2.c 2023-02-11 16:15:46.140840726 +0000
--- src/misc2.c 2023-03-04 20:41:54.724339840 +0000
***************
*** 1410,1416 ****
            bp += 3;    // skip t_xx, xx may be '-' or '>'
        else if (STRNICMP(bp, "char-", 5) == 0)
        {
!           vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE);
            if (l == 0)
            {
                emsg(_(e_invalid_argument));
--- 1410,1416 ----
            bp += 3;    // skip t_xx, xx may be '-' or '>'
        else if (STRNICMP(bp, "char-", 5) == 0)
        {
!           vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0, TRUE, NULL);
            if (l == 0)
            {
                emsg(_(e_invalid_argument));
***************
*** 1448,1454 ****
            {
                // <Char-123> or <Char-033> or <Char-0x33>
                vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
!                                                                 &n, 0, TRUE);
                if (l == 0)
                {
                    emsg(_(e_invalid_argument));
--- 1448,1454 ----
            {
                // <Char-123> or <Char-033> or <Char-0x33>
                vim_str2nr(last_dash + 6, NULL, &l, STR2NR_ALL, NULL,
!                                                           &n, 0, TRUE, NULL);
                if (l == 0)
                {
                    emsg(_(e_invalid_argument));
*** ../vim-9.0.1379/src/ops.c   2023-02-20 12:16:33.332269406 +0000
--- src/ops.c   2023-03-04 20:43:16.540412494 +0000
***************
*** 2781,2791 ****
                    ? (int)STRLEN(ptr) - col
                    : length);
  
        vim_str2nr(ptr + col, &pre, &length,
                0 + (do_bin ? STR2NR_BIN : 0)
                    + (do_oct ? STR2NR_OCT : 0)
                    + (do_hex ? STR2NR_HEX : 0),
!               NULL, &n, maxlen, FALSE);
  
        // ignore leading '-' for hex and octal and bin numbers
        if (pre && negative)
--- 2781,2792 ----
                    ? (int)STRLEN(ptr) - col
                    : length);
  
+       int overflow = FALSE;
        vim_str2nr(ptr + col, &pre, &length,
                0 + (do_bin ? STR2NR_BIN : 0)
                    + (do_oct ? STR2NR_OCT : 0)
                    + (do_hex ? STR2NR_HEX : 0),
!               NULL, &n, maxlen, FALSE, &overflow);
  
        // ignore leading '-' for hex and octal and bin numbers
        if (pre && negative)
***************
*** 2802,2811 ****
            subtract ^= TRUE;
  
        oldn = n;
!       if (subtract)
!           n -= (uvarnumber_T)Prenum1;
!       else
!           n += (uvarnumber_T)Prenum1;
        // handle wraparound for decimal numbers
        if (!pre)
        {
--- 2803,2816 ----
            subtract ^= TRUE;
  
        oldn = n;
!       if (!overflow)  // if number is too big don't add/subtract
!       {
!           if (subtract)
!               n -= (uvarnumber_T)Prenum1;
!           else
!               n += (uvarnumber_T)Prenum1;
!       }
! 
        // handle wraparound for decimal numbers
        if (!pre)
        {
*** ../vim-9.0.1379/src/option.c        2023-03-04 19:57:28.342671183 +0000
--- src/option.c        2023-03-04 20:43:32.100425875 +0000
***************
*** 2157,2163 ****
      else if (*arg == '-' || VIM_ISDIGIT(*arg))
      {
        // Allow negative (for 'undolevels'), octal and hex numbers.
!       vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE);
        if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
        {
            errmsg = e_number_required_after_equal;
--- 2157,2163 ----
      else if (*arg == '-' || VIM_ISDIGIT(*arg))
      {
        // Allow negative (for 'undolevels'), octal and hex numbers.
!       vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0, TRUE, NULL);
        if (i == 0 || (arg[i] != NUL && !VIM_ISWHITE(arg[i])))
        {
            errmsg = e_number_required_after_equal;
*** ../vim-9.0.1379/src/strings.c       2023-01-23 20:46:16.166493150 +0000
--- src/strings.c       2023-03-04 20:43:37.844430785 +0000
***************
*** 1188,1194 ****
        case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
        case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
      }
!     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
      // Text after the number is silently ignored.
      if (isneg)
        rettv->vval.v_number = -n;
--- 1188,1194 ----
        case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
        case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
      }
!     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE, NULL);
      // Text after the number is silently ignored.
      if (isneg)
        rettv->vval.v_number = -n;
*** ../vim-9.0.1379/src/typval.c        2023-01-25 21:05:35.131042802 +0000
--- src/typval.c        2023-03-04 20:43:56.792446834 +0000
***************
*** 217,223 ****
            }
            if (varp->vval.v_string != NULL)
                vim_str2nr(varp->vval.v_string, NULL, NULL,
!                                           STR2NR_ALL, &n, NULL, 0, FALSE);
            return n;
        case VAR_LIST:
            emsg(_(e_using_list_as_number));
--- 217,223 ----
            }
            if (varp->vval.v_string != NULL)
                vim_str2nr(varp->vval.v_string, NULL, NULL,
!                                        STR2NR_ALL, &n, NULL, 0, FALSE, NULL);
            return n;
        case VAR_LIST:
            emsg(_(e_using_list_as_number));
***************
*** 2230,2236 ****
        // decimal, hex or octal number
        vim_str2nr(*arg, NULL, &len, skip_quotes
                      ? STR2NR_NO_OCT + STR2NR_QUOTE
!                     : STR2NR_ALL, &n, NULL, 0, TRUE);
        if (len == 0)
        {
            if (evaluate)
--- 2230,2236 ----
        // decimal, hex or octal number
        vim_str2nr(*arg, NULL, &len, skip_quotes
                      ? STR2NR_NO_OCT + STR2NR_QUOTE
!                     : STR2NR_ALL, &n, NULL, 0, TRUE, NULL);
        if (len == 0)
        {
            if (evaluate)
*** ../vim-9.0.1379/src/testdir/test_increment.vim      2023-01-28 
19:18:56.729720605 +0000
--- src/testdir/test_increment.vim      2023-03-04 20:46:49.696585531 +0000
***************
*** 840,845 ****
--- 840,861 ----
    set nrformats-=unsigned
  endfunc
  
+ func Test_in_decrement_large_number()
+   " NOTE: 18446744073709551616 == 2^64
+   call setline(1, '18446744073709551616')
+   exec "norm! gg0\<C-X>"
+   call assert_equal('18446744073709551615', getline(1))
+ 
+   exec "norm! gg0\<C-X>"
+   call assert_equal('18446744073709551614', getline(1))
+ 
+   exec "norm! gg0\<C-A>"
+   call assert_equal('18446744073709551615', getline(1))
+ 
+   exec "norm! gg0\<C-A>"
+   call assert_equal('-18446744073709551615', getline(1))
+ endfunc
+ 
  func Test_normal_increment_with_virtualedit()
    set virtualedit=all
  
*** ../vim-9.0.1379/src/version.c       2023-03-04 19:57:28.342671183 +0000
--- src/version.c       2023-03-04 20:20:43.225852411 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1380,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
224. You set up your own Web page. You set up a Web page for each
     of your kids... and your pets.

 /// Bram Moolenaar -- b...@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    ///

-- 
-- 
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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230304204805.4C3DE1C0419%40moolenaar.net.

Reply via email to