Home | History | Annotate | Download | only in Python
      1 
      2 #include "Python.h"
      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(Py_CHARMASK(*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(Py_CHARMASK(*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(Py_CHARMASK(*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 }
    292