blob: e67730528249211c0dee3993e98dfcf34d70725e [file] [log] [blame]
Martin v. Löwis737ea822004-06-08 18:52:54 +00001/* -*- Mode: C; c-file-style: "python" -*- */
2
3#include <Python.h>
4#include <locale.h>
5
Martin v. Löwis737ea822004-06-08 18:52:54 +00006/**
7 * PyOS_ascii_strtod:
8 * @nptr: the string to convert to a numeric value.
9 * @endptr: if non-%NULL, it returns the character after
10 * the last character used in the conversion.
11 *
12 * Converts a string to a #gdouble value.
13 * This function behaves like the standard strtod() function
14 * does in the C locale. It does this without actually
15 * changing the current locale, since that would not be
16 * thread-safe.
17 *
18 * This function is typically used when reading configuration
19 * files or other non-user input that should be locale independent.
20 * To handle input from the user you should normally use the
21 * locale-sensitive system strtod() function.
22 *
23 * If the correct value would cause overflow, plus or minus %HUGE_VAL
24 * is returned (according to the sign of the value), and %ERANGE is
25 * stored in %errno. If the correct value would cause underflow,
26 * zero is returned and %ERANGE is stored in %errno.
Georg Brandlb569ee42006-05-29 14:28:05 +000027 * If memory allocation fails, %ENOMEM is stored in %errno.
Martin v. Löwis737ea822004-06-08 18:52:54 +000028 *
29 * This function resets %errno before calling strtod() so that
30 * you can reliably detect overflow and underflow.
31 *
32 * Return value: the #gdouble value.
33 **/
Eric Smithaca19e62009-04-22 13:29:05 +000034
35/*
36 Use system strtod; since strtod is locale aware, we may
37 have to first fix the decimal separator.
38
39 Note that unlike _Py_dg_strtod, the system strtod may not always give
40 correctly rounded results.
41*/
42
Martin v. Löwis737ea822004-06-08 18:52:54 +000043double
Neal Norwitze7214a12005-12-18 05:03:17 +000044PyOS_ascii_strtod(const char *nptr, char **endptr)
Martin v. Löwis737ea822004-06-08 18:52:54 +000045{
46 char *fail_pos;
Neal Norwitz0e7a0ed2005-12-18 05:37:36 +000047 double val = -1.0;
Martin v. Löwis737ea822004-06-08 18:52:54 +000048 struct lconv *locale_data;
49 const char *decimal_point;
Neal Norwitzd39d8612006-01-08 01:03:36 +000050 size_t decimal_point_len;
Martin v. Löwis737ea822004-06-08 18:52:54 +000051 const char *p, *decimal_point_pos;
52 const char *end = NULL; /* Silence gcc */
Guido van Rossum3b835492008-01-05 00:59:59 +000053 const char *digits_pos = NULL;
54 int negate = 0;
Martin v. Löwis737ea822004-06-08 18:52:54 +000055
Martin v. Löwis737ea822004-06-08 18:52:54 +000056 assert(nptr != NULL);
57
58 fail_pos = NULL;
59
60 locale_data = localeconv();
61 decimal_point = locale_data->decimal_point;
62 decimal_point_len = strlen(decimal_point);
63
64 assert(decimal_point_len != 0);
65
66 decimal_point_pos = NULL;
Guido van Rossum3b835492008-01-05 00:59:59 +000067
Mark Dickinson6d6b2202009-04-26 16:04:05 +000068 /* Set errno to zero, so that we can distinguish zero results
69 and underflows */
70 errno = 0;
71
Guido van Rossum3b835492008-01-05 00:59:59 +000072 /* We process any leading whitespace and the optional sign manually,
73 then pass the remainder to the system strtod. This ensures that
74 the result of an underflow has the correct sign. (bug #1725) */
75
76 p = nptr;
77 /* Skip leading space */
Eric Smithcac7af62009-04-27 19:04:37 +000078 while (Py_ISSPACE(*p))
Guido van Rossum3b835492008-01-05 00:59:59 +000079 p++;
80
81 /* Process leading sign, if present */
82 if (*p == '-') {
83 negate = 1;
84 p++;
Mark Dickinson6d6b2202009-04-26 16:04:05 +000085 }
86 else if (*p == '+') {
Guido van Rossum3b835492008-01-05 00:59:59 +000087 p++;
88 }
89
Mark Dickinson6d6b2202009-04-26 16:04:05 +000090 /* Parse infinities and nans */
91 if (*p == 'i' || *p == 'I') {
92 if (PyOS_strnicmp(p, "inf", 3) == 0) {
93 val = Py_HUGE_VAL;
94 if (PyOS_strnicmp(p+3, "inity", 5) == 0)
95 fail_pos = (char *)p+8;
96 else
97 fail_pos = (char *)p+3;
98 goto got_val;
99 }
100 else
101 goto invalid_string;
Guido van Rossum3b835492008-01-05 00:59:59 +0000102 }
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000103#ifdef Py_NAN
104 if (*p == 'n' || *p == 'N') {
105 if (PyOS_strnicmp(p, "nan", 3) == 0) {
106 val = Py_NAN;
107 fail_pos = (char *)p+3;
108 goto got_val;
109 }
110 else
111 goto invalid_string;
112 }
113#endif
Guido van Rossum3b835492008-01-05 00:59:59 +0000114
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000115 /* Some platform strtods accept hex floats; Python shouldn't (at the
116 moment), so we check explicitly for strings starting with '0x'. */
117 if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X'))
118 goto invalid_string;
119
120 /* Check that what's left begins with a digit or decimal point */
Eric Smithcac7af62009-04-27 19:04:37 +0000121 if (!Py_ISDIGIT(*p) && *p != '.')
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000122 goto invalid_string;
123
124 digits_pos = p;
125 if (decimal_point[0] != '.' ||
Martin v. Löwis737ea822004-06-08 18:52:54 +0000126 decimal_point[1] != 0)
127 {
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000128 /* Look for a '.' in the input; if present, it'll need to be
129 swapped for the current locale's decimal point before we
130 call strtod. On the other hand, if we find the current
131 locale's decimal point then the input is invalid. */
Eric Smithcac7af62009-04-27 19:04:37 +0000132 while (Py_ISDIGIT(*p))
Neal Norwitze7214a12005-12-18 05:03:17 +0000133 p++;
134
135 if (*p == '.')
Martin v. Löwis737ea822004-06-08 18:52:54 +0000136 {
Neal Norwitze7214a12005-12-18 05:03:17 +0000137 decimal_point_pos = p++;
Martin v. Löwis737ea822004-06-08 18:52:54 +0000138
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000139 /* locate end of number */
Eric Smithcac7af62009-04-27 19:04:37 +0000140 while (Py_ISDIGIT(*p))
Martin v. Löwis737ea822004-06-08 18:52:54 +0000141 p++;
142
Neal Norwitze7214a12005-12-18 05:03:17 +0000143 if (*p == 'e' || *p == 'E')
144 p++;
145 if (*p == '+' || *p == '-')
146 p++;
Eric Smithcac7af62009-04-27 19:04:37 +0000147 while (Py_ISDIGIT(*p))
Neal Norwitze7214a12005-12-18 05:03:17 +0000148 p++;
149 end = p;
Martin v. Löwis737ea822004-06-08 18:52:54 +0000150 }
Martin v. Löwisfcfff0a2006-07-03 12:19:50 +0000151 else if (strncmp(p, decimal_point, decimal_point_len) == 0)
Martin v. Löwisfcfff0a2006-07-03 12:19:50 +0000152 /* Python bug #1417699 */
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000153 goto invalid_string;
Eric Smith5c35a9d2008-03-17 12:14:29 +0000154 /* For the other cases, we need not convert the decimal
155 point */
Martin v. Löwis737ea822004-06-08 18:52:54 +0000156 }
157
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000158 if (decimal_point_pos) {
Martin v. Löwis737ea822004-06-08 18:52:54 +0000159 char *copy, *c;
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000160 /* Create a copy of the input, with the '.' converted to the
161 locale-specific decimal point */
Guido van Rossum3b835492008-01-05 00:59:59 +0000162 copy = (char *)PyMem_MALLOC(end - digits_pos +
163 1 + decimal_point_len);
Georg Brandlb569ee42006-05-29 14:28:05 +0000164 if (copy == NULL) {
165 if (endptr)
Georg Brandl80181e22006-05-29 14:33:55 +0000166 *endptr = (char *)nptr;
Georg Brandlb569ee42006-05-29 14:28:05 +0000167 errno = ENOMEM;
168 return val;
169 }
Martin v. Löwis737ea822004-06-08 18:52:54 +0000170
171 c = copy;
Guido van Rossum3b835492008-01-05 00:59:59 +0000172 memcpy(c, digits_pos, decimal_point_pos - digits_pos);
173 c += decimal_point_pos - digits_pos;
Martin v. Löwis737ea822004-06-08 18:52:54 +0000174 memcpy(c, decimal_point, decimal_point_len);
175 c += decimal_point_len;
Eric Smith5c35a9d2008-03-17 12:14:29 +0000176 memcpy(c, decimal_point_pos + 1,
177 end - (decimal_point_pos + 1));
Martin v. Löwis737ea822004-06-08 18:52:54 +0000178 c += end - (decimal_point_pos + 1);
179 *c = 0;
180
181 val = strtod(copy, &fail_pos);
182
183 if (fail_pos)
184 {
185 if (fail_pos > decimal_point_pos)
Guido van Rossum3b835492008-01-05 00:59:59 +0000186 fail_pos = (char *)digits_pos +
187 (fail_pos - copy) -
188 (decimal_point_len - 1);
Martin v. Löwis737ea822004-06-08 18:52:54 +0000189 else
Guido van Rossum3b835492008-01-05 00:59:59 +0000190 fail_pos = (char *)digits_pos +
191 (fail_pos - copy);
Martin v. Löwis737ea822004-06-08 18:52:54 +0000192 }
193
Brett Cannon0ed05872006-05-25 20:44:08 +0000194 PyMem_FREE(copy);
Martin v. Löwis737ea822004-06-08 18:52:54 +0000195
196 }
Neal Norwitze7214a12005-12-18 05:03:17 +0000197 else {
Guido van Rossum3b835492008-01-05 00:59:59 +0000198 val = strtod(digits_pos, &fail_pos);
Neal Norwitze7214a12005-12-18 05:03:17 +0000199 }
Martin v. Löwis737ea822004-06-08 18:52:54 +0000200
Guido van Rossum3b835492008-01-05 00:59:59 +0000201 if (fail_pos == digits_pos)
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000202 goto invalid_string;
Guido van Rossum3b835492008-01-05 00:59:59 +0000203
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000204 got_val:
Guido van Rossum3b835492008-01-05 00:59:59 +0000205 if (negate && fail_pos != nptr)
206 val = -val;
207
Martin v. Löwis737ea822004-06-08 18:52:54 +0000208 if (endptr)
209 *endptr = fail_pos;
210
211 return val;
Mark Dickinson6d6b2202009-04-26 16:04:05 +0000212
213 invalid_string:
214 if (endptr)
215 *endptr = (char*)nptr;
216 errno = EINVAL;
217 return -1.0;
Martin v. Löwis737ea822004-06-08 18:52:54 +0000218}
219
Eric Smithaca19e62009-04-22 13:29:05 +0000220double
221PyOS_ascii_atof(const char *nptr)
222{
223 return PyOS_ascii_strtod(nptr, NULL);
224}
225
226
Eric Smith0a950632008-04-30 01:09:30 +0000227/* Given a string that may have a decimal point in the current
228 locale, change it back to a dot. Since the string cannot get
229 longer, no need for a maximum buffer size parameter. */
230Py_LOCAL_INLINE(void)
231change_decimal_from_locale_to_dot(char* buffer)
232{
233 struct lconv *locale_data = localeconv();
234 const char *decimal_point = locale_data->decimal_point;
235
236 if (decimal_point[0] != '.' || decimal_point[1] != 0) {
237 size_t decimal_point_len = strlen(decimal_point);
238
239 if (*buffer == '+' || *buffer == '-')
240 buffer++;
Eric Smithcac7af62009-04-27 19:04:37 +0000241 while (Py_ISDIGIT(*buffer))
Eric Smith0a950632008-04-30 01:09:30 +0000242 buffer++;
243 if (strncmp(buffer, decimal_point, decimal_point_len) == 0) {
244 *buffer = '.';
245 buffer++;
246 if (decimal_point_len > 1) {
247 /* buffer needs to get smaller */
248 size_t rest_len = strlen(buffer +
249 (decimal_point_len - 1));
250 memmove(buffer,
251 buffer + (decimal_point_len - 1),
252 rest_len);
253 buffer[rest_len] = 0;
254 }
255 }
256 }
257}
258
Martin v. Löwis737ea822004-06-08 18:52:54 +0000259
Eric Smith068f0652009-04-25 21:40:15 +0000260Py_LOCAL_INLINE(void)
261ensure_sign(char* buffer, size_t buf_size)
262{
263 Py_ssize_t len;
264
265 if (buffer[0] == '-')
266 /* Already have a sign. */
267 return;
268
269 /* Include the trailing 0 byte. */
270 len = strlen(buffer)+1;
271 if (len >= buf_size+1)
272 /* No room for the sign, don't do anything. */
273 return;
274
275 memmove(buffer+1, buffer, len);
276 buffer[0] = '+';
277}
278
Eric Smith7ef40bf2008-02-20 23:34:22 +0000279/* From the C99 standard, section 7.19.6:
280The exponent always contains at least two digits, and only as many more digits
281as necessary to represent the exponent.
282*/
283#define MIN_EXPONENT_DIGITS 2
284
Eric Smith0a950632008-04-30 01:09:30 +0000285/* Ensure that any exponent, if present, is at least MIN_EXPONENT_DIGITS
286 in length. */
287Py_LOCAL_INLINE(void)
Mark Dickinsone73cbe72009-04-26 19:54:55 +0000288ensure_minimum_exponent_length(char* buffer, size_t buf_size)
Eric Smith0a950632008-04-30 01:09:30 +0000289{
290 char *p = strpbrk(buffer, "eE");
291 if (p && (*(p + 1) == '-' || *(p + 1) == '+')) {
292 char *start = p + 2;
293 int exponent_digit_cnt = 0;
294 int leading_zero_cnt = 0;
295 int in_leading_zeros = 1;
296 int significant_digit_cnt;
297
298 /* Skip over the exponent and the sign. */
299 p += 2;
300
301 /* Find the end of the exponent, keeping track of leading
302 zeros. */
Eric Smithcac7af62009-04-27 19:04:37 +0000303 while (*p && Py_ISDIGIT(*p)) {
Eric Smith0a950632008-04-30 01:09:30 +0000304 if (in_leading_zeros && *p == '0')
305 ++leading_zero_cnt;
306 if (*p != '0')
307 in_leading_zeros = 0;
308 ++p;
309 ++exponent_digit_cnt;
310 }
311
312 significant_digit_cnt = exponent_digit_cnt - leading_zero_cnt;
313 if (exponent_digit_cnt == MIN_EXPONENT_DIGITS) {
314 /* If there are 2 exactly digits, we're done,
315 regardless of what they contain */
316 }
317 else if (exponent_digit_cnt > MIN_EXPONENT_DIGITS) {
318 int extra_zeros_cnt;
319
320 /* There are more than 2 digits in the exponent. See
321 if we can delete some of the leading zeros */
322 if (significant_digit_cnt < MIN_EXPONENT_DIGITS)
323 significant_digit_cnt = MIN_EXPONENT_DIGITS;
324 extra_zeros_cnt = exponent_digit_cnt -
325 significant_digit_cnt;
326
327 /* Delete extra_zeros_cnt worth of characters from the
328 front of the exponent */
329 assert(extra_zeros_cnt >= 0);
330
331 /* Add one to significant_digit_cnt to copy the
332 trailing 0 byte, thus setting the length */
333 memmove(start,
334 start + extra_zeros_cnt,
335 significant_digit_cnt + 1);
336 }
337 else {
338 /* If there are fewer than 2 digits, add zeros
339 until there are 2, if there's enough room */
340 int zeros = MIN_EXPONENT_DIGITS - exponent_digit_cnt;
341 if (start + zeros + exponent_digit_cnt + 1
342 < buffer + buf_size) {
343 memmove(start + zeros, start,
344 exponent_digit_cnt + 1);
345 memset(start, '0', zeros);
346 }
347 }
348 }
349}
350
Eric Smithaca19e62009-04-22 13:29:05 +0000351/* Ensure that buffer has a decimal point in it. The decimal point will not
352 be in the current locale, it will always be '.'. Don't add a decimal if an
353 exponent is present. */
Eric Smith0a950632008-04-30 01:09:30 +0000354Py_LOCAL_INLINE(void)
355ensure_decimal_point(char* buffer, size_t buf_size)
356{
357 int insert_count = 0;
358 char* chars_to_insert;
359
360 /* search for the first non-digit character */
361 char *p = buffer;
Eric Smithf032a002008-07-19 00:24:05 +0000362 if (*p == '-' || *p == '+')
363 /* Skip leading sign, if present. I think this could only
364 ever be '-', but it can't hurt to check for both. */
365 ++p;
Eric Smithcac7af62009-04-27 19:04:37 +0000366 while (*p && Py_ISDIGIT(*p))
Eric Smith0a950632008-04-30 01:09:30 +0000367 ++p;
368
369 if (*p == '.') {
Eric Smithcac7af62009-04-27 19:04:37 +0000370 if (Py_ISDIGIT(*(p+1))) {
Eric Smith0a950632008-04-30 01:09:30 +0000371 /* Nothing to do, we already have a decimal
372 point and a digit after it */
373 }
374 else {
375 /* We have a decimal point, but no following
376 digit. Insert a zero after the decimal. */
377 ++p;
378 chars_to_insert = "0";
379 insert_count = 1;
380 }
381 }
Eric Smithaca19e62009-04-22 13:29:05 +0000382 else if (!(*p == 'e' || *p == 'E')) {
383 /* Don't add ".0" if we have an exponent. */
Eric Smith0a950632008-04-30 01:09:30 +0000384 chars_to_insert = ".0";
385 insert_count = 2;
386 }
387 if (insert_count) {
388 size_t buf_len = strlen(buffer);
389 if (buf_len + insert_count + 1 >= buf_size) {
390 /* If there is not enough room in the buffer
391 for the additional text, just skip it. It's
392 not worth generating an error over. */
393 }
394 else {
395 memmove(p + insert_count, p,
396 buffer + strlen(buffer) - p + 1);
397 memcpy(p, chars_to_insert, insert_count);
398 }
399 }
400}
401
Eric Smith7ef40bf2008-02-20 23:34:22 +0000402/* see FORMATBUFLEN in unicodeobject.c */
403#define FLOAT_FORMATBUFLEN 120
404
Martin v. Löwis737ea822004-06-08 18:52:54 +0000405/**
Eric Smith068f0652009-04-25 21:40:15 +0000406 * _PyOS_ascii_formatd:
Martin v. Löwis737ea822004-06-08 18:52:54 +0000407 * @buffer: A buffer to place the resulting string in
Eric Smith8113ca62008-03-17 11:01:01 +0000408 * @buf_size: The length of the buffer.
Martin v. Löwis737ea822004-06-08 18:52:54 +0000409 * @format: The printf()-style format to use for the
410 * code to use for converting.
411 * @d: The #gdouble to convert
412 *
413 * Converts a #gdouble to a string, using the '.' as
414 * decimal point. To format the number you pass in
415 * a printf()-style format string. Allowed conversion
Eric Smithaca19e62009-04-22 13:29:05 +0000416 * specifiers are 'e', 'E', 'f', 'F', 'g', 'G', and 'Z'.
Martin v. Löwis737ea822004-06-08 18:52:54 +0000417 *
Eric Smith8113ca62008-03-17 11:01:01 +0000418 * 'Z' is the same as 'g', except it always has a decimal and
419 * at least one digit after the decimal.
Eric Smith7ef40bf2008-02-20 23:34:22 +0000420 *
Martin v. Löwis737ea822004-06-08 18:52:54 +0000421 * Return value: The pointer to the buffer with the converted string.
422 **/
Eric Smith068f0652009-04-25 21:40:15 +0000423/* DEPRECATED, will be deleted in 2.8 and 3.2 */
424PyAPI_FUNC(char *)
Martin v. Löwis737ea822004-06-08 18:52:54 +0000425PyOS_ascii_formatd(char *buffer,
Eric Smith8113ca62008-03-17 11:01:01 +0000426 size_t buf_size,
Martin v. Löwis737ea822004-06-08 18:52:54 +0000427 const char *format,
428 double d)
429{
Martin v. Löwis737ea822004-06-08 18:52:54 +0000430 char format_char;
Eric Smith7ef40bf2008-02-20 23:34:22 +0000431 size_t format_len = strlen(format);
432
Eric Smith8113ca62008-03-17 11:01:01 +0000433 /* Issue 2264: code 'Z' requires copying the format. 'Z' is 'g', but
434 also with at least one character past the decimal. */
Eric Smith7ef40bf2008-02-20 23:34:22 +0000435 char tmp_format[FLOAT_FORMATBUFLEN];
Martin v. Löwis737ea822004-06-08 18:52:54 +0000436
Eric Smith068f0652009-04-25 21:40:15 +0000437 if (PyErr_WarnEx(PyExc_DeprecationWarning,
438 "PyOS_ascii_formatd is deprecated, "
439 "use PyOS_double_to_string instead", 1) < 0)
440 return NULL;
441
Eric Smith7ef40bf2008-02-20 23:34:22 +0000442 /* The last character in the format string must be the format char */
443 format_char = format[format_len - 1];
Martin v. Löwis737ea822004-06-08 18:52:54 +0000444
Martin v. Löwis737ea822004-06-08 18:52:54 +0000445 if (format[0] != '%')
446 return NULL;
447
Eric Smith7ef40bf2008-02-20 23:34:22 +0000448 /* I'm not sure why this test is here. It's ensuring that the format
449 string after the first character doesn't have a single quote, a
450 lowercase l, or a percent. This is the reverse of the commented-out
451 test about 10 lines ago. */
Martin v. Löwis737ea822004-06-08 18:52:54 +0000452 if (strpbrk(format + 1, "'l%"))
453 return NULL;
454
Eric Smith8113ca62008-03-17 11:01:01 +0000455 /* Also curious about this function is that it accepts format strings
456 like "%xg", which are invalid for floats. In general, the
457 interface to this function is not very good, but changing it is
458 difficult because it's a public API. */
459
Martin v. Löwis737ea822004-06-08 18:52:54 +0000460 if (!(format_char == 'e' || format_char == 'E' ||
461 format_char == 'f' || format_char == 'F' ||
Eric Smith7ef40bf2008-02-20 23:34:22 +0000462 format_char == 'g' || format_char == 'G' ||
Eric Smithaca19e62009-04-22 13:29:05 +0000463 format_char == 'Z'))
Martin v. Löwis737ea822004-06-08 18:52:54 +0000464 return NULL;
465
Eric Smithaca19e62009-04-22 13:29:05 +0000466 /* Map 'Z' format_char to 'g', by copying the format string and
Eric Smith8113ca62008-03-17 11:01:01 +0000467 replacing the final char with a 'g' */
Eric Smithaca19e62009-04-22 13:29:05 +0000468 if (format_char == 'Z') {
Eric Smith7ef40bf2008-02-20 23:34:22 +0000469 if (format_len + 1 >= sizeof(tmp_format)) {
470 /* The format won't fit in our copy. Error out. In
Eric Smith5c35a9d2008-03-17 12:14:29 +0000471 practice, this will never happen and will be
472 detected by returning NULL */
Eric Smith7ef40bf2008-02-20 23:34:22 +0000473 return NULL;
474 }
475 strcpy(tmp_format, format);
476 tmp_format[format_len - 1] = 'g';
477 format = tmp_format;
478 }
Martin v. Löwis737ea822004-06-08 18:52:54 +0000479
Eric Smith8113ca62008-03-17 11:01:01 +0000480
Eric Smith7ef40bf2008-02-20 23:34:22 +0000481 /* Have PyOS_snprintf do the hard work */
Eric Smith8113ca62008-03-17 11:01:01 +0000482 PyOS_snprintf(buffer, buf_size, format, d);
Martin v. Löwis737ea822004-06-08 18:52:54 +0000483
Eric Smith0a950632008-04-30 01:09:30 +0000484 /* Do various fixups on the return string */
Martin v. Löwis737ea822004-06-08 18:52:54 +0000485
Eric Smith0a950632008-04-30 01:09:30 +0000486 /* Get the current locale, and find the decimal point string.
Eric Smithaca19e62009-04-22 13:29:05 +0000487 Convert that string back to a dot. */
488 change_decimal_from_locale_to_dot(buffer);
Eric Smith7ef40bf2008-02-20 23:34:22 +0000489
490 /* If an exponent exists, ensure that the exponent is at least
491 MIN_EXPONENT_DIGITS digits, providing the buffer is large enough
492 for the extra zeros. Also, if there are more than
493 MIN_EXPONENT_DIGITS, remove as many zeros as possible until we get
494 back to MIN_EXPONENT_DIGITS */
Mark Dickinsone73cbe72009-04-26 19:54:55 +0000495 ensure_minimum_exponent_length(buffer, buf_size);
Martin v. Löwis737ea822004-06-08 18:52:54 +0000496
Eric Smith8113ca62008-03-17 11:01:01 +0000497 /* If format_char is 'Z', make sure we have at least one character
498 after the decimal point (and make sure we have a decimal point). */
Eric Smith0a950632008-04-30 01:09:30 +0000499 if (format_char == 'Z')
500 ensure_decimal_point(buffer, buf_size);
Eric Smith8113ca62008-03-17 11:01:01 +0000501
Martin v. Löwis737ea822004-06-08 18:52:54 +0000502 return buffer;
503}
504
Eric Smith068f0652009-04-25 21:40:15 +0000505PyAPI_FUNC(void)
506_PyOS_double_to_string(char *buf, size_t buf_len, double val,
507 char format_code, int precision,
508 int flags, int *ptype)
Martin v. Löwis737ea822004-06-08 18:52:54 +0000509{
Eric Smithaca19e62009-04-22 13:29:05 +0000510 char format[32];
Eric Smithaca19e62009-04-22 13:29:05 +0000511 int t;
512 int upper = 0;
513
Eric Smith068f0652009-04-25 21:40:15 +0000514 if (buf_len < 1) {
515 assert(0);
516 /* There's no way to signal this error. Just return. */
517 return;
518 }
519 buf[0] = 0;
520
Eric Smithaca19e62009-04-22 13:29:05 +0000521 /* Validate format_code, and map upper and lower case */
522 switch (format_code) {
523 case 'e': /* exponent */
524 case 'f': /* fixed */
525 case 'g': /* general */
526 break;
527 case 'E':
528 upper = 1;
529 format_code = 'e';
530 break;
531 case 'F':
532 upper = 1;
533 format_code = 'f';
534 break;
535 case 'G':
536 upper = 1;
537 format_code = 'g';
538 break;
539 case 'r': /* repr format */
540 /* Supplied precision is unused, must be 0. */
Eric Smith068f0652009-04-25 21:40:15 +0000541 if (precision != 0)
542 return;
Eric Smithaca19e62009-04-22 13:29:05 +0000543 precision = 17;
544 format_code = 'g';
545 break;
546 case 's': /* str format */
547 /* Supplied precision is unused, must be 0. */
Eric Smith068f0652009-04-25 21:40:15 +0000548 if (precision != 0)
549 return;
Eric Smithaca19e62009-04-22 13:29:05 +0000550 precision = 12;
551 format_code = 'g';
552 break;
553 default:
Eric Smith068f0652009-04-25 21:40:15 +0000554 assert(0);
555 return;
556 }
557
558 /* Check for buf too small to fit "-inf". Other buffer too small
559 conditions are dealt with when converting or formatting finite
560 numbers. */
561 if (buf_len < 5) {
562 assert(0);
563 return;
Eric Smithaca19e62009-04-22 13:29:05 +0000564 }
565
566 /* Handle nan and inf. */
567 if (Py_IS_NAN(val)) {
568 strcpy(buf, "nan");
569 t = Py_DTST_NAN;
570 } else if (Py_IS_INFINITY(val)) {
571 if (copysign(1., val) == 1.)
572 strcpy(buf, "inf");
573 else
574 strcpy(buf, "-inf");
575 t = Py_DTST_INFINITE;
576 } else {
577 t = Py_DTST_FINITE;
578
Eric Smith068f0652009-04-25 21:40:15 +0000579 /* Build the format string. */
580 PyOS_snprintf(format, sizeof(format), "%%%s.%i%c",
581 (flags & Py_DTSF_ALT ? "#" : ""), precision,
582 format_code);
Eric Smithaca19e62009-04-22 13:29:05 +0000583
Eric Smith068f0652009-04-25 21:40:15 +0000584 /* Have PyOS_snprintf do the hard work. */
585 PyOS_snprintf(buf, buf_len, format, val);
586
587 /* Do various fixups on the return string */
588
589 /* Get the current locale, and find the decimal point string.
590 Convert that string back to a dot. */
591 change_decimal_from_locale_to_dot(buf);
592
593 /* If an exponent exists, ensure that the exponent is at least
594 MIN_EXPONENT_DIGITS digits, providing the buffer is large
595 enough for the extra zeros. Also, if there are more than
596 MIN_EXPONENT_DIGITS, remove as many zeros as possible until
597 we get back to MIN_EXPONENT_DIGITS */
Mark Dickinsone73cbe72009-04-26 19:54:55 +0000598 ensure_minimum_exponent_length(buf, buf_len);
Eric Smith068f0652009-04-25 21:40:15 +0000599
600 /* Possibly make sure we have at least one character after the
601 decimal point (and make sure we have a decimal point). */
Eric Smithaca19e62009-04-22 13:29:05 +0000602 if (flags & Py_DTSF_ADD_DOT_0)
Eric Smith068f0652009-04-25 21:40:15 +0000603 ensure_decimal_point(buf, buf_len);
Eric Smithaca19e62009-04-22 13:29:05 +0000604 }
605
Eric Smith068f0652009-04-25 21:40:15 +0000606 /* Add the sign if asked and the result isn't negative. */
607 if (flags & Py_DTSF_SIGN && buf[0] != '-')
608 ensure_sign(buf, buf_len);
Eric Smithaca19e62009-04-22 13:29:05 +0000609
Eric Smith068f0652009-04-25 21:40:15 +0000610 if (upper) {
611 /* Convert to upper case. */
612 char *p;
613 for (p = buf; *p; p++)
614 *p = toupper(*p);
615 }
616
617 if (ptype)
618 *ptype = t;
619}
620
621
622PyAPI_FUNC(char *) PyOS_double_to_string(double val,
623 char format_code,
624 int precision,
625 int flags,
626 int *ptype)
627{
628 char buf[128];
629 Py_ssize_t len;
630 char *result;
631
632 _PyOS_double_to_string(buf, sizeof(buf), val, format_code, precision,
633 flags, ptype);
634 len = strlen(buf);
635 if (len == 0) {
636 PyErr_BadInternalCall();
637 return NULL;
638 }
639
640 /* Add 1 for the trailing 0 byte. */
641 result = PyMem_Malloc(len + 1);
Eric Smithaca19e62009-04-22 13:29:05 +0000642 if (result == NULL) {
643 PyErr_NoMemory();
644 return NULL;
645 }
Eric Smith068f0652009-04-25 21:40:15 +0000646 strcpy(result, buf);
Eric Smithaca19e62009-04-22 13:29:05 +0000647
Eric Smithaca19e62009-04-22 13:29:05 +0000648 return result;
Martin v. Löwis737ea822004-06-08 18:52:54 +0000649}