Home | History | Annotate | Download | only in Python
      1 
      2 #include "Python.h"
      3 
      4 #if defined(__sgi) && defined(WITH_THREAD) && !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 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 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 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 0, 0b, 0B, 0o, 0O, 0x or 0X
     87 **              to tell which base.  If these are absent it defaults
     88 **              to 10. 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(register char *str, char **ptr, int base)
     96 {
     97     register unsigned long result = 0; /* return value of the function */
     98     register int c;             /* current input character */
     99     register int ovlimit;       /* required digits to overflow */
    100 
    101     /* skip leading white space */
    102     while (*str && isspace(Py_CHARMASK(*str)))
    103         ++str;
    104 
    105     /* check for leading 0 or 0x for auto-base or base 16 */
    106     switch (base) {
    107     case 0:             /* look for leading 0, 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 = 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 = 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 = str;
    133                     return 0;
    134                 }
    135                 ++str;
    136                 base = 2;
    137             } else {
    138                 base = 8;
    139             }
    140         }
    141         else
    142             base = 10;
    143         break;
    144 
    145     case 2:     /* skip leading 0b or 0B */
    146         if (*str == '0') {
    147             ++str;
    148             if (*str == 'b' || *str == 'B') {
    149                 /* there must be at least one digit after 0b */
    150                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
    151                     if (ptr)
    152                         *ptr = str;
    153                     return 0;
    154                 }
    155                 ++str;
    156             }
    157         }
    158         break;
    159 
    160     case 8:     /* skip leading 0o or 0O */
    161         if (*str == '0') {
    162             ++str;
    163             if (*str == 'o' || *str == 'O') {
    164                 /* there must be at least one digit after 0o */
    165                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
    166                     if (ptr)
    167                         *ptr = str;
    168                     return 0;
    169                 }
    170                 ++str;
    171             }
    172         }
    173         break;
    174 
    175     case 16:            /* skip leading 0x or 0X */
    176         if (*str == '0') {
    177             ++str;
    178             if (*str == 'x' || *str == 'X') {
    179                 /* there must be at least one digit after 0x */
    180                 if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
    181                     if (ptr)
    182                         *ptr = str;
    183                     return 0;
    184                 }
    185                 ++str;
    186             }
    187         }
    188         break;
    189     }
    190 
    191     /* catch silly bases */
    192     if (base < 2 || base > 36) {
    193         if (ptr)
    194             *ptr = str;
    195         return 0;
    196     }
    197 
    198     /* skip leading zeroes */
    199     while (*str == '0')
    200         ++str;
    201 
    202     /* base is guaranteed to be in [2, 36] at this point */
    203     ovlimit = digitlimit[base];
    204 
    205     /* do the conversion until non-digit character encountered */
    206     while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
    207         if (ovlimit > 0) /* no overflow check required */
    208             result = result * base + c;
    209         else { /* requires overflow check */
    210             register unsigned long temp_result;
    211 
    212             if (ovlimit < 0) /* guaranteed overflow */
    213                 goto overflowed;
    214 
    215             /* there could be an overflow */
    216             /* check overflow just from shifting */
    217             if (result > smallmax[base])
    218                 goto overflowed;
    219 
    220             result *= base;
    221 
    222             /* check overflow from the digit's value */
    223             temp_result = result + c;
    224             if (temp_result < result)
    225                 goto overflowed;
    226 
    227             result = temp_result;
    228         }
    229 
    230         ++str;
    231         --ovlimit;
    232     }
    233 
    234     /* set pointer to point to the last character scanned */
    235     if (ptr)
    236         *ptr = str;
    237 
    238     return result;
    239 
    240 overflowed:
    241     if (ptr) {
    242         /* spool through remaining digit characters */
    243         while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
    244             ++str;
    245         *ptr = str;
    246     }
    247     errno = ERANGE;
    248     return (unsigned long)-1;
    249 }
    250 
    251 /* Checking for overflow in PyOS_strtol is a PITA; see comments
    252  * about PY_ABS_LONG_MIN in longobject.c.
    253  */
    254 #define PY_ABS_LONG_MIN         (0-(unsigned long)LONG_MIN)
    255 
    256 long
    257 PyOS_strtol(char *str, char **ptr, int base)
    258 {
    259     long result;
    260     unsigned long uresult;
    261     char sign;
    262 
    263     while (*str && isspace(Py_CHARMASK(*str)))
    264         str++;
    265 
    266     sign = *str;
    267     if (sign == '+' || sign == '-')
    268         str++;
    269 
    270     uresult = PyOS_strtoul(str, ptr, base);
    271 
    272     if (uresult <= (unsigned long)LONG_MAX) {
    273         result = (long)uresult;
    274         if (sign == '-')
    275             result = -result;
    276     }
    277     else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
    278         result = LONG_MIN;
    279     }
    280     else {
    281         errno = ERANGE;
    282         result = LONG_MAX;
    283     }
    284     return result;
    285 }
    286