PageRenderTime 33ms CodeModel.GetById 22ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/Python/mystrtoul.c

http://unladen-swallow.googlecode.com/
C | 285 lines | 210 code | 32 blank | 43 comment | 83 complexity | 0cd7dc64cfd9ca820f6c99bc3095eea5 MD5 | raw file
  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 */
 20static 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
 65static 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)] */
 72static 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*/
 94unsigned long
 95PyOS_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
240overflowed:
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
256long
257PyOS_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}