mirror of
https://github.com/python/cpython.git
synced 2024-11-29 04:44:13 +08:00
Bug 415514 reported that e.g.
"%#x" % 0 blew up, at heart because C sprintf supplies a base marker if and only if the value is not 0. I then fixed that, by tolerating C's inconsistency when it does %#x, and taking away that *Python* produced 0x0 when formatting 0L (the "long" flavor of 0) under %#x itself. But after talking with Guido, we agreed it would be better to supply 0x for the short int case too, despite that it's inconsistent with C, because C is inconsistent with itself and with Python's hex(0) (plus, while "%#x" % 0 didn't work before, "%#x" % 0L *did*, and returned "0x0"). Similarly for %#X conversion.
This commit is contained in:
parent
bfb0cf822b
commit
fff5325078
@ -176,10 +176,10 @@ testboth("%o", 0, "0")
|
|||||||
testboth("%o", 0L, "0")
|
testboth("%o", 0L, "0")
|
||||||
testboth("%d", 0, "0")
|
testboth("%d", 0, "0")
|
||||||
testboth("%d", 0L, "0")
|
testboth("%d", 0L, "0")
|
||||||
testboth("%#x", 0, "0")
|
testboth("%#x", 0, "0x0")
|
||||||
testboth("%#x", 0L, "0")
|
testboth("%#x", 0L, "0x0")
|
||||||
testboth("%#X", 0, "0")
|
testboth("%#X", 0, "0X0")
|
||||||
testboth("%#X", 0L, "0")
|
testboth("%#X", 0L, "0X0")
|
||||||
|
|
||||||
testboth("%x", 0x42, "42")
|
testboth("%x", 0x42, "42")
|
||||||
# testboth("%x", -0x42, "ffffffbe") # Alas, that's specific to 32-bit machines
|
# testboth("%x", -0x42, "ffffffbe") # Alas, that's specific to 32-bit machines
|
||||||
|
@ -2575,16 +2575,8 @@ _PyString_FormatLong(PyObject *val, int flags, int prec, int type,
|
|||||||
numdigits = len - numnondigits;
|
numdigits = len - numnondigits;
|
||||||
assert(numdigits > 0);
|
assert(numdigits > 0);
|
||||||
|
|
||||||
/* Get rid of base marker unless F_ALT. Even if F_ALT, leading 0x
|
/* Get rid of base marker unless F_ALT */
|
||||||
* must be stripped if the *value* is 0.
|
if ((flags & F_ALT) == 0) {
|
||||||
*/
|
|
||||||
if ((flags & F_ALT) == 0 ||
|
|
||||||
((flags & F_ALT) &&
|
|
||||||
(type == 'x' || type == 'X') &&
|
|
||||||
numdigits == 1 &&
|
|
||||||
!sign &&
|
|
||||||
buf[2] == '0'
|
|
||||||
)) {
|
|
||||||
/* Need to skip 0x, 0X or 0. */
|
/* Need to skip 0x, 0X or 0. */
|
||||||
int skipped = 0;
|
int skipped = 0;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -2678,6 +2670,16 @@ formatint(char *buf, size_t buflen, int flags,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(buf, fmt, x);
|
sprintf(buf, 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).
|
||||||
|
*/
|
||||||
|
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X')) {
|
||||||
|
assert(buf[1] != type); /* else this C *is* adding 0x/0X */
|
||||||
|
memmove(buf+2, buf, strlen(buf) + 1);
|
||||||
|
buf[0] = '0';
|
||||||
|
buf[1] = (char)type;
|
||||||
|
}
|
||||||
return strlen(buf);
|
return strlen(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3023,21 +3025,17 @@ PyString_Format(PyObject *format, PyObject *args)
|
|||||||
width--;
|
width--;
|
||||||
}
|
}
|
||||||
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
|
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
|
||||||
/* There's a base marker ("0x" or "0X") if and
|
|
||||||
* only if the value is non-zero.
|
|
||||||
*/
|
|
||||||
assert(pbuf[0] == '0');
|
assert(pbuf[0] == '0');
|
||||||
if (pbuf[1] == c) {
|
assert(pbuf[1] == c);
|
||||||
if (fill != ' ') {
|
if (fill != ' ') {
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
}
|
|
||||||
rescnt -= 2;
|
|
||||||
width -= 2;
|
|
||||||
if (width < 0)
|
|
||||||
width = 0;
|
|
||||||
len -= 2;
|
|
||||||
}
|
}
|
||||||
|
rescnt -= 2;
|
||||||
|
width -= 2;
|
||||||
|
if (width < 0)
|
||||||
|
width = 0;
|
||||||
|
len -= 2;
|
||||||
}
|
}
|
||||||
if (width > len && !(flags & F_LJUST)) {
|
if (width > len && !(flags & F_LJUST)) {
|
||||||
do {
|
do {
|
||||||
@ -3049,8 +3047,9 @@ PyString_Format(PyObject *format, PyObject *args)
|
|||||||
if (sign)
|
if (sign)
|
||||||
*res++ = sign;
|
*res++ = sign;
|
||||||
if ((flags & F_ALT) &&
|
if ((flags & F_ALT) &&
|
||||||
(c == 'x' || c == 'X') &&
|
(c == 'x' || c == 'X')) {
|
||||||
pbuf[1] == c) {
|
assert(pbuf[0] == '0');
|
||||||
|
assert(pbuf[1] == c);
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
}
|
}
|
||||||
|
@ -4683,7 +4683,14 @@ formatint(Py_UNICODE *buf,
|
|||||||
"formatted integer is too long (precision too long?)");
|
"formatted integer is too long (precision too long?)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
sprintf(fmt, "%%%s.%dl%c", (flags & F_ALT) ? "#" : "", prec, type);
|
/* 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).
|
||||||
|
*/
|
||||||
|
if (x == 0 && (flags & F_ALT) && (type == 'x' || type == 'X'))
|
||||||
|
sprintf(fmt, "0%c%%%s.%dl%c", type, "#", prec, type);
|
||||||
|
else
|
||||||
|
sprintf(fmt, "%%%s.%dl%c", (flags & F_ALT) ? "#" : "", prec, type);
|
||||||
return usprintf(buf, fmt, x);
|
return usprintf(buf, fmt, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5081,17 +5088,16 @@ PyObject *PyUnicode_Format(PyObject *format,
|
|||||||
}
|
}
|
||||||
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
|
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
|
||||||
assert(pbuf[0] == '0');
|
assert(pbuf[0] == '0');
|
||||||
if (pbuf[1] == c) {
|
assert(pbuf[1] == c);
|
||||||
if (fill != ' ') {
|
if (fill != ' ') {
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
}
|
|
||||||
rescnt -= 2;
|
|
||||||
width -= 2;
|
|
||||||
if (width < 0)
|
|
||||||
width = 0;
|
|
||||||
len -= 2;
|
|
||||||
}
|
}
|
||||||
|
rescnt -= 2;
|
||||||
|
width -= 2;
|
||||||
|
if (width < 0)
|
||||||
|
width = 0;
|
||||||
|
len -= 2;
|
||||||
}
|
}
|
||||||
if (width > len && !(flags & F_LJUST)) {
|
if (width > len && !(flags & F_LJUST)) {
|
||||||
do {
|
do {
|
||||||
@ -5102,9 +5108,9 @@ PyObject *PyUnicode_Format(PyObject *format,
|
|||||||
if (fill == ' ') {
|
if (fill == ' ') {
|
||||||
if (sign)
|
if (sign)
|
||||||
*res++ = sign;
|
*res++ = sign;
|
||||||
if ((flags & F_ALT) && (c == 'x' || c == 'X') &&
|
if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
|
||||||
pbuf[1] == c) {
|
|
||||||
assert(pbuf[0] == '0');
|
assert(pbuf[0] == '0');
|
||||||
|
assert(pbuf[1] == c);
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
*res++ = *pbuf++;
|
*res++ = *pbuf++;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user