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:
Tim Peters 2000-09-21 05:43:11 +00:00
parent 31575ce817
commit 38fd5b6413
4 changed files with 409 additions and 75 deletions

View file

@ -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;