summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/whatsnew/3.12.rst3
-rw-r--r--Misc/ACKS2
-rw-r--r--Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst3
-rw-r--r--Modules/_testcapi/unicode.c60
-rw-r--r--Objects/unicodeobject.c25
5 files changed, 86 insertions, 7 deletions
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 6df122a..acf5961 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -475,6 +475,9 @@ Porting to Python 3.12
copied as-is to the result string, and any extra arguments discarded.
(Contributed by Serhiy Storchaka in :gh:`95781`.)
+* Fixed wrong sign placement in :c:func:`PyUnicode_FromFormat` and
+ :c:func:`PyUnicode_FromFormatV`.
+ (Contributed by Philip Georgi in :gh:`95504`.)
Deprecated
----------
diff --git a/Misc/ACKS b/Misc/ACKS
index 7065267..28b4ce4 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -608,8 +608,8 @@ Marius Gedminas
Jan-Philip Gehrcke
Thomas Gellekum
Gabriel Genellina
-Christos Georgiou
Philip Georgi
+Christos Georgiou
Elazar (אלעזר) Gershuni
Ben Gertzfield
Nadim Ghaznavi
diff --git a/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst b/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst
new file mode 100644
index 0000000..955bdd4
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2022-07-31-21-58-27.gh-issue-95504.wy7B1F.rst
@@ -0,0 +1,3 @@
+Fix sign placement when specifying width or precision in
+:c:func:`PyUnicode_FromFormat` and :c:func:`PyUnicode_FromFormatV`.
+Patch by Philip Georgi.
diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c
index 5821424..d0f1e2a 100644
--- a/Modules/_testcapi/unicode.c
+++ b/Modules/_testcapi/unicode.c
@@ -433,6 +433,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%05zu", "00123", (size_t)123);
CHECK_FORMAT_1("%05x", "0007b", (int)123);
+ CHECK_FORMAT_1("%05d", "-0123", (int)-123);
+ CHECK_FORMAT_1("%05i", "-0123", (int)-123);
+ CHECK_FORMAT_1("%05ld", "-0123", (long)-123);
+ CHECK_FORMAT_1("%05li", "-0123", (long)-123);
+ CHECK_FORMAT_1("%05lld", "-0123", (long long)-123);
+ CHECK_FORMAT_1("%05lli", "-0123", (long long)-123);
+ CHECK_FORMAT_1("%05zd", "-0123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%05zi", "-0123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%09x", "0ffffff85", (int)-123);
+
// Integers: precision < length
CHECK_FORMAT_1("%.1d", "123", (int)123);
CHECK_FORMAT_1("%.1i", "123", (int)123);
@@ -473,6 +483,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%.5zu", "00123", (size_t)123);
CHECK_FORMAT_1("%.5x", "0007b", (int)123);
+ CHECK_FORMAT_1("%.5d", "-00123", (int)-123);
+ CHECK_FORMAT_1("%.5i", "-00123", (int)-123);
+ CHECK_FORMAT_1("%.5ld", "-00123", (long)-123);
+ CHECK_FORMAT_1("%.5li", "-00123", (long)-123);
+ CHECK_FORMAT_1("%.5lld", "-00123", (long long)-123);
+ CHECK_FORMAT_1("%.5lli", "-00123", (long long)-123);
+ CHECK_FORMAT_1("%.5zd", "-00123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%.5zi", "-00123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%.9x", "0ffffff85", (int)-123);
+
// Integers: width > precision > length
CHECK_FORMAT_1("%7.5d", " 00123", (int)123);
CHECK_FORMAT_1("%7.5i", " 00123", (int)123);
@@ -488,6 +508,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%7.5zu", " 00123", (size_t)123);
CHECK_FORMAT_1("%7.5x", " 0007b", (int)123);
+ CHECK_FORMAT_1("%7.5d", " -00123", (int)-123);
+ CHECK_FORMAT_1("%7.5i", " -00123", (int)-123);
+ CHECK_FORMAT_1("%7.5ld", " -00123", (long)-123);
+ CHECK_FORMAT_1("%7.5li", " -00123", (long)-123);
+ CHECK_FORMAT_1("%7.5lld", " -00123", (long long)-123);
+ CHECK_FORMAT_1("%7.5lli", " -00123", (long long)-123);
+ CHECK_FORMAT_1("%7.5zd", " -00123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%7.5zi", " -00123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%10.9x", " 0ffffff85", (int)-123);
+
// Integers: width > precision > length, 0-flag
CHECK_FORMAT_1("%07.5d", "0000123", (int)123);
CHECK_FORMAT_1("%07.5i", "0000123", (int)123);
@@ -503,6 +533,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%07.5zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%07.5x", "000007b", (int)123);
+ CHECK_FORMAT_1("%07.5d", "-000123", (int)-123);
+ CHECK_FORMAT_1("%07.5i", "-000123", (int)-123);
+ CHECK_FORMAT_1("%07.5ld", "-000123", (long)-123);
+ CHECK_FORMAT_1("%07.5li", "-000123", (long)-123);
+ CHECK_FORMAT_1("%07.5lld", "-000123", (long long)-123);
+ CHECK_FORMAT_1("%07.5lli", "-000123", (long long)-123);
+ CHECK_FORMAT_1("%07.5zd", "-000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%07.5zi", "-000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%010.9x", "00ffffff85", (int)-123);
+
// Integers: precision > width > length
CHECK_FORMAT_1("%5.7d", "0000123", (int)123);
CHECK_FORMAT_1("%5.7i", "0000123", (int)123);
@@ -518,6 +558,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%5.7zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%5.7x", "000007b", (int)123);
+ CHECK_FORMAT_1("%5.7d", "-0000123", (int)-123);
+ CHECK_FORMAT_1("%5.7i", "-0000123", (int)-123);
+ CHECK_FORMAT_1("%5.7ld", "-0000123", (long)-123);
+ CHECK_FORMAT_1("%5.7li", "-0000123", (long)-123);
+ CHECK_FORMAT_1("%5.7lld", "-0000123", (long long)-123);
+ CHECK_FORMAT_1("%5.7lli", "-0000123", (long long)-123);
+ CHECK_FORMAT_1("%5.7zd", "-0000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%5.7zi", "-0000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%9.10x", "00ffffff85", (int)-123);
+
// Integers: precision > width > length, 0-flag
CHECK_FORMAT_1("%05.7d", "0000123", (int)123);
CHECK_FORMAT_1("%05.7i", "0000123", (int)123);
@@ -533,6 +583,16 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%05.7zu", "0000123", (size_t)123);
CHECK_FORMAT_1("%05.7x", "000007b", (int)123);
+ CHECK_FORMAT_1("%05.7d", "-0000123", (int)-123);
+ CHECK_FORMAT_1("%05.7i", "-0000123", (int)-123);
+ CHECK_FORMAT_1("%05.7ld", "-0000123", (long)-123);
+ CHECK_FORMAT_1("%05.7li", "-0000123", (long)-123);
+ CHECK_FORMAT_1("%05.7lld", "-0000123", (long long)-123);
+ CHECK_FORMAT_1("%05.7lli", "-0000123", (long long)-123);
+ CHECK_FORMAT_1("%05.7zd", "-0000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%05.7zi", "-0000123", (Py_ssize_t)-123);
+ CHECK_FORMAT_1("%09.10x", "00ffffff85", (int)-123);
+
// Integers: precision = 0, arg = 0 (empty string in C)
CHECK_FORMAT_1("%.0d", "0", (int)0);
CHECK_FORMAT_1("%.0i", "0", (int)0);
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 184a2bf..b1d14a3 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -2481,21 +2481,34 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
}
assert(len >= 0);
- if (precision < len)
- precision = len;
+ int negative = (buffer[0] == '-');
+ len -= negative;
+
+ precision = Py_MAX(precision, len);
+ width = Py_MAX(width, precision + negative);
arglen = Py_MAX(precision, width);
if (_PyUnicodeWriter_Prepare(writer, arglen, 127) == -1)
return NULL;
if (width > precision) {
- Py_UCS4 fillchar;
- fill = width - precision;
- fillchar = zeropad?'0':' ';
+ if (negative && zeropad) {
+ if (_PyUnicodeWriter_WriteChar(writer, '-') == -1)
+ return NULL;
+ }
+
+ Py_UCS4 fillchar = zeropad?'0':' ';
+ fill = width - precision - negative;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, fillchar) == -1)
return NULL;
writer->pos += fill;
+
+ if (negative && !zeropad) {
+ if (_PyUnicodeWriter_WriteChar(writer, '-') == -1)
+ return NULL;
+ }
}
+
if (precision > len) {
fill = precision - len;
if (PyUnicode_Fill(writer->buffer, writer->pos, fill, '0') == -1)
@@ -2503,7 +2516,7 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer,
writer->pos += fill;
}
- if (_PyUnicodeWriter_WriteASCIIString(writer, buffer, len) < 0)
+ if (_PyUnicodeWriter_WriteASCIIString(writer, &buffer[negative], len) < 0)
return NULL;
break;
}