diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2023-05-21 21:32:39 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-21 21:32:39 (GMT) |
commit | f3466bc04008660c4a5c3ed6f70144f138ae2e7f (patch) | |
tree | 3aada373c1a064f47e8273f30439c5fcea1d7e3a /Modules | |
parent | 6ba8406cb6e656e47e908f8c7354e07ed0f2d774 (diff) | |
download | cpython-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.c | 5 | ||||
-rw-r--r-- | Modules/_testcapi/unicode.c | 63 | ||||
-rw-r--r-- | Modules/selectmodule.c | 5 | ||||
-rw-r--r-- | Modules/socketmodule.c | 8 |
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 |