diff options
Diffstat (limited to 'Python/pystrtod.c')
| -rw-r--r-- | Python/pystrtod.c | 792 | 
1 files changed, 699 insertions, 93 deletions
diff --git a/Python/pystrtod.c b/Python/pystrtod.c index 79f63e2..2f34b9b 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -3,6 +3,60 @@  #include <Python.h>  #include <locale.h> +/* Case-insensitive string match used for nan and inf detection; t should be +   lower-case.  Returns 1 for a successful match, 0 otherwise. */ + +static int +case_insensitive_match(const char *s, const char *t) +{ +	while(*t && Py_TOLOWER(*s) == *t) { +		s++; +		t++; +	} +	return *t ? 0 : 1; +} + +/* _Py_parse_inf_or_nan: Attempt to parse a string of the form "nan", "inf" or +   "infinity", with an optional leading sign of "+" or "-".  On success, +   return the NaN or Infinity as a double and set *endptr to point just beyond +   the successfully parsed portion of the string.  On failure, return -1.0 and +   set *endptr to point to the start of the string. */ + +double +_Py_parse_inf_or_nan(const char *p, char **endptr) +{ +	double retval; +	const char *s; +	int negate = 0; + +	s = p; +	if (*s == '-') { +		negate = 1; +		s++; +	} +	else if (*s == '+') { +		s++; +	} +	if (case_insensitive_match(s, "inf")) { +		s += 3; +		if (case_insensitive_match(s, "inity")) +			s += 5; +		retval = negate ? -Py_HUGE_VAL : Py_HUGE_VAL; +	} +#ifdef Py_NAN +	else if (case_insensitive_match(s, "nan")) { +		s += 3; +		retval = negate ? -Py_NAN : Py_NAN; +	} +#endif +	else { +		s = p; +		retval = -1.0; +	} +	*endptr = (char *)s; +	return retval; +} +  /**   * PyOS_ascii_strtod:   * @nptr:    the string to convert to a numeric value. @@ -32,6 +86,33 @@   * Return value: the #gdouble value.   **/ +#ifndef PY_NO_SHORT_FLOAT_REPR + +double +_PyOS_ascii_strtod(const char *nptr, char **endptr) +{ +	double result; +	_Py_SET_53BIT_PRECISION_HEADER; + +	assert(nptr != NULL); +	/* Set errno to zero, so that we can distinguish zero results +	   and underflows */ +	errno = 0; + +	_Py_SET_53BIT_PRECISION_START; +	result = _Py_dg_strtod(nptr, endptr); +	_Py_SET_53BIT_PRECISION_END; + +	if (*endptr == nptr) +		/* string might represent and inf or nan */ +		result = _Py_parse_inf_or_nan(nptr, endptr); + +	return result; + +} + +#else +  /*     Use system strtod;  since strtod is locale aware, we may     have to first fix the decimal separator. @@ -40,21 +121,8 @@     correctly rounded results.  */ -/* Case-insensitive string match used for nan and inf detection; t should be -   lower-case.  Returns 1 for a successful match, 0 otherwise. */ - -static int -case_insensitive_match(const char *s, const char *t) -{ -	while(*t && Py_TOLOWER(*s) == *t) { -		s++; -		t++; -	} -	return *t ? 0 : 1; -} -  double -PyOS_ascii_strtod(const char *nptr, char **endptr) +_PyOS_ascii_strtod(const char *nptr, char **endptr)  {  	char *fail_pos;  	double val = -1.0; @@ -78,19 +146,19 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)  	decimal_point_pos = NULL; +	/* Parse infinities and nans */ +	val = _Py_parse_inf_or_nan(nptr, endptr); +	if (*endptr != nptr) +		return val; +  	/* Set errno to zero, so that we can distinguish zero results  	   and underflows */  	errno = 0; -	/* We process any leading whitespace and the optional sign manually, -	   then pass the remainder to the system strtod.  This ensures that -	   the result of an underflow has the correct sign. (bug #1725)  */ - +	/* We process the optional sign manually, then pass the remainder to +	   the system strtod.  This ensures that the result of an underflow +	   has the correct sign. (bug #1725)  */  	p = nptr; -	/* Skip leading space */ -	while (Py_ISSPACE(*p)) -		p++; -  	/* Process leading sign, if present */  	if (*p == '-') {  		negate = 1; @@ -100,31 +168,6 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)  		p++;  	} -	/* Parse infinities and nans */ -	if (*p == 'i' || *p == 'I') { -		if (case_insensitive_match(p+1, "nf")) { -			val = Py_HUGE_VAL; -			if (case_insensitive_match(p+3, "inity")) -				fail_pos = (char *)p+8; -			else -				fail_pos = (char *)p+3; -			goto got_val; -		} -		else -			goto invalid_string; -	} -#ifdef Py_NAN -	if (*p == 'n' || *p == 'N') { -		if (case_insensitive_match(p+1, "an")) { -			val = Py_NAN; -			fail_pos = (char *)p+3; -			goto got_val; -		} -		else -			goto invalid_string; -	} -#endif -  	/* Some platform strtods accept hex floats; Python shouldn't (at the  	   moment), so we check explicitly for strings starting with '0x'. */  	if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) @@ -175,8 +218,7 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)  		copy = (char *)PyMem_MALLOC(end - digits_pos +  					    1 + decimal_point_len);  		if (copy == NULL) { -			if (endptr) -				*endptr = (char *)nptr; +			*endptr = (char *)nptr;  			errno = ENOMEM;  			return val;  		} @@ -214,28 +256,108 @@ PyOS_ascii_strtod(const char *nptr, char **endptr)  	if (fail_pos == digits_pos)  		goto invalid_string; -  got_val:  	if (negate && fail_pos != nptr)  		val = -val; - -	if (endptr) -		*endptr = fail_pos; +	*endptr = fail_pos;  	return val;    invalid_string: -	if (endptr) -		*endptr = (char*)nptr; +	*endptr = (char*)nptr;  	errno = EINVAL;  	return -1.0;  } +#endif + +double +PyOS_ascii_strtod(const char *nptr, char **endptr) +{ +	char *fail_pos; +	const char *p; +	double x; + +	/* _PyOS_ascii_strtod already does everything that we want, +	   except that it doesn't parse leading whitespace */ +	p = nptr; +	while (Py_ISSPACE(*p)) +		p++; +	x = _PyOS_ascii_strtod(p, &fail_pos); +	if (fail_pos == p) +		fail_pos = (char *)nptr; +	if (endptr) +		*endptr = (char *)fail_pos; +	return x; +} +  double  PyOS_ascii_atof(const char *nptr)  {  	return PyOS_ascii_strtod(nptr, NULL);  } +/* PyOS_string_to_double is the recommended replacement for the +   PyOS_ascii_strtod and PyOS_ascii_atof functions.  It converts a +   null-terminated byte string s (interpreted as a string of ASCII characters) +   to a float.  The string should not have leading or trailing whitespace (in +   contrast, PyOS_ascii_strtod allows leading whitespace but not trailing +   whitespace).  The conversion is independent of the current locale. + +   If endptr is NULL, try to convert the whole string.  Raise ValueError and +   return -1.0 if the string is not a valid representation of a floating-point +   number. + +   If endptr is non-NULL, try to convert as much of the string as possible. +   If no initial segment of the string is the valid representation of a +   floating-point number then *endptr is set to point to the beginning of the +   string, -1.0 is returned and again ValueError is raised. + +   On overflow (e.g., when trying to convert '1e500' on an IEEE 754 machine), +   if overflow_exception is NULL then +-Py_HUGE_VAL is returned, and no Python +   exception is raised.  Otherwise, overflow_exception should point to a +   a Python exception, this exception will be raised, -1.0 will be returned, +   and *endptr will point just past the end of the converted value. + +   If any other failure occurs (for example lack of memory), -1.0 is returned +   and the appropriate Python exception will have been set. +*/ + +double +PyOS_string_to_double(const char *s, +		      char **endptr, +		      PyObject *overflow_exception) +{ +	double x, result=-1.0; +	char *fail_pos; + +	errno = 0; +	PyFPE_START_PROTECT("PyOS_string_to_double", return -1.0) +	x = PyOS_ascii_strtod(s, &fail_pos); +	PyFPE_END_PROTECT(x) + +	if (errno == ENOMEM) { +		PyErr_NoMemory(); +		fail_pos = (char *)s; +	} +	else if (!endptr && (fail_pos == s || *fail_pos != '\0')) +		PyErr_Format(PyExc_ValueError, +			      "could not convert string to float: " +			      "%.200s", s); +	else if (fail_pos == s) +		PyErr_Format(PyExc_ValueError, +			      "could not convert string to float: " +			      "%.200s", s); +	else if (errno == ERANGE && fabs(x) >= 1.0 && overflow_exception) +		PyErr_Format(overflow_exception, +			      "value too large to convert to float: " +			      "%.200s", s); +	else +		result = x; + +	if (endptr != NULL) +		*endptr = fail_pos; +	return result; +}  /* Given a string that may have a decimal point in the current     locale, change it back to a dot.  Since the string cannot get @@ -415,7 +537,7 @@ Py_LOCAL_INLINE(char *)  ensure_decimal_point(char* buffer, size_t buf_size, int precision)  {  	int digit_count, insert_count = 0, convert_to_exp = 0; -	char* chars_to_insert, *digits_start; +	char *chars_to_insert, *digits_start;  	/* search for the first non-digit character */  	char *p = buffer; @@ -505,7 +627,7 @@ ensure_decimal_point(char* buffer, size_t buf_size, int precision)  #define FLOAT_FORMATBUFLEN 120  /** - * _PyOS_ascii_formatd: + * PyOS_ascii_formatd:   * @buffer: A buffer to place the resulting string in   * @buf_size: The length of the buffer.   * @format: The printf()-style format to use for the @@ -523,12 +645,12 @@ ensure_decimal_point(char* buffer, size_t buf_size, int precision)   * Return value: The pointer to the buffer with the converted string.   * On failure returns NULL but does not set any Python exception.   **/ -/* DEPRECATED, will be deleted in 2.8 and 3.2 */ -PyAPI_FUNC(char *) -PyOS_ascii_formatd(char       *buffer,  +char * +_PyOS_ascii_formatd(char       *buffer,   		   size_t      buf_size,   		   const char *format,  -		   double      d) +		   double      d,  +		   int         precision)  {  	char format_char;  	size_t format_len = strlen(format); @@ -537,11 +659,6 @@ PyOS_ascii_formatd(char       *buffer,  	   also with at least one character past the decimal. */  	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 */  	format_char = format[format_len - 1]; @@ -603,24 +720,24 @@ PyOS_ascii_formatd(char       *buffer,  	   extra character would produce more significant digits that we  	   really want. */  	if (format_char == 'Z') -		buffer = ensure_decimal_point(buffer, buf_size, -1); +		buffer = ensure_decimal_point(buffer, buf_size, precision);  	return buffer;  } -/* Precisions used by repr() and str(), respectively. - -   The repr() precision (17 significant decimal digits) is the minimal number -   that is guaranteed to have enough precision so that if the number is read -   back in the exact same binary value is recreated.  This is true for IEEE -   floating point by design, and also happens to work for all other modern -   hardware. - -   The str() precision (12 significant decimal digits) is chosen so that in -   most cases, the rounding noise created by various operations is suppressed, -   while giving plenty of precision for practical use. +char * +PyOS_ascii_formatd(char       *buffer,  +		   size_t      buf_size,  +		   const char *format,  +		   double      d) +{ +	if (PyErr_WarnEx(PyExc_DeprecationWarning, +			 "PyOS_ascii_formatd is deprecated, " +			 "use PyOS_double_to_string instead", 1) < 0) +		return NULL; -*/ +	return _PyOS_ascii_formatd(buffer, buf_size, format, d, -1); +}  PyAPI_FUNC(void)  _PyOS_double_to_string(char *buf, size_t buf_len, double val, @@ -738,31 +855,520 @@ _PyOS_double_to_string(char *buf, size_t buf_len, double val,  } +#ifdef PY_NO_SHORT_FLOAT_REPR + +/* The fallback code to use if _Py_dg_dtoa is not available. */ +  PyAPI_FUNC(char *) PyOS_double_to_string(double val,                                           char format_code,                                           int precision,                                           int flags, -                                         int *ptype) +                                         int *type)  { -	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) { +	char format[32]; +	Py_ssize_t bufsize; +	char *buf; +	int t, exp; +	int upper = 0; + +	/* Validate format_code, and map upper and lower case */ +	switch (format_code) { +	case 'e':          /* exponent */ +	case 'f':          /* fixed */ +	case 'g':          /* general */ +		break; +	case 'E': +		upper = 1; +		format_code = 'e'; +		break; +	case 'F': +		upper = 1; +		format_code = 'f'; +		break; +	case 'G': +		upper = 1; +		format_code = 'g'; +		break; +	case 'r':          /* repr format */ +		/* Supplied precision is unused, must be 0. */ +		if (precision != 0) { +			PyErr_BadInternalCall(); +			return NULL; +		} +		/* The repr() precision (17 significant decimal digits) is the +		   minimal number that is guaranteed to have enough precision +		   so that if the number is read back in the exact same binary +		   value is recreated.  This is true for IEEE floating point +		   by design, and also happens to work for all other modern +		   hardware. */ +		precision = 17; +		format_code = 'g'; +		break; +	default:  		PyErr_BadInternalCall();  		return NULL;  	} -	/* Add 1 for the trailing 0 byte. */ -	result = PyMem_Malloc(len + 1); -	if (result == NULL) { +	/* Here's a quick-and-dirty calculation to figure out how big a buffer +	   we need.  In general, for a finite float we need: + +	     1 byte for each digit of the decimal significand, and + +	     1 for a possible sign +	     1 for a possible decimal point +	     2 for a possible [eE][+-] +	     1 for each digit of the exponent;  if we allow 19 digits +	       total then we're safe up to exponents of 2**63. +	     1 for the trailing nul byte + +	   This gives a total of 24 + the number of digits in the significand, +	   and the number of digits in the significand is: + +	     for 'g' format: at most precision, except possibly +	       when precision == 0, when it's 1. +	     for 'e' format: precision+1 +	     for 'f' format: precision digits after the point, at least 1 +	       before.  To figure out how many digits appear before the point +	       we have to examine the size of the number.  If fabs(val) < 1.0 +	       then there will be only one digit before the point.  If +	       fabs(val) >= 1.0, then there are at most + +	         1+floor(log10(ceiling(fabs(val)))) + +	       digits before the point (where the 'ceiling' allows for the +	       possibility that the rounding rounds the integer part of val +	       up).  A safe upper bound for the above quantity is +	       1+floor(exp/3), where exp is the unique integer such that 0.5 +	       <= fabs(val)/2**exp < 1.0.  This exp can be obtained from +	       frexp. + +	   So we allow room for precision+1 digits for all formats, plus an +	   extra floor(exp/3) digits for 'f' format. + +	*/ + +	if (Py_IS_NAN(val) || Py_IS_INFINITY(val)) +		/* 3 for 'inf'/'nan', 1 for sign, 1 for '\0' */ +		bufsize = 5; +	else { +		bufsize = 25 + precision; +		if (format_code == 'f' && fabs(val) >= 1.0) { +			frexp(val, &exp); +			bufsize += exp/3; +		} +	} + +	buf = PyMem_Malloc(bufsize); +	if (buf == NULL) {  		PyErr_NoMemory();  		return NULL;  	} -	strcpy(result, buf); -	return result; +	/* Handle nan and inf. */ +	if (Py_IS_NAN(val)) { +		strcpy(buf, "nan"); +		t = Py_DTST_NAN; +	} else if (Py_IS_INFINITY(val)) { +		if (copysign(1., val) == 1.) +			strcpy(buf, "inf"); +		else +			strcpy(buf, "-inf"); +		t = Py_DTST_INFINITE; +	} else { +		t = Py_DTST_FINITE; +		if (flags & Py_DTSF_ADD_DOT_0) +			format_code = 'Z'; + +		PyOS_snprintf(format, sizeof(format), "%%%s.%i%c", +			      (flags & Py_DTSF_ALT ? "#" : ""), precision, +			      format_code); +		_PyOS_ascii_formatd(buf, bufsize, format, val, precision); +	} + +	/* 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] != '-') { +		size_t len = strlen(buf); +		/* the bufsize calculations above should ensure that we've got +		   space to add a sign */ +		assert((size_t)bufsize >= len+2); +		memmove(buf+1, buf, len+1); +		buf[0] = '+'; +	} +	if (upper) { +		/* Convert to upper case. */ +		char *p1; +		for (p1 = buf; *p1; p1++) +			*p1 = Py_TOUPPER(*p1); +	} + +	if (type) +		*type = t; +	return buf; +} + +#else + +/* _Py_dg_dtoa is available. */ + +/* I'm using a lookup table here so that I don't have to invent a non-locale +   specific way to convert to uppercase */ +#define OFS_INF 0 +#define OFS_NAN 1 +#define OFS_E 2 + +/* The lengths of these are known to the code below, so don't change them */ +static char *lc_float_strings[] = { +	"inf", +	"nan", +	"e", +}; +static char *uc_float_strings[] = { +	"INF", +	"NAN", +	"E", +}; + + +/* Convert a double d to a string, and return a PyMem_Malloc'd block of +   memory contain the resulting string. + +   Arguments: +     d is the double to be converted +     format_code is one of 'e', 'f', 'g', 'r'.  'e', 'f' and 'g' +       correspond to '%e', '%f' and '%g';  'r' corresponds to repr. +     mode is one of '0', '2' or '3', and is completely determined by +       format_code: 'e' and 'g' use mode 2; 'f' mode 3, 'r' mode 0. +     precision is the desired precision +     always_add_sign is nonzero if a '+' sign should be included for positive +       numbers +     add_dot_0_if_integer is nonzero if integers in non-exponential form +       should have ".0" added.  Only applies to format codes 'r' and 'g'. +     use_alt_formatting is nonzero if alternative formatting should be +       used.  Only applies to format codes 'e', 'f' and 'g'.  For code 'g', +       at most one of use_alt_formatting and add_dot_0_if_integer should +       be nonzero. +     type, if non-NULL, will be set to one of these constants to identify +       the type of the 'd' argument: +         Py_DTST_FINITE +         Py_DTST_INFINITE +         Py_DTST_NAN + +   Returns a PyMem_Malloc'd block of memory containing the resulting string, +    or NULL on error. If NULL is returned, the Python error has been set. + */ + +static char * +format_float_short(double d, char format_code, +		   int mode, Py_ssize_t precision, +		   int always_add_sign, int add_dot_0_if_integer, +		   int use_alt_formatting, char **float_strings, int *type) +{ +	char *buf = NULL; +	char *p = NULL; +	Py_ssize_t bufsize = 0; +	char *digits, *digits_end; +	int decpt_as_int, sign, exp_len, exp = 0, use_exp = 0; +	Py_ssize_t decpt, digits_len, vdigits_start, vdigits_end; +	_Py_SET_53BIT_PRECISION_HEADER; + +	/* _Py_dg_dtoa returns a digit string (no decimal point or exponent). +	   Must be matched by a call to _Py_dg_freedtoa. */ +	_Py_SET_53BIT_PRECISION_START; +	digits = _Py_dg_dtoa(d, mode, precision, &decpt_as_int, &sign, +			     &digits_end); +	_Py_SET_53BIT_PRECISION_END; + +	decpt = (Py_ssize_t)decpt_as_int; +	if (digits == NULL) { +		/* The only failure mode is no memory. */ +		PyErr_NoMemory(); +		goto exit; +	} +	assert(digits_end != NULL && digits_end >= digits); +	digits_len = digits_end - digits; + +	if (digits_len && !Py_ISDIGIT(digits[0])) { +		/* Infinities and nans here; adapt Gay's output, +		   so convert Infinity to inf and NaN to nan, and +		   ignore sign of nan. Then return. */ + +		/* ignore the actual sign of a nan */ +		if (digits[0] == 'n' || digits[0] == 'N') +			sign = 0; + +		/* We only need 5 bytes to hold the result "+inf\0" . */ +		bufsize = 5; /* Used later in an assert. */ +		buf = (char *)PyMem_Malloc(bufsize); +		if (buf == NULL) { +			PyErr_NoMemory(); +			goto exit; +		} +		p = buf; + +		if (sign == 1) { +			*p++ = '-'; +		} +		else if (always_add_sign) { +			*p++ = '+'; +		} +		if (digits[0] == 'i' || digits[0] == 'I') { +			strncpy(p, float_strings[OFS_INF], 3); +			p += 3; + +			if (type) +				*type = Py_DTST_INFINITE; +		} +		else if (digits[0] == 'n' || digits[0] == 'N') { +			strncpy(p, float_strings[OFS_NAN], 3); +			p += 3; + +			if (type) +				*type = Py_DTST_NAN; +		} +		else { +			/* shouldn't get here: Gay's code should always return +			   something starting with a digit, an 'I',  or 'N' */ +			strncpy(p, "ERR", 3); +			p += 3; +			assert(0); +		} +		goto exit; +	} + +	/* The result must be finite (not inf or nan). */ +	if (type) +		*type = Py_DTST_FINITE; + + +	/* We got digits back, format them.  We may need to pad 'digits' +	   either on the left or right (or both) with extra zeros, so in +	   general the resulting string has the form + +	     [<sign>]<zeros><digits><zeros>[<exponent>] + +	   where either of the <zeros> pieces could be empty, and there's a +	   decimal point that could appear either in <digits> or in the +	   leading or trailing <zeros>. + +	   Imagine an infinite 'virtual' string vdigits, consisting of the +	   string 'digits' (starting at index 0) padded on both the left and +	   right with infinite strings of zeros.  We want to output a slice + +	     vdigits[vdigits_start : vdigits_end] + +	   of this virtual string.  Thus if vdigits_start < 0 then we'll end +	   up producing some leading zeros; if vdigits_end > digits_len there +	   will be trailing zeros in the output.  The next section of code +	   determines whether to use an exponent or not, figures out the +	   position 'decpt' of the decimal point, and computes 'vdigits_start' +	   and 'vdigits_end'. */ +	vdigits_end = digits_len; +	switch (format_code) { +	case 'e': +		use_exp = 1; +		vdigits_end = precision; +		break; +	case 'f': +		vdigits_end = decpt + precision; +		break; +	case 'g': +		if (decpt <= -4 || decpt > +		    (add_dot_0_if_integer ? precision-1 : precision)) +			use_exp = 1; +		if (use_alt_formatting) +			vdigits_end = precision; +		break; +	case 'r': +		/* convert to exponential format at 1e16.  We used to convert +		   at 1e17, but that gives odd-looking results for some values +		   when a 16-digit 'shortest' repr is padded with bogus zeros. +		   For example, repr(2e16+8) would give 20000000000000010.0; +		   the true value is 20000000000000008.0. */ +		if (decpt <= -4 || decpt > 16) +			use_exp = 1; +		break; +	default: +		PyErr_BadInternalCall(); +		goto exit; +	} + +	/* if using an exponent, reset decimal point position to 1 and adjust +	   exponent accordingly.*/ +	if (use_exp) { +		exp = decpt - 1; +		decpt = 1; +	} +	/* ensure vdigits_start < decpt <= vdigits_end, or vdigits_start < +	   decpt < vdigits_end if add_dot_0_if_integer and no exponent */ +	vdigits_start = decpt <= 0 ? decpt-1 : 0; +	if (!use_exp && add_dot_0_if_integer) +		vdigits_end = vdigits_end > decpt ? vdigits_end : decpt + 1; +	else +		vdigits_end = vdigits_end > decpt ? vdigits_end : decpt; + +	/* double check inequalities */ +	assert(vdigits_start <= 0 && +	       0 <= digits_len && +	       digits_len <= vdigits_end); +	/* decimal point should be in (vdigits_start, vdigits_end] */ +	assert(vdigits_start < decpt && decpt <= vdigits_end); + +	/* Compute an upper bound how much memory we need. This might be a few +	   chars too long, but no big deal. */ +	bufsize = +		/* sign, decimal point and trailing 0 byte */ +		3 + + +		/* total digit count (including zero padding on both sides) */ +		(vdigits_end - vdigits_start) + + +		/* exponent "e+100", max 3 numerical digits */ +		(use_exp ? 5 : 0); + +	/* Now allocate the memory and initialize p to point to the start of +	   it. */ +	buf = (char *)PyMem_Malloc(bufsize); +	if (buf == NULL) { +		PyErr_NoMemory(); +		goto exit; +	} +	p = buf; + +	/* Add a negative sign if negative, and a plus sign if non-negative +	   and always_add_sign is true. */ +	if (sign == 1) +		*p++ = '-'; +	else if (always_add_sign) +		*p++ = '+'; + +	/* note that exactly one of the three 'if' conditions is true, +	   so we include exactly one decimal point */ +	/* Zero padding on left of digit string */ +	if (decpt <= 0) { +		memset(p, '0', decpt-vdigits_start); +		p += decpt - vdigits_start; +		*p++ = '.'; +		memset(p, '0', 0-decpt); +		p += 0-decpt; +	} +	else { +		memset(p, '0', 0-vdigits_start); +		p += 0 - vdigits_start; +	} + +	/* Digits, with included decimal point */ +	if (0 < decpt && decpt <= digits_len) { +		strncpy(p, digits, decpt-0); +		p += decpt-0; +		*p++ = '.'; +		strncpy(p, digits+decpt, digits_len-decpt); +		p += digits_len-decpt; +	} +	else { +		strncpy(p, digits, digits_len); +		p += digits_len; +	} + +	/* And zeros on the right */ +	if (digits_len < decpt) { +		memset(p, '0', decpt-digits_len); +		p += decpt-digits_len; +		*p++ = '.'; +		memset(p, '0', vdigits_end-decpt); +		p += vdigits_end-decpt; +	} +	else { +		memset(p, '0', vdigits_end-digits_len); +		p += vdigits_end-digits_len; +	} + +	/* Delete a trailing decimal pt unless using alternative formatting. */ +	if (p[-1] == '.' && !use_alt_formatting) +		p--; + +	/* Now that we've done zero padding, add an exponent if needed. */ +	if (use_exp) { +		*p++ = float_strings[OFS_E][0]; +		exp_len = sprintf(p, "%+.02d", exp); +		p += exp_len; +	} +  exit: +	if (buf) { +		*p = '\0'; +		/* It's too late if this fails, as we've already stepped on +		   memory that isn't ours. But it's an okay debugging test. */ +		assert(p-buf < bufsize); +	} +	if (digits) +		_Py_dg_freedtoa(digits); + +	return buf; +} + + +PyAPI_FUNC(char *) PyOS_double_to_string(double val, +					 char format_code, +					 int precision, +					 int flags, +					 int *type) +{ +	char **float_strings = lc_float_strings; +	int mode; + +	/* Validate format_code, and map upper and lower case. Compute the +	   mode and make any adjustments as needed. */ +	switch (format_code) { +	/* exponent */ +	case 'E': +		float_strings = uc_float_strings; +		format_code = 'e'; +		/* Fall through. */ +	case 'e': +		mode = 2; +		precision++; +		break; + +	/* fixed */ +	case 'F': +		float_strings = uc_float_strings; +		format_code = 'f'; +		/* Fall through. */ +	case 'f': +		mode = 3; +		break; + +	/* general */ +	case 'G': +		float_strings = uc_float_strings; +		format_code = 'g'; +		/* Fall through. */ +	case 'g': +		mode = 2; +		/* precision 0 makes no sense for 'g' format; interpret as 1 */ +		if (precision == 0) +			precision = 1; +		break; + +	/* repr format */ +	case 'r': +		mode = 0; +		/* Supplied precision is unused, must be 0. */ +		if (precision != 0) { +			PyErr_BadInternalCall(); +			return NULL; +		} +		break; + +	default: +		PyErr_BadInternalCall(); +		return NULL; +	} + +	return format_float_short(val, format_code, mode, precision, +				  flags & Py_DTSF_SIGN, +				  flags & Py_DTSF_ADD_DOT_0, +				  flags & Py_DTSF_ALT, +				  float_strings, type);  } +#endif /* ifdef PY_NO_SHORT_FLOAT_REPR */  | 
