%#x/%#X format conversion cleanup (see patch #450267):

Objects/
    stringobject.c
    unicodeobject.c
This commit is contained in:
Andrew MacIntyre 2002-02-28 11:38:24 +00:00
parent bbea4717bc
commit 5e9c80d906
2 changed files with 74 additions and 63 deletions

View File

@ -3069,46 +3069,52 @@ formatint(char *buf, size_t buflen, int flags,
+ 1 + 1 = 24 */
char fmt[64]; /* plenty big enough! */
long x;
if (!PyArg_Parse(v, "l;int argument required", &x))
return -1;
if (prec < 0)
prec = 1;
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%dl%c",
(flags&F_ALT) ? "#" : "",
prec, type);
if ((flags & F_ALT) &&
(type == 'x' || type == 'X')) {
/* When converting under %#x or %#X, there are a number
* of issues that cause pain:
* - when 0 is being converted, the C standard leaves off
* the '0x' or '0X', which is inconsistent with other
* %#x/%#X conversions and inconsistent with Python's
* hex() function
* - there are platforms that violate the standard and
* convert 0 with the '0x' or '0X'
* (Metrowerks, Compaq Tru64)
* - there are platforms that give '0x' when converting
* under %#X, but convert 0 in accordance with the
* standard (OS/2 EMX)
*
* We can achieve the desired consistency by inserting our
* own '0x' or '0X' prefix, and substituting %x/%X in place
* of %#x/%#X.
*
* Note that this is the same approach as used in
* formatint() in unicodeobject.c
*/
PyOS_snprintf(fmt, sizeof(fmt), "0%c%%.%dl%c",
type, prec, type);
}
else {
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%dl%c",
(flags&F_ALT) ? "#" : "",
prec, type);
}
/* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec, len(x in octal))
worst case buf = '0x' + [0-9]*prec, where prec >= 11 */
* worst case buf = '0x' + [0-9]*prec, where prec >= 11
*/
if (buflen <= 13 || buflen <= (size_t)2 + (size_t)prec) {
PyErr_SetString(PyExc_OverflowError,
"formatted integer is too long (precision too large?)");
return -1;
}
PyOS_snprintf(buf, buflen, fmt, x);
/* When converting 0 under %#x or %#X, C leaves off the base marker,
* but we want it (for consistency with other %#x conversions, and
* for consistency with Python's hex() function).
* BUG 28-Apr-2001 tim: At least two platform Cs (Metrowerks &
* Compaq Tru64) violate the std by converting 0 w/ leading 0x anyway.
* So add it only if the platform didn't already.
*/
if (x == 0 &&
(flags & F_ALT) &&
(type == 'x' || type == 'X') &&
buf[1] != (char)type) /* this last always true under std C */
{
memmove(buf+2, buf, strlen(buf) + 1);
buf[0] = '0';
buf[1] = (char)type;
}
#if defined(PYOS_OS2) && defined(PYCC_GCC)
/* unfortunately, the EMX C runtime gives us '0x' as the base
* marker for %X when we expect/want '0X'
*/
else if ((flags & F_ALT) && (type == 'X')) {
assert(buf[1] == 'x');
buf[1] = (char)type;
}
#endif
return strlen(buf);
}

View File

@ -5137,53 +5137,58 @@ formatint(Py_UNICODE *buf,
PyObject *v)
{
/* fmt = '%#.' + `prec` + 'l' + `type`
worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine)
+ 1 + 1 = 24*/
* worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine)
* + 1 + 1
* = 24
*/
char fmt[64]; /* plenty big enough! */
long x;
int use_native_c_format = 1;
x = PyInt_AsLong(v);
if (x == -1 && PyErr_Occurred())
return -1;
return -1;
if (prec < 0)
prec = 1;
prec = 1;
/* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal))
worst case buf = '0x' + [0-9]*prec, where prec >= 11 */
if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) {
* worst case buf = '0x' + [0-9]*prec, where prec >= 11
*/
if (buflen <= 13 || buflen <= (size_t)2 + (size_t)prec) {
PyErr_SetString(PyExc_OverflowError,
"formatted integer is too long (precision too long?)");
"formatted integer is too long (precision too large?)");
return -1;
}
/* When converting 0 under %#x or %#X, C leaves off the base marker,
* but we want it (for consistency with other %#x conversions, and
* for consistency with Python's hex() function).
* BUG 28-Apr-2001 tim: At least two platform Cs (Metrowerks &
* Compaq Tru64) violate the std by converting 0 w/ leading 0x anyway.
* So add it only if the platform doesn't already.
*/
#if defined(PYOS_OS2) && defined(PYCC_GCC)
if ((flags & F_ALT) && (type == 'x' || type == 'X')) {
/* the EMX runtime gives 0x as the base marker when we want 0X
* so we cover all bets by supplying our own for both cases.
if ((flags & F_ALT) &&
(type == 'x' || type == 'X')) {
/* When converting under %#x or %#X, there are a number
* of issues that cause pain:
* - when 0 is being converted, the C standard leaves off
* the '0x' or '0X', which is inconsistent with other
* %#x/%#X conversions and inconsistent with Python's
* hex() function
* - there are platforms that violate the standard and
* convert 0 with the '0x' or '0X'
* (Metrowerks, Compaq Tru64)
* - there are platforms that give '0x' when converting
* under %#X, but convert 0 in accordance with the
* standard (OS/2 EMX)
*
* We can achieve the desired consistency by inserting our
* own '0x' or '0X' prefix, and substituting %x/%X in place
* of %#x/%#X.
*
* Note that this is the same approach as used in
* formatint() in stringobject.c
*/
use_native_c_format = 0;
PyOS_snprintf(fmt, sizeof(fmt), "0%c%%.%dl%c", type, prec, type);
PyOS_snprintf(fmt, sizeof(fmt), "0%c%%.%dl%c",
type, prec, type);
}
#else
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X')) {
/* Only way to know what the platform does is to try it. */
PyOS_snprintf(fmt, sizeof(fmt), type == 'x' ? "%#x" : "%#X", 0);
if (fmt[1] != (char)type) {
/* Supply our own leading 0x/0X -- needed under std C */
use_native_c_format = 0;
PyOS_snprintf(fmt, sizeof(fmt), "0%c%%#.%dl%c", type, prec, type);
}
else {
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%dl%c",
(flags&F_ALT) ? "#" : "",
prec, type);
}
#endif
if (use_native_c_format)
PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%dl%c",
(flags & F_ALT) ? "#" : "", prec, type);
return usprintf(buf, fmt, x);
}