cpython/Python/mystrtoul.c
Georg Brandl fceab5a385 Merged revisions 60080-60089,60091-60093 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r60080 | andrew.kuchling | 2008-01-19 17:26:13 +0100 (Sat, 19 Jan 2008) | 2 lines

  Patch #742598 from Michael Pomraning: add .timeout attribute to SocketServer that will call
  .handle_timeout() method when no requests are received within the timeout period.
........
  r60081 | andrew.kuchling | 2008-01-19 17:34:09 +0100 (Sat, 19 Jan 2008) | 1 line

  Add item
........
  r60082 | christian.heimes | 2008-01-19 17:39:27 +0100 (Sat, 19 Jan 2008) | 2 lines

  Disabled test_xmlrpc:test_404. It's causing lots of false alarms.
  I also disabled a test in test_ssl which requires network access to svn.python.org. This fixes a bug Skip has reported a while ago.
........
  r60083 | georg.brandl | 2008-01-19 18:38:53 +0100 (Sat, 19 Jan 2008) | 2 lines

  Clarify thread.join() docs. #1873.
........
  r60084 | georg.brandl | 2008-01-19 19:02:46 +0100 (Sat, 19 Jan 2008) | 2 lines

  #1782: don't leak in error case in PyModule_AddXxxConstant. Patch by Hrvoje Nik?\197?\161i?\196?\135.
........
  r60085 | andrew.kuchling | 2008-01-19 19:08:52 +0100 (Sat, 19 Jan 2008) | 1 line

  Sort two names into position
........
  r60086 | andrew.kuchling | 2008-01-19 19:18:41 +0100 (Sat, 19 Jan 2008) | 2 lines

  Patch #976880: add mmap .rfind() method, and 'end' paramter to .find().
  Contributed by John Lenton.
........
  r60087 | facundo.batista | 2008-01-19 19:38:19 +0100 (Sat, 19 Jan 2008) | 5 lines


  Fix #1693149.  Now you can pass several modules separated by
  coma to trace.py in the same --ignore-module option.
  Thanks Raghuram Devarakonda.
........
  r60088 | facundo.batista | 2008-01-19 19:45:46 +0100 (Sat, 19 Jan 2008) | 3 lines


  Comment in NEWS regarding the change in trace.py.
........
  r60089 | skip.montanaro | 2008-01-19 19:47:24 +0100 (Sat, 19 Jan 2008) | 2 lines

  missing from r60088 checkin.
........
  r60091 | andrew.kuchling | 2008-01-19 20:14:05 +0100 (Sat, 19 Jan 2008) | 1 line

  Add item
........
  r60092 | georg.brandl | 2008-01-19 20:27:05 +0100 (Sat, 19 Jan 2008) | 4 lines

  Fix #1679: "0x" was taken as a valid integer literal.
  Fixes the tokenizer, tokenize.py and int() to reject this.
  Patches by Malte Helmert.
........
  r60093 | georg.brandl | 2008-01-19 20:48:19 +0100 (Sat, 19 Jan 2008) | 3 lines

  Fix #1146: TextWrap vs words 1-character shorter than the width.
  Patch by Quentin Gallet-Gilles.
........
2008-01-19 20:08:23 +00:00

299 lines
6.7 KiB
C

#include "Python.h"
#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE)
#define _SGI_MP_SOURCE
#endif
/* 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
/* strtol and strtoul, renamed to avoid conflicts */
#include <ctype.h>
#ifdef HAVE_ERRNO_H
#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.
*/
#if SIZEOF_LONG == 4
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 */
#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
/*
** 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 0b, 0o 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
PyOS_strtoul(register char *str, char **ptr, int base)
{
register unsigned long result = 0; /* return value of the function */
register int c; /* current input character */
register int ovlimit; /* required digits to overflow */
/* skip leading white space */
while (*str && isspace(Py_CHARMASK(*str)))
++str;
/* check for leading 0b, 0o or 0x for auto-base or base 16 */
switch (base) {
case 0: /* look for leading 0b, 0o or 0x */
if (*str == '0') {
++str;
if (*str == 'x' || *str == 'X') {
/* there must be at least one digit after 0x */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 16;
} else if (*str == 'o' || *str == 'O') {
/* there must be at least one digit after 0o */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 8;
} else if (*str == 'b' || *str == 'B') {
/* there must be at least one digit after 0b */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
if (ptr)
*ptr = str;
return 0;
}
++str;
base = 2;
} else {
/* skip all zeroes... */
while (*str == '0')
++str;
while (isspace(Py_CHARMASK(*str)))
++str;
if (ptr)
*ptr = str;
return 0;
}
}
else
base = 10;
break;
/* even with explicit base, skip leading 0? prefix */
case 16:
if (*str == '0') {
++str;
if (*str == 'x' || *str == 'X') {
/* there must be at least one digit after 0x */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 16) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
case 8:
if (*str == '0') {
++str;
if (*str == 'o' || *str == 'O') {
/* there must be at least one digit after 0o */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 8) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
case 2:
if(*str == '0') {
++str;
if (*str == 'b' || *str == 'B') {
/* there must be at least one digit after 0b */
if (_PyLong_DigitValue[Py_CHARMASK(str[1])] >= 2) {
if (ptr)
*ptr = str;
return 0;
}
++str;
}
}
break;
}
/* catch silly bases */
if (base < 2 || base > 36) {
if (ptr)
*ptr = str;
return 0;
}
/* 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 */
while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) {
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;
}
/* set pointer to point to the last character scanned */
if (ptr)
*ptr = str;
return result;
overflowed:
if (ptr) {
/* spool through remaining digit characters */
while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base)
++str;
*ptr = str;
}
errno = ERANGE;
return (unsigned long)-1;
}
/* Checking for overflow in PyOS_strtol is a PITA; see comments
* about PY_ABS_LONG_MIN in longobject.c.
*/
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
long
PyOS_strtol(char *str, char **ptr, int base)
{
long result;
unsigned long uresult;
char sign;
while (*str && isspace(Py_CHARMASK(*str)))
str++;
sign = *str;
if (sign == '+' || sign == '-')
str++;
uresult = PyOS_strtoul(str, ptr, base);
if (uresult <= (unsigned long)LONG_MAX) {
result = (long)uresult;
if (sign == '-')
result = -result;
}
else if (sign == '-' && uresult == PY_ABS_LONG_MIN) {
result = LONG_MIN;
}
else {
errno = ERANGE;
result = LONG_MAX;
}
return result;
}