Bump version
[pytest.git] / Python / pystrtod.c
blobe1c84ea03e0eb735841b3493a85b6e6d4690a2b1
1 /* -*- Mode: C; c-file-style: "python" -*- */
3 #include <Python.h>
4 #include <locale.h>
6 /* ascii character tests (as opposed to locale tests) */
7 #define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \
8 (c) == '\r' || (c) == '\t' || (c) == '\v')
9 #define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
10 #define ISXDIGIT(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
13 /**
14 * PyOS_ascii_strtod:
15 * @nptr: the string to convert to a numeric value.
16 * @endptr: if non-%NULL, it returns the character after
17 * the last character used in the conversion.
19 * Converts a string to a #gdouble value.
20 * This function behaves like the standard strtod() function
21 * does in the C locale. It does this without actually
22 * changing the current locale, since that would not be
23 * thread-safe.
25 * This function is typically used when reading configuration
26 * files or other non-user input that should be locale independent.
27 * To handle input from the user you should normally use the
28 * locale-sensitive system strtod() function.
30 * If the correct value would cause overflow, plus or minus %HUGE_VAL
31 * is returned (according to the sign of the value), and %ERANGE is
32 * stored in %errno. If the correct value would cause underflow,
33 * zero is returned and %ERANGE is stored in %errno.
34 * If memory allocation fails, %ENOMEM is stored in %errno.
36 * This function resets %errno before calling strtod() so that
37 * you can reliably detect overflow and underflow.
39 * Return value: the #gdouble value.
40 **/
41 double
42 PyOS_ascii_strtod(const char *nptr, char **endptr)
44 char *fail_pos;
45 double val = -1.0;
46 struct lconv *locale_data;
47 const char *decimal_point;
48 size_t decimal_point_len;
49 const char *p, *decimal_point_pos;
50 const char *end = NULL; /* Silence gcc */
52 assert(nptr != NULL);
54 fail_pos = NULL;
56 locale_data = localeconv();
57 decimal_point = locale_data->decimal_point;
58 decimal_point_len = strlen(decimal_point);
60 assert(decimal_point_len != 0);
62 decimal_point_pos = NULL;
63 if (decimal_point[0] != '.' ||
64 decimal_point[1] != 0)
66 p = nptr;
67 /* Skip leading space */
68 while (ISSPACE(*p))
69 p++;
71 /* Skip leading optional sign */
72 if (*p == '+' || *p == '-')
73 p++;
75 while (ISDIGIT(*p))
76 p++;
78 if (*p == '.')
80 decimal_point_pos = p++;
82 while (ISDIGIT(*p))
83 p++;
85 if (*p == 'e' || *p == 'E')
86 p++;
87 if (*p == '+' || *p == '-')
88 p++;
89 while (ISDIGIT(*p))
90 p++;
91 end = p;
93 /* For the other cases, we need not convert the decimal point */
96 /* Set errno to zero, so that we can distinguish zero results
97 and underflows */
98 errno = 0;
100 if (decimal_point_pos)
102 char *copy, *c;
104 /* We need to convert the '.' to the locale specific decimal point */
105 copy = (char *)PyMem_MALLOC(end - nptr + 1 + decimal_point_len);
106 if (copy == NULL) {
107 if (endptr)
108 *endptr = (char *)nptr;
109 errno = ENOMEM;
110 return val;
113 c = copy;
114 memcpy(c, nptr, decimal_point_pos - nptr);
115 c += decimal_point_pos - nptr;
116 memcpy(c, decimal_point, decimal_point_len);
117 c += decimal_point_len;
118 memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
119 c += end - (decimal_point_pos + 1);
120 *c = 0;
122 val = strtod(copy, &fail_pos);
124 if (fail_pos)
126 if (fail_pos > decimal_point_pos)
127 fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
128 else
129 fail_pos = (char *)nptr + (fail_pos - copy);
132 PyMem_FREE(copy);
135 else {
136 unsigned i = 0;
137 if (nptr[i] == '-')
138 i++;
139 if (nptr[i] == '0' && (nptr[i+1] == 'x' || nptr[i+1] == 'X'))
140 fail_pos = (char*)nptr;
141 else
142 val = strtod(nptr, &fail_pos);
145 if (endptr)
146 *endptr = fail_pos;
148 return val;
153 * PyOS_ascii_formatd:
154 * @buffer: A buffer to place the resulting string in
155 * @buf_len: The length of the buffer.
156 * @format: The printf()-style format to use for the
157 * code to use for converting.
158 * @d: The #gdouble to convert
160 * Converts a #gdouble to a string, using the '.' as
161 * decimal point. To format the number you pass in
162 * a printf()-style format string. Allowed conversion
163 * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'.
165 * Return value: The pointer to the buffer with the converted string.
167 char *
168 PyOS_ascii_formatd(char *buffer,
169 size_t buf_len,
170 const char *format,
171 double d)
173 struct lconv *locale_data;
174 const char *decimal_point;
175 size_t decimal_point_len, rest_len;
176 char *p;
177 char format_char;
179 /* g_return_val_if_fail (buffer != NULL, NULL); */
180 /* g_return_val_if_fail (format[0] == '%', NULL); */
181 /* g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); */
183 format_char = format[strlen(format) - 1];
185 /* g_return_val_if_fail (format_char == 'e' || format_char == 'E' || */
186 /* format_char == 'f' || format_char == 'F' || */
187 /* format_char == 'g' || format_char == 'G', */
188 /* NULL); */
190 if (format[0] != '%')
191 return NULL;
193 if (strpbrk(format + 1, "'l%"))
194 return NULL;
196 if (!(format_char == 'e' || format_char == 'E' ||
197 format_char == 'f' || format_char == 'F' ||
198 format_char == 'g' || format_char == 'G'))
199 return NULL;
202 PyOS_snprintf(buffer, buf_len, format, d);
204 locale_data = localeconv();
205 decimal_point = locale_data->decimal_point;
206 decimal_point_len = strlen(decimal_point);
208 assert(decimal_point_len != 0);
210 if (decimal_point[0] != '.' ||
211 decimal_point[1] != 0)
213 p = buffer;
215 if (*p == '+' || *p == '-')
216 p++;
218 while (isdigit((unsigned char)*p))
219 p++;
221 if (strncmp(p, decimal_point, decimal_point_len) == 0)
223 *p = '.';
224 p++;
225 if (decimal_point_len > 1) {
226 rest_len = strlen(p + (decimal_point_len - 1));
227 memmove(p, p + (decimal_point_len - 1),
228 rest_len);
229 p[rest_len] = 0;
234 return buffer;
237 double
238 PyOS_ascii_atof(const char *nptr)
240 return PyOS_ascii_strtod(nptr, NULL);