mystrtoul.c 8.1 KB

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