(root)/
Python-3.12.0/
Python/
mystrtoul.c
       1  #include "Python.h"
       2  #include "pycore_long.h"          // _PyLong_DigitValue
       3  
       4  #if defined(__sgi) && !defined(_SGI_MP_SOURCE)
       5  #define _SGI_MP_SOURCE
       6  #endif
       7  
       8  /* strtol and strtoul, renamed to avoid conflicts */
       9  
      10  
      11  #include <ctype.h>
      12  #ifdef HAVE_ERRNO_H
      13  #include <errno.h>
      14  #endif
      15  
      16  /* Static overflow check values for bases 2 through 36.
      17   * smallmax[base] is the largest unsigned long i such that
      18   * i * base doesn't overflow unsigned long.
      19   */
      20  static const unsigned long smallmax[] = {
      21      0, /* bases 0 and 1 are invalid */
      22      0,
      23      ULONG_MAX / 2,
      24      ULONG_MAX / 3,
      25      ULONG_MAX / 4,
      26      ULONG_MAX / 5,
      27      ULONG_MAX / 6,
      28      ULONG_MAX / 7,
      29      ULONG_MAX / 8,
      30      ULONG_MAX / 9,
      31      ULONG_MAX / 10,
      32      ULONG_MAX / 11,
      33      ULONG_MAX / 12,
      34      ULONG_MAX / 13,
      35      ULONG_MAX / 14,
      36      ULONG_MAX / 15,
      37      ULONG_MAX / 16,
      38      ULONG_MAX / 17,
      39      ULONG_MAX / 18,
      40      ULONG_MAX / 19,
      41      ULONG_MAX / 20,
      42      ULONG_MAX / 21,
      43      ULONG_MAX / 22,
      44      ULONG_MAX / 23,
      45      ULONG_MAX / 24,
      46      ULONG_MAX / 25,
      47      ULONG_MAX / 26,
      48      ULONG_MAX / 27,
      49      ULONG_MAX / 28,
      50      ULONG_MAX / 29,
      51      ULONG_MAX / 30,
      52      ULONG_MAX / 31,
      53      ULONG_MAX / 32,
      54      ULONG_MAX / 33,
      55      ULONG_MAX / 34,
      56      ULONG_MAX / 35,
      57      ULONG_MAX / 36,
      58  };
      59  
      60  /* maximum digits that can't ever overflow for bases 2 through 36,
      61   * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
      62   * Note that this is pessimistic if sizeof(long) > 4.
      63   */
      64  #if SIZEOF_LONG == 4
      65  static const int digitlimit[] = {
      66      0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  /*  0 -  9 */
      67      9,  9,  8,  8,  8,  8,  8,  7,  7,  7,  /* 10 - 19 */
      68      7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  /* 20 - 29 */
      69      6,  6,  6,  6,  6,  6,  6};             /* 30 - 36 */
      70  #elif SIZEOF_LONG == 8
      71  /* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
      72  static const int digitlimit[] = {
      73           0,   0, 64, 40, 32, 27, 24, 22, 21, 20,  /*  0 -  9 */
      74      19,  18, 17, 17, 16, 16, 16, 15, 15, 15,  /* 10 - 19 */
      75      14,  14, 14, 14, 13, 13, 13, 13, 13, 13,  /* 20 - 29 */
      76      13,  12, 12, 12, 12, 12, 12};             /* 30 - 36 */
      77  #else
      78  #error "Need table for SIZEOF_LONG"
      79  #endif
      80  
      81  /*
      82  **      strtoul
      83  **              This is a general purpose routine for converting
      84  **              an ascii string to an integer in an arbitrary base.
      85  **              Leading white space is ignored.  If 'base' is zero
      86  **              it looks for a leading 0b, 0o or 0x to tell which
      87  **              base.  If these are absent it defaults to 10.
      88  **              Base must be 0 or between 2 and 36 (inclusive).
      89  **              If 'ptr' is non-NULL it will contain a pointer to
      90  **              the end of the scan.
      91  **              Errors due to bad pointers will probably result in
      92  **              exceptions - we don't check for them.
      93  */
      94  unsigned long
      95  PyOS_strtoul(const char *str, char **ptr, int base)
      96  {
      97      unsigned long result = 0; /* return value of the function */
      98      int c;             /* current input character */
      99      int ovlimit;       /* required digits to overflow */
     100  
     101      /* skip leading white space */
     102      while (*str && Py_ISSPACE(*str))
     103          ++str;
     104  
     105      /* check for leading 0b, 0o or 0x for auto-base or base 16 */
     106      switch (base) {
     107      case 0:             /* look for leading 0b, 0o or 0x */
     108          if (*str == '0') {
     109              ++str;
     110              if (*str == 'x' || *str == 'X') {
     111                  /* there must be at least one digit after 0x */
     112                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     113                      if (ptr)
     114                          *ptr = (char *)str;
     115                      return 0;
     116                  }
     117                  ++str;
     118                  base = 16;
     119              } else if (*str == 'o' || *str == 'O') {
     120                  /* there must be at least one digit after 0o */
     121                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     122                      if (ptr)
     123                          *ptr = (char *)str;
     124                      return 0;
     125                  }
     126                  ++str;
     127                  base = 8;
     128              } else if (*str == 'b' || *str == 'B') {
     129                  /* there must be at least one digit after 0b */
     130                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     131                      if (ptr)
     132                          *ptr = (char *)str;
     133                      return 0;
     134                  }
     135                  ++str;
     136                  base = 2;
     137              } else {
     138                  /* skip all zeroes... */
     139                  while (*str == '0')
     140                      ++str;
     141                  while (Py_ISSPACE(*str))
     142                      ++str;
     143                  if (ptr)
     144                      *ptr = (char *)str;
     145                  return 0;
     146              }
     147          }
     148          else
     149              base = 10;
     150          break;
     151  
     152      /* even with explicit base, skip leading 0? prefix */
     153      case 16:
     154          if (*str == '0') {
     155              ++str;
     156              if (*str == 'x' || *str == 'X') {
     157                  /* there must be at least one digit after 0x */
     158                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
     159                      if (ptr)
     160                          *ptr = (char *)str;
     161                      return 0;
     162                  }
     163                  ++str;
     164              }
     165          }
     166          break;
     167      case 8:
     168          if (*str == '0') {
     169              ++str;
     170              if (*str == 'o' || *str == 'O') {
     171                  /* there must be at least one digit after 0o */
     172                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
     173                      if (ptr)
     174                          *ptr = (char *)str;
     175                      return 0;
     176                  }
     177                  ++str;
     178              }
     179          }
     180          break;
     181      case 2:
     182          if(*str == '0') {
     183              ++str;
     184              if (*str == 'b' || *str == 'B') {
     185                  /* there must be at least one digit after 0b */
     186                  if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
     187                      if (ptr)
     188                          *ptr = (char *)str;
     189                      return 0;
     190                  }
     191                  ++str;
     192              }
     193          }
     194          break;
     195      }
     196  
     197      /* catch silly bases */
     198      if (base < 2 || base > 36) {
     199          if (ptr)
     200              *ptr = (char *)str;
     201          return 0;
     202      }
     203  
     204      /* skip leading zeroes */
     205      while (*str == '0')
     206          ++str;
     207  
     208      /* base is guaranteed to be in [2, 36] at this point */
     209      ovlimit = digitlimit[base];
     210  
     211      /* do the conversion until non-digit character encountered */
     212      while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
     213          if (ovlimit > 0) /* no overflow check required */
     214              result = result * base + c;
     215          else { /* requires overflow check */
     216              unsigned long temp_result;
     217  
     218              if (ovlimit < 0) /* guaranteed overflow */
     219                  goto overflowed;
     220  
     221              /* there could be an overflow */
     222              /* check overflow just from shifting */
     223              if (result > smallmax[base])
     224                  goto overflowed;
     225  
     226              result *= base;
     227  
     228              /* check overflow from the digit's value */
     229              temp_result = result + c;
     230              if (temp_result < result)
     231                  goto overflowed;
     232  
     233              result = temp_result;
     234          }
     235  
     236          ++str;
     237          --ovlimit;
     238      }
     239  
     240      /* set pointer to point to the last character scanned */
     241      if (ptr)
     242          *ptr = (char *)str;
     243  
     244      return result;
     245  
     246  overflowed:
     247      if (ptr) {
     248          /* spool through remaining digit characters */
     249          while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
     250              ++str;
     251          *ptr = (char *)str;
     252      }
     253      errno = ERANGE;
     254      return (unsigned long)-1;
     255  }
     256  
     257  /* Checking for overflow in PyOS_strtol is a PITA; see comments
     258   * about PY_ABS_LONG_MIN in longobject.c.
     259   */
     260  #define PY_ABS_LONG_MIN         (0-(unsigned long)LONG_MIN)
     261  
     262  long
     263  PyOS_strtol(const char *str, char **ptr, int base)
     264  {
     265      long result;
     266      unsigned long uresult;
     267      char sign;
     268  
     269      while (*str && Py_ISSPACE(*str))
     270          str++;
     271  
     272      sign = *str;
     273      if (sign == '+' || sign == '-')
     274          str++;
     275  
     276      uresult = PyOS_strtoul(str, ptr, base);
     277  
     278      if (uresult <= (unsigned long)LONG_MAX) {
     279          result = (long)uresult;
     280          if (sign == '-')
     281              result = -result;
     282      }
     283      else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
     284          result = LONG_MIN;
     285      }
     286      else {
     287          errno = ERANGE;
     288          result = LONG_MAX;
     289      }
     290      return result;
     291  }