mirror of
https://github.com/python/cpython.git
synced 2025-07-30 06:34:15 +00:00
Issue #5835, deprecate PyOS_ascii_formatd.
If anyone wants to clean up the documentation, feel free. It's my first documentation foray, and it's not that great. Will port to py3k with a different strategy.
This commit is contained in:
parent
dfcffd4044
commit
068f06568b
9 changed files with 234 additions and 68 deletions
|
@ -76,7 +76,42 @@ The following functions provide locale-independent string to number conversions.
|
||||||
the conversion failed.
|
the conversion failed.
|
||||||
|
|
||||||
.. versionadded:: 2.4
|
.. versionadded:: 2.4
|
||||||
|
.. deprecated:: 2.7
|
||||||
|
This function is removed in Python 2.7 and 3.1. Use :func:`PyOS_double_to_string`
|
||||||
|
instead.
|
||||||
|
|
||||||
|
.. cfunction:: char * PyOS_double_to_string(double val, char format_code, int precision, int flags, int *ptype)
|
||||||
|
|
||||||
|
Convert a :ctype:`double` *val* to a string using supplied
|
||||||
|
*format_code*, *precision*, and *flags*.
|
||||||
|
|
||||||
|
*format_code* must be one of ``'e'``, ``'E'``, ``'f'``, ``'F'``,
|
||||||
|
``'g'``, ``'G'``, ``'s'``, or ``'r'``. For ``'s'`` and ``'r'``, the
|
||||||
|
supplied *precision* must be 0 and is ignored. These specify the
|
||||||
|
standards :func:`str` and :func:`repr` formats, respectively.
|
||||||
|
|
||||||
|
*flags* can be zero or more of the values *Py_DTSF_SIGN*,
|
||||||
|
*Py_DTSF_ADD_DOT_0*, or *Py_DTSF_ALT*, and-ed together.
|
||||||
|
|
||||||
|
*Py_DTSF_SIGN* means always precede the returned string with a
|
||||||
|
sign character, even if *val* is non-negative.
|
||||||
|
|
||||||
|
*Py_DTSF_ADD_DOT_0* means ensure that the returned string will
|
||||||
|
not look like an integer.
|
||||||
|
|
||||||
|
*Py_DTSF_ALT* means apply "alternate" formatting rules. See the
|
||||||
|
documentation for the :func:`PyOS_snprintf` ``'#'`` specifier
|
||||||
|
for details.
|
||||||
|
|
||||||
|
If *ptype* is non-NULL, then the value it points to will be set to
|
||||||
|
one of *Py_DTST_FINITE*, *Py_DTST_INFINITE*, or *Py_DTST_NAN*,
|
||||||
|
signifying that *val* is a finite number, an infinite number, or
|
||||||
|
not a number, respectively.
|
||||||
|
|
||||||
|
The return value is a pointer to *buffer* with the converted string or NULL if
|
||||||
|
the conversion failed.
|
||||||
|
|
||||||
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
.. cfunction:: double PyOS_ascii_atof(const char *nptr)
|
.. cfunction:: double PyOS_ascii_atof(const char *nptr)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,17 @@ extern "C" {
|
||||||
|
|
||||||
PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr);
|
PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr);
|
||||||
PyAPI_FUNC(double) PyOS_ascii_atof(const char *str);
|
PyAPI_FUNC(double) PyOS_ascii_atof(const char *str);
|
||||||
PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d);
|
|
||||||
|
/* Deprecated in 2.7 and 3.1. Will disappear in 2.8 (if it exists) and 3.2 */
|
||||||
|
PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len,
|
||||||
|
const char *format, double d);
|
||||||
|
|
||||||
|
/* Use PyOS_double_to_string instead. It's the same, except it allocates
|
||||||
|
the appropriately sized buffer and returns it. This function will go
|
||||||
|
away in Python 2.8 and 3.2. */
|
||||||
|
PyAPI_FUNC(void) _PyOS_double_to_string(char *buf, size_t buf_len, double val,
|
||||||
|
char format_code, int precision,
|
||||||
|
int flags, int* type);
|
||||||
|
|
||||||
/* The caller is responsible for calling PyMem_Free to free the buffer
|
/* The caller is responsible for calling PyMem_Free to free the buffer
|
||||||
that's is returned. */
|
that's is returned. */
|
||||||
|
|
62
Lib/test/test_ascii_formatd.py
Normal file
62
Lib/test/test_ascii_formatd.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
# PyOS_ascii_formatd is deprecated and not called from anywhere in
|
||||||
|
# Python itself. So this module is the only place it gets tested.
|
||||||
|
# Test that it works, and test that it's deprecated.
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from test_support import check_warnings, run_unittest, cpython_only
|
||||||
|
|
||||||
|
|
||||||
|
class FormatDeprecationTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@cpython_only
|
||||||
|
def testFormatDeprecation(self):
|
||||||
|
# delay importing ctypes until we know we're in CPython
|
||||||
|
from ctypes import (pythonapi, create_string_buffer, sizeof, byref,
|
||||||
|
c_double)
|
||||||
|
PyOS_ascii_formatd = pythonapi.PyOS_ascii_formatd
|
||||||
|
buf = create_string_buffer(' ' * 100)
|
||||||
|
|
||||||
|
with check_warnings() as w:
|
||||||
|
PyOS_ascii_formatd(byref(buf), sizeof(buf), '%+.10f',
|
||||||
|
c_double(10.0))
|
||||||
|
self.assertEqual(buf.value, '+10.0000000000')
|
||||||
|
|
||||||
|
self.assertEqual(str(w.message), 'PyOS_ascii_formatd is deprecated, '
|
||||||
|
'use PyOS_double_to_string instead')
|
||||||
|
|
||||||
|
class FormatTests(unittest.TestCase):
|
||||||
|
# ensure that, for the restricted set of format codes,
|
||||||
|
# %-formatting returns the same values os PyOS_ascii_formatd
|
||||||
|
@cpython_only
|
||||||
|
def testFormat(self):
|
||||||
|
# delay importing ctypes until we know we're in CPython
|
||||||
|
from ctypes import (pythonapi, create_string_buffer, sizeof, byref,
|
||||||
|
c_double)
|
||||||
|
PyOS_ascii_formatd = pythonapi.PyOS_ascii_formatd
|
||||||
|
buf = create_string_buffer(' ' * 100)
|
||||||
|
|
||||||
|
tests = [
|
||||||
|
('%f', 100.0),
|
||||||
|
('%g', 100.0),
|
||||||
|
('%#g', 100.0),
|
||||||
|
('%#.2g', 100.0),
|
||||||
|
('%#.2g', 123.4567),
|
||||||
|
('%#.2g', 1.234567e200),
|
||||||
|
('%e', 1.234567e200),
|
||||||
|
('%e', 1.234),
|
||||||
|
('%+e', 1.234),
|
||||||
|
('%-e', 1.234),
|
||||||
|
]
|
||||||
|
|
||||||
|
with check_warnings():
|
||||||
|
for format, val in tests:
|
||||||
|
PyOS_ascii_formatd(byref(buf), sizeof(buf), format,
|
||||||
|
c_double(val))
|
||||||
|
self.assertEqual(buf.value, format % val)
|
||||||
|
|
||||||
|
|
||||||
|
def test_main():
|
||||||
|
run_unittest(FormatDeprecationTests, FormatTests)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_main()
|
|
@ -12,6 +12,9 @@ What's New in Python 2.7 alpha 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #5835: Deprecate PyOS_ascii_formatd and replace it with
|
||||||
|
_PyOS_double_to_string or PyOS_double_to_string.
|
||||||
|
|
||||||
- Issue #5283: Setting __class__ in __del__ caused a segfault.
|
- Issue #5283: Setting __class__ in __del__ caused a segfault.
|
||||||
|
|
||||||
- Issue #5816: complex(repr(z)) now recovers z exactly, even when
|
- Issue #5816: complex(repr(z)) now recovers z exactly, even when
|
||||||
|
|
|
@ -1166,7 +1166,8 @@ save_float(Picklerobject *self, PyObject *args)
|
||||||
else {
|
else {
|
||||||
char c_str[250];
|
char c_str[250];
|
||||||
c_str[0] = FLOAT;
|
c_str[0] = FLOAT;
|
||||||
PyOS_ascii_formatd(c_str + 1, sizeof(c_str) - 2, "%.17g", x);
|
_PyOS_double_to_string(c_str + 1, sizeof(c_str) - 2, x, 'g',
|
||||||
|
17, 0, NULL);
|
||||||
/* Extend the formatted string with a newline character */
|
/* Extend the formatted string with a newline character */
|
||||||
strcat(c_str, "\n");
|
strcat(c_str, "\n");
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,6 @@ static void
|
||||||
format_float(char *buf, size_t buflen, PyFloatObject *v, int precision)
|
format_float(char *buf, size_t buflen, PyFloatObject *v, int precision)
|
||||||
{
|
{
|
||||||
register char *cp;
|
register char *cp;
|
||||||
char format[32];
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Subroutine for float_repr and float_print.
|
/* Subroutine for float_repr and float_print.
|
||||||
|
@ -352,8 +351,8 @@ format_float(char *buf, size_t buflen, PyFloatObject *v, int precision)
|
||||||
in such cases, we append ".0" to the string. */
|
in such cases, we append ".0" to the string. */
|
||||||
|
|
||||||
assert(PyFloat_Check(v));
|
assert(PyFloat_Check(v));
|
||||||
PyOS_snprintf(format, 32, "%%.%ig", precision);
|
_PyOS_double_to_string(buf, buflen, v->ob_fval, 'g', precision,
|
||||||
PyOS_ascii_formatd(buf, buflen, format, v->ob_fval);
|
0, NULL);
|
||||||
cp = buf;
|
cp = buf;
|
||||||
if (*cp == '-')
|
if (*cp == '-')
|
||||||
cp++;
|
cp++;
|
||||||
|
|
|
@ -4332,9 +4332,6 @@ Py_LOCAL_INLINE(int)
|
||||||
formatfloat(char *buf, size_t buflen, int flags,
|
formatfloat(char *buf, size_t buflen, int flags,
|
||||||
int prec, int type, PyObject *v)
|
int prec, int type, PyObject *v)
|
||||||
{
|
{
|
||||||
/* fmt = '%#.' + `prec` + `type`
|
|
||||||
worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/
|
|
||||||
char fmt[20];
|
|
||||||
double x;
|
double x;
|
||||||
x = PyFloat_AsDouble(v);
|
x = PyFloat_AsDouble(v);
|
||||||
if (x == -1.0 && PyErr_Occurred()) {
|
if (x == -1.0 && PyErr_Occurred()) {
|
||||||
|
@ -4378,10 +4375,8 @@ formatfloat(char *buf, size_t buflen, int flags,
|
||||||
"formatted float is too long (precision too large?)");
|
"formatted float is too long (precision too large?)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
|
_PyOS_double_to_string(buf, buflen, x, type, prec,
|
||||||
(flags&F_ALT) ? "#" : "",
|
(flags&F_ALT)?Py_DTSF_ALT:0, NULL);
|
||||||
prec, type);
|
|
||||||
PyOS_ascii_formatd(buf, buflen, fmt, x);
|
|
||||||
return (int)strlen(buf);
|
return (int)strlen(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8245,11 +8245,13 @@ strtounicode(Py_UNICODE *buffer, const char *charbuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
doubletounicode(Py_UNICODE *buffer, size_t len, const char *format, double x)
|
doubletounicode(Py_UNICODE *buffer, size_t len, int format_code,
|
||||||
|
int precision, int flags, double x)
|
||||||
{
|
{
|
||||||
Py_ssize_t result;
|
Py_ssize_t result;
|
||||||
|
|
||||||
PyOS_ascii_formatd((char *)buffer, len, format, x);
|
_PyOS_double_to_string((char *)buffer, len, x, format_code, precision,
|
||||||
|
flags, NULL);
|
||||||
result = strtounicode(buffer, (char *)buffer);
|
result = strtounicode(buffer, (char *)buffer);
|
||||||
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
|
return Py_SAFE_DOWNCAST(result, Py_ssize_t, int);
|
||||||
}
|
}
|
||||||
|
@ -8276,9 +8278,6 @@ formatfloat(Py_UNICODE *buf,
|
||||||
int type,
|
int type,
|
||||||
PyObject *v)
|
PyObject *v)
|
||||||
{
|
{
|
||||||
/* fmt = '%#.' + `prec` + `type`
|
|
||||||
worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/
|
|
||||||
char fmt[20];
|
|
||||||
double x;
|
double x;
|
||||||
|
|
||||||
x = PyFloat_AsDouble(v);
|
x = PyFloat_AsDouble(v);
|
||||||
|
@ -8320,10 +8319,8 @@ formatfloat(Py_UNICODE *buf,
|
||||||
"formatted float is too long (precision too large?)");
|
"formatted float is too long (precision too large?)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
|
return doubletounicode(buf, buflen, type, prec,
|
||||||
(flags&F_ALT) ? "#" : "",
|
(flags&F_ALT)?Py_DTSF_ALT:0, x);
|
||||||
prec, type);
|
|
||||||
return doubletounicode(buf, buflen, fmt, x);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
|
|
|
@ -236,6 +236,25 @@ change_decimal_from_locale_to_dot(char* buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Py_LOCAL_INLINE(void)
|
||||||
|
ensure_sign(char* buffer, size_t buf_size)
|
||||||
|
{
|
||||||
|
Py_ssize_t len;
|
||||||
|
|
||||||
|
if (buffer[0] == '-')
|
||||||
|
/* Already have a sign. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Include the trailing 0 byte. */
|
||||||
|
len = strlen(buffer)+1;
|
||||||
|
if (len >= buf_size+1)
|
||||||
|
/* No room for the sign, don't do anything. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
memmove(buffer+1, buffer, len);
|
||||||
|
buffer[0] = '+';
|
||||||
|
}
|
||||||
|
|
||||||
/* From the C99 standard, section 7.19.6:
|
/* From the C99 standard, section 7.19.6:
|
||||||
The exponent always contains at least two digits, and only as many more digits
|
The exponent always contains at least two digits, and only as many more digits
|
||||||
as necessary to represent the exponent.
|
as necessary to represent the exponent.
|
||||||
|
@ -363,7 +382,7 @@ ensure_decimal_point(char* buffer, size_t buf_size)
|
||||||
#define FLOAT_FORMATBUFLEN 120
|
#define FLOAT_FORMATBUFLEN 120
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PyOS_ascii_formatd:
|
* _PyOS_ascii_formatd:
|
||||||
* @buffer: A buffer to place the resulting string in
|
* @buffer: A buffer to place the resulting string in
|
||||||
* @buf_size: The length of the buffer.
|
* @buf_size: The length of the buffer.
|
||||||
* @format: The printf()-style format to use for the
|
* @format: The printf()-style format to use for the
|
||||||
|
@ -380,7 +399,8 @@ ensure_decimal_point(char* buffer, size_t buf_size)
|
||||||
*
|
*
|
||||||
* Return value: The pointer to the buffer with the converted string.
|
* Return value: The pointer to the buffer with the converted string.
|
||||||
**/
|
**/
|
||||||
char *
|
/* DEPRECATED, will be deleted in 2.8 and 3.2 */
|
||||||
|
PyAPI_FUNC(char *)
|
||||||
PyOS_ascii_formatd(char *buffer,
|
PyOS_ascii_formatd(char *buffer,
|
||||||
size_t buf_size,
|
size_t buf_size,
|
||||||
const char *format,
|
const char *format,
|
||||||
|
@ -393,6 +413,11 @@ PyOS_ascii_formatd(char *buffer,
|
||||||
also with at least one character past the decimal. */
|
also with at least one character past the decimal. */
|
||||||
char tmp_format[FLOAT_FORMATBUFLEN];
|
char tmp_format[FLOAT_FORMATBUFLEN];
|
||||||
|
|
||||||
|
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
||||||
|
"PyOS_ascii_formatd is deprecated, "
|
||||||
|
"use PyOS_double_to_string instead", 1) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* The last character in the format string must be the format char */
|
/* The last character in the format string must be the format char */
|
||||||
format_char = format[format_len - 1];
|
format_char = format[format_len - 1];
|
||||||
|
|
||||||
|
@ -456,20 +481,22 @@ PyOS_ascii_formatd(char *buffer,
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
PyAPI_FUNC(void)
|
||||||
char format_code,
|
_PyOS_double_to_string(char *buf, size_t buf_len, double val,
|
||||||
int precision,
|
char format_code, int precision,
|
||||||
int flags,
|
int flags, int *ptype)
|
||||||
int *type)
|
|
||||||
{
|
{
|
||||||
char buf[128];
|
|
||||||
char format[32];
|
char format[32];
|
||||||
Py_ssize_t len;
|
|
||||||
char *result;
|
|
||||||
char *p;
|
|
||||||
int t;
|
int t;
|
||||||
int upper = 0;
|
int upper = 0;
|
||||||
|
|
||||||
|
if (buf_len < 1) {
|
||||||
|
assert(0);
|
||||||
|
/* There's no way to signal this error. Just return. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buf[0] = 0;
|
||||||
|
|
||||||
/* Validate format_code, and map upper and lower case */
|
/* Validate format_code, and map upper and lower case */
|
||||||
switch (format_code) {
|
switch (format_code) {
|
||||||
case 'e': /* exponent */
|
case 'e': /* exponent */
|
||||||
|
@ -490,25 +517,29 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
break;
|
break;
|
||||||
case 'r': /* repr format */
|
case 'r': /* repr format */
|
||||||
/* Supplied precision is unused, must be 0. */
|
/* Supplied precision is unused, must be 0. */
|
||||||
if (precision != 0) {
|
if (precision != 0)
|
||||||
PyErr_BadInternalCall();
|
return;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
precision = 17;
|
precision = 17;
|
||||||
format_code = 'g';
|
format_code = 'g';
|
||||||
break;
|
break;
|
||||||
case 's': /* str format */
|
case 's': /* str format */
|
||||||
/* Supplied precision is unused, must be 0. */
|
/* Supplied precision is unused, must be 0. */
|
||||||
if (precision != 0) {
|
if (precision != 0)
|
||||||
PyErr_BadInternalCall();
|
return;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
precision = 12;
|
precision = 12;
|
||||||
format_code = 'g';
|
format_code = 'g';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_BadInternalCall();
|
assert(0);
|
||||||
return NULL;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for buf too small to fit "-inf". Other buffer too small
|
||||||
|
conditions are dealt with when converting or formatting finite
|
||||||
|
numbers. */
|
||||||
|
if (buf_len < 5) {
|
||||||
|
assert(0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle nan and inf. */
|
/* Handle nan and inf. */
|
||||||
|
@ -524,41 +555,74 @@ PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
} else {
|
} else {
|
||||||
t = Py_DTST_FINITE;
|
t = Py_DTST_FINITE;
|
||||||
|
|
||||||
|
/* Build the format string. */
|
||||||
|
PyOS_snprintf(format, sizeof(format), "%%%s.%i%c",
|
||||||
|
(flags & Py_DTSF_ALT ? "#" : ""), precision,
|
||||||
|
format_code);
|
||||||
|
|
||||||
|
/* Have PyOS_snprintf do the hard work. */
|
||||||
|
PyOS_snprintf(buf, buf_len, format, val);
|
||||||
|
|
||||||
|
/* Do various fixups on the return string */
|
||||||
|
|
||||||
|
/* Get the current locale, and find the decimal point string.
|
||||||
|
Convert that string back to a dot. */
|
||||||
|
change_decimal_from_locale_to_dot(buf);
|
||||||
|
|
||||||
|
/* If an exponent exists, ensure that the exponent is at least
|
||||||
|
MIN_EXPONENT_DIGITS digits, providing the buffer is large
|
||||||
|
enough for the extra zeros. Also, if there are more than
|
||||||
|
MIN_EXPONENT_DIGITS, remove as many zeros as possible until
|
||||||
|
we get back to MIN_EXPONENT_DIGITS */
|
||||||
|
ensure_minumim_exponent_length(buf, buf_len);
|
||||||
|
|
||||||
|
/* Possibly make sure we have at least one character after the
|
||||||
|
decimal point (and make sure we have a decimal point). */
|
||||||
if (flags & Py_DTSF_ADD_DOT_0)
|
if (flags & Py_DTSF_ADD_DOT_0)
|
||||||
format_code = 'Z';
|
ensure_decimal_point(buf, buf_len);
|
||||||
|
|
||||||
PyOS_snprintf(format, 32, "%%%s.%i%c", (flags & Py_DTSF_ALT ? "#" : ""), precision, format_code);
|
|
||||||
PyOS_ascii_formatd(buf, sizeof(buf), format, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
len = strlen(buf);
|
/* Add the sign if asked and the result isn't negative. */
|
||||||
|
if (flags & Py_DTSF_SIGN && buf[0] != '-')
|
||||||
|
ensure_sign(buf, buf_len);
|
||||||
|
|
||||||
/* Add 1 for the trailing 0 byte.
|
if (upper) {
|
||||||
Add 1 because we might need to make room for the sign.
|
/* Convert to upper case. */
|
||||||
*/
|
char *p;
|
||||||
result = PyMem_Malloc(len + 2);
|
for (p = buf; *p; p++)
|
||||||
|
*p = toupper(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptype)
|
||||||
|
*ptype = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyAPI_FUNC(char *) PyOS_double_to_string(double val,
|
||||||
|
char format_code,
|
||||||
|
int precision,
|
||||||
|
int flags,
|
||||||
|
int *ptype)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
Py_ssize_t len;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
_PyOS_double_to_string(buf, sizeof(buf), val, format_code, precision,
|
||||||
|
flags, ptype);
|
||||||
|
len = strlen(buf);
|
||||||
|
if (len == 0) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add 1 for the trailing 0 byte. */
|
||||||
|
result = PyMem_Malloc(len + 1);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p = result;
|
strcpy(result, buf);
|
||||||
|
|
||||||
/* Add sign when requested. It's convenient (esp. when formatting
|
|
||||||
complex numbers) to include a sign even for inf and nan. */
|
|
||||||
if (flags & Py_DTSF_SIGN && buf[0] != '-')
|
|
||||||
*p++ = '+';
|
|
||||||
|
|
||||||
strcpy(p, buf);
|
|
||||||
|
|
||||||
if (upper) {
|
|
||||||
/* Convert to upper case. */
|
|
||||||
char *p1;
|
|
||||||
for (p1 = p; *p1; p1++)
|
|
||||||
*p1 = toupper(*p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type)
|
|
||||||
*type = t;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue