mirror of
https://github.com/python/cpython.git
synced 2025-07-12 22:05:16 +00:00
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.
This commit is contained in:
parent
31575ce817
commit
38fd5b6413
4 changed files with 409 additions and 75 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue