mystrtoul.c 5.22 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1

Guido van Rossum's avatar
Guido van Rossum committed
2
#include "Python.h"
3

4 5 6 7
#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
#define _SGI_MP_SOURCE
#endif

Guido van Rossum's avatar
Guido van Rossum committed
8 9 10 11 12 13 14 15
/* Convert a possibly signed character to a nonnegative int */
/* XXX This assumes characters are 8 bits wide */
#ifdef __CHAR_UNSIGNED__
#define Py_CHARMASK(c)		(c)
#else
#define Py_CHARMASK(c)		((c) & 0xff)
#endif

16 17
/* strtol and strtoul, renamed to avoid conflicts */

18 19

#include <ctype.h>
20
#ifdef HAVE_ERRNO_H
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include <errno.h>
#endif

/* Static overflow check values for bases 2 through 36.
 * smallmax[base] is the largest unsigned long i such that
 * i * base doesn't overflow unsigned long.
 */
static unsigned long smallmax[] = {
	0, /* bases 0 and 1 are invalid */
	0,
	ULONG_MAX / 2,
	ULONG_MAX / 3,
	ULONG_MAX / 4,
	ULONG_MAX / 5,
	ULONG_MAX / 6,
	ULONG_MAX / 7,
	ULONG_MAX / 8,
	ULONG_MAX / 9,
	ULONG_MAX / 10,
	ULONG_MAX / 11,
	ULONG_MAX / 12,
	ULONG_MAX / 13,
	ULONG_MAX / 14,
	ULONG_MAX / 15,
	ULONG_MAX / 16,
	ULONG_MAX / 17,
	ULONG_MAX / 18,
	ULONG_MAX / 19,
	ULONG_MAX / 20,
	ULONG_MAX / 21,
	ULONG_MAX / 22,
	ULONG_MAX / 23,
	ULONG_MAX / 24,
	ULONG_MAX / 25,
	ULONG_MAX / 26,
	ULONG_MAX / 27,
	ULONG_MAX / 28,
	ULONG_MAX / 29,
	ULONG_MAX / 30,
	ULONG_MAX / 31,
	ULONG_MAX / 32,
	ULONG_MAX / 33,
	ULONG_MAX / 34,
	ULONG_MAX / 35,
	ULONG_MAX / 36,
};

/* maximum digits that can't ever overflow for bases 2 through 36,
 * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)].
 * Note that this is pessimistic if sizeof(long) > 4.
 */
72
#if SIZEOF_LONG == 4
73 74 75 76 77
static int digitlimit[] = {
	0,  0, 32, 20, 16, 13, 12, 11, 10, 10,  /*  0 -  9 */
	9,  9,  8,  8,  8,  8,  8,  7,  7,  7,  /* 10 - 19 */
	7,  7,  7,  7,  6,  6,  6,  6,  6,  6,  /* 20 - 29 */
	6,  6,  6,  6,  6,  6,  6};             /* 30 - 36 */
78 79 80 81 82 83 84 85 86 87
#elif SIZEOF_LONG == 8
/* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */
static int digitlimit[] = {
	 0,   0, 64, 40, 32, 27, 24, 22, 21, 20,  /*  0 -  9 */
	19,  18, 17, 17, 16, 16, 16, 15, 15, 15,  /* 10 - 19 */
	14,  14, 14, 14, 13, 13, 13, 13, 13, 13,  /* 20 - 29 */
	13,  12, 12, 12, 12, 12, 12};             /* 30 - 36 */
#else
#error "Need table for SIZEOF_LONG"
#endif
88

Guido van Rossum's avatar
Guido van Rossum committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102
/*
**	strtoul
**		This is a general purpose routine for converting
**		an ascii string to an integer in an arbitrary base.
**		Leading white space is ignored.  If 'base' is zero
**		it looks for a leading 0, 0x or 0X to tell which
**		base.  If these are absent it defaults to 10.
**		Base must be 0 or between 2 and 36 (inclusive).
**		If 'ptr' is non-NULL it will contain a pointer to
**		the end of the scan.
**		Errors due to bad pointers will probably result in
**		exceptions - we don't check for them.
*/
unsigned long
103
PyOS_strtoul(register char *str, char **ptr, int base)
Guido van Rossum's avatar
Guido van Rossum committed
104
{
105 106 107
	register unsigned long result = 0; /* return value of the function */
	register int c;	 	/* current input character */
	register int ovlimit; 	/* required digits to overflow */
Guido van Rossum's avatar
Guido van Rossum committed
108

109 110 111
	/* skip leading white space */
	while (*str && isspace(Py_CHARMASK(*str)))
		++str;
Guido van Rossum's avatar
Guido van Rossum committed
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
	/* check for leading 0 or 0x for auto-base or base 16 */
	switch (base) {
		case 0:		/* look for leading 0, 0x or 0X */
			if (*str == '0') {
				++str;
				if (*str == 'x' || *str == 'X') {
					++str;
					base = 16;
				}
				else
					base = 8;
			}
			else
				base = 10;
			break;

		case 16:	/* skip leading 0x or 0X */
			if (*str == '0') {
				++str;
				if (*str == 'x' || *str == 'X')
					++str;
			}
			break;
Guido van Rossum's avatar
Guido van Rossum committed
136
	}
137 138 139 140 141 142

	/* catch silly bases */
	if (base < 2 || base > 36) {
		if (ptr)
			*ptr = str;
		return 0;
Guido van Rossum's avatar
Guido van Rossum committed
143
	}
144 145 146 147 148 149 150 151 152

	/* skip leading zeroes */
	while (*str == '0')
		++str;

	/* base is guaranteed to be in [2, 36] at this point */
	ovlimit = digitlimit[base];

	/* do the conversion until non-digit character encountered */
153
	while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
		if (ovlimit > 0) /* no overflow check required */
			result = result * base + c;
		else { /* requires overflow check */
			register unsigned long temp_result;

			if (ovlimit < 0) /* guaranteed overflow */
				goto overflowed;

			/* there could be an overflow */
			/* check overflow just from shifting */
			if (result > smallmax[base])
				goto overflowed;

			result *= base;

			/* check overflow from the digit's value */
			temp_result = result + c;
			if (temp_result < result)
				goto overflowed;

			result = temp_result;
		}

		++str;
		--ovlimit;
179
	}
180 181 182 183 184 185 186 187 188 189

	/* set pointer to point to the last character scanned */
	if (ptr)
		*ptr = str;

	return result;

overflowed:
	if (ptr) {
		/* spool through remaining digit characters */
190
		while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
191 192
			++str;
		*ptr = str;
193
	}
Guido van Rossum's avatar
Guido van Rossum committed
194
	errno = ERANGE;
195
	return (unsigned long)-1;
Guido van Rossum's avatar
Guido van Rossum committed
196 197
}

198 199
/* Checking for overflow in PyOS_strtol is a PITA; see comments
 * about PY_ABS_LONG_MIN in longobject.c.
200
 */
201
#define PY_ABS_LONG_MIN		(0-(unsigned long)LONG_MIN)
202

Guido van Rossum's avatar
Guido van Rossum committed
203
long
204
PyOS_strtol(char *str, char **ptr, int base)
Guido van Rossum's avatar
Guido van Rossum committed
205 206
{
	long result;
207
	unsigned long uresult;
Guido van Rossum's avatar
Guido van Rossum committed
208
	char sign;
209

Guido van Rossum's avatar
Guido van Rossum committed
210
	while (*str && isspace(Py_CHARMASK(*str)))
Guido van Rossum's avatar
Guido van Rossum committed
211
		str++;
212

Guido van Rossum's avatar
Guido van Rossum committed
213 214 215
	sign = *str;
	if (sign == '+' || sign == '-')
		str++;
216

217
	uresult = PyOS_strtoul(str, ptr, base);
218

219 220 221 222 223
	if (uresult <= (unsigned long)LONG_MAX) {
		result = (long)uresult;
		if (sign == '-')
			result = -result;
	}
224
	else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
225 226 227
		result = LONG_MIN;
	}
	else {
Guido van Rossum's avatar
Guido van Rossum committed
228
		errno = ERANGE;
229
		result = LONG_MAX;
Guido van Rossum's avatar
Guido van Rossum committed
230 231 232
	}
	return result;
}