Fix "%f" format of str%args if the result is not an ASCII or latin1 string

This commit is contained in:
Victor Stinner 2012-06-16 02:57:41 +02:00
parent 9a77770add
commit 184252ad3f
2 changed files with 21 additions and 17 deletions

View File

@ -265,6 +265,8 @@ class FormatTest(unittest.TestCase):
raise TestFailed('"%*d"%(maxsize, -127) should fail') raise TestFailed('"%*d"%(maxsize, -127) should fail')
def test_non_ascii(self): def test_non_ascii(self):
testformat("\u20ac=%f", (1.0,), "\u20ac=1.000000")
self.assertEqual(format("abc", "\u2007<5"), "abc\u2007\u2007") self.assertEqual(format("abc", "\u2007<5"), "abc\u2007\u2007")
self.assertEqual(format(123, "\u2007<5"), "123\u2007\u2007") self.assertEqual(format(123, "\u2007<5"), "123\u2007\u2007")
self.assertEqual(format(12.3, "\u2007<6"), "12.3\u2007\u2007") self.assertEqual(format(12.3, "\u2007<6"), "12.3\u2007\u2007")

View File

@ -1660,34 +1660,34 @@ unicode_putchar(PyObject **p_unicode, Py_ssize_t *pos,
} }
/* Copy a ASCII or latin1 char* string into a Python Unicode string. /* Copy a ASCII or latin1 char* string into a Python Unicode string.
Return the length of the input string.
WARNING: The function doesn't copy the terminating null character and WARNING: The function doesn't copy the terminating null character and
doesn't check the maximum character (may write a latin1 character in an doesn't check the maximum character (may write a latin1 character in an
ASCII string). */ ASCII string). */
static Py_ssize_t static void
unicode_write_cstr(PyObject *unicode, Py_ssize_t index, const char *str) unicode_write_cstr(PyObject *unicode, Py_ssize_t index,
const char *str, Py_ssize_t len)
{ {
enum PyUnicode_Kind kind = PyUnicode_KIND(unicode); enum PyUnicode_Kind kind = PyUnicode_KIND(unicode);
void *data = PyUnicode_DATA(unicode); void *data = PyUnicode_DATA(unicode);
const char *end = str + len;
switch (kind) { switch (kind) {
case PyUnicode_1BYTE_KIND: { case PyUnicode_1BYTE_KIND: {
Py_ssize_t len = strlen(str);
assert(index + len <= PyUnicode_GET_LENGTH(unicode)); assert(index + len <= PyUnicode_GET_LENGTH(unicode));
memcpy((char *) data + index, str, len); memcpy((char *) data + index, str, len);
return len; break;
} }
case PyUnicode_2BYTE_KIND: { case PyUnicode_2BYTE_KIND: {
Py_UCS2 *start = (Py_UCS2 *)data + index; Py_UCS2 *start = (Py_UCS2 *)data + index;
Py_UCS2 *ucs2 = start; Py_UCS2 *ucs2 = start;
assert(index <= PyUnicode_GET_LENGTH(unicode)); assert(index <= PyUnicode_GET_LENGTH(unicode));
for (; *str; ++ucs2, ++str) for (; str < end; ++ucs2, ++str)
*ucs2 = (Py_UCS2)*str; *ucs2 = (Py_UCS2)*str;
assert((ucs2 - start) <= PyUnicode_GET_LENGTH(unicode)); assert((ucs2 - start) <= PyUnicode_GET_LENGTH(unicode));
return ucs2 - start; break;
} }
default: { default: {
Py_UCS4 *start = (Py_UCS4 *)data + index; Py_UCS4 *start = (Py_UCS4 *)data + index;
@ -1695,11 +1695,10 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index, const char *str)
assert(kind == PyUnicode_4BYTE_KIND); assert(kind == PyUnicode_4BYTE_KIND);
assert(index <= PyUnicode_GET_LENGTH(unicode)); assert(index <= PyUnicode_GET_LENGTH(unicode));
for (; *str; ++ucs4, ++str) for (; str < end; ++ucs4, ++str)
*ucs4 = (Py_UCS4)*str; *ucs4 = (Py_UCS4)*str;
assert((ucs4 - start) <= PyUnicode_GET_LENGTH(unicode)); assert((ucs4 - start) <= PyUnicode_GET_LENGTH(unicode));
return ucs4 - start;
} }
} }
} }
@ -2730,17 +2729,18 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
case 'x': case 'x':
case 'p': case 'p':
{ {
Py_ssize_t written; Py_ssize_t len;
/* unused, since we already have the result */ /* unused, since we already have the result */
if (*f == 'p') if (*f == 'p')
(void) va_arg(vargs, void *); (void) va_arg(vargs, void *);
else else
(void) va_arg(vargs, int); (void) va_arg(vargs, int);
/* extract the result from numberresults and append. */ /* extract the result from numberresults and append. */
written = unicode_write_cstr(string, i, numberresult); len = strlen(numberresult);
unicode_write_cstr(string, i, numberresult, len);
/* skip over the separating '\0' */ /* skip over the separating '\0' */
i += written; i += len;
numberresult += written; numberresult += len;
assert(*numberresult == '\0'); assert(*numberresult == '\0');
numberresult++; numberresult++;
assert(numberresult <= numberresults + numbersize); assert(numberresult <= numberresults + numbersize);
@ -2812,10 +2812,14 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
PyUnicode_WRITE(kind, data, i++, '%'); PyUnicode_WRITE(kind, data, i++, '%');
break; break;
default: default:
i += unicode_write_cstr(string, i, p); {
Py_ssize_t len = strlen(p);
unicode_write_cstr(string, i, p, len);
i += len;
assert(i == PyUnicode_GET_LENGTH(string)); assert(i == PyUnicode_GET_LENGTH(string));
goto end; goto end;
} }
}
} }
else { else {
assert(i < PyUnicode_GET_LENGTH(string)); assert(i < PyUnicode_GET_LENGTH(string));
@ -13211,9 +13215,7 @@ formatfloat(PyObject *v, int flags, int prec, int type,
if (writer) { if (writer) {
if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1) if (_PyUnicodeWriter_Prepare(writer, len, 127) == -1)
return -1; return -1;
memcpy((char*)writer->data + writer->pos * writer->kind, unicode_write_cstr(writer->buffer, writer->pos, p, len);
p,
len);
writer->pos += len; writer->pos += len;
} }
else else