diff options
author | Tim Peters <tim.peters@gmail.com> | 2000-09-21 05:43:11 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2000-09-21 05:43:11 (GMT) |
commit | 38fd5b641366eedc74e4be3a0e4d2210f3bcdb5a (patch) | |
tree | 38536cf33e6f83fa3ca8af62dbafebcd4dfd5921 /Objects/unicodeobject.c | |
parent | 31575ce8172d40575be3c3d7a3a4a51d4aaf1a86 (diff) | |
download | cpython-38fd5b641366eedc74e4be3a0e4d2210f3bcdb5a.zip cpython-38fd5b641366eedc74e4be3a0e4d2210f3bcdb5a.tar.gz cpython-38fd5b641366eedc74e4be3a0e4d2210f3bcdb5a.tar.bz2 |
Derived from Martin's SF patch 110609: support unbounded ints in %d,i,u,x,X,o formats.
Note a curious extension to the std C rules: x, X and o formatting can never produce
a sign character in C, so the '+' and ' ' flags are meaningless for them. But
unbounded ints *can* produce a sign character under these conversions (no fixed-
width bitstring is wide enough to hold all negative values in 2's-comp form). So
these flags become meaningful in Python when formatting a Python long which is too
big to fit in a C long. This required shuffling around existing code, which hacked
x and X conversions to death when both the '#' and '0' flags were specified: the
hacks weren't strong enough to deal with the simultaneous possibility of the ' ' or
'+' flags too, since signs were always meaningless before for x and X conversions.
Isomorphic shuffling was required in unicodeobject.c.
Also added dozens of non-trivial new unbounded-int test cases to test_format.py.
Diffstat (limited to 'Objects/unicodeobject.c')
-rw-r--r-- | Objects/unicodeobject.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 76bb92a..1559542 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4668,6 +4668,25 @@ formatfloat(Py_UNICODE *buf, return usprintf(buf, fmt, x); } +static PyObject* +formatlong(PyObject *val, int flags, int prec, int type) +{ + char *buf; + int i, len; + PyObject *str; /* temporary string object. */ + PyUnicodeObject *result; + + str = _PyString_FormatLong(val, flags, prec, type, &buf, &len); + if (!str) + return NULL; + result = _PyUnicode_New(len); + for (i = 0; i < len; i++) + result->str[i] = buf[i]; + result->str[len] = 0; + Py_DECREF(str); + return (PyObject*)result; +} + static int formatint(Py_UNICODE *buf, size_t buflen, @@ -4677,8 +4696,9 @@ formatint(Py_UNICODE *buf, PyObject *v) { /* fmt = '%#.' + `prec` + 'l' + `type` - worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/ - char fmt[20]; + 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; x = PyInt_AsLong(v); @@ -5006,26 +5026,29 @@ PyObject *PyUnicode_Format(PyObject *format, case 'X': if (c == 'i') c = 'd'; - pbuf = formatbuf; - len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) - goto onError; - sign = (c == 'd'); - if (flags & F_ZERO) { - fill = '0'; - if ((flags&F_ALT) && - (c == 'x' || c == 'X') && - pbuf[0] == '0' && pbuf[1] == c) { - *res++ = *pbuf++; - *res++ = *pbuf++; - rescnt -= 2; - len -= 2; - width -= 2; - if (width < 0) - width = 0; - } + if (PyLong_Check(v) && PyLong_AsLong(v) == -1 + && PyErr_Occurred()) { + PyErr_Clear(); + temp = formatlong(v, flags, prec, c); + if (!temp) + goto onError; + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); + /* unbounded ints can always produce + a sign character! */ + sign = 1; } + else { + pbuf = formatbuf; + len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), + flags, prec, c, v); + if (len < 0) + goto onError; + /* only d conversion is signed */ + sign = c == 'd'; + } + if (flags & F_ZERO) + fill = '0'; break; case 'e': @@ -5039,7 +5062,7 @@ PyObject *PyUnicode_Format(PyObject *format, if (len < 0) goto onError; sign = 1; - if (flags&F_ZERO) + if (flags & F_ZERO) fill = '0'; break; @@ -5086,14 +5109,35 @@ PyObject *PyUnicode_Format(PyObject *format, if (width > len) width--; } + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + 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 { --rescnt; *res++ = fill; } while (--width > len); } - if (sign && fill == ' ') - *res++ = sign; + if (fill == ' ') { + if (sign) + *res++ = sign; + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + *res++ = *pbuf++; + *res++ = *pbuf++; + } + } memcpy(res, pbuf, len * sizeof(Py_UNICODE)); res += len; rescnt -= len; |