summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2023-05-21 21:32:39 (GMT)
committerGitHub <noreply@github.com>2023-05-21 21:32:39 (GMT)
commitf3466bc04008660c4a5c3ed6f70144f138ae2e7f (patch)
tree3aada373c1a064f47e8273f30439c5fcea1d7e3a /Modules
parent6ba8406cb6e656e47e908f8c7354e07ed0f2d774 (diff)
downloadcpython-f3466bc04008660c4a5c3ed6f70144f138ae2e7f.zip
cpython-f3466bc04008660c4a5c3ed6f70144f138ae2e7f.tar.gz
cpython-f3466bc04008660c4a5c3ed6f70144f138ae2e7f.tar.bz2
gh-98836: Extend PyUnicode_FromFormat() (GH-98838)
* Support for conversion specifiers o (octal) and X (uppercase hexadecimal). * Support for length modifiers j (intmax_t) and t (ptrdiff_t). * Length modifiers are now applied to all integer conversions. * Support for wchar_t C strings (%ls and %lV). * Support for variable width and precision (*). * Support for flag - (left alignment).
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ssl.c5
-rw-r--r--Modules/_testcapi/unicode.c63
-rw-r--r--Modules/selectmodule.c5
-rw-r--r--Modules/socketmodule.c8
4 files changed, 52 insertions, 29 deletions
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 016a5a5..5bf6b3b 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -1330,10 +1330,8 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) {
p[0], p[1], p[2], p[3]
);
} else if (name->d.ip->length == 16) {
- /* PyUnicode_FromFormat() does not support %X */
unsigned char *p = name->d.ip->data;
- len = sprintf(
- buf,
+ v = PyUnicode_FromFormat(
"%X:%X:%X:%X:%X:%X:%X:%X",
p[0] << 8 | p[1],
p[2] << 8 | p[3],
@@ -1344,7 +1342,6 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) {
p[12] << 8 | p[13],
p[14] << 8 | p[15]
);
- v = PyUnicode_FromStringAndSize(buf, len);
} else {
v = PyUnicode_FromString("<invalid>");
}
diff --git a/Modules/_testcapi/unicode.c b/Modules/_testcapi/unicode.c
index 7dd3b9c..73929ea 100644
--- a/Modules/_testcapi/unicode.c
+++ b/Modules/_testcapi/unicode.c
@@ -1,3 +1,5 @@
+#include <stddef.h> // ptrdiff_t
+
#define PY_SSIZE_T_CLEAN
#include "parts.h"
@@ -1130,25 +1132,48 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1( "%c", "c", 'c');
CHECK_FORMAT_1( "%0c", "c", 'c');
CHECK_FORMAT_1("%00c", "c", 'c');
- CHECK_FORMAT_1( "%2c", "c", 'c');
- CHECK_FORMAT_1("%02c", "c", 'c');
- CHECK_FORMAT_1("%.0c", "c", 'c');
- CHECK_FORMAT_1("%.2c", "c", 'c');
+ CHECK_FORMAT_1( "%2c", NULL, 'c');
+ CHECK_FORMAT_1("%02c", NULL, 'c');
+ CHECK_FORMAT_1("%.0c", NULL, 'c');
+ CHECK_FORMAT_1("%.2c", NULL, 'c');
// Integers
CHECK_FORMAT_1("%d", "123", (int)123);
CHECK_FORMAT_1("%i", "123", (int)123);
CHECK_FORMAT_1("%u", "123", (unsigned int)123);
+ CHECK_FORMAT_1("%x", "7b", (unsigned int)123);
+ CHECK_FORMAT_1("%X", "7B", (unsigned int)123);
+ CHECK_FORMAT_1("%o", "173", (unsigned int)123);
CHECK_FORMAT_1("%ld", "123", (long)123);
CHECK_FORMAT_1("%li", "123", (long)123);
CHECK_FORMAT_1("%lu", "123", (unsigned long)123);
+ CHECK_FORMAT_1("%lx", "7b", (unsigned long)123);
+ CHECK_FORMAT_1("%lX", "7B", (unsigned long)123);
+ CHECK_FORMAT_1("%lo", "173", (unsigned long)123);
CHECK_FORMAT_1("%lld", "123", (long long)123);
CHECK_FORMAT_1("%lli", "123", (long long)123);
CHECK_FORMAT_1("%llu", "123", (unsigned long long)123);
+ CHECK_FORMAT_1("%llx", "7b", (unsigned long long)123);
+ CHECK_FORMAT_1("%llX", "7B", (unsigned long long)123);
+ CHECK_FORMAT_1("%llo", "173", (unsigned long long)123);
CHECK_FORMAT_1("%zd", "123", (Py_ssize_t)123);
CHECK_FORMAT_1("%zi", "123", (Py_ssize_t)123);
CHECK_FORMAT_1("%zu", "123", (size_t)123);
- CHECK_FORMAT_1("%x", "7b", (int)123);
+ CHECK_FORMAT_1("%zx", "7b", (size_t)123);
+ CHECK_FORMAT_1("%zX", "7B", (size_t)123);
+ CHECK_FORMAT_1("%zo", "173", (size_t)123);
+ CHECK_FORMAT_1("%td", "123", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%ti", "123", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%tu", "123", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%tx", "7b", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%tX", "7B", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%to", "173", (ptrdiff_t)123);
+ CHECK_FORMAT_1("%jd", "123", (intmax_t)123);
+ CHECK_FORMAT_1("%ji", "123", (intmax_t)123);
+ CHECK_FORMAT_1("%ju", "123", (uintmax_t)123);
+ CHECK_FORMAT_1("%jx", "7b", (uintmax_t)123);
+ CHECK_FORMAT_1("%jX", "7B", (uintmax_t)123);
+ CHECK_FORMAT_1("%jo", "173", (uintmax_t)123);
CHECK_FORMAT_1("%d", "-123", (int)-123);
CHECK_FORMAT_1("%i", "-123", (int)-123);
@@ -1158,7 +1183,10 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%lli", "-123", (long long)-123);
CHECK_FORMAT_1("%zd", "-123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%zi", "-123", (Py_ssize_t)-123);
- CHECK_FORMAT_1("%x", "ffffff85", (int)-123);
+ CHECK_FORMAT_1("%td", "-123", (ptrdiff_t)-123);
+ CHECK_FORMAT_1("%ti", "-123", (ptrdiff_t)-123);
+ CHECK_FORMAT_1("%jd", "-123", (intmax_t)-123);
+ CHECK_FORMAT_1("%ji", "-123", (intmax_t)-123);
// Integers: width < length
CHECK_FORMAT_1("%1d", "123", (int)123);
@@ -1183,7 +1211,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%1lli", "-123", (long long)-123);
CHECK_FORMAT_1("%1zd", "-123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%1zi", "-123", (Py_ssize_t)-123);
- CHECK_FORMAT_1("%1x", "ffffff85", (int)-123);
// Integers: width > length
CHECK_FORMAT_1("%5d", " 123", (int)123);
@@ -1208,7 +1235,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%5lli", " -123", (long long)-123);
CHECK_FORMAT_1("%5zd", " -123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%5zi", " -123", (Py_ssize_t)-123);
- CHECK_FORMAT_1("%9x", " ffffff85", (int)-123);
// Integers: width > length, 0-flag
CHECK_FORMAT_1("%05d", "00123", (int)123);
@@ -1233,7 +1259,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1258,7 +1283,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
CHECK_FORMAT_1("%.1lli", "-123", (long long)-123);
CHECK_FORMAT_1("%.1zd", "-123", (Py_ssize_t)-123);
CHECK_FORMAT_1("%.1zi", "-123", (Py_ssize_t)-123);
- CHECK_FORMAT_1("%.1x", "ffffff85", (int)-123);
// Integers: precision > length
CHECK_FORMAT_1("%.5d", "00123", (int)123);
@@ -1283,7 +1307,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1308,7 +1331,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1333,7 +1355,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1358,7 +1379,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1383,7 +1403,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
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);
@@ -1402,66 +1421,80 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
// Strings
CHECK_FORMAT_1("%s", "None", "None");
+ CHECK_FORMAT_1("%ls", "None", L"None");
CHECK_FORMAT_1("%U", "None", unicode);
CHECK_FORMAT_1("%A", "None", Py_None);
CHECK_FORMAT_1("%S", "None", Py_None);
CHECK_FORMAT_1("%R", "None", Py_None);
CHECK_FORMAT_2("%V", "None", unicode, "ignored");
CHECK_FORMAT_2("%V", "None", NULL, "None");
+ CHECK_FORMAT_2("%lV", "None", NULL, L"None");
// Strings: width < length
CHECK_FORMAT_1("%1s", "None", "None");
+ CHECK_FORMAT_1("%1ls", "None", L"None");
CHECK_FORMAT_1("%1U", "None", unicode);
CHECK_FORMAT_1("%1A", "None", Py_None);
CHECK_FORMAT_1("%1S", "None", Py_None);
CHECK_FORMAT_1("%1R", "None", Py_None);
CHECK_FORMAT_2("%1V", "None", unicode, "ignored");
CHECK_FORMAT_2("%1V", "None", NULL, "None");
+ CHECK_FORMAT_2("%1lV", "None", NULL, L"None");
// Strings: width > length
CHECK_FORMAT_1("%5s", " None", "None");
+ CHECK_FORMAT_1("%5ls", " None", L"None");
CHECK_FORMAT_1("%5U", " None", unicode);
CHECK_FORMAT_1("%5A", " None", Py_None);
CHECK_FORMAT_1("%5S", " None", Py_None);
CHECK_FORMAT_1("%5R", " None", Py_None);
CHECK_FORMAT_2("%5V", " None", unicode, "ignored");
CHECK_FORMAT_2("%5V", " None", NULL, "None");
+ CHECK_FORMAT_2("%5lV", " None", NULL, L"None");
// Strings: precision < length
CHECK_FORMAT_1("%.1s", "N", "None");
+ CHECK_FORMAT_1("%.1ls", "N", L"None");
CHECK_FORMAT_1("%.1U", "N", unicode);
CHECK_FORMAT_1("%.1A", "N", Py_None);
CHECK_FORMAT_1("%.1S", "N", Py_None);
CHECK_FORMAT_1("%.1R", "N", Py_None);
CHECK_FORMAT_2("%.1V", "N", unicode, "ignored");
CHECK_FORMAT_2("%.1V", "N", NULL, "None");
+ CHECK_FORMAT_2("%.1lV", "N", NULL, L"None");
// Strings: precision > length
CHECK_FORMAT_1("%.5s", "None", "None");
+ CHECK_FORMAT_1("%.5ls", "None", L"None");
CHECK_FORMAT_1("%.5U", "None", unicode);
CHECK_FORMAT_1("%.5A", "None", Py_None);
CHECK_FORMAT_1("%.5S", "None", Py_None);
CHECK_FORMAT_1("%.5R", "None", Py_None);
CHECK_FORMAT_2("%.5V", "None", unicode, "ignored");
CHECK_FORMAT_2("%.5V", "None", NULL, "None");
+ CHECK_FORMAT_2("%.5lV", "None", NULL, L"None");
// Strings: precision < length, width > length
CHECK_FORMAT_1("%5.1s", " N", "None");
+ CHECK_FORMAT_1("%5.1ls"," N", L"None");
CHECK_FORMAT_1("%5.1U", " N", unicode);
CHECK_FORMAT_1("%5.1A", " N", Py_None);
CHECK_FORMAT_1("%5.1S", " N", Py_None);
CHECK_FORMAT_1("%5.1R", " N", Py_None);
CHECK_FORMAT_2("%5.1V", " N", unicode, "ignored");
CHECK_FORMAT_2("%5.1V", " N", NULL, "None");
+ CHECK_FORMAT_2("%5.1lV"," N", NULL, L"None");
// Strings: width < length, precision > length
CHECK_FORMAT_1("%1.5s", "None", "None");
+ CHECK_FORMAT_1("%1.5ls", "None", L"None");
CHECK_FORMAT_1("%1.5U", "None", unicode);
CHECK_FORMAT_1("%1.5A", "None", Py_None);
CHECK_FORMAT_1("%1.5S", "None", Py_None);
CHECK_FORMAT_1("%1.5R", "None", Py_None);
CHECK_FORMAT_2("%1.5V", "None", unicode, "ignored");
CHECK_FORMAT_2("%1.5V", "None", NULL, "None");
+ CHECK_FORMAT_2("%1.5lV", "None", NULL, L"None");
Py_XDECREF(unicode);
Py_RETURN_NONE;
diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c
index 79bd5b5..9a4943c 100644
--- a/Modules/selectmodule.c
+++ b/Modules/selectmodule.c
@@ -1849,14 +1849,11 @@ static PyObject *
kqueue_event_repr(kqueue_event_Object *s)
{
- char buf[1024];
- PyOS_snprintf(
- buf, sizeof(buf),
+ return PyUnicode_FromFormat(
"<select.kevent ident=%zu filter=%d flags=0x%x fflags=0x%x "
"data=0x%llx udata=%p>",
(size_t)(s->e.ident), (int)s->e.filter, (unsigned int)s->e.flags,
(unsigned int)s->e.fflags, (long long)(s->e.data), (void *)s->e.udata);
- return PyUnicode_FromString(buf);
}
static int
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index c11fb44..a86aaed 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1339,8 +1339,6 @@ setbdaddr(const char *name, bdaddr_t *bdaddr)
static PyObject *
makebdaddr(bdaddr_t *bdaddr)
{
- char buf[(6 * 2) + 5 + 1];
-
#ifdef MS_WINDOWS
int i;
unsigned int octets[6];
@@ -1349,16 +1347,14 @@ makebdaddr(bdaddr_t *bdaddr)
octets[i] = ((*bdaddr) >> (8 * i)) & 0xFF;
}
- sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+ return PyUnicode_FromFormat("%02X:%02X:%02X:%02X:%02X:%02X",
octets[5], octets[4], octets[3],
octets[2], octets[1], octets[0]);
#else
- sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
+ return PyUnicode_FromFormat("%02X:%02X:%02X:%02X:%02X:%02X",
bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
#endif
-
- return PyUnicode_FromString(buf);
}
#endif