annotate Python/pystrtod.c @ 70303:2d760cb20e1e 2.6

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