Branch data Line data Source code
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 : 5873766 : PyOS_strtoul(const char *str, char **ptr, int base)
96 : : {
97 : 5873766 : 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 [ + - - + ]: 5873766 : while (*str && Py_ISSPACE(*str))
103 : 0 : ++str;
104 : :
105 : : /* check for leading 0b, 0o or 0x for auto-base or base 16 */
106 [ + - - - : 5873766 : switch (base) {
- ]
107 : 5873766 : case 0: /* look for leading 0b, 0o or 0x */
108 [ + + ]: 5873766 : if (*str == '0') {
109 : 1813334 : ++str;
110 [ + + + + ]: 1813334 : if (*str == 'x' || *str == 'X') {
111 : : /* there must be at least one digit after 0x */
112 [ - + ]: 194000 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
113 [ # # ]: 0 : if (ptr)
114 : 0 : *ptr = (char *)str;
115 : 0 : return 0;
116 : : }
117 : 194000 : ++str;
118 : 194000 : base = 16;
119 [ + + + + ]: 1619334 : } else if (*str == 'o' || *str == 'O') {
120 : : /* there must be at least one digit after 0o */
121 [ - + ]: 4002 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
122 [ # # ]: 0 : if (ptr)
123 : 0 : *ptr = (char *)str;
124 : 0 : return 0;
125 : : }
126 : 4002 : ++str;
127 : 4002 : base = 8;
128 [ + + + + ]: 1615332 : } else if (*str == 'b' || *str == 'B') {
129 : : /* there must be at least one digit after 0b */
130 [ - + ]: 754 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
131 [ # # ]: 0 : if (ptr)
132 : 0 : *ptr = (char *)str;
133 : 0 : return 0;
134 : : }
135 : 754 : ++str;
136 : 754 : base = 2;
137 : : } else {
138 : : /* skip all zeroes... */
139 [ + + ]: 1614922 : while (*str == '0')
140 : 344 : ++str;
141 [ - + ]: 1614578 : while (Py_ISSPACE(*str))
142 : 0 : ++str;
143 [ + - ]: 1614578 : if (ptr)
144 : 1614578 : *ptr = (char *)str;
145 : 1614578 : return 0;
146 : : }
147 : : }
148 : : else
149 : 4060432 : base = 10;
150 : 4259188 : break;
151 : :
152 : : /* even with explicit base, skip leading 0? prefix */
153 : 0 : case 16:
154 [ # # ]: 0 : if (*str == '0') {
155 : 0 : ++str;
156 [ # # # # ]: 0 : if (*str == 'x' || *str == 'X') {
157 : : /* there must be at least one digit after 0x */
158 [ # # ]: 0 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
159 [ # # ]: 0 : if (ptr)
160 : 0 : *ptr = (char *)str;
161 : 0 : return 0;
162 : : }
163 : 0 : ++str;
164 : : }
165 : : }
166 : 0 : break;
167 : 0 : case 8:
168 [ # # ]: 0 : if (*str == '0') {
169 : 0 : ++str;
170 [ # # # # ]: 0 : if (*str == 'o' || *str == 'O') {
171 : : /* there must be at least one digit after 0o */
172 [ # # ]: 0 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
173 [ # # ]: 0 : if (ptr)
174 : 0 : *ptr = (char *)str;
175 : 0 : return 0;
176 : : }
177 : 0 : ++str;
178 : : }
179 : : }
180 : 0 : break;
181 : 0 : case 2:
182 [ # # ]: 0 : if(*str == '0') {
183 : 0 : ++str;
184 [ # # # # ]: 0 : if (*str == 'b' || *str == 'B') {
185 : : /* there must be at least one digit after 0b */
186 [ # # ]: 0 : if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
187 [ # # ]: 0 : if (ptr)
188 : 0 : *ptr = (char *)str;
189 : 0 : return 0;
190 : : }
191 : 0 : ++str;
192 : : }
193 : : }
194 : 0 : break;
195 : : }
196 : :
197 : : /* catch silly bases */
198 [ + - - + ]: 4259188 : if (base < 2 || base > 36) {
199 [ # # ]: 0 : if (ptr)
200 : 0 : *ptr = (char *)str;
201 : 0 : return 0;
202 : : }
203 : :
204 : : /* skip leading zeroes */
205 [ + + ]: 4321258 : while (*str == '0')
206 : 62070 : ++str;
207 : :
208 : : /* base is guaranteed to be in [2, 36] at this point */
209 : 4259188 : ovlimit = digitlimit[base];
210 : :
211 : : /* do the conversion until non-digit character encountered */
212 [ + + ]: 14492272 : while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
213 [ + + ]: 10233776 : if (ovlimit > 0) /* no overflow check required */
214 : 10232719 : result = result * base + c;
215 : : else { /* requires overflow check */
216 : : unsigned long temp_result;
217 : :
218 [ + + ]: 1057 : if (ovlimit < 0) /* guaranteed overflow */
219 : 183 : goto overflowed;
220 : :
221 : : /* there could be an overflow */
222 : : /* check overflow just from shifting */
223 [ + + ]: 874 : if (result > smallmax[base])
224 : 495 : goto overflowed;
225 : :
226 : 379 : result *= base;
227 : :
228 : : /* check overflow from the digit's value */
229 : 379 : temp_result = result + c;
230 [ + + ]: 379 : if (temp_result < result)
231 : 14 : goto overflowed;
232 : :
233 : 365 : result = temp_result;
234 : : }
235 : :
236 : 10233084 : ++str;
237 : 10233084 : --ovlimit;
238 : : }
239 : :
240 : : /* set pointer to point to the last character scanned */
241 [ + - ]: 4258496 : if (ptr)
242 : 4258496 : *ptr = (char *)str;
243 : :
244 : 4258496 : return result;
245 : :
246 : 692 : overflowed:
247 [ + - ]: 692 : if (ptr) {
248 : : /* spool through remaining digit characters */
249 [ + + ]: 10236 : while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
250 : 9544 : ++str;
251 : 692 : *ptr = (char *)str;
252 : : }
253 : 692 : errno = ERANGE;
254 : 692 : 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 : 4060432 : PyOS_strtol(const char *str, char **ptr, int base)
264 : : {
265 : : long result;
266 : : unsigned long uresult;
267 : : char sign;
268 : :
269 [ + - - + ]: 4060432 : while (*str && Py_ISSPACE(*str))
270 : 0 : str++;
271 : :
272 : 4060432 : sign = *str;
273 [ + - - + ]: 4060432 : if (sign == '+' || sign == '-')
274 : 0 : str++;
275 : :
276 : 4060432 : uresult = PyOS_strtoul(str, ptr, base);
277 : :
278 [ + + ]: 4060432 : if (uresult <= (unsigned long)LONG_MAX) {
279 : 4059620 : result = (long)uresult;
280 [ - + ]: 4059620 : if (sign == '-')
281 : 0 : result = -result;
282 : : }
283 [ - + - - ]: 812 : else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
284 : 0 : result = LONG_MIN;
285 : : }
286 : : else {
287 : 812 : errno = ERANGE;
288 : 812 : result = LONG_MAX;
289 : : }
290 : 4060432 : return result;
291 : : }
|