PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/utils/python/python26/Python/pystrtod.c

https://bitbucket.org/apexgames-ondemand/zombie-onslaught-source
C | 490 lines | 278 code | 65 blank | 147 comment | 147 complexity | 3a0853f47bb37e5bf9766fac780522b4 MD5 | raw file
  1. /* -*- Mode: C; c-file-style: "python" -*- */
  2. #include <Python.h>
  3. #include <locale.h>
  4. /* ascii character tests (as opposed to locale tests) */
  5. #define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \
  6. (c) == '\r' || (c) == '\t' || (c) == '\v')
  7. #define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
  8. /**
  9. * PyOS_ascii_strtod:
  10. * @nptr: the string to convert to a numeric value.
  11. * @endptr: if non-%NULL, it returns the character after
  12. * the last character used in the conversion.
  13. *
  14. * Converts a string to a #gdouble value.
  15. * This function behaves like the standard strtod() function
  16. * does in the C locale. It does this without actually
  17. * changing the current locale, since that would not be
  18. * thread-safe.
  19. *
  20. * This function is typically used when reading configuration
  21. * files or other non-user input that should be locale independent.
  22. * To handle input from the user you should normally use the
  23. * locale-sensitive system strtod() function.
  24. *
  25. * If the correct value would cause overflow, plus or minus %HUGE_VAL
  26. * is returned (according to the sign of the value), and %ERANGE is
  27. * stored in %errno. If the correct value would cause underflow,
  28. * zero is returned and %ERANGE is stored in %errno.
  29. * If memory allocation fails, %ENOMEM is stored in %errno.
  30. *
  31. * This function resets %errno before calling strtod() so that
  32. * you can reliably detect overflow and underflow.
  33. *
  34. * Return value: the #gdouble value.
  35. **/
  36. double
  37. PyOS_ascii_strtod(const char *nptr, char **endptr)
  38. {
  39. char *fail_pos;
  40. double val = -1.0;
  41. struct lconv *locale_data;
  42. const char *decimal_point;
  43. size_t decimal_point_len;
  44. const char *p, *decimal_point_pos;
  45. const char *end = NULL; /* Silence gcc */
  46. const char *digits_pos = NULL;
  47. int negate = 0;
  48. assert(nptr != NULL);
  49. fail_pos = NULL;
  50. locale_data = localeconv();
  51. decimal_point = locale_data->decimal_point;
  52. decimal_point_len = strlen(decimal_point);
  53. assert(decimal_point_len != 0);
  54. decimal_point_pos = NULL;
  55. /* We process any leading whitespace and the optional sign manually,
  56. then pass the remainder to the system strtod. This ensures that
  57. the result of an underflow has the correct sign. (bug #1725) */
  58. p = nptr;
  59. /* Skip leading space */
  60. while (ISSPACE(*p))
  61. p++;
  62. /* Process leading sign, if present */
  63. if (*p == '-') {
  64. negate = 1;
  65. p++;
  66. } else if (*p == '+') {
  67. p++;
  68. }
  69. /* What's left should begin with a digit, a decimal point, or one of
  70. the letters i, I, n, N. It should not begin with 0x or 0X */
  71. if ((!ISDIGIT(*p) &&
  72. *p != '.' && *p != 'i' && *p != 'I' && *p != 'n' && *p != 'N')
  73. ||
  74. (*p == '0' && (p[1] == 'x' || p[1] == 'X')))
  75. {
  76. if (endptr)
  77. *endptr = (char*)nptr;
  78. errno = EINVAL;
  79. return val;
  80. }
  81. digits_pos = p;
  82. if (decimal_point[0] != '.' ||
  83. decimal_point[1] != 0)
  84. {
  85. while (ISDIGIT(*p))
  86. p++;
  87. if (*p == '.')
  88. {
  89. decimal_point_pos = p++;
  90. while (ISDIGIT(*p))
  91. p++;
  92. if (*p == 'e' || *p == 'E')
  93. p++;
  94. if (*p == '+' || *p == '-')
  95. p++;
  96. while (ISDIGIT(*p))
  97. p++;
  98. end = p;
  99. }
  100. else if (strncmp(p, decimal_point, decimal_point_len) == 0)
  101. {
  102. /* Python bug #1417699 */
  103. if (endptr)
  104. *endptr = (char*)nptr;
  105. errno = EINVAL;
  106. return val;
  107. }
  108. /* For the other cases, we need not convert the decimal
  109. point */
  110. }
  111. /* Set errno to zero, so that we can distinguish zero results
  112. and underflows */
  113. errno = 0;
  114. if (decimal_point_pos)
  115. {
  116. char *copy, *c;
  117. /* We need to convert the '.' to the locale specific decimal
  118. point */
  119. copy = (char *)PyMem_MALLOC(end - digits_pos +
  120. 1 + decimal_point_len);
  121. if (copy == NULL) {
  122. if (endptr)
  123. *endptr = (char *)nptr;
  124. errno = ENOMEM;
  125. return val;
  126. }
  127. c = copy;
  128. memcpy(c, digits_pos, decimal_point_pos - digits_pos);
  129. c += decimal_point_pos - digits_pos;
  130. memcpy(c, decimal_point, decimal_point_len);
  131. c += decimal_point_len;
  132. memcpy(c, decimal_point_pos + 1,
  133. end - (decimal_point_pos + 1));
  134. c += end - (decimal_point_pos + 1);
  135. *c = 0;
  136. val = strtod(copy, &fail_pos);
  137. if (fail_pos)
  138. {
  139. if (fail_pos > decimal_point_pos)
  140. fail_pos = (char *)digits_pos +
  141. (fail_pos - copy) -
  142. (decimal_point_len - 1);
  143. else
  144. fail_pos = (char *)digits_pos +
  145. (fail_pos - copy);
  146. }
  147. PyMem_FREE(copy);
  148. }
  149. else {
  150. val = strtod(digits_pos, &fail_pos);
  151. }
  152. if (fail_pos == digits_pos)
  153. fail_pos = (char *)nptr;
  154. if (negate && fail_pos != nptr)
  155. val = -val;
  156. if (endptr)
  157. *endptr = fail_pos;
  158. return val;
  159. }
  160. /* Given a string that may have a decimal point in the current
  161. locale, change it back to a dot. Since the string cannot get
  162. longer, no need for a maximum buffer size parameter. */
  163. Py_LOCAL_INLINE(void)
  164. change_decimal_from_locale_to_dot(char* buffer)
  165. {
  166. struct lconv *locale_data = localeconv();
  167. const char *decimal_point = locale_data->decimal_point;
  168. if (decimal_point[0] != '.' || decimal_point[1] != 0) {
  169. size_t decimal_point_len = strlen(decimal_point);
  170. if (*buffer == '+' || *buffer == '-')
  171. buffer++;
  172. while (isdigit(Py_CHARMASK(*buffer)))
  173. buffer++;
  174. if (strncmp(buffer, decimal_point, decimal_point_len) == 0) {
  175. *buffer = '.';
  176. buffer++;
  177. if (decimal_point_len > 1) {
  178. /* buffer needs to get smaller */
  179. size_t rest_len = strlen(buffer +
  180. (decimal_point_len - 1));
  181. memmove(buffer,
  182. buffer + (decimal_point_len - 1),
  183. rest_len);
  184. buffer[rest_len] = 0;
  185. }
  186. }
  187. }
  188. }
  189. /* From the C99 standard, section 7.19.6:
  190. The exponent always contains at least two digits, and only as many more digits
  191. as necessary to represent the exponent.
  192. */
  193. #define MIN_EXPONENT_DIGITS 2
  194. /* Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS
  195. in length. */
  196. Py_LOCAL_INLINE(void)
  197. ensure_minumim_exponent_length(char* buffer, size_t buf_size)
  198. {
  199. char *p = strpbrk(buffer, "eE");
  200. if (p && (*(p + 1) == '-' || *(p + 1) == '+')) {
  201. char *start = p + 2;
  202. int exponent_digit_cnt = 0;
  203. int leading_zero_cnt = 0;
  204. int in_leading_zeros = 1;
  205. int significant_digit_cnt;
  206. /* Skip over the exponent and the sign. */
  207. p += 2;
  208. /* Find the end of the exponent, keeping track of leading
  209. zeros. */
  210. while (*p && isdigit(Py_CHARMASK(*p))) {
  211. if (in_leading_zeros && *p == '0')
  212. ++leading_zero_cnt;
  213. if (*p != '0')
  214. in_leading_zeros = 0;
  215. ++p;
  216. ++exponent_digit_cnt;
  217. }
  218. significant_digit_cnt = exponent_digit_cnt - leading_zero_cnt;
  219. if (exponent_digit_cnt == MIN_EXPONENT_DIGITS) {
  220. /* If there are 2 exactly digits, we're done,
  221. regardless of what they contain */
  222. }
  223. else if (exponent_digit_cnt > MIN_EXPONENT_DIGITS) {
  224. int extra_zeros_cnt;
  225. /* There are more than 2 digits in the exponent. See
  226. if we can delete some of the leading zeros */
  227. if (significant_digit_cnt < MIN_EXPONENT_DIGITS)
  228. significant_digit_cnt = MIN_EXPONENT_DIGITS;
  229. extra_zeros_cnt = exponent_digit_cnt -
  230. significant_digit_cnt;
  231. /* Delete extra_zeros_cnt worth of characters from the
  232. front of the exponent */
  233. assert(extra_zeros_cnt >= 0);
  234. /* Add one to significant_digit_cnt to copy the
  235. trailing 0 byte, thus setting the length */
  236. memmove(start,
  237. start + extra_zeros_cnt,
  238. significant_digit_cnt + 1);
  239. }
  240. else {
  241. /* If there are fewer than 2 digits, add zeros
  242. until there are 2, if there's enough room */
  243. int zeros = MIN_EXPONENT_DIGITS - exponent_digit_cnt;
  244. if (start + zeros + exponent_digit_cnt + 1
  245. < buffer + buf_size) {
  246. memmove(start + zeros, start,
  247. exponent_digit_cnt + 1);
  248. memset(start, '0', zeros);
  249. }
  250. }
  251. }
  252. }
  253. /* Ensure that buffer has a decimal point in it. The decimal point
  254. will not be in the current locale, it will always be '.' */
  255. Py_LOCAL_INLINE(void)
  256. ensure_decimal_point(char* buffer, size_t buf_size)
  257. {
  258. int insert_count = 0;
  259. char* chars_to_insert;
  260. /* search for the first non-digit character */
  261. char *p = buffer;
  262. if (*p == '-' || *p == '+')
  263. /* Skip leading sign, if present. I think this could only
  264. ever be '-', but it can't hurt to check for both. */
  265. ++p;
  266. while (*p && isdigit(Py_CHARMASK(*p)))
  267. ++p;
  268. if (*p == '.') {
  269. if (isdigit(Py_CHARMASK(*(p+1)))) {
  270. /* Nothing to do, we already have a decimal
  271. point and a digit after it */
  272. }
  273. else {
  274. /* We have a decimal point, but no following
  275. digit. Insert a zero after the decimal. */
  276. ++p;
  277. chars_to_insert = "0";
  278. insert_count = 1;
  279. }
  280. }
  281. else {
  282. chars_to_insert = ".0";
  283. insert_count = 2;
  284. }
  285. if (insert_count) {
  286. size_t buf_len = strlen(buffer);
  287. if (buf_len + insert_count + 1 >= buf_size) {
  288. /* If there is not enough room in the buffer
  289. for the additional text, just skip it. It's
  290. not worth generating an error over. */
  291. }
  292. else {
  293. memmove(p + insert_count, p,
  294. buffer + strlen(buffer) - p + 1);
  295. memcpy(p, chars_to_insert, insert_count);
  296. }
  297. }
  298. }
  299. /* Add the locale specific grouping characters to buffer. Note
  300. that any decimal point (if it's present) in buffer is already
  301. locale-specific. Return 0 on error, else 1. */
  302. Py_LOCAL_INLINE(int)
  303. add_thousands_grouping(char* buffer, size_t buf_size)
  304. {
  305. Py_ssize_t len = strlen(buffer);
  306. struct lconv *locale_data = localeconv();
  307. const char *decimal_point = locale_data->decimal_point;
  308. /* Find the decimal point, if any. We're only concerned
  309. about the characters to the left of the decimal when
  310. adding grouping. */
  311. char *p = strstr(buffer, decimal_point);
  312. if (!p) {
  313. /* No decimal, use the entire string. */
  314. /* If any exponent, adjust p. */
  315. p = strpbrk(buffer, "eE");
  316. if (!p)
  317. /* No exponent and no decimal. Use the entire
  318. string. */
  319. p = buffer + len;
  320. }
  321. /* At this point, p points just past the right-most character we
  322. want to format. We need to add the grouping string for the
  323. characters between buffer and p. */
  324. return _PyString_InsertThousandsGrouping(buffer, len, p-buffer,
  325. buf_size, NULL, 1);
  326. }
  327. /* see FORMATBUFLEN in unicodeobject.c */
  328. #define FLOAT_FORMATBUFLEN 120
  329. /**
  330. * PyOS_ascii_formatd:
  331. * @buffer: A buffer to place the resulting string in
  332. * @buf_size: The length of the buffer.
  333. * @format: The printf()-style format to use for the
  334. * code to use for converting.
  335. * @d: The #gdouble to convert
  336. *
  337. * Converts a #gdouble to a string, using the '.' as
  338. * decimal point. To format the number you pass in
  339. * a printf()-style format string. Allowed conversion
  340. * specifiers are 'e', 'E', 'f', 'F', 'g', 'G', and 'n'.
  341. *
  342. * 'n' is the same as 'g', except it uses the current locale.
  343. * 'Z' is the same as 'g', except it always has a decimal and
  344. * at least one digit after the decimal.
  345. *
  346. * Return value: The pointer to the buffer with the converted string.
  347. **/
  348. char *
  349. PyOS_ascii_formatd(char *buffer,
  350. size_t buf_size,
  351. const char *format,
  352. double d)
  353. {
  354. char format_char;
  355. size_t format_len = strlen(format);
  356. /* For type 'n', we need to make a copy of the format string, because
  357. we're going to modify 'n' -> 'g', and format is const char*, so we
  358. can't modify it directly. FLOAT_FORMATBUFLEN should be longer than
  359. we ever need this to be. There's an upcoming check to ensure it's
  360. big enough. */
  361. /* Issue 2264: code 'Z' requires copying the format. 'Z' is 'g', but
  362. also with at least one character past the decimal. */
  363. char tmp_format[FLOAT_FORMATBUFLEN];
  364. /* The last character in the format string must be the format char */
  365. format_char = format[format_len - 1];
  366. if (format[0] != '%')
  367. return NULL;
  368. /* I'm not sure why this test is here. It's ensuring that the format
  369. string after the first character doesn't have a single quote, a
  370. lowercase l, or a percent. This is the reverse of the commented-out
  371. test about 10 lines ago. */
  372. if (strpbrk(format + 1, "'l%"))
  373. return NULL;
  374. /* Also curious about this function is that it accepts format strings
  375. like "%xg", which are invalid for floats. In general, the
  376. interface to this function is not very good, but changing it is
  377. difficult because it's a public API. */
  378. if (!(format_char == 'e' || format_char == 'E' ||
  379. format_char == 'f' || format_char == 'F' ||
  380. format_char == 'g' || format_char == 'G' ||
  381. format_char == 'n' || format_char == 'Z'))
  382. return NULL;
  383. /* Map 'n' or 'Z' format_char to 'g', by copying the format string and
  384. replacing the final char with a 'g' */
  385. if (format_char == 'n' || format_char == 'Z') {
  386. if (format_len + 1 >= sizeof(tmp_format)) {
  387. /* The format won't fit in our copy. Error out. In
  388. practice, this will never happen and will be
  389. detected by returning NULL */
  390. return NULL;
  391. }
  392. strcpy(tmp_format, format);
  393. tmp_format[format_len - 1] = 'g';
  394. format = tmp_format;
  395. }
  396. /* Have PyOS_snprintf do the hard work */
  397. PyOS_snprintf(buffer, buf_size, format, d);
  398. /* Do various fixups on the return string */
  399. /* Get the current locale, and find the decimal point string.
  400. Convert that string back to a dot. Do not do this if using the
  401. 'n' (number) format code, since we want to keep the localized
  402. decimal point in that case. */
  403. if (format_char != 'n')
  404. change_decimal_from_locale_to_dot(buffer);
  405. /* If an exponent exists, ensure that the exponent is at least
  406. MIN_EXPONENT_DIGITS digits, providing the buffer is large enough
  407. for the extra zeros. Also, if there are more than
  408. MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get
  409. back to MIN_EXPONENT_DIGITS */
  410. ensure_minumim_exponent_length(buffer, buf_size);
  411. /* If format_char is 'Z', make sure we have at least one character
  412. after the decimal point (and make sure we have a decimal point). */
  413. if (format_char == 'Z')
  414. ensure_decimal_point(buffer, buf_size);
  415. /* If format_char is 'n', add the thousands grouping. */
  416. if (format_char == 'n')
  417. if (!add_thousands_grouping(buffer, buf_size))
  418. return NULL;
  419. return buffer;
  420. }
  421. double
  422. PyOS_ascii_atof(const char *nptr)
  423. {
  424. return PyOS_ascii_strtod(nptr, NULL);
  425. }