Python-2.7.3/Python/mystrtoul.c

No issues found

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