]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Bug 415514 reported that e.g.
authorTim Peters <tim.peters@gmail.com>
Thu, 12 Apr 2001 18:38:48 +0000 (18:38 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 12 Apr 2001 18:38:48 +0000 (18:38 +0000)
    "%#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.

Lib/test/test_format.py
Objects/stringobject.c
Objects/unicodeobject.c

index ce5d5f2c80752ec5e721d63f49a33a129c4b74a9..c74db0fedca97973c0e408202dbccadc68e9b705 100644 (file)
@@ -176,10 +176,10 @@ testboth("%o", 0, "0")
 testboth("%o", 0L, "0")
 testboth("%d", 0, "0")
 testboth("%d", 0L, "0")
-testboth("%#x", 0, "0")
-testboth("%#x", 0L, "0")
-testboth("%#X", 0, "0")
-testboth("%#X", 0L, "0")
+testboth("%#x", 0, "0x0")
+testboth("%#x", 0L, "0x0")
+testboth("%#X", 0, "0X0")
+testboth("%#X", 0L, "0X0")
 
 testboth("%x", 0x42, "42")
 # testboth("%x", -0x42, "ffffffbe") # Alas, that's specific to 32-bit machines
index 8e1153693d0cd1e57747450aa58c7fc609d61a75..1701b2fcc39abaebb82704b69ca379b0a5a9ea2b 100644 (file)
@@ -2575,16 +2575,8 @@ _PyString_FormatLong(PyObject *val, int flags, int prec, int type,
        numdigits = len - numnondigits;
        assert(numdigits > 0);
 
-       /* Get rid of base marker unless F_ALT.  Even if F_ALT, leading 0x
-        * must be stripped if the *value* is 0.
-        */
-       if ((flags & F_ALT) == 0 ||
-           ((flags & F_ALT) &&
-            (type == 'x' || type == 'X') &&
-            numdigits == 1 &&
-            !sign &&
-            buf[2] == '0'
-           )) {
+       /* Get rid of base marker unless F_ALT */
+       if ((flags & F_ALT) == 0) {
                /* Need to skip 0x, 0X or 0. */
                int skipped = 0;
                switch (type) {
@@ -2678,6 +2670,16 @@ formatint(char *buf, size_t buflen, int flags,
                return -1;
        }
        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);
 }
 
@@ -3023,21 +3025,17 @@ PyString_Format(PyObject *format, PyObject *args)
                                        width--;
                        }
                        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');
-                               if (pbuf[1] == c) {
-                                       if (fill != ' ') {
-                                               *res++ = *pbuf++;
-                                               *res++ = *pbuf++;
-                                       }
-                                       rescnt -= 2;
-                                       width -= 2;
-                                       if (width < 0)
-                                               width = 0;
-                                       len -= 2;
+                               assert(pbuf[1] == c);
+                               if (fill != ' ') {
+                                       *res++ = *pbuf++;
+                                       *res++ = *pbuf++;
                                }
+                               rescnt -= 2;
+                               width -= 2;
+                               if (width < 0)
+                                       width = 0;
+                               len -= 2;
                        }
                        if (width > len && !(flags & F_LJUST)) {
                                do {
@@ -3049,8 +3047,9 @@ PyString_Format(PyObject *format, PyObject *args)
                                if (sign)
                                        *res++ = sign;
                                if ((flags & F_ALT) &&
-                                   (c == 'x' || c == 'X') &&
-                                   pbuf[1] == c) {
+                                   (c == 'x' || c == 'X')) {
+                                       assert(pbuf[0] == '0');
+                                       assert(pbuf[1] == c);
                                        *res++ = *pbuf++;
                                        *res++ = *pbuf++;
                                }
index aecc2618d1520b408dbcc83cacb25431721f2eec..b623c204cb4c3cafd8c0def79075e8658ebec567 100644 (file)
@@ -4683,7 +4683,14 @@ formatint(Py_UNICODE *buf,
             "formatted integer is too long (precision too long?)");
         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);
 }
 
@@ -5081,17 +5088,16 @@ PyObject *PyUnicode_Format(PyObject *format,
            }
            if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
                assert(pbuf[0] == '0');
-               if (pbuf[1] == c) {
-                       if (fill != ' ') {
-                           *res++ = *pbuf++;
-                           *res++ = *pbuf++;
-                       }
-                       rescnt -= 2;
-                       width -= 2;
-                       if (width < 0)
-                           width = 0;
-                       len -= 2;
+               assert(pbuf[1] == c);
+               if (fill != ' ') {
+                   *res++ = *pbuf++;
+                   *res++ = *pbuf++;
                }
+               rescnt -= 2;
+               width -= 2;
+               if (width < 0)
+                   width = 0;
+               len -= 2;
            }
            if (width > len && !(flags & F_LJUST)) {
                do {
@@ -5102,9 +5108,9 @@ PyObject *PyUnicode_Format(PyObject *format,
            if (fill == ' ') {
                if (sign)
                    *res++ = sign;
-               if ((flags & F_ALT) && (c == 'x' || c == 'X') &&
-                   pbuf[1] == c) {
+               if ((flags & F_ALT) && (c == 'x' || c == 'X')) {
                    assert(pbuf[0] == '0');
+                   assert(pbuf[1] == c);
                    *res++ = *pbuf++;
                    *res++ = *pbuf++;
                }