summaryrefslogtreecommitdiffstats
path: root/Objects/unicodeobject.c
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2000-09-21 05:43:11 (GMT)
committerTim Peters <tim.peters@gmail.com>2000-09-21 05:43:11 (GMT)
commit38fd5b641366eedc74e4be3a0e4d2210f3bcdb5a (patch)
tree38536cf33e6f83fa3ca8af62dbafebcd4dfd5921 /Objects/unicodeobject.c
parent31575ce8172d40575be3c3d7a3a4a51d4aaf1a86 (diff)
downloadcpython-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.c92
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;