From be87bfa8a1a68516cedc618c7cf5bb7b0b251678 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Aug 2026 14:42:46 +0300 Subject: [PATCH 1/4] gh-156234: Fix and rewrite the curses documentation on reading (GH-156235) Fix wrong types: instr() and getstr() return a bytes object, not a str, and their n limits the number of bytes; getkey() returns a str; unctrl() returns a bytes object. Make clear whether an integer standing for a character is an encoded byte or a character code. Rewrite the documentation of getch(), get_wch(), getkey(), getstr(), get_wstr(), instr(), in_wstr() and in_wchstr(), following X/Open Curses. --- Doc/library/curses.rst | 158 +++++++++++++++++++++---------- Modules/_cursesmodule.c | 107 ++++++++++++--------- Modules/clinic/_cursesmodule.c.h | 91 +++++++++++------- 3 files changed, 226 insertions(+), 130 deletions(-) diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index c1afdb71c89e888..d6bccbb730f8b4a 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -27,9 +27,15 @@ Linux and the BSD variants of Unix. Whenever the documentation mentions a *character* it can be specified as an integer, a one-character Unicode string or a one-byte byte string. + An integer is the code of a single encoded byte, optionally combined with + attributes and a color pair, as returned by :meth:`window.inch`. + Methods that write to a window accept also a character cell: a Unicode + string of a spacing character followed by combining characters, or a + :class:`complexchar`. Whenever the documentation mentions a *character string* it can be specified as a Unicode string or a byte string. + Methods that write to a window accept also a :class:`complexstr`. .. note:: @@ -364,9 +370,9 @@ Keyboard input Push *ch* so the next :meth:`~window.getch` or :meth:`~window.get_wch` will return it. - *ch* may be an integer (a key code or character code), a byte, or a string of - length 1. A one-character string is pushed like :func:`unget_wch`; on a - narrow build it must encode to a single byte. + *ch* may be an integer (a key code or the code of an encoded byte), a byte, + or a string of length 1. A one-character string is pushed like + :func:`unget_wch`; on a narrow build it must encode to a single byte. .. note:: @@ -380,6 +386,9 @@ Keyboard input Push *ch* so the next :meth:`~window.get_wch` will return it. + *ch* may be an integer (a character code, not a key code) or a string of + length 1. + .. note:: Only one *ch* can be pushed before :meth:`!get_wch` is called. @@ -1015,7 +1024,7 @@ Terminfo database .. function:: tparm(str[, ...]) Instantiate the bytes object *str* with the supplied parameters, where *str* should - be a parameterized string obtained from the terminfo database. For example, + be a parameterized byte string obtained from the terminfo database. For example, ``tparm(tigetstr("cup"), 5, 3)`` could result in ``b'\033[6;4H'``, the exact result depending on terminal type. Up to nine integer parameters may be supplied. @@ -1024,8 +1033,8 @@ Terminfo database .. function:: putp(str) Equivalent to ``tputs(str, 1, putchar)``; emit the value of a specified - terminfo capability for the current terminal. Note that the output of :func:`putp` - always goes to standard output. + terminfo capability, a bytes object, for the current terminal. + Note that the output of :func:`putp` always goes to standard output. :func:`setupterm` (or :func:`initscr`) must be called first. @@ -1035,9 +1044,15 @@ Utilities .. function:: unctrl(ch) - Return a bytes object which is a printable representation of the character *ch*. - *ch* cannot be a character that does not fit in a single byte; use - :func:`wunctrl` for those. + Return a bytes object which is a printable representation of the character *ch*; + any attributes and color pair are ignored. + Control characters are represented as a caret followed by a character, + for example as ``b'^C'``. + Printing characters are left as they are. + The representation of other characters is defined by the underlying curses + library. + + *ch* must fit in a single byte; use :func:`wunctrl` for other characters. .. function:: wunctrl(ch) @@ -1264,19 +1279,47 @@ Reading input .. method:: window.getch([y, x]) - Get a character. Note that the integer returned does *not* have to be in ASCII - range: function keys, keypad keys and so on are represented by numbers higher - than 255. In no-delay mode, return ``-1`` if there is no input, otherwise - wait until a key is pressed. - A multibyte character is returned as its encoded bytes one at a time; use - :meth:`get_wch` to read it as a single character. + Read a key press, after moving the cursor to *y*, *x* if specified, + and return it as an integer. + The window is refreshed first if it is not a pad and was modified since + the last refresh. + Wait until a key is pressed, or return ``-1`` if the read is non-blocking + or times out (see :meth:`nodelay` and :meth:`timeout`). + + An ordinary key is returned as the code of a single byte of its encoding + in the current locale, + so a character encoded with several bytes takes several calls. + For example, in a UTF-8 locale ``'é'`` is read as ``195``, then ``169``. + Use :meth:`get_wch` to read it as a single character. + + In keypad mode (see :meth:`keypad`) function keys and other special keys + are returned as one of the :ref:`KEY_* constants `, + which cannot be mistaken for an ordinary key. + Otherwise, or if their escape sequence does not arrive in time + (see :meth:`notimeout` and :func:`set_escdelay`), + their bytes are returned one at a time. + + In echo mode (see :func:`echo`) the key is added to the window as by + :meth:`addch`; special keys are not echoed. .. method:: window.get_wch([y, x]) - Get a wide character. Return a character for most keys, or an integer for - function keys, keypad keys, and other special keys. Unlike :meth:`getch`, an - ordinary key is returned as a one-character :class:`str`. - In no-delay mode, raise an exception if there is no input. + Read a key press, after moving the cursor to *y*, *x* if specified, + and return it as a one-character :class:`str`. + The window is refreshed first if it is not a pad and was modified since + the last refresh. + Wait until a key is pressed, or raise :exc:`error` if the read is + non-blocking or times out (see :meth:`nodelay` and :meth:`timeout`). + + In keypad mode (see :meth:`keypad`) function keys and other special keys + are returned as one of the :ref:`KEY_* constants `, + an integer. + Otherwise, or if their escape sequence does not arrive in time + (see :meth:`notimeout` and :func:`set_escdelay`), + their characters are returned one at a time. + + In echo mode (see :func:`echo`) the key is added to the window as by + :meth:`addch`; special keys are not echoed. .. versionadded:: 3.3 @@ -1286,21 +1329,24 @@ Reading input .. method:: window.getkey([y, x]) - Get a character, returning a string instead of an integer, as :meth:`getch` - does. Function keys, keypad keys and other special keys return a multibyte - string containing the key name. In no-delay mode, raise an exception if - there is no input. + Read a key press as :meth:`getch` does, but return it as a :class:`str`: + an ordinary key as a one-character string, the byte decoded as Latin-1, + and a special key as its name, such as ``'KEY_UP'`` (see :func:`keyname`). + Raise :exc:`error` instead of returning ``-1`` if there is no input. .. method:: window.getstr() window.getstr(n) window.getstr(y, x) window.getstr(y, x, n) - Read a bytes object from the user, with primitive line editing capacity. - At most *n* characters are read; + Read a line of input from the user, with primitive line editing capacity, + after moving the cursor to *y*, *x* if specified. + Return it as a bytes object, in the encoding of the current locale + and without the terminating newline. + At most *n* bytes are read; *n* defaults to and cannot exceed 2047. - A multibyte character is returned as its encoded bytes; use :meth:`get_wstr` - to read the input as a :class:`str`. + + Use :meth:`get_wstr` to read the input as a :class:`str`. .. versionchanged:: 3.14 The maximum value for *n* was increased from 1023 to 2047. @@ -1310,10 +1356,13 @@ Reading input window.get_wstr(y, x) window.get_wstr(y, x, n) - Read a string from the user, with primitive line editing capacity. - Unlike :meth:`getstr`, it can return characters that are not representable in - the window's encoding. - At most *n* characters are read; *n* defaults to and cannot exceed 2047. + Read a line of input from the user, with primitive line editing capacity, + after moving the cursor to *y*, *x* if specified. + Return it as a :class:`str`, without the terminating newline. + At most *n* characters are read; + *n* defaults to and cannot exceed 2047. + + This is the wide-character variant of :meth:`getstr`. .. versionadded:: next @@ -1354,13 +1403,13 @@ Reading window contents .. method:: window.instr([n]) window.instr(y, x[, n]) - Return a bytes object of characters, extracted from the window starting at the - current cursor position, or at *y*, *x* if specified, and stopping at the end - of the line. Attributes and color information are stripped - from the characters. If *n* is specified, :meth:`instr` returns a string - at most *n* characters long (exclusive of the trailing NUL). - The maximum value for *n* is 2047. - A character not representable in the window's encoding cannot be returned; + Read the text of the window from the current cursor position, + or from *y*, *x* if specified, to the end of the line, + and return it as a bytes object, in the encoding of the current locale. + Attributes and color pairs are stripped; + use :meth:`in_wchstr` to read them too. + At most *n* bytes are read; *n* defaults to and cannot exceed 2047. + A character not representable in the encoding cannot be returned; use :meth:`in_wstr` for those. .. versionchanged:: 3.14 @@ -1369,26 +1418,27 @@ Reading window contents .. method:: window.in_wstr([n]) window.in_wstr(y, x[, n]) - Return a string of characters, extracted from the window starting at the - current cursor position, or at *y*, *x* if specified. Unlike :meth:`instr`, - it can return characters that are not representable in the window's encoding. - Attributes and color information are stripped from the characters. The - maximum value for *n* is 2047. + Read the text of the window from the current cursor position, + or from *y*, *x* if specified, to the end of the line, + and return it as a :class:`str`. + Attributes and color pairs are stripped; + use :meth:`in_wchstr` to read them too. + At most *n* characters are read; *n* defaults to and cannot exceed 2047. + + This is the wide-character variant of :meth:`instr`. .. versionadded:: next .. method:: window.in_wchstr([n]) window.in_wchstr(y, x[, n]) - Return a :class:`complexstr` of the styled cells extracted from the window - starting at the current cursor position, or at *y*, *x* if specified, and - stopping at the end of the line. This is the variant of :meth:`instr` and - :meth:`in_wstr` that *keeps* each cell's attributes and color pair (those - methods strip the rendition). If *n* is specified, at most *n* cells are - returned. The maximum value for *n* is 2047. - - The result can be written back unchanged with :meth:`addstr` (a read and a - re-write is a round-trip that preserves every cell's rendition). + Read the styled cells of the window from the current cursor position, + or from *y*, *x* if specified, to the end of the line, + and return them as a :class:`complexstr`. + Unlike :meth:`instr` and :meth:`in_wstr`, each cell keeps its attributes + and color pair, so the result can be written back unchanged + with :meth:`addstr`. + At most *n* cells are read; *n* defaults to and cannot exceed 2047. .. versionadded:: next @@ -1835,6 +1885,8 @@ Input options If *flag* is ``True``, escape sequences generated by some keys (keypad, function keys) will be interpreted by :mod:`!curses`. If *flag* is ``False``, escape sequences will be left as is in the input stream. + Keypad mode is disabled by default, but :func:`wrapper` enables it for the + main window. .. method:: window.nodelay(flag) @@ -2331,6 +2383,8 @@ by some methods. | .. data:: A_COLOR | | Bit-mask to extract color-pair field information | +-------------------------+--------------------------+--------------------------------------------------+ +.. _curses-key-constants: + Keys ~~~~ diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 7cc72b96d0a46de..82effccb1fe3277 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3342,18 +3342,25 @@ _curses.window.getch ] / -Get a character code from terminal keyboard. +Read a key press and return it as an integer. -The integer returned does not have to be in ASCII range: function -keys, keypad keys and so on return numbers higher than 256. In -no-delay mode, -1 is returned if there is no input, else getch() -waits until a key is pressed. +Wait until a key is pressed, or return -1 if the read is +non-blocking or times out. + +An ordinary key is returned as the code of a single byte of its +encoding in the current locale, so a character encoded with several +bytes takes several calls. Use get_wch() to read it as a single +character. + +In keypad mode function keys and other special keys are returned as +one of the KEY_* constants, which cannot be mistaken for an ordinary +key. Otherwise their bytes are returned one at a time. [clinic start generated code]*/ static PyObject * _curses_window_getch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=e1639e87d545e676 input=0dc5ff40e079787a]*/ +/*[clinic end generated code: output=e1639e87d545e676 input=882ddab9b41afbbd]*/ { int rtn; @@ -3394,18 +3401,18 @@ _curses.window.getkey ] / -Get a character (string) from terminal keyboard. +Read a key press and return it as a str. -Returning a string instead of an integer, as getch() does. Function -keys, keypad keys and other special keys return a multibyte string -containing the key name. In no-delay mode, an exception is raised -if there is no input. +Read as getch() does, but return an ordinary key as a one-character +string, the byte decoded as Latin-1, and a special key as its name, +such as 'KEY_UP'. Raise curses.error instead of returning -1 if +there is no input. [clinic start generated code]*/ static PyObject * _curses_window_getkey_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=8490a182db46b10f input=bd24a7da1ed9c73b]*/ +/*[clinic end generated code: output=8490a182db46b10f input=f054cf034c69e879]*/ { int rtn; @@ -3453,16 +3460,20 @@ _curses.window.get_wch ] / -Get a wide character from terminal keyboard. +Read a key press and return it as a one-character str. -Return a character for most keys, or an integer for function keys, -keypad keys, and other special keys. +Wait until a key is pressed, or raise curses.error if the read is +non-blocking or times out. + +In keypad mode function keys and other special keys are returned as +one of the KEY_* constants, an integer. Otherwise their characters +are returned one at a time. [clinic start generated code]*/ static PyObject * _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, int y, int x) -/*[clinic end generated code: output=9f4f86e91fe50ef3 input=dd7e5367fb49dc48]*/ +/*[clinic end generated code: output=9f4f86e91fe50ef3 input=77eb2da426ebe71f]*/ { if (!curses_window_check_terminal(self)) { return NULL; @@ -3566,16 +3577,20 @@ _curses.window.getstr X-coordinate. ] n: unsigned_int = 2047 - Maximal number of characters. + Maximal number of bytes. / -Read a string from the user, with primitive line editing capacity. +Read a line of input and return it as a bytes object. + +The input is read with primitive line editing capacity, encoded in +the current locale, and does not include the terminating newline. +At most n bytes are read. [clinic start generated code]*/ static PyObject * _curses_window_getstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n) -/*[clinic end generated code: output=bea9b0ab7e8f34d9 input=c0fc273c2277a985]*/ +/*[clinic end generated code: output=bea9b0ab7e8f34d9 input=0335501e45f55caf]*/ { if (!curses_window_check_terminal(self)) { return NULL; @@ -3842,23 +3857,21 @@ _curses.window.instr X-coordinate. ] n: unsigned_int = 2047 - Maximal number of characters. + Maximal number of bytes. / -Return a string of characters, extracted from the window. +Return the text of the window as a bytes object. -Return a string of characters, extracted from the window starting -at the current cursor position, or at y, x if specified, and -stopping at the end of the line. Attributes and color -information are stripped from the characters. If n is specified, -instr() returns a string at most n characters long (exclusive of -the trailing NUL). +Read from the current cursor position, or from y, x if specified, to +the end of the line, and return the text in the encoding of the +current locale, with attributes and color pairs stripped. At most n +bytes are read. [clinic start generated code]*/ static PyObject * _curses_window_instr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n) -/*[clinic end generated code: output=40081f67070132da input=85e62048d2d92642]*/ +/*[clinic end generated code: output=40081f67070132da input=4ece6af75b09346f]*/ { return curses_window_instr_bytes(self, group_left_1, y, x, n); } @@ -3876,15 +3889,17 @@ _curses.window.get_wstr Maximal number of characters. / -Read a string from the user, with primitive line editing capacity. +Read a line of input and return it as a str. -This is the wide-character variant of getstr(); it returns a str. +This is the wide-character variant of getstr(). The input is read +with primitive line editing capacity and does not include the +terminating newline. At most n characters are read. [clinic start generated code]*/ static PyObject * _curses_window_get_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n) -/*[clinic end generated code: output=e0a6670551cbe79f input=874fc230c4e82ca7]*/ +/*[clinic end generated code: output=e0a6670551cbe79f input=8920c99e9134670b]*/ { if (!curses_window_check_terminal(self)) { return NULL; @@ -3960,15 +3975,18 @@ _curses.window.in_wstr Maximal number of characters. / -Return a string of characters, extracted from the window. +Return the text of the window as a str. -This is the wide-character variant of instr(); it returns a str. +This is the wide-character variant of instr(). Read from the +current cursor position, or from y, x if specified, to the end of +the line, with attributes and color pairs stripped. At most n +characters are read. [clinic start generated code]*/ static PyObject * _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n) -/*[clinic end generated code: output=e3db72a1f10b9875 input=196703989dc57361]*/ +/*[clinic end generated code: output=e3db72a1f10b9875 input=436737264c54d8d3]*/ { #ifdef HAVE_NCURSESW int rtn; @@ -4022,17 +4040,18 @@ _curses.window.in_wchstr Maximal number of cells. / -Return a complexstr of the styled cells extracted from the window. +Return the styled cells of the window as a complexstr. -This is the wide-character variant of instr() and in_wstr() that -keeps each cell's attributes and color pair; it returns a -complexstr. +Read from the current cursor position, or from y, x if specified, to +the end of the line. Unlike instr() and in_wstr(), each cell keeps +its attributes and color pair, so the result can be written back +unchanged with addstr(). At most n cells are read. [clinic start generated code]*/ static PyObject * _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, int y, int x, unsigned int n) -/*[clinic end generated code: output=7fb5216f2088835b input=b725c0b8abff62c2]*/ +/*[clinic end generated code: output=7fb5216f2088835b input=8104e661c3cb7fea]*/ { int rtn; unsigned int max_buf_size = 2048; @@ -8270,15 +8289,17 @@ _curses.unctrl ch: object / -Return a string which is a printable representation of the character ch. +Return a bytes object which is a printable representation of ch. -Control characters are displayed as a caret followed by the character, -for example as ^C. Printing characters are left as they are. +Control characters are displayed as a caret followed by the +character, for example as ^C. Printing characters are left as they +are. Any attributes and color pair are ignored. ch must fit in a +single byte; use wunctrl() for other characters. [clinic start generated code]*/ static PyObject * _curses_unctrl(PyObject *module, PyObject *ch) -/*[clinic end generated code: output=8e07fafc430c9434 input=cd1e35e16cd1ace4]*/ +/*[clinic end generated code: output=8e07fafc430c9434 input=eed6686669f5ca21]*/ { chtype ch_; diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index d2f30178b1c33c7..61c324e04c5bdcf 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1328,17 +1328,24 @@ _curses_window_getbkgrnd(PyObject *self, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(_curses_window_getch__doc__, "getch([y, x])\n" -"Get a character code from terminal keyboard.\n" +"Read a key press and return it as an integer.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" " X-coordinate.\n" "\n" -"The integer returned does not have to be in ASCII range: function\n" -"keys, keypad keys and so on return numbers higher than 256. In\n" -"no-delay mode, -1 is returned if there is no input, else getch()\n" -"waits until a key is pressed."); +"Wait until a key is pressed, or return -1 if the read is\n" +"non-blocking or times out.\n" +"\n" +"An ordinary key is returned as the code of a single byte of its\n" +"encoding in the current locale, so a character encoded with several\n" +"bytes takes several calls. Use get_wch() to read it as a single\n" +"character.\n" +"\n" +"In keypad mode function keys and other special keys are returned as\n" +"one of the KEY_* constants, which cannot be mistaken for an ordinary\n" +"key. Otherwise their bytes are returned one at a time."); #define _CURSES_WINDOW_GETCH_METHODDEF \ {"getch", (PyCFunction)_curses_window_getch, METH_VARARGS, _curses_window_getch__doc__}, @@ -1376,17 +1383,17 @@ _curses_window_getch(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_getkey__doc__, "getkey([y, x])\n" -"Get a character (string) from terminal keyboard.\n" +"Read a key press and return it as a str.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" " X-coordinate.\n" "\n" -"Returning a string instead of an integer, as getch() does. Function\n" -"keys, keypad keys and other special keys return a multibyte string\n" -"containing the key name. In no-delay mode, an exception is raised\n" -"if there is no input."); +"Read as getch() does, but return an ordinary key as a one-character\n" +"string, the byte decoded as Latin-1, and a special key as its name,\n" +"such as \'KEY_UP\'. Raise curses.error instead of returning -1 if\n" +"there is no input."); #define _CURSES_WINDOW_GETKEY_METHODDEF \ {"getkey", (PyCFunction)_curses_window_getkey, METH_VARARGS, _curses_window_getkey__doc__}, @@ -1424,15 +1431,19 @@ _curses_window_getkey(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_get_wch__doc__, "get_wch([y, x])\n" -"Get a wide character from terminal keyboard.\n" +"Read a key press and return it as a one-character str.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" " X-coordinate.\n" "\n" -"Return a character for most keys, or an integer for function keys,\n" -"keypad keys, and other special keys."); +"Wait until a key is pressed, or raise curses.error if the read is\n" +"non-blocking or times out.\n" +"\n" +"In keypad mode function keys and other special keys are returned as\n" +"one of the KEY_* constants, an integer. Otherwise their characters\n" +"are returned one at a time."); #define _CURSES_WINDOW_GET_WCH_METHODDEF \ {"get_wch", (PyCFunction)_curses_window_get_wch, METH_VARARGS, _curses_window_get_wch__doc__}, @@ -1470,14 +1481,18 @@ _curses_window_get_wch(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_getstr__doc__, "getstr([y, x,] n=2047)\n" -"Read a string from the user, with primitive line editing capacity.\n" +"Read a line of input and return it as a bytes object.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" " X-coordinate.\n" " n\n" -" Maximal number of characters."); +" Maximal number of bytes.\n" +"\n" +"The input is read with primitive line editing capacity, encoded in\n" +"the current locale, and does not include the terminating newline.\n" +"At most n bytes are read."); #define _CURSES_WINDOW_GETSTR_METHODDEF \ {"getstr", (PyCFunction)_curses_window_getstr, METH_VARARGS, _curses_window_getstr__doc__}, @@ -1707,21 +1722,19 @@ _curses_window_inch(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_instr__doc__, "instr([y, x,] n=2047)\n" -"Return a string of characters, extracted from the window.\n" +"Return the text of the window as a bytes object.\n" "\n" " y\n" " Y-coordinate.\n" " x\n" " X-coordinate.\n" " n\n" -" Maximal number of characters.\n" +" Maximal number of bytes.\n" "\n" -"Return a string of characters, extracted from the window starting\n" -"at the current cursor position, or at y, x if specified, and\n" -"stopping at the end of the line. Attributes and color\n" -"information are stripped from the characters. If n is specified,\n" -"instr() returns a string at most n characters long (exclusive of\n" -"the trailing NUL)."); +"Read from the current cursor position, or from y, x if specified, to\n" +"the end of the line, and return the text in the encoding of the\n" +"current locale, with attributes and color pairs stripped. At most n\n" +"bytes are read."); #define _CURSES_WINDOW_INSTR_METHODDEF \ {"instr", (PyCFunction)_curses_window_instr, METH_VARARGS, _curses_window_instr__doc__}, @@ -1765,7 +1778,7 @@ _curses_window_instr(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_get_wstr__doc__, "get_wstr([y, x,] n=2047)\n" -"Read a string from the user, with primitive line editing capacity.\n" +"Read a line of input and return it as a str.\n" "\n" " y\n" " Y-coordinate.\n" @@ -1774,7 +1787,9 @@ PyDoc_STRVAR(_curses_window_get_wstr__doc__, " n\n" " Maximal number of characters.\n" "\n" -"This is the wide-character variant of getstr(); it returns a str."); +"This is the wide-character variant of getstr(). The input is read\n" +"with primitive line editing capacity and does not include the\n" +"terminating newline. At most n characters are read."); #define _CURSES_WINDOW_GET_WSTR_METHODDEF \ {"get_wstr", (PyCFunction)_curses_window_get_wstr, METH_VARARGS, _curses_window_get_wstr__doc__}, @@ -1818,7 +1833,7 @@ _curses_window_get_wstr(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_in_wstr__doc__, "in_wstr([y, x,] n=2047)\n" -"Return a string of characters, extracted from the window.\n" +"Return the text of the window as a str.\n" "\n" " y\n" " Y-coordinate.\n" @@ -1827,7 +1842,10 @@ PyDoc_STRVAR(_curses_window_in_wstr__doc__, " n\n" " Maximal number of characters.\n" "\n" -"This is the wide-character variant of instr(); it returns a str."); +"This is the wide-character variant of instr(). Read from the\n" +"current cursor position, or from y, x if specified, to the end of\n" +"the line, with attributes and color pairs stripped. At most n\n" +"characters are read."); #define _CURSES_WINDOW_IN_WSTR_METHODDEF \ {"in_wstr", (PyCFunction)_curses_window_in_wstr, METH_VARARGS, _curses_window_in_wstr__doc__}, @@ -1871,7 +1889,7 @@ _curses_window_in_wstr(PyObject *self, PyObject *args) PyDoc_STRVAR(_curses_window_in_wchstr__doc__, "in_wchstr([y, x,] n=2047)\n" -"Return a complexstr of the styled cells extracted from the window.\n" +"Return the styled cells of the window as a complexstr.\n" "\n" " y\n" " Y-coordinate.\n" @@ -1880,9 +1898,10 @@ PyDoc_STRVAR(_curses_window_in_wchstr__doc__, " n\n" " Maximal number of cells.\n" "\n" -"This is the wide-character variant of instr() and in_wstr() that\n" -"keeps each cell\'s attributes and color pair; it returns a\n" -"complexstr."); +"Read from the current cursor position, or from y, x if specified, to\n" +"the end of the line. Unlike instr() and in_wstr(), each cell keeps\n" +"its attributes and color pair, so the result can be written back\n" +"unchanged with addstr(). At most n cells are read."); #define _CURSES_WINDOW_IN_WCHSTR_METHODDEF \ {"in_wchstr", (PyCFunction)_curses_window_in_wchstr, METH_VARARGS, _curses_window_in_wchstr__doc__}, @@ -5754,10 +5773,12 @@ PyDoc_STRVAR(_curses_unctrl__doc__, "unctrl($module, ch, /)\n" "--\n" "\n" -"Return a string which is a printable representation of the character ch.\n" +"Return a bytes object which is a printable representation of ch.\n" "\n" -"Control characters are displayed as a caret followed by the character,\n" -"for example as ^C. Printing characters are left as they are."); +"Control characters are displayed as a caret followed by the\n" +"character, for example as ^C. Printing characters are left as they\n" +"are. Any attributes and color pair are ignored. ch must fit in a\n" +"single byte; use wunctrl() for other characters."); #define _CURSES_UNCTRL_METHODDEF \ {"unctrl", (PyCFunction)_curses_unctrl, METH_O, _curses_unctrl__doc__}, @@ -6582,4 +6603,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=4e98ddbfb69f2c04 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=5616d0371c2240be input=a9049054013a1b77]*/ From 43a1869f7eea006f04647d4225d5fda80cb3fbd9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Aug 2026 15:31:51 +0300 Subject: [PATCH 2/4] gh-154855: Ask non-ncurses curses for one more character (GH-154870) Passing n to the library is ncurses' reading of n: it stores n characters and adds a terminator. NetBSD curses counts the terminator in n. Ask a library that is neither ncurses nor PDCurses for n + 1, and read again if it stored more than asked; truncating could split a multibyte character. This is not possible for input, so getstr() and get_wstr() are left as they are. instr() now takes the length from the value returned by winnstr(), as X/Open specifies, instead of searching for a terminator which it does not. --- ...-07-29-14-20-40.gh-issue-154855.vfF453.rst | 4 ++ Modules/_cursesmodule.c | 55 ++++++++++++++----- 2 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-29-14-20-40.gh-issue-154855.vfF453.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-29-14-20-40.gh-issue-154855.vfF453.rst b/Misc/NEWS.d/next/Library/2026-07-29-14-20-40.gh-issue-154855.vfF453.rst new file mode 100644 index 000000000000000..c92cfaa4a72953b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-29-14-20-40.gh-issue-154855.vfF453.rst @@ -0,0 +1,4 @@ +Fix :meth:`curses.window.instr`, :meth:`~curses.window.in_wstr` and +:meth:`~curses.window.in_wchstr` returning one character too few when the +:mod:`curses` module is built against a curses library that counts the +terminator in the requested length, such as the NetBSD one. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 82effccb1fe3277..45ba6476bbc4a60 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -309,6 +309,14 @@ curses_window_set_null_error(PyCursesWindowObject *win, _curses_set_null_error(state, curses_funcname, python_funcname); } +/* ncurses and PDCurses store n characters and add a terminator; NetBSD + curses counts the terminator in n. Ask an unknown library for one more. */ +#if defined(NCURSES_VERSION) || defined(PDCURSES) +# define CURSES_STR_EXTRA 0 +#else +# define CURSES_STR_EXTRA 1 +#endif + /* Utility Checking Procedures */ /* @@ -3826,25 +3834,33 @@ curses_window_instr_bytes(PyCursesWindowObject *self, int use_xy, int rtn; unsigned int max_buf_size = 2048; - n = Py_MIN(n, max_buf_size - 1); + n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); + n += CURSES_STR_EXTRA; PyBytesWriter *writer = PyBytesWriter_Create(n + 1); if (writer == NULL) { return NULL; } char *buf = PyBytesWriter_GetData(writer); - if (use_xy) { - rtn = mvwinnstr(self->win, y, x, buf, n); - } - else { - rtn = winnstr(self->win, buf, n); + /* Read again if the library stored more than asked: truncating could + split a multibyte character. */ + for (unsigned int want = n - CURSES_STR_EXTRA; ; n = want) { + if (use_xy) { + rtn = mvwinnstr(self->win, y, x, buf, n); + } + else { + rtn = winnstr(self->win, buf, n); + } + if (rtn == ERR || (unsigned int)rtn <= want) { + break; + } } if (rtn == ERR) { PyBytesWriter_Discard(writer); return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES); } - return PyBytesWriter_FinishWithSize(writer, strlen(buf)); + return PyBytesWriter_FinishWithSize(writer, rtn); } /*[clinic input] @@ -3992,17 +4008,25 @@ _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, int rtn; unsigned int max_buf_size = 2048; - n = Py_MIN(n, max_buf_size - 1); + n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); + n += CURSES_STR_EXTRA; wchar_t *buf = PyMem_New(wchar_t, n + 1); if (buf == NULL) { return PyErr_NoMemory(); } - if (group_left_1) { - rtn = mvwinnwstr(self->win, y, x, buf, n); - } - else { - rtn = winnwstr(self->win, buf, n); + /* Read again if the library stored more than asked: truncating could + separate a combining character from its base. */ + for (unsigned int want = n - CURSES_STR_EXTRA; ; n = want) { + if (group_left_1) { + rtn = mvwinnwstr(self->win, y, x, buf, n); + } + else { + rtn = winnwstr(self->win, buf, n); + } + if (rtn == ERR || (unsigned int)rtn <= want) { + break; + } } if (rtn == ERR) { @@ -4056,7 +4080,8 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, int rtn; unsigned int max_buf_size = 2048; - n = Py_MIN(n, max_buf_size - 1); + n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); + n += CURSES_STR_EXTRA; cursesmodule_state *state = get_cursesmodule_state_by_win(self); /* Zero the cells: reading a cell back through getcchar() relies on the cchar_t text array being NUL-terminated, which some curses libraries @@ -4079,6 +4104,7 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, return PyCursesComplexStr_New(state, NULL, 0); } + n -= CURSES_STR_EXTRA; /* win_wchnstr() stores at most n cells and zero-terminates the array at the actual count; every real cell holds at least a space, so the first empty cell marks the end of the run. */ @@ -4111,6 +4137,7 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, return PyCursesComplexStr_New(state, NULL, 0); } + n -= CURSES_STR_EXTRA; Py_ssize_t count = 0; while (count < (Py_ssize_t)n && buf[count] != 0) { count++; From 2c47c65f2e140ba6a1519252c36f454df38196b9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Aug 2026 19:47:55 +0300 Subject: [PATCH 3/4] gh-156261: Move converters used in several files to Argument Clinic (GH-156262) The pid_t, Py_off_t, HANDLE, DWORD and BOOL converters were defined in 9 files. The Py_off_t type and its converter function are now shared too. DWORD in _winapi is used with bitwise=True to keep accepting negative values. The pid_t converter is now used for the pid parameters in the _remote_debugging module, which were declared as int. Co-authored-by: Claude Opus 5 (1M context) --- Include/internal/pycore_fileutils.h | 10 + Lib/test/test_clinic.py | 5 + ...-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst | 3 + Modules/_io/_iomodule.h | 4 +- Modules/_multiprocessing/multiprocessing.c | 16 - Modules/_posixsubprocess.c | 16 - Modules/_remote_debugging/clinic/module.c.h | 42 +- Modules/_remote_debugging/module.c | 34 +- Modules/_ssl.c | 28 - Modules/_winapi.c | 109 ++- Modules/clinic/_posixsubprocess.c.h | 4 +- Modules/clinic/_ssl.c.h | 5 +- Modules/clinic/_winapi.c.h | 816 ++++++++++++++++-- Modules/clinic/posixmodule.c.h | 33 +- Modules/clinic/resource.c.h | 4 +- Modules/overlapped.c | 10 +- Modules/posixmodule.c | 47 +- Modules/resource.c | 16 - Objects/fileobject.c | 11 + PC/_testconsole.c | 15 - PC/clinic/msvcrtmodule.c.h | 10 +- PC/msvcrtmodule.c | 23 +- PC/winreg.c | 5 +- Tools/clinic/libclinic/converter.py | 3 + Tools/clinic/libclinic/converters.py | 44 + 25 files changed, 957 insertions(+), 356 deletions(-) create mode 100644 Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst diff --git a/Include/internal/pycore_fileutils.h b/Include/internal/pycore_fileutils.h index 2c6d6daa01994ee..83cdc4f3dfdd44a 100644 --- a/Include/internal/pycore_fileutils.h +++ b/Include/internal/pycore_fileutils.h @@ -302,6 +302,16 @@ extern void _Py_skiproot(const wchar_t *path, Py_ssize_t size, Py_ssize_t *drvsi // Export for 'select' shared extension (Argument Clinic code) PyAPI_FUNC(int) _PyLong_FileDescriptor_Converter(PyObject *, void *); +#ifdef MS_WINDOWS +/* Windows uses long long for offsets */ +typedef long long Py_off_t; +#else +typedef off_t Py_off_t; +#endif + +// Export for '_ssl' and 'zlib' shared extensions (Argument Clinic code) +PyAPI_FUNC(int) _Py_Off_t_Converter(PyObject *, void *); + // Export for test_peg_generator PyAPI_FUNC(char*) _Py_UniversalNewlineFgetsWithSize(char *, int, FILE*, PyObject *, size_t*); diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 43a1a52874e0196..d07447d66571e52 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -3561,18 +3561,23 @@ def test_cli_converters(self): """) expected_converters = ( "bool", + "BOOL", "byte", "char", "defining_class", "double", + "DWORD", "fildes", "float", + "HANDLE", "int", "long", "long_long", "object", + "pid_t", "Py_buffer", "Py_complex", + "Py_off_t", "Py_ssize_t", "Py_UNICODE", "PyByteArrayObject", diff --git a/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst new file mode 100644 index 000000000000000..da5e42dfa744297 --- /dev/null +++ b/Misc/NEWS.d/next/Tools-Demos/2026-08-23-18-10-00.gh-issue-156261.Rw8pKd.rst @@ -0,0 +1,3 @@ +Argument Clinic: the ``pid_t``, ``Py_off_t``, ``HANDLE``, ``DWORD`` and +``BOOL`` converters, previously defined in 9 different files, are now +provided by Argument Clinic itself. diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h index 4ae487c8e2adf72..c9bbbf24bd466d7 100644 --- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -4,6 +4,7 @@ #include "exports.h" +#include "pycore_fileutils.h" // Py_off_t #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_typeobject.h" // _PyType_GetModuleState() #include "structmember.h" @@ -94,8 +95,6 @@ extern int _PyIO_trap_eintr(void); #ifdef MS_WINDOWS -/* Windows uses long long for offsets */ -typedef long long Py_off_t; # define PyLong_AsOff_t PyLong_AsLongLong # define PyLong_FromOff_t PyLong_FromLongLong # define PY_OFF_T_MAX LLONG_MAX @@ -106,7 +105,6 @@ typedef long long Py_off_t; #else /* Other platforms use off_t */ -typedef off_t Py_off_t; #if (SIZEOF_OFF_T == SIZEOF_SIZE_T) # define PyLong_AsOff_t PyLong_AsSsize_t # define PyLong_FromOff_t PyLong_FromSsize_t diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c index 201cedbb59818f2..6ca1bbe30f20c77 100644 --- a/Modules/_multiprocessing/multiprocessing.c +++ b/Modules/_multiprocessing/multiprocessing.c @@ -9,22 +9,6 @@ #include "multiprocessing.h" -/*[python input] -class HANDLE_converter(CConverter): - type = "HANDLE" - format_unit = '"F_HANDLE"' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsVoidPtr({argname}); - if (!{paramname} && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, - argname=argname) - -[python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=3cf0318efc6a8772]*/ /*[clinic input] module _multiprocessing diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 5d8ee661fa3b6de..07cfba8c8be74be 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -84,22 +84,6 @@ module _posixsubprocess [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c62211df27cf7334]*/ -/*[python input] -class pid_t_converter(CConverter): - type = 'pid_t' - format_unit = '" _Py_PARSE_PID "' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsPid({argname}); - if ({paramname} == -1 && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, - argname=argname) -[python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=c94349aa1aad151d]*/ - #include "clinic/_posixsubprocess.c.h" /* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */ diff --git a/Modules/_remote_debugging/clinic/module.c.h b/Modules/_remote_debugging/clinic/module.c.h index d01f3d13e85f09f..ad66d947d19c52f 100644 --- a/Modules/_remote_debugging/clinic/module.c.h +++ b/Modules/_remote_debugging/clinic/module.c.h @@ -56,7 +56,7 @@ PyDoc_STRVAR(_remote_debugging_RemoteUnwinder___init____doc__, static int _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, - int pid, int all_threads, + pid_t pid, int all_threads, int only_active_thread, int mode, int debug, int skip_non_matching_threads, @@ -99,7 +99,7 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; - int pid; + pid_t pid; int all_threads = 0; int only_active_thread = 0; int mode = 0; @@ -116,8 +116,8 @@ _remote_debugging_RemoteUnwinder___init__(PyObject *self, PyObject *args, PyObje if (!fastargs) { goto exit; } - pid = PyLong_AsInt(fastargs[0]); - if (pid == -1 && PyErr_Occurred()) { + pid = PyLong_AsPid(fastargs[0]); + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } if (!noptargs) { @@ -559,7 +559,7 @@ PyDoc_STRVAR(_remote_debugging_GCMonitor___init____doc__, " target process"); static int -_remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, int pid, +_remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, pid_t pid, int debug); static int @@ -597,7 +597,7 @@ _remote_debugging_GCMonitor___init__(PyObject *self, PyObject *args, PyObject *k PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; - int pid; + pid_t pid; int debug = 0; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, @@ -605,8 +605,8 @@ _remote_debugging_GCMonitor___init__(PyObject *self, PyObject *args, PyObject *k if (!fastargs) { goto exit; } - pid = PyLong_AsInt(fastargs[0]); - if (pid == -1 && PyErr_Occurred()) { + pid = PyLong_AsPid(fastargs[0]); + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } if (!noptargs) { @@ -1374,7 +1374,7 @@ PyDoc_STRVAR(_remote_debugging_get_child_pids__doc__, {"get_child_pids", _PyCFunction_CAST(_remote_debugging_get_child_pids), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_get_child_pids__doc__}, static PyObject * -_remote_debugging_get_child_pids_impl(PyObject *module, int pid, +_remote_debugging_get_child_pids_impl(PyObject *module, pid_t pid, int recursive); static PyObject * @@ -1410,7 +1410,7 @@ _remote_debugging_get_child_pids(PyObject *module, PyObject *const *args, Py_ssi #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - int pid; + pid_t pid; int recursive = 1; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, @@ -1418,8 +1418,8 @@ _remote_debugging_get_child_pids(PyObject *module, PyObject *const *args, Py_ssi if (!args) { goto exit; } - pid = PyLong_AsInt(args[0]); - if (pid == -1 && PyErr_Occurred()) { + pid = PyLong_AsPid(args[0]); + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } if (!noptargs) { @@ -1446,7 +1446,7 @@ PyDoc_STRVAR(_remote_debugging_is_python_process__doc__, {"is_python_process", _PyCFunction_CAST(_remote_debugging_is_python_process), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_is_python_process__doc__}, static PyObject * -_remote_debugging_is_python_process_impl(PyObject *module, int pid); +_remote_debugging_is_python_process_impl(PyObject *module, pid_t pid); static PyObject * _remote_debugging_is_python_process(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -1480,15 +1480,15 @@ _remote_debugging_is_python_process(PyObject *module, PyObject *const *args, Py_ }; #undef KWTUPLE PyObject *argsbuf[1]; - int pid; + pid_t pid; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!args) { goto exit; } - pid = PyLong_AsInt(args[0]); - if (pid == -1 && PyErr_Occurred()) { + pid = PyLong_AsPid(args[0]); + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } return_value = _remote_debugging_is_python_process_impl(module, pid); @@ -1527,7 +1527,7 @@ PyDoc_STRVAR(_remote_debugging_get_gc_stats__doc__, {"get_gc_stats", _PyCFunction_CAST(_remote_debugging_get_gc_stats), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_get_gc_stats__doc__}, static PyObject * -_remote_debugging_get_gc_stats_impl(PyObject *module, int pid, +_remote_debugging_get_gc_stats_impl(PyObject *module, pid_t pid, int all_interpreters); static PyObject * @@ -1563,7 +1563,7 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize #undef KWTUPLE PyObject *argsbuf[2]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; - int pid; + pid_t pid; int all_interpreters = 0; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, @@ -1571,8 +1571,8 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize if (!args) { goto exit; } - pid = PyLong_AsInt(args[0]); - if (pid == -1 && PyErr_Occurred()) { + pid = PyLong_AsPid(args[0]); + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } if (!noptargs) { @@ -1588,4 +1588,4 @@ _remote_debugging_get_gc_stats(PyObject *module, PyObject *const *args, Py_ssize exit: return return_value; } -/*[clinic end generated code: output=a3df14a6ab7f2998 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=22511c10d9224b28 input=a9049054013a1b77]*/ diff --git a/Modules/_remote_debugging/module.c b/Modules/_remote_debugging/module.c index adafee97a94ada7..4f365f303f14c77 100644 --- a/Modules/_remote_debugging/module.c +++ b/Modules/_remote_debugging/module.c @@ -281,7 +281,7 @@ class _remote_debugging.RemoteUnwinder "RemoteUnwinderObject *" "&RemoteUnwinder /*[clinic input] @permit_long_summary _remote_debugging.RemoteUnwinder.__init__ - pid: int + pid: pid_t * all_threads: bool = False only_active_thread: bool = False @@ -334,14 +334,14 @@ other runtime data. static int _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self, - int pid, int all_threads, + pid_t pid, int all_threads, int only_active_thread, int mode, int debug, int skip_non_matching_threads, int native, int gc, int opcodes, int cache_frames, int stats) -/*[clinic end generated code: output=0031f743f4b9ad52 input=9d25ae328d62626d]*/ +/*[clinic end generated code: output=acfe554c8a92cf6b input=3b5a5ad153709125]*/ { // Validate that all_threads and only_active_thread are not both True if (all_threads && only_active_thread) { @@ -1376,7 +1376,7 @@ cleanup_runtime_offsets(RuntimeOffsets *offsets) } static int -init_runtime_offsets(RuntimeOffsets *offsets, int pid, int debug) +init_runtime_offsets(RuntimeOffsets *offsets, pid_t pid, int debug) { offsets->debug = debug; if (_Py_RemoteDebug_InitProcHandle(&offsets->handle, pid) < 0) { @@ -1414,7 +1414,7 @@ class _remote_debugging.GCMonitor "GCMonitorObject *" "&GCMonitor_Type" /*[clinic input] @permit_long_summary _remote_debugging.GCMonitor.__init__ - pid: int + pid: pid_t * debug: bool = False @@ -1437,9 +1437,9 @@ a running Python process. [clinic start generated code]*/ static int -_remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, int pid, +_remote_debugging_GCMonitor___init___impl(GCMonitorObject *self, pid_t pid, int debug) -/*[clinic end generated code: output=2cdf351c2f6335db input=03da0b2d3282ae1b]*/ +/*[clinic end generated code: output=03b4c92bef0673ad input=dcc6ee2ec5a16fa1]*/ { return init_runtime_offsets(&self->offsets, pid, debug); } @@ -2226,7 +2226,7 @@ _remote_debugging_zstd_available_impl(PyObject *module) /*[clinic input] _remote_debugging.get_child_pids - pid: int + pid: pid_t Process ID of the parent process * recursive: bool = True @@ -2248,24 +2248,24 @@ list is returned. [clinic start generated code]*/ static PyObject * -_remote_debugging_get_child_pids_impl(PyObject *module, int pid, +_remote_debugging_get_child_pids_impl(PyObject *module, pid_t pid, int recursive) -/*[clinic end generated code: output=1ae2289c6b953e4b input=c6437b52e2fdd880]*/ +/*[clinic end generated code: output=fa3dfd1b02eed29b input=3325d95e9f39d75d]*/ { - return enumerate_child_pids((pid_t)pid, recursive); + return enumerate_child_pids(pid, recursive); } /*[clinic input] _remote_debugging.is_python_process - pid: int + pid: pid_t Check if a process is a Python process. [clinic start generated code]*/ static PyObject * -_remote_debugging_is_python_process_impl(PyObject *module, int pid) -/*[clinic end generated code: output=22947dc8afcac362 input=13488e28c7295d84]*/ +_remote_debugging_is_python_process_impl(PyObject *module, pid_t pid) +/*[clinic end generated code: output=63541478c889e536 input=ff998fef4aeef433]*/ { proc_handle_t handle; @@ -2288,7 +2288,7 @@ _remote_debugging_is_python_process_impl(PyObject *module, int pid) /*[clinic input] _remote_debugging.get_gc_stats - pid: int + pid: pid_t * all_interpreters: bool = False If True, return GC statistics from all interpreters. @@ -2314,9 +2314,9 @@ Get garbage collector statistics from external Python process. [clinic start generated code]*/ static PyObject * -_remote_debugging_get_gc_stats_impl(PyObject *module, int pid, +_remote_debugging_get_gc_stats_impl(PyObject *module, pid_t pid, int all_interpreters) -/*[clinic end generated code: output=d9dce5f7add149bb input=a2a08a45a8f0b119]*/ +/*[clinic end generated code: output=dd33199ccb6a56e9 input=41399e77788aa369]*/ { RuntimeOffsets offsets; if (init_runtime_offsets(&offsets, pid, /*debug=*/1) < 0) { diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 9f8a6a58cd9327e..aadc015405453f3 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -80,34 +80,6 @@ #endif -#ifdef BIO_get_ktls_send -# ifdef MS_WINDOWS -typedef long long Py_off_t; -# else -typedef off_t Py_off_t; -# endif - -static int -Py_off_t_converter(PyObject *arg, void *addr) -{ -#ifdef HAVE_LARGEFILE_SUPPORT - *((Py_off_t *)addr) = PyLong_AsLongLong(arg); -#else - *((Py_off_t *)addr) = PyLong_AsLong(arg); -#endif - return PyErr_Occurred() ? 0 : 1; -} - -/*[python input] - -class Py_off_t_converter(CConverter): - type = 'Py_off_t' - converter = 'Py_off_t_converter' - -[python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=3fd9ca8ca6f0cbb8]*/ -#endif /* BIO_get_ktls_send */ - struct py_ssl_error_code { const char *mnemonic; int library, reason; diff --git a/Modules/_winapi.c b/Modules/_winapi.c index a649d84a7925a04..36eb831044a7861 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -227,13 +227,10 @@ def create_converter(type_, format_unit): type(name, (CConverter,), {'type': type_, 'format_unit': format_unit}) # format unit differs between platforms for these -create_converter('HANDLE', '" F_HANDLE "') create_converter('HMODULE', '" F_HANDLE "') create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "') create_converter('LPCVOID', '" F_POINTER "') -create_converter('BOOL', 'i') # F_BOOL used previously (always 'i') -create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter) create_converter('UINT', 'I') # F_UINT used previously (always 'I') class LPCWSTR_converter(Py_UNICODE_converter): @@ -268,7 +265,7 @@ class LPVOID_return_converter(CReturnConverter): data.return_conversion.append( 'return_value = HANDLE_TO_PYNUM(_return_value);\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=da0a4db751936ee7]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=59b6c67bbb5411d5]*/ #include "clinic/_winapi.c.h" @@ -520,11 +517,11 @@ _winapi_CreateEventW_impl(PyObject *module, _winapi.CreateFile -> HANDLE file_name: LPCWSTR - desired_access: DWORD - share_mode: DWORD + desired_access: DWORD(bitwise=True) + share_mode: DWORD(bitwise=True) security_attributes: LPSECURITY_ATTRIBUTES - creation_disposition: DWORD - flags_and_attributes: DWORD + creation_disposition: DWORD(bitwise=True) + flags_and_attributes: DWORD(bitwise=True) template_file: HANDLE / [clinic start generated code]*/ @@ -535,7 +532,7 @@ _winapi_CreateFile_impl(PyObject *module, LPCWSTR file_name, LPSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD flags_and_attributes, HANDLE template_file) -/*[clinic end generated code: output=818c811e5e04d550 input=1fa870ed1c2e3d69]*/ +/*[clinic end generated code: output=818c811e5e04d550 input=de198846d329724e]*/ { HANDLE handle; @@ -564,9 +561,9 @@ _winapi.CreateFileMapping -> HANDLE file_handle: HANDLE security_attributes: LPSECURITY_ATTRIBUTES - protect: DWORD - max_size_high: DWORD - max_size_low: DWORD + protect: DWORD(bitwise=True) + max_size_high: DWORD(bitwise=True) + max_size_low: DWORD(bitwise=True) name: LPCWSTR / [clinic start generated code]*/ @@ -576,7 +573,7 @@ _winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle, LPSECURITY_ATTRIBUTES security_attributes, DWORD protect, DWORD max_size_high, DWORD max_size_low, LPCWSTR name) -/*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/ +/*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=06507c1bc186b047]*/ { HANDLE handle; @@ -787,12 +784,12 @@ _winapi_CreateMutexW_impl(PyObject *module, _winapi.CreateNamedPipe -> HANDLE name: LPCWSTR - open_mode: DWORD - pipe_mode: DWORD - max_instances: DWORD - out_buffer_size: DWORD - in_buffer_size: DWORD - default_timeout: DWORD + open_mode: DWORD(bitwise=True) + pipe_mode: DWORD(bitwise=True) + max_instances: DWORD(bitwise=True) + out_buffer_size: DWORD(bitwise=True) + in_buffer_size: DWORD(bitwise=True) + default_timeout: DWORD(bitwise=True) security_attributes: LPSECURITY_ATTRIBUTES / [clinic start generated code]*/ @@ -803,7 +800,7 @@ _winapi_CreateNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD open_mode, DWORD out_buffer_size, DWORD in_buffer_size, DWORD default_timeout, LPSECURITY_ATTRIBUTES security_attributes) -/*[clinic end generated code: output=7d6fde93227680ba input=5bd4e4a55639ee02]*/ +/*[clinic end generated code: output=7d6fde93227680ba input=83dfbf822975724b]*/ { HANDLE handle; @@ -830,7 +827,7 @@ _winapi.CreatePipe pipe_attrs: object Ignored internally, can be None. - size: DWORD + size: DWORD(bitwise=True) / Create an anonymous pipe. @@ -840,7 +837,7 @@ Returns a 2-tuple of handles, to the read and write ends of the pipe. static PyObject * _winapi_CreatePipe_impl(PyObject *module, PyObject *pipe_attrs, DWORD size) -/*[clinic end generated code: output=1c4411d8699f0925 input=c4f2cfa56ef68d90]*/ +/*[clinic end generated code: output=1c4411d8699f0925 input=ccfdf00b218dfe06]*/ { HANDLE read_pipe; HANDLE write_pipe; @@ -1337,7 +1334,7 @@ _winapi.CreateProcess thread_attrs: object Ignored internally, can be None. inherit_handles: BOOL - creation_flags: DWORD + creation_flags: DWORD(bitwise=True) env_mapping: object current_directory: Py_UNICODE(accept={str, NoneType}) startup_info: object @@ -1356,7 +1353,7 @@ _winapi_CreateProcess_impl(PyObject *module, const wchar_t *application_name, DWORD creation_flags, PyObject *env_mapping, const wchar_t *current_directory, PyObject *startup_info) -/*[clinic end generated code: output=a25c8e49ea1d6427 input=42ac293eaea03fc4]*/ +/*[clinic end generated code: output=a25c8e49ea1d6427 input=84e2175279a3f5c2]*/ { PyObject *ret = NULL; BOOL result; @@ -1447,9 +1444,9 @@ _winapi.DuplicateHandle -> HANDLE source_process_handle: HANDLE source_handle: HANDLE target_process_handle: HANDLE - desired_access: DWORD + desired_access: DWORD(bitwise=True) inherit_handle: BOOL - options: DWORD = 0 + options: DWORD(bitwise=True) = 0 / Return a duplicate handle object. @@ -1465,7 +1462,7 @@ _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle, HANDLE target_process_handle, DWORD desired_access, BOOL inherit_handle, DWORD options) -/*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/ +/*[clinic end generated code: output=ad9711397b5dcd4e input=f4965c09aa01993a]*/ { HANDLE target_handle; BOOL result; @@ -1698,7 +1695,7 @@ _winapi_GetShortPathName_impl(PyObject *module, LPCWSTR path) /*[clinic input] _winapi.GetStdHandle -> HANDLE - std_handle: DWORD + std_handle: DWORD(bitwise=True) One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE. / @@ -1709,7 +1706,7 @@ The integer associated with the handle object is returned. static HANDLE _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle) -/*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/ +/*[clinic end generated code: output=0e613001e73ab614 input=377191071925fe8d]*/ { HANDLE handle; @@ -1760,9 +1757,9 @@ _winapi_GetVersion_impl(PyObject *module) _winapi.MapViewOfFile -> LPVOID file_map: HANDLE - desired_access: DWORD - file_offset_high: DWORD - file_offset_low: DWORD + desired_access: DWORD(bitwise=True) + file_offset_high: DWORD(bitwise=True) + file_offset_low: DWORD(bitwise=True) number_bytes: size_t / [clinic start generated code]*/ @@ -1771,7 +1768,7 @@ static LPVOID _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map, DWORD desired_access, DWORD file_offset_high, DWORD file_offset_low, size_t number_bytes) -/*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/ +/*[clinic end generated code: output=f23b1ee4823663e3 input=cc9e7e33663d3b8e]*/ { LPVOID address; @@ -1813,7 +1810,7 @@ _winapi_UnmapViewOfFile_impl(PyObject *module, LPCVOID address) /*[clinic input] _winapi.OpenEventW -> HANDLE - desired_access: DWORD + desired_access: DWORD(bitwise=True) inherit_handle: BOOL name: LPCWSTR [clinic start generated code]*/ @@ -1821,7 +1818,7 @@ _winapi.OpenEventW -> HANDLE static HANDLE _winapi_OpenEventW_impl(PyObject *module, DWORD desired_access, BOOL inherit_handle, LPCWSTR name) -/*[clinic end generated code: output=c4a45e95545a4bd2 input=dec26598748d35aa]*/ +/*[clinic end generated code: output=c4a45e95545a4bd2 input=ca388b35dcd10b1e]*/ { HANDLE handle; @@ -1844,7 +1841,7 @@ _winapi_OpenEventW_impl(PyObject *module, DWORD desired_access, /*[clinic input] _winapi.OpenMutexW -> HANDLE - desired_access: DWORD + desired_access: DWORD(bitwise=True) inherit_handle: BOOL name: LPCWSTR [clinic start generated code]*/ @@ -1852,7 +1849,7 @@ _winapi.OpenMutexW -> HANDLE static HANDLE _winapi_OpenMutexW_impl(PyObject *module, DWORD desired_access, BOOL inherit_handle, LPCWSTR name) -/*[clinic end generated code: output=dda39d7844397bf0 input=f3a7b466c5307712]*/ +/*[clinic end generated code: output=dda39d7844397bf0 input=c1a077777c7f88f6]*/ { HANDLE handle; @@ -1874,7 +1871,7 @@ _winapi_OpenMutexW_impl(PyObject *module, DWORD desired_access, /*[clinic input] _winapi.OpenFileMapping -> HANDLE - desired_access: DWORD + desired_access: DWORD(bitwise=True) inherit_handle: BOOL name: LPCWSTR / @@ -1883,7 +1880,7 @@ _winapi.OpenFileMapping -> HANDLE static HANDLE _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access, BOOL inherit_handle, LPCWSTR name) -/*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/ +/*[clinic end generated code: output=08cc44def1cb11f1 input=1f82471d4cdc232f]*/ { HANDLE handle; @@ -1904,16 +1901,16 @@ _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access, /*[clinic input] _winapi.OpenProcess -> HANDLE - desired_access: DWORD + desired_access: DWORD(bitwise=True) inherit_handle: BOOL - process_id: DWORD + process_id: DWORD(bitwise=True) / [clinic start generated code]*/ static HANDLE _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access, BOOL inherit_handle, DWORD process_id) -/*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/ +/*[clinic end generated code: output=b42b6b81ea5a0fc3 input=13af8d7640f1313f]*/ { HANDLE handle; @@ -1990,7 +1987,7 @@ _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size) _winapi.LCMapStringEx locale: LPCWSTR - flags: DWORD + flags: DWORD(bitwise=True) src: unicode [clinic start generated code]*/ @@ -1998,7 +1995,7 @@ _winapi.LCMapStringEx static PyObject * _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags, PyObject *src) -/*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/ +/*[clinic end generated code: output=b90e6b26e028ff0a input=247d3967a9c480ba]*/ { if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV | LCMAP_SORTKEY)) { @@ -2050,14 +2047,14 @@ _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags, _winapi.ReadFile handle: HANDLE - size: DWORD + size: DWORD(bitwise=True) overlapped as use_overlapped: bool = False [clinic start generated code]*/ static PyObject * _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size, int use_overlapped) -/*[clinic end generated code: output=d3d5b44a8201b944 input=4f82f8e909ad91ad]*/ +/*[clinic end generated code: output=d3d5b44a8201b944 input=aa266e0df79fe16a]*/ { DWORD nread; PyObject *buf; @@ -2277,13 +2274,13 @@ _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address) _winapi.WaitNamedPipe name: LPCWSTR - timeout: DWORD + timeout: DWORD(bitwise=True) / [clinic start generated code]*/ static PyObject * _winapi_WaitNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD timeout) -/*[clinic end generated code: output=e161e2e630b3e9c2 input=099a4746544488fa]*/ +/*[clinic end generated code: output=e161e2e630b3e9c2 input=e35bf1f712f3193d]*/ { BOOL success; @@ -2334,7 +2331,7 @@ _winapi.BatchedWaitForMultipleObjects handle_seq: object wait_all: BOOL - milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE + milliseconds: DWORD(bitwise=True, c_default='INFINITE') = _winapi.INFINITE Supports a larger number of handles than WaitForMultipleObjects @@ -2356,7 +2353,7 @@ static PyObject * _winapi_BatchedWaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq, BOOL wait_all, DWORD milliseconds) -/*[clinic end generated code: output=d21c1a4ad0a252fd input=7e196f29005dc77b]*/ +/*[clinic end generated code: output=d21c1a4ad0a252fd input=c93e93b7fce1da4f]*/ { Py_ssize_t thread_count = 0, handle_count = 0, i; Py_ssize_t nhandles; @@ -2607,14 +2604,14 @@ _winapi.WaitForMultipleObjects handle_seq: object wait_flag: BOOL - milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE + milliseconds: DWORD(bitwise=True, c_default='INFINITE') = _winapi.INFINITE / [clinic start generated code]*/ static PyObject * _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq, BOOL wait_flag, DWORD milliseconds) -/*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/ +/*[clinic end generated code: output=295e3f00b8e45899 input=8ea1dd762d873559]*/ { DWORD result; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; @@ -2677,7 +2674,7 @@ _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq, _winapi.WaitForSingleObject -> long handle: HANDLE - milliseconds: DWORD + milliseconds: DWORD(bitwise=True) / Wait for a single object. @@ -2690,7 +2687,7 @@ in milliseconds. static long _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle, DWORD milliseconds) -/*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/ +/*[clinic end generated code: output=3c4715d8f1b39859 input=1f74a3422daef05c]*/ { DWORD result; @@ -2954,7 +2951,7 @@ _winapi.CopyFile2 existing_file_name: LPCWSTR new_file_name: LPCWSTR - flags: DWORD + flags: DWORD(bitwise=True) progress_routine: object = None Copies a file from one name to a new name. @@ -2970,7 +2967,7 @@ static PyObject * _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name, LPCWSTR new_file_name, DWORD flags, PyObject *progress_routine) -/*[clinic end generated code: output=43d960d9df73d984 input=fb976b8d1492d130]*/ +/*[clinic end generated code: output=43d960d9df73d984 input=16394ddb6b3bd276]*/ { HRESULT hr; COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) }; diff --git a/Modules/clinic/_posixsubprocess.c.h b/Modules/clinic/_posixsubprocess.c.h index e7e9707f182a2ed..3414dc5fa261df0 100644 --- a/Modules/clinic/_posixsubprocess.c.h +++ b/Modules/clinic/_posixsubprocess.c.h @@ -134,7 +134,7 @@ subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } pgid_to_set = PyLong_AsPid(args[16]); - if (pgid_to_set == -1 && PyErr_Occurred()) { + if (pgid_to_set == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } gid_object = args[17]; @@ -150,4 +150,4 @@ subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=138941c284792aa1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=59df66f994e6251d input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index 62d52fc5f1aa5dd..aa6416805e463a6 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -7,6 +7,7 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() +#include "pycore_fileutils.h" // _Py_Off_t_Converter() #include "pycore_long.h" // _PyLong_Size_t_Converter() #include "pycore_modsupport.h" // _PyArg_CheckPositional() @@ -613,7 +614,7 @@ _ssl__SSLSocket_sendfile(PyObject *self, PyObject *const *args, Py_ssize_t nargs if (fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[1], &offset)) { + if (!_Py_Off_t_Converter(args[1], &offset)) { goto exit; } if (!_PyLong_Size_t_Converter(args[2], &size)) { @@ -3398,4 +3399,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=3a5bdd8db17e32b1 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=aef11b9d635db158 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index 031a0783aef60bb..144d03bdf30dcf0 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -88,7 +88,8 @@ _winapi_CloseHandle(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HANDLE handle; - if (!PyArg_Parse(arg, "" F_HANDLE ":CloseHandle", &handle)) { + handle = PyLong_AsVoidPtr(arg); + if (!handle && PyErr_Occurred()) { goto exit; } return_value = _winapi_CloseHandle_impl(module, handle); @@ -136,17 +137,32 @@ _winapi_ConnectNamedPipe(PyObject *module, PyObject *const *args, Py_ssize_t nar static const char * const _keywords[] = {"handle", "overlapped", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "|p:ConnectNamedPipe", + .fname = "ConnectNamedPipe", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; HANDLE handle; int use_overlapped = 0; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, &use_overlapped)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { goto exit; } + if (!noptargs) { + goto skip_optional_pos; + } + use_overlapped = PyObject_IsTrue(args[1]); + if (use_overlapped < 0) { + goto exit; + } +skip_optional_pos: return_value = _winapi_ConnectNamedPipe_impl(module, handle, use_overlapped); exit: @@ -255,7 +271,7 @@ _winapi_CreateFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs) HANDLE template_file; HANDLE _return_value; - if (!_PyArg_ParseStack(args, nargs, "O&kk" F_POINTER "kk" F_HANDLE ":CreateFile", + if (!_PyArg_ParseStack(args, nargs, "O&kk" F_POINTER "kk"_Py_PARSE_UINTPTR":CreateFile", _PyUnicode_WideCharString_Converter, &file_name, &desired_access, &share_mode, &security_attributes, &creation_disposition, &flags_and_attributes, &template_file)) { goto exit; } @@ -302,7 +318,7 @@ _winapi_CreateFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t na LPCWSTR name = NULL; HANDLE _return_value; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_POINTER "kkkO&:CreateFileMapping", + if (!_PyArg_ParseStack(args, nargs, ""_Py_PARSE_UINTPTR"" F_POINTER "kkkO&:CreateFileMapping", &file_handle, &security_attributes, &protect, &max_size_high, &max_size_low, _PyUnicode_WideCharString_Converter, &name)) { goto exit; } @@ -515,10 +531,30 @@ _winapi_CreatePipe(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *pipe_attrs; DWORD size; - if (!_PyArg_ParseStack(args, nargs, "Ok:CreatePipe", - &pipe_attrs, &size)) { + if (!_PyArg_CheckPositional("CreatePipe", nargs, 2, 2)) { + goto exit; + } + pipe_attrs = args[0]; + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("CreatePipe", "argument 2", "int", args[1]); goto exit; } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &size, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } return_value = _winapi_CreatePipe_impl(module, pipe_attrs, size); exit: @@ -568,10 +604,64 @@ _winapi_CreateProcess(PyObject *module, PyObject *const *args, Py_ssize_t nargs) const wchar_t *current_directory = NULL; PyObject *startup_info; - if (!_PyArg_ParseStack(args, nargs, "O&OOOikOO&O:CreateProcess", - _PyUnicode_WideCharString_Opt_Converter, &application_name, &command_line, &proc_attrs, &thread_attrs, &inherit_handles, &creation_flags, &env_mapping, _PyUnicode_WideCharString_Opt_Converter, ¤t_directory, &startup_info)) { + if (!_PyArg_CheckPositional("CreateProcess", nargs, 9, 9)) { + goto exit; + } + if (args[0] == Py_None) { + application_name = NULL; + } + else if (PyUnicode_Check(args[0])) { + application_name = PyUnicode_AsWideCharString(args[0], NULL); + if (application_name == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("CreateProcess", "argument 1", "str or None", args[0]); + goto exit; + } + command_line = args[1]; + proc_attrs = args[2]; + thread_attrs = args[3]; + inherit_handles = PyLong_AsInt(args[4]); + if (inherit_handles == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyIndex_Check(args[5])) { + _PyArg_BadArgument("CreateProcess", "argument 6", "int", args[5]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[5], &creation_flags, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + env_mapping = args[6]; + if (args[7] == Py_None) { + current_directory = NULL; + } + else if (PyUnicode_Check(args[7])) { + current_directory = PyUnicode_AsWideCharString(args[7], NULL); + if (current_directory == NULL) { + goto exit; + } + } + else { + _PyArg_BadArgument("CreateProcess", "argument 8", "str or None", args[7]); goto exit; } + startup_info = args[8]; return_value = _winapi_CreateProcess_impl(module, application_name, command_line, proc_attrs, thread_attrs, inherit_handles, creation_flags, env_mapping, current_directory, startup_info); exit: @@ -617,10 +707,69 @@ _winapi_DuplicateHandle(PyObject *module, PyObject *const *args, Py_ssize_t narg DWORD options = 0; HANDLE _return_value; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_HANDLE "" F_HANDLE "ki|k:DuplicateHandle", - &source_process_handle, &source_handle, &target_process_handle, &desired_access, &inherit_handle, &options)) { + if (!_PyArg_CheckPositional("DuplicateHandle", nargs, 5, 6)) { + goto exit; + } + source_process_handle = PyLong_AsVoidPtr(args[0]); + if (!source_process_handle && PyErr_Occurred()) { + goto exit; + } + source_handle = PyLong_AsVoidPtr(args[1]); + if (!source_handle && PyErr_Occurred()) { + goto exit; + } + target_process_handle = PyLong_AsVoidPtr(args[2]); + if (!target_process_handle && PyErr_Occurred()) { + goto exit; + } + if (!PyIndex_Check(args[3])) { + _PyArg_BadArgument("DuplicateHandle", "argument 4", "int", args[3]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[3], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + inherit_handle = PyLong_AsInt(args[4]); + if (inherit_handle == -1 && PyErr_Occurred()) { + goto exit; + } + if (nargs < 6) { + goto skip_optional; + } + if (!PyIndex_Check(args[5])) { + _PyArg_BadArgument("DuplicateHandle", "argument 6", "int", args[5]); goto exit; } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[5], &options, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } +skip_optional: _return_value = _winapi_DuplicateHandle_impl(module, source_process_handle, source_handle, target_process_handle, desired_access, inherit_handle, options); if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { goto exit; @@ -710,7 +859,8 @@ _winapi_GetExitCodeProcess(PyObject *module, PyObject *arg) HANDLE process; DWORD _return_value; - if (!PyArg_Parse(arg, "" F_HANDLE ":GetExitCodeProcess", &process)) { + process = PyLong_AsVoidPtr(arg); + if (!process && PyErr_Occurred()) { goto exit; } _return_value = _winapi_GetExitCodeProcess_impl(module, process); @@ -958,9 +1108,26 @@ _winapi_GetStdHandle(PyObject *module, PyObject *arg) DWORD std_handle; HANDLE _return_value; - if (!PyArg_Parse(arg, "k:GetStdHandle", &std_handle)) { + if (!PyIndex_Check(arg)) { + _PyArg_BadArgument("GetStdHandle", "argument", "int", arg); goto exit; } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(arg, &std_handle, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } _return_value = _winapi_GetStdHandle_impl(module, std_handle); if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { goto exit; @@ -1027,8 +1194,74 @@ _winapi_MapViewOfFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs) size_t number_bytes; LPVOID _return_value; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "kkkO&:MapViewOfFile", - &file_map, &desired_access, &file_offset_high, &file_offset_low, _PyLong_Size_t_Converter, &number_bytes)) { + if (!_PyArg_CheckPositional("MapViewOfFile", nargs, 5, 5)) { + goto exit; + } + file_map = PyLong_AsVoidPtr(args[0]); + if (!file_map && PyErr_Occurred()) { + goto exit; + } + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("MapViewOfFile", "argument 2", "int", args[1]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!PyIndex_Check(args[2])) { + _PyArg_BadArgument("MapViewOfFile", "argument 3", "int", args[2]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[2], &file_offset_high, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!PyIndex_Check(args[3])) { + _PyArg_BadArgument("MapViewOfFile", "argument 4", "int", args[3]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[3], &file_offset_low, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!_PyLong_Size_t_Converter(args[4], &number_bytes)) { goto exit; } _return_value = _winapi_MapViewOfFile_impl(module, file_map, desired_access, file_offset_high, file_offset_low, number_bytes); @@ -1106,17 +1339,51 @@ _winapi_OpenEventW(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"desired_access", "inherit_handle", "name", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "kiO&:OpenEventW", + .fname = "OpenEventW", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; DWORD desired_access; BOOL inherit_handle; LPCWSTR name = NULL; HANDLE _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &desired_access, &inherit_handle, _PyUnicode_WideCharString_Converter, &name)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyIndex_Check(args[0])) { + _PyArg_BadArgument("OpenEventW", "argument 'desired_access'", "int", args[0]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + inherit_handle = PyLong_AsInt(args[1]); + if (inherit_handle == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("OpenEventW", "argument 'name'", "str", args[2]); + goto exit; + } + name = PyUnicode_AsWideCharString(args[2], NULL); + if (name == NULL) { goto exit; } _return_value = _winapi_OpenEventW_impl(module, desired_access, inherit_handle, name); @@ -1174,17 +1441,51 @@ _winapi_OpenMutexW(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"desired_access", "inherit_handle", "name", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "kiO&:OpenMutexW", + .fname = "OpenMutexW", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; DWORD desired_access; BOOL inherit_handle; LPCWSTR name = NULL; HANDLE _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &desired_access, &inherit_handle, _PyUnicode_WideCharString_Converter, &name)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyIndex_Check(args[0])) { + _PyArg_BadArgument("OpenMutexW", "argument 'desired_access'", "int", args[0]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + inherit_handle = PyLong_AsInt(args[1]); + if (inherit_handle == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("OpenMutexW", "argument 'name'", "str", args[2]); + goto exit; + } + name = PyUnicode_AsWideCharString(args[2], NULL); + if (name == NULL) { goto exit; } _return_value = _winapi_OpenMutexW_impl(module, desired_access, inherit_handle, name); @@ -1224,8 +1525,39 @@ _winapi_OpenFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t narg LPCWSTR name = NULL; HANDLE _return_value; - if (!_PyArg_ParseStack(args, nargs, "kiO&:OpenFileMapping", - &desired_access, &inherit_handle, _PyUnicode_WideCharString_Converter, &name)) { + if (!_PyArg_CheckPositional("OpenFileMapping", nargs, 3, 3)) { + goto exit; + } + if (!PyIndex_Check(args[0])) { + _PyArg_BadArgument("OpenFileMapping", "argument 1", "int", args[0]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + inherit_handle = PyLong_AsInt(args[1]); + if (inherit_handle == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("OpenFileMapping", "argument 3", "str", args[2]); + goto exit; + } + name = PyUnicode_AsWideCharString(args[2], NULL); + if (name == NULL) { goto exit; } _return_value = _winapi_OpenFileMapping_impl(module, desired_access, inherit_handle, name); @@ -1265,10 +1597,53 @@ _winapi_OpenProcess(PyObject *module, PyObject *const *args, Py_ssize_t nargs) DWORD process_id; HANDLE _return_value; - if (!_PyArg_ParseStack(args, nargs, "kik:OpenProcess", - &desired_access, &inherit_handle, &process_id)) { + if (!_PyArg_CheckPositional("OpenProcess", nargs, 3, 3)) { + goto exit; + } + if (!PyIndex_Check(args[0])) { + _PyArg_BadArgument("OpenProcess", "argument 1", "int", args[0]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &desired_access, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + inherit_handle = PyLong_AsInt(args[1]); + if (inherit_handle == -1 && PyErr_Occurred()) { goto exit; } + if (!PyIndex_Check(args[2])) { + _PyArg_BadArgument("OpenProcess", "argument 3", "int", args[2]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[2], &process_id, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } _return_value = _winapi_OpenProcess_impl(module, desired_access, inherit_handle, process_id); if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { goto exit; @@ -1300,10 +1675,21 @@ _winapi_PeekNamedPipe(PyObject *module, PyObject *const *args, Py_ssize_t nargs) HANDLE handle; int size = 0; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "|i:PeekNamedPipe", - &handle, &size)) { + if (!_PyArg_CheckPositional("PeekNamedPipe", nargs, 1, 2)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { goto exit; } + if (nargs < 2) { + goto skip_optional; + } + size = PyLong_AsInt(args[1]); + if (size == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: return_value = _winapi_PeekNamedPipe_impl(module, handle, size); exit: @@ -1349,18 +1735,53 @@ _winapi_LCMapStringEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, static const char * const _keywords[] = {"locale", "flags", "src", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "O&kU:LCMapStringEx", + .fname = "LCMapStringEx", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; LPCWSTR locale = NULL; DWORD flags; PyObject *src; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - _PyUnicode_WideCharString_Converter, &locale, &flags, &src)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("LCMapStringEx", "argument 'locale'", "str", args[0]); + goto exit; + } + locale = PyUnicode_AsWideCharString(args[0], NULL); + if (locale == NULL) { + goto exit; + } + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("LCMapStringEx", "argument 'flags'", "int", args[1]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &flags, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!PyUnicode_Check(args[2])) { + _PyArg_BadArgument("LCMapStringEx", "argument 'src'", "str", args[2]); goto exit; } + src = args[2]; return_value = _winapi_LCMapStringEx_impl(module, locale, flags, src); exit: @@ -1409,18 +1830,53 @@ _winapi_ReadFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb static const char * const _keywords[] = {"handle", "size", "overlapped", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "k|p:ReadFile", + .fname = "ReadFile", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HANDLE handle; DWORD size; int use_overlapped = 0; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, &size, &use_overlapped)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("ReadFile", "argument 'size'", "int", args[1]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &size, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!noptargs) { + goto skip_optional_pos; + } + use_overlapped = PyObject_IsTrue(args[2]); + if (use_overlapped < 0) { goto exit; } +skip_optional_pos: return_value = _winapi_ReadFile_impl(module, handle, size, use_overlapped); exit: @@ -1465,14 +1921,20 @@ _winapi_ReleaseMutex(PyObject *module, PyObject *const *args, Py_ssize_t nargs, static const char * const _keywords[] = {"mutex", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE ":ReleaseMutex", + .fname = "ReleaseMutex", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[1]; HANDLE mutex; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &mutex)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + mutex = PyLong_AsVoidPtr(args[0]); + if (!mutex && PyErr_Occurred()) { goto exit; } return_value = _winapi_ReleaseMutex_impl(module, mutex); @@ -1519,14 +1981,20 @@ _winapi_ResetEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py static const char * const _keywords[] = {"event", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE ":ResetEvent", + .fname = "ResetEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[1]; HANDLE event; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &event)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + event = PyLong_AsVoidPtr(args[0]); + if (!event && PyErr_Occurred()) { goto exit; } return_value = _winapi_ResetEvent_impl(module, event); @@ -1573,14 +2041,20 @@ _winapi_SetEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb static const char * const _keywords[] = {"event", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE ":SetEvent", + .fname = "SetEvent", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[1]; HANDLE event; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &event)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + event = PyLong_AsVoidPtr(args[0]); + if (!event && PyErr_Occurred()) { goto exit; } return_value = _winapi_SetEvent_impl(module, event); @@ -1613,10 +2087,16 @@ _winapi_SetNamedPipeHandleState(PyObject *module, PyObject *const *args, Py_ssiz PyObject *max_collection_count; PyObject *collect_data_timeout; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "OOO:SetNamedPipeHandleState", - &named_pipe, &mode, &max_collection_count, &collect_data_timeout)) { + if (!_PyArg_CheckPositional("SetNamedPipeHandleState", nargs, 4, 4)) { goto exit; } + named_pipe = PyLong_AsVoidPtr(args[0]); + if (!named_pipe && PyErr_Occurred()) { + goto exit; + } + mode = args[1]; + max_collection_count = args[2]; + collect_data_timeout = args[3]; return_value = _winapi_SetNamedPipeHandleState_impl(module, named_pipe, mode, max_collection_count, collect_data_timeout); exit: @@ -1643,7 +2123,7 @@ _winapi_TerminateProcess(PyObject *module, PyObject *const *args, Py_ssize_t nar HANDLE handle; UINT exit_code; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "I:TerminateProcess", + if (!_PyArg_ParseStack(args, nargs, ""_Py_PARSE_UINTPTR"I:TerminateProcess", &handle, &exit_code)) { goto exit; } @@ -1702,10 +2182,37 @@ _winapi_WaitNamedPipe(PyObject *module, PyObject *const *args, Py_ssize_t nargs) LPCWSTR name = NULL; DWORD timeout; - if (!_PyArg_ParseStack(args, nargs, "O&k:WaitNamedPipe", - _PyUnicode_WideCharString_Converter, &name, &timeout)) { + if (!_PyArg_CheckPositional("WaitNamedPipe", nargs, 2, 2)) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("WaitNamedPipe", "argument 1", "str", args[0]); + goto exit; + } + name = PyUnicode_AsWideCharString(args[0], NULL); + if (name == NULL) { + goto exit; + } + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("WaitNamedPipe", "argument 2", "int", args[1]); goto exit; } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &timeout, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } return_value = _winapi_WaitNamedPipe_impl(module, name, timeout); exit: @@ -1770,18 +2277,50 @@ _winapi_BatchedWaitForMultipleObjects(PyObject *module, PyObject *const *args, P static const char * const _keywords[] = {"handle_seq", "wait_all", "milliseconds", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "Oi|k:BatchedWaitForMultipleObjects", + .fname = "BatchedWaitForMultipleObjects", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; PyObject *handle_seq; BOOL wait_all; DWORD milliseconds = INFINITE; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle_seq, &wait_all, &milliseconds)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + handle_seq = args[0]; + wait_all = PyLong_AsInt(args[1]); + if (wait_all == -1 && PyErr_Occurred()) { goto exit; } + if (!noptargs) { + goto skip_optional_pos; + } + if (!PyIndex_Check(args[2])) { + _PyArg_BadArgument("BatchedWaitForMultipleObjects", "argument 'milliseconds'", "int", args[2]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[2], &milliseconds, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } +skip_optional_pos: return_value = _winapi_BatchedWaitForMultipleObjects_impl(module, handle_seq, wait_all, milliseconds); exit: @@ -1809,10 +2348,38 @@ _winapi_WaitForMultipleObjects(PyObject *module, PyObject *const *args, Py_ssize BOOL wait_flag; DWORD milliseconds = INFINITE; - if (!_PyArg_ParseStack(args, nargs, "Oi|k:WaitForMultipleObjects", - &handle_seq, &wait_flag, &milliseconds)) { + if (!_PyArg_CheckPositional("WaitForMultipleObjects", nargs, 2, 3)) { + goto exit; + } + handle_seq = args[0]; + wait_flag = PyLong_AsInt(args[1]); + if (wait_flag == -1 && PyErr_Occurred()) { goto exit; } + if (nargs < 3) { + goto skip_optional; + } + if (!PyIndex_Check(args[2])) { + _PyArg_BadArgument("WaitForMultipleObjects", "argument 3", "int", args[2]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[2], &milliseconds, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } +skip_optional: return_value = _winapi_WaitForMultipleObjects_impl(module, handle_seq, wait_flag, milliseconds); exit: @@ -1844,10 +2411,33 @@ _winapi_WaitForSingleObject(PyObject *module, PyObject *const *args, Py_ssize_t DWORD milliseconds; long _return_value; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "k:WaitForSingleObject", - &handle, &milliseconds)) { + if (!_PyArg_CheckPositional("WaitForSingleObject", nargs, 2, 2)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { goto exit; } + if (!PyIndex_Check(args[1])) { + _PyArg_BadArgument("WaitForSingleObject", "argument 2", "int", args[1]); + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[1], &milliseconds, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } _return_value = _winapi_WaitForSingleObject_impl(module, handle, milliseconds); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; @@ -1897,18 +2487,34 @@ _winapi_WriteFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO static const char * const _keywords[] = {"handle", "buffer", "overlapped", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE "O|p:WriteFile", + .fname = "WriteFile", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[3]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2; HANDLE handle; PyObject *buffer; int use_overlapped = 0; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle, &buffer, &use_overlapped)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 3, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { goto exit; } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + buffer = args[1]; + if (!noptargs) { + goto skip_optional_pos; + } + use_overlapped = PyObject_IsTrue(args[2]); + if (use_overlapped < 0) { + goto exit; + } +skip_optional_pos: return_value = _winapi_WriteFile_impl(module, handle, buffer, use_overlapped); exit: @@ -1989,15 +2595,21 @@ _winapi_GetFileType(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P static const char * const _keywords[] = {"handle", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "" F_HANDLE ":GetFileType", + .fname = "GetFileType", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[1]; HANDLE handle; DWORD _return_value; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &handle)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { goto exit; } _return_value = _winapi_GetFileType_impl(module, handle); @@ -2160,19 +2772,63 @@ _winapi_CopyFile2(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyO static const char * const _keywords[] = {"existing_file_name", "new_file_name", "flags", "progress_routine", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, - .format = "O&O&k|O:CopyFile2", + .fname = "CopyFile2", .kwtuple = KWTUPLE, }; #undef KWTUPLE + PyObject *argsbuf[4]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3; LPCWSTR existing_file_name = NULL; LPCWSTR new_file_name = NULL; DWORD flags; PyObject *progress_routine = Py_None; - if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - _PyUnicode_WideCharString_Converter, &existing_file_name, _PyUnicode_WideCharString_Converter, &new_file_name, &flags, &progress_routine)) { + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 3, /*maxpos*/ 4, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("CopyFile2", "argument 'existing_file_name'", "str", args[0]); + goto exit; + } + existing_file_name = PyUnicode_AsWideCharString(args[0], NULL); + if (existing_file_name == NULL) { + goto exit; + } + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("CopyFile2", "argument 'new_file_name'", "str", args[1]); + goto exit; + } + new_file_name = PyUnicode_AsWideCharString(args[1], NULL); + if (new_file_name == NULL) { + goto exit; + } + if (!PyIndex_Check(args[2])) { + _PyArg_BadArgument("CopyFile2", "argument 'flags'", "int", args[2]); goto exit; } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[2], &flags, sizeof(DWORD), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(DWORD)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + if (!noptargs) { + goto skip_optional_pos; + } + progress_routine = args[3]; +skip_optional_pos: return_value = _winapi_CopyFile2_impl(module, existing_file_name, new_file_name, flags, progress_routine); exit: @@ -2274,7 +2930,8 @@ _winapi_DeregisterEventSource(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HANDLE handle; - if (!PyArg_Parse(arg, "" F_HANDLE ":DeregisterEventSource", &handle)) { + handle = PyLong_AsVoidPtr(arg); + if (!handle && PyErr_Occurred()) { goto exit; } return_value = _winapi_DeregisterEventSource_impl(module, handle); @@ -2318,8 +2975,28 @@ _winapi_ReportEvent(PyObject *module, PyObject *const *args, Py_ssize_t nargs) unsigned int event_id; LPCWSTR string = NULL; - if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "O&O&O&O&:ReportEvent", - &handle, _PyLong_UnsignedShort_Converter, &type, _PyLong_UnsignedShort_Converter, &category, _PyLong_UnsignedInt_Converter, &event_id, _PyUnicode_WideCharString_Converter, &string)) { + if (!_PyArg_CheckPositional("ReportEvent", nargs, 5, 5)) { + goto exit; + } + handle = PyLong_AsVoidPtr(args[0]); + if (!handle && PyErr_Occurred()) { + goto exit; + } + if (!_PyLong_UnsignedShort_Converter(args[1], &type)) { + goto exit; + } + if (!_PyLong_UnsignedShort_Converter(args[2], &category)) { + goto exit; + } + if (!_PyLong_UnsignedInt_Converter(args[3], &event_id)) { + goto exit; + } + if (!PyUnicode_Check(args[4])) { + _PyArg_BadArgument("ReportEvent", "argument 5", "str", args[4]); + goto exit; + } + string = PyUnicode_AsWideCharString(args[4], NULL); + if (string == NULL) { goto exit; } return_value = _winapi_ReportEvent_impl(module, handle, type, category, event_id, string); @@ -2349,7 +3026,8 @@ _winapi_GetProcessMemoryInfo(PyObject *module, PyObject *arg) PyObject *return_value = NULL; HANDLE handle; - if (!PyArg_Parse(arg, "" F_HANDLE ":GetProcessMemoryInfo", &handle)) { + handle = PyLong_AsVoidPtr(arg); + if (!handle && PyErr_Occurred()) { goto exit; } return_value = _winapi_GetProcessMemoryInfo_impl(module, handle); @@ -2379,4 +3057,4 @@ _winapi_GetTickCount64(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef _WINAPI_GETSHORTPATHNAME_METHODDEF #define _WINAPI_GETSHORTPATHNAME_METHODDEF #endif /* !defined(_WINAPI_GETSHORTPATHNAME_METHODDEF) */ -/*[clinic end generated code: output=713a8ce97185b017 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8173751196d44211 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index c9307a1c44d315c..6278eb81481402d 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -7,6 +7,7 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_fileutils.h" // _Py_Off_t_Converter() #include "pycore_long.h" // _PyLong_UnsignedInt_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() @@ -7761,7 +7762,7 @@ os_lockf(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (command == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[2], &length)) { + if (!_Py_Off_t_Converter(args[2], &length)) { goto exit; } return_value = os_lockf_impl(module, fd, command, length); @@ -7813,7 +7814,7 @@ os_lseek(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[1], &position)) { + if (!_Py_Off_t_Converter(args[1], &position)) { goto exit; } how = PyLong_AsInt(args[2]); @@ -8024,7 +8025,7 @@ os_pread(PyObject *module, PyObject *const *args, Py_ssize_t nargs) } length = ival; } - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } return_value = os_pread_impl(module, fd, length, offset); @@ -8084,7 +8085,7 @@ os_preadv(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } buffers = args[1]; - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } if (nargs < 4) { @@ -8223,10 +8224,10 @@ os_sendfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject if (in_fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } - if (!Py_off_t_converter(args[3], &sbytes)) { + if (!_Py_Off_t_Converter(args[3], &sbytes)) { goto exit; } if (!noptargs) { @@ -8328,7 +8329,7 @@ os_sendfile(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject if (in_fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } { @@ -8757,7 +8758,7 @@ os_pwrite(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (PyObject_GetBuffer(args[1], &buffer, PyBUF_SIMPLE) != 0) { goto exit; } - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } _return_value = os_pwrite_impl(module, fd, &buffer, offset); @@ -8830,7 +8831,7 @@ os_pwritev(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } buffers = args[1]; - if (!Py_off_t_converter(args[2], &offset)) { + if (!_Py_Off_t_Converter(args[2], &offset)) { goto exit; } if (nargs < 4) { @@ -9444,7 +9445,7 @@ os_ftruncate(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[1], &length)) { + if (!_Py_Off_t_Converter(args[1], &length)) { goto exit; } return_value = os_ftruncate_impl(module, fd, length); @@ -9516,7 +9517,7 @@ os_truncate(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject if (!path_converter(args[0], &path)) { goto exit; } - if (!Py_off_t_converter(args[1], &length)) { + if (!_Py_Off_t_Converter(args[1], &length)) { goto exit; } return_value = os_truncate_impl(module, &path, length); @@ -9564,10 +9565,10 @@ os_posix_fallocate(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[1], &offset)) { + if (!_Py_Off_t_Converter(args[1], &offset)) { goto exit; } - if (!Py_off_t_converter(args[2], &length)) { + if (!_Py_Off_t_Converter(args[2], &length)) { goto exit; } return_value = os_posix_fallocate_impl(module, fd, offset, length); @@ -9617,10 +9618,10 @@ os_posix_fadvise(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (fd == -1 && PyErr_Occurred()) { goto exit; } - if (!Py_off_t_converter(args[1], &offset)) { + if (!_Py_Off_t_Converter(args[1], &offset)) { goto exit; } - if (!Py_off_t_converter(args[2], &length)) { + if (!_Py_Off_t_Converter(args[2], &length)) { goto exit; } advice = PyLong_AsInt(args[3]); @@ -13746,4 +13747,4 @@ os__emscripten_log(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py #ifndef OS__EMSCRIPTEN_LOG_METHODDEF #define OS__EMSCRIPTEN_LOG_METHODDEF #endif /* !defined(OS__EMSCRIPTEN_LOG_METHODDEF) */ -/*[clinic end generated code: output=f77ed566165d51da input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a5bea01c02d27152 input=a9049054013a1b77]*/ diff --git a/Modules/clinic/resource.c.h b/Modules/clinic/resource.c.h index e4ef93900d17978..173e3f977721c27 100644 --- a/Modules/clinic/resource.c.h +++ b/Modules/clinic/resource.c.h @@ -120,7 +120,7 @@ resource_prlimit(PyObject *module, PyObject *const *args, Py_ssize_t nargs) goto exit; } pid = PyLong_AsPid(args[0]); - if (pid == -1 && PyErr_Occurred()) { + if (pid == (pid_t)(-1) && PyErr_Occurred()) { goto exit; } resource = PyLong_AsInt(args[1]); @@ -174,4 +174,4 @@ resource_getpagesize(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef RESOURCE_PRLIMIT_METHODDEF #define RESOURCE_PRLIMIT_METHODDEF #endif /* !defined(RESOURCE_PRLIMIT_METHODDEF) */ -/*[clinic end generated code: output=8e905b2f5c35170e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4044ef9ffbf7278b input=a9049054013a1b77]*/ diff --git a/Modules/overlapped.c b/Modules/overlapped.c index 255576cc057cdd4..646cb66605295e7 100644 --- a/Modules/overlapped.c +++ b/Modules/overlapped.c @@ -51,9 +51,6 @@ class pointer_converter(CConverter): class OVERLAPPED_converter(pointer_converter): type = 'OVERLAPPED *' -class HANDLE_converter(pointer_converter): - type = 'HANDLE' - class ULONG_PTR_converter(pointer_converter): type = 'ULONG_PTR' @@ -66,13 +63,8 @@ class ULONG_PTR_converter(pointer_converter): """, argname=argname) -class DWORD_converter(unsigned_long_converter): - type = 'DWORD' - -class BOOL_converter(int_converter): - type = 'BOOL' [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=436f4440630a304c]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=e3b1c126cba99725]*/ /*[clinic input] module _overlapped diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index bec305a4042c49d..a9375e48a11d899 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1702,25 +1702,6 @@ idtype_t_converter(PyObject *arg, void *addr) } #endif -#ifdef MS_WINDOWS - typedef long long Py_off_t; -#else - typedef off_t Py_off_t; -#endif - -static int -Py_off_t_converter(PyObject *arg, void *addr) -{ -#ifdef HAVE_LARGEFILE_SUPPORT - *((Py_off_t *)addr) = PyLong_AsLongLong(arg); -#else - *((Py_off_t *)addr) = PyLong_AsLong(arg); -#endif - if (PyErr_Occurred()) - return 0; - return 1; -} - static PyObject * PyLong_FromPy_off_t(Py_off_t offset) { @@ -3221,18 +3202,6 @@ class dev_t_return_converter(unsigned_long_return_converter): conversion_fn = '_PyLong_FromDev' unsigned_cast = '(dev_t)' -class pid_t_converter(CConverter): - type = 'pid_t' - format_unit = '" _Py_PARSE_PID "' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsPid({argname}); - if ({paramname} == (pid_t)(-1) && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, argname=argname) - class idtype_t_converter(CConverter): type = 'idtype_t' converter = 'idtype_t_converter' @@ -3261,10 +3230,6 @@ class intptr_t_converter(CConverter): }}}} """, argname=argname) -class Py_off_t_converter(CConverter): - type = 'Py_off_t' - converter = 'Py_off_t_converter' - class Py_off_t_return_converter(long_return_converter): type = 'Py_off_t' conversion_fn = 'PyLong_FromPy_off_t' @@ -3284,7 +3249,7 @@ class confname_converter(CConverter): """, argname=argname, converter=self.converter, table=self.table) [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=ddbf3ac90a981122]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=e459765bdf453ebf]*/ /*[clinic input] @@ -12642,7 +12607,7 @@ os_sendfile_impl(PyObject *module, int out_fd, int in_fd, PyObject *offobj, } #endif off_t offset; - if (!Py_off_t_converter(offobj, &offset)) + if (!_Py_Off_t_Converter(offobj, &offset)) return NULL; #if defined(__sun) && defined(__SVR4) @@ -13176,14 +13141,14 @@ os_copy_file_range_impl(PyObject *module, int src, int dst, Py_ssize_t count, if (offset_src != Py_None) { - if (!Py_off_t_converter(offset_src, &offset_src_val)) { + if (!_Py_Off_t_Converter(offset_src, &offset_src_val)) { return NULL; } p_offset_src = &offset_src_val; } if (offset_dst != Py_None) { - if (!Py_off_t_converter(offset_dst, &offset_dst_val)) { + if (!_Py_Off_t_Converter(offset_dst, &offset_dst_val)) { return NULL; } p_offset_dst = &offset_dst_val; @@ -13247,14 +13212,14 @@ os_splice_impl(PyObject *module, int src, int dst, Py_ssize_t count, if (offset_src != Py_None) { - if (!Py_off_t_converter(offset_src, &offset_src_val)) { + if (!_Py_Off_t_Converter(offset_src, &offset_src_val)) { return NULL; } p_offset_src = &offset_src_val; } if (offset_dst != Py_None) { - if (!Py_off_t_converter(offset_dst, &offset_dst_val)) { + if (!_Py_Off_t_Converter(offset_dst, &offset_dst_val)) { return NULL; } p_offset_dst = &offset_dst_val; diff --git a/Modules/resource.c b/Modules/resource.c index 9bf8d2782766ccb..614b05769869a1e 100644 --- a/Modules/resource.c +++ b/Modules/resource.c @@ -22,22 +22,6 @@ module resource [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e89d38ed52609d7c]*/ -/*[python input] -class pid_t_converter(CConverter): - type = 'pid_t' - format_unit = '" _Py_PARSE_PID "' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsPid({argname}); - if ({paramname} == -1 && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, - argname=argname) -[python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=c94349aa1aad151d]*/ - #include "clinic/resource.c.h" PyDoc_STRVAR(struct_rusage__doc__, diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 05c3e75b4642ee5..d5cdea1410b46aa 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -216,6 +216,17 @@ PyObject_AsFileDescriptor(PyObject *o) return fd; } +int +_Py_Off_t_Converter(PyObject *arg, void *addr) +{ +#ifdef HAVE_LARGEFILE_SUPPORT + *((Py_off_t *)addr) = PyLong_AsLongLong(arg); +#else + *((Py_off_t *)addr) = PyLong_AsLong(arg); +#endif + return PyErr_Occurred() ? 0 : 1; +} + int _PyLong_FileDescriptor_Converter(PyObject *o, void *ptr) { diff --git a/PC/_testconsole.c b/PC/_testconsole.c index 2538ae3ceba643d..76a4033bbbb1381 100644 --- a/PC/_testconsole.c +++ b/PC/_testconsole.c @@ -35,21 +35,6 @@ PyModuleDef_Slot testconsole_slots[] = { {0, NULL}, }; -/*[python input] -class HANDLE_converter(CConverter): - type = 'void *' - format_unit = '"_Py_PARSE_UINTPTR"' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsVoidPtr({argname}); - if (!{paramname} && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, - argname=argname) -[python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=380aa5c91076742b]*/ /*[python end generated code:]*/ /*[clinic input] diff --git a/PC/clinic/msvcrtmodule.c.h b/PC/clinic/msvcrtmodule.c.h index 647aadfa46bbed4..7a43daa987b2066 100644 --- a/PC/clinic/msvcrtmodule.c.h +++ b/PC/clinic/msvcrtmodule.c.h @@ -133,13 +133,13 @@ PyDoc_STRVAR(msvcrt_open_osfhandle__doc__, {"open_osfhandle", _PyCFunction_CAST(msvcrt_open_osfhandle), METH_FASTCALL, msvcrt_open_osfhandle__doc__}, static long -msvcrt_open_osfhandle_impl(PyObject *module, void *handle, int flags); +msvcrt_open_osfhandle_impl(PyObject *module, HANDLE handle, int flags); static PyObject * msvcrt_open_osfhandle(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - void *handle; + HANDLE handle; int flags; long _return_value; @@ -531,14 +531,14 @@ PyDoc_STRVAR(msvcrt_CrtSetReportFile__doc__, {"CrtSetReportFile", _PyCFunction_CAST(msvcrt_CrtSetReportFile), METH_FASTCALL, msvcrt_CrtSetReportFile__doc__}, static void * -msvcrt_CrtSetReportFile_impl(PyObject *module, int type, void *file); +msvcrt_CrtSetReportFile_impl(PyObject *module, int type, HANDLE file); static PyObject * msvcrt_CrtSetReportFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; int type; - void *file; + HANDLE file; void *_return_value; if (!_PyArg_CheckPositional("CrtSetReportFile", nargs, 2, 2)) { @@ -743,4 +743,4 @@ msvcrt_SetErrorMode(PyObject *module, PyObject *arg) #ifndef MSVCRT_GETERRORMODE_METHODDEF #define MSVCRT_GETERRORMODE_METHODDEF #endif /* !defined(MSVCRT_GETERRORMODE_METHODDEF) */ -/*[clinic end generated code: output=f67eaf745685429d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=58c1771c8b9a209b input=a9049054013a1b77]*/ diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c index 26d7547c387f5f8..868650dd31d9a1b 100644 --- a/PC/msvcrtmodule.c +++ b/PC/msvcrtmodule.c @@ -34,19 +34,6 @@ #endif /*[python input] -class HANDLE_converter(CConverter): - type = 'void *' - format_unit = '"_Py_PARSE_UINTPTR"' - - def parse_arg(self, argname, displayname, *, limited_capi): - return self.format_code(""" - {paramname} = PyLong_AsVoidPtr({argname}); - if (!{paramname} && PyErr_Occurred()) {{{{ - goto exit; - }}}} - """, - argname=argname) - class HANDLE_return_converter(CReturnConverter): type = 'void *' @@ -76,7 +63,7 @@ class wchar_t_return_converter(CReturnConverter): f'{data.parser_retval} = ' f'PyUnicode_FromOrdinal({data.converter_retval});\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=ed7a4a045a6d0496]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=f61ae699a69482ba]*/ /*[clinic input] module msvcrt @@ -185,8 +172,8 @@ to os.fdopen() to create a file object. [clinic start generated code]*/ static long -msvcrt_open_osfhandle_impl(PyObject *module, void *handle, int flags) -/*[clinic end generated code: output=b2fb97c4b515e4e6 input=d5db190a307cf4bb]*/ +msvcrt_open_osfhandle_impl(PyObject *module, HANDLE handle, int flags) +/*[clinic end generated code: output=646759b9fd02ca7b input=d5db190a307cf4bb]*/ { if (PySys_Audit("msvcrt.open_osfhandle", "Ki", handle, flags) < 0) { return -1; @@ -460,8 +447,8 @@ Only available on Debug builds. [clinic start generated code]*/ static void * -msvcrt_CrtSetReportFile_impl(PyObject *module, int type, void *file) -/*[clinic end generated code: output=9393e8c77088bbe9 input=290809b5f19e65b9]*/ +msvcrt_CrtSetReportFile_impl(PyObject *module, int type, HANDLE file) +/*[clinic end generated code: output=55858e446d583c5f input=290809b5f19e65b9]*/ { HANDLE res; diff --git a/PC/winreg.c b/PC/winreg.c index 26bcd259efd9879..1fe5020419c3dac 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -238,9 +238,6 @@ class winreg.HKEYType "PyHKEYObject *" "&PyHKEY_Type" class REGSAM_converter(int_converter): type = 'REGSAM' -class DWORD_converter(unsigned_long_converter): - type = 'DWORD' - class HKEY_converter(CConverter): type = 'HKEY' converter = 'clinic_HKEY_converter' @@ -265,7 +262,7 @@ class HKEY_return_converter(CReturnConverter): data.return_conversion.append( 'return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=b34c8217647f5fef]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=e345501438d93fa2]*/ #include "clinic/winreg.c.h" diff --git a/Tools/clinic/libclinic/converter.py b/Tools/clinic/libclinic/converter.py index c10235237d4b716..29cbad4d5a84c42 100644 --- a/Tools/clinic/libclinic/converter.py +++ b/Tools/clinic/libclinic/converter.py @@ -44,7 +44,10 @@ def add_default_legacy_c_converter(cls: CConverterClassT) -> CConverterClassT: # automatically add converter for default format unit # (but without stomping on the existing one if it's already # set, in case you subclass) + # A format unit which contains a quote is a C expression, not a legacy + # format unit which can be used as an annotation. if ((cls.format_unit not in ('O&', '')) and + ('"' not in cls.format_unit) and (cls.format_unit not in legacy_converters)): legacy_converters[cls.format_unit] = cls return cls diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 5539bd2e12e35f5..c2ac6fd22d5bdc9 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -601,6 +601,50 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st argname=argname) +class pid_t_converter(CConverter): + type = 'pid_t' + format_unit = '" _Py_PARSE_PID "' + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + return self.format_code(""" + {paramname} = PyLong_AsPid({argname}); + if ({paramname} == (pid_t)(-1) && PyErr_Occurred()) {{{{ + goto exit; + }}}} + """, + argname=argname) + + +class Py_off_t_converter(CConverter): + type = 'Py_off_t' + converter = '_Py_Off_t_Converter' + + def use_converter(self) -> None: + self.add_include('pycore_fileutils.h', '_Py_Off_t_Converter()') + + +class BOOL_converter(int_converter): + type = 'BOOL' + + +class DWORD_converter(unsigned_long_converter): + type = 'DWORD' + + +class HANDLE_converter(CConverter): + type = 'HANDLE' + format_unit = '"_Py_PARSE_UINTPTR"' + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + return self.format_code(""" + {paramname} = PyLong_AsVoidPtr({argname}); + if (!{paramname} && PyErr_Occurred()) {{{{ + goto exit; + }}}} + """, + argname=argname) + + class float_converter(CConverter): type = 'float' default_type = float From ca79981cc08f23990e2f00d78d84681e40f369bd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Aug 2026 19:53:59 +0300 Subject: [PATCH 4/4] gh-156230: Bound a curses window read by the window, not by 2047 (GH-156282) instr(), in_wstr() and in_wchstr() clamped the count to 2047 and silently truncated a longer line, which a pad can have. A window read cannot return more than the columns left on the line, in the unit each method counts: cells, characters, or bytes at CCHARW_MAX characters of MB_CUR_MAX bytes per cell. Cap the count by that, and read the rest of the line when the count is omitted, which it now can be. getstr() and get_wstr() read the keyboard rather than the window, so their limit stays. --- Doc/library/curses.rst | 15 +- Lib/test/test_curses.py | 34 ++++ ...-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst | 3 + Modules/_cursesmodule.c | 157 +++++++++++------- Modules/clinic/_cursesmodule.c.h | 109 +++++++----- 5 files changed, 208 insertions(+), 110 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index d6bccbb730f8b4a..858371f927f4fad 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1404,26 +1404,29 @@ Reading window contents window.instr(y, x[, n]) Read the text of the window from the current cursor position, - or from *y*, *x* if specified, to the end of the line, + or from *y*, *x* if specified, to the end of the line + or at most *n* bytes if *n* is specified, and return it as a bytes object, in the encoding of the current locale. Attributes and color pairs are stripped; use :meth:`in_wchstr` to read them too. - At most *n* bytes are read; *n* defaults to and cannot exceed 2047. A character not representable in the encoding cannot be returned; use :meth:`in_wstr` for those. .. versionchanged:: 3.14 The maximum value for *n* was increased from 1023 to 2047. + .. versionchanged:: next + *n* is no longer limited to 2047. + .. method:: window.in_wstr([n]) window.in_wstr(y, x[, n]) Read the text of the window from the current cursor position, - or from *y*, *x* if specified, to the end of the line, + or from *y*, *x* if specified, to the end of the line + or at most *n* characters if *n* is specified, and return it as a :class:`str`. Attributes and color pairs are stripped; use :meth:`in_wchstr` to read them too. - At most *n* characters are read; *n* defaults to and cannot exceed 2047. This is the wide-character variant of :meth:`instr`. @@ -1433,12 +1436,12 @@ Reading window contents window.in_wchstr(y, x[, n]) Read the styled cells of the window from the current cursor position, - or from *y*, *x* if specified, to the end of the line, + or from *y*, *x* if specified, to the end of the line + or at most *n* cells if *n* is specified, and return them as a :class:`complexstr`. Unlike :meth:`instr` and :meth:`in_wstr`, each cell keeps its attributes and color pair, so the result can be written back unchanged with :meth:`addstr`. - At most *n* cells are read; *n* defaults to and cannot exceed 2047. .. versionadded:: next diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index ea2dcd76b585a99..630de544a457f40 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -672,6 +672,11 @@ def test_in_wstr(self): stdscr.addstr(0, 0, 'abz') self.assertEqual(stdscr.in_wstr(0, 0, 0), '') self.assertEqual(stdscr.in_wstr(0), '') + self.assertEqual(stdscr.in_wstr(0, 0, 2**31), stdscr.in_wstr(0, 0)) + self.assertRaises(OverflowError, stdscr.in_wstr, 2**1000) + self.assertRaises(ValueError, stdscr.in_wstr, -2) + self.assertRaises(ValueError, stdscr.in_wstr, 0, 2, -2) + self.assertRaises(ValueError, stdscr.in_wstr, -2**1000) def test_complexchar(self): # A complexchar is a styled wide-character cell: str() is its text, @@ -871,6 +876,11 @@ def test_in_wchstr(self): # The count is optional and reads to the end of the line by default. stdscr.move(0, 0) self.assertEqual(str(stdscr.in_wchstr())[:3], 'AbC') + self.assertEqual(stdscr.in_wchstr(0, 0, 2**31), stdscr.in_wchstr(0, 0)) + self.assertRaises(OverflowError, stdscr.in_wchstr, 2**1000) + self.assertRaises(ValueError, stdscr.in_wchstr, -2) + self.assertRaises(ValueError, stdscr.in_wchstr, 0, 2, -2) + self.assertRaises(ValueError, stdscr.in_wchstr, -2**1000) def test_complexstr_in_write_methods(self): # addstr/addnstr/insstr/insnstr also accept a complexstr, written via @@ -1188,8 +1198,13 @@ def test_read_from_window(self): self.assertEqual(stdscr.instr(3)[:6], b' AB') self.assertEqual(stdscr.instr(0, 2)[:4], b'BCD ') self.assertEqual(stdscr.instr(0, 2, 4), b'BCD ') + # A huge count is bounded by the line, and is not used to size the + # read buffer. + self.assertEqual(stdscr.instr(0, 0, 2**31), stdscr.instr(0, 0)) + self.assertRaises(OverflowError, stdscr.instr, 2**1000) self.assertRaises(ValueError, stdscr.instr, -2) self.assertRaises(ValueError, stdscr.instr, 0, 2, -2) + self.assertRaises(ValueError, stdscr.instr, -2**1000) # instr(y, x, 1) reads a single cell byte, so only a character that the # window encoding maps to one byte is checked. inch() returns the cell # value, which is the locale byte. @@ -1206,6 +1221,25 @@ def test_read_from_window(self): self.assertEqual(stdscr.instr(2, 0, 1), b) self.assertEqual(stdscr.inch(2, 0), v) + def test_read_long_line(self): + # A pad line can be longer than a window, and a character can be + # encoded with several bytes, so instr() can read more bytes than + # there are cells. See _encodable for the character set. + width = 3000 + pad = curses.newpad(1, width) + for ch in ['z', '\u00e9', '\u20ac', '\u0434', '\uff71']: + if not self._storable(ch): + continue + pad.addstr(0, 0, ch) + if pad.getyx()[1] != 1: + continue # a wide character occupies two cells + with self.subTest(ch=ch): + line = ch * (width - 1) + ' ' # the last cell is left blank + pad.addstr(0, 0, line[:-1]) + self.assertEqual(pad.instr(0, 0), line.encode(pad.encoding)) + self.assertEqual(pad.in_wstr(0, 0), line) + self.assertEqual(str(pad.in_wchstr(0, 0)), line) + def test_coordinate_errors(self): # Addressing a cell outside the window raises curses.error. win = curses.newwin(5, 10, 0, 0) diff --git a/Misc/NEWS.d/next/Library/2026-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst b/Misc/NEWS.d/next/Library/2026-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst new file mode 100644 index 000000000000000..3b9b41c389580e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst @@ -0,0 +1,3 @@ +:meth:`curses.window.instr`, :meth:`~curses.window.in_wstr` and +:meth:`~curses.window.in_wchstr` no longer limit the count to 2047, which +silently truncated a longer line. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 45ba6476bbc4a60..12d7664b395967b 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -3535,6 +3535,29 @@ _curses_window_get_wch_impl(PyCursesWindowObject *self, int group_right_1, #endif } +/* Characters one cell can hold. */ +#ifdef HAVE_NCURSESW +#define CURSES_CELL_CHARS CCHARW_MAX +#else +#define CURSES_CELL_CHARS 1 +#endif + +/* The columns left on the line, in the unit the caller counts. */ +static unsigned int +curses_window_read_limit(PyCursesWindowObject *self, int use_xy, int x, + unsigned int per_cell) +{ + int col = use_xy ? x : getcurx(self->win); + int maxx = getmaxx(self->win); + if (col < 0) { + col = 0; + } + if (col > maxx) { + return 0; + } + return ((unsigned int)(maxx - col) + 1) * per_cell; +} + /* Read user input into a new bytes object (empty on ERR), with primitive line editing. Shared by getstr() and, without the wide library, by get_wstr(). */ static PyObject * @@ -3828,15 +3851,15 @@ _curses_window_inch_impl(PyCursesWindowObject *self, int group_right_1, with attributes and color stripped. Shared by instr() and, without the wide library, by in_wstr(). */ static PyObject * -curses_window_instr_bytes(PyCursesWindowObject *self, int use_xy, +curses_window_instr_bytes(PyCursesWindowObject *self, int use_xy, int use_n, int y, int x, unsigned int n) { int rtn; - unsigned int max_buf_size = 2048; - - n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); - n += CURSES_STR_EXTRA; - PyBytesWriter *writer = PyBytesWriter_Create(n + 1); + unsigned int limit = curses_window_read_limit(self, use_xy, x, + CURSES_CELL_CHARS + * (unsigned int)MB_CUR_MAX); + unsigned int nread = use_n ? Py_MIN(n, limit) : limit; + PyBytesWriter *writer = PyBytesWriter_Create(nread + CURSES_STR_EXTRA + 1); if (writer == NULL) { return NULL; } @@ -3844,14 +3867,14 @@ curses_window_instr_bytes(PyCursesWindowObject *self, int use_xy, /* Read again if the library stored more than asked: truncating could split a multibyte character. */ - for (unsigned int want = n - CURSES_STR_EXTRA; ; n = want) { + for (unsigned int ask = nread + CURSES_STR_EXTRA; ; ask = nread) { if (use_xy) { - rtn = mvwinnstr(self->win, y, x, buf, n); + rtn = mvwinnstr(self->win, y, x, buf, ask); } else { - rtn = winnstr(self->win, buf, n); + rtn = winnstr(self->win, buf, ask); } - if (rtn == ERR || (unsigned int)rtn <= want) { + if (rtn == ERR || (unsigned int)rtn <= nread) { break; } } @@ -3872,24 +3895,27 @@ _curses.window.instr x: int X-coordinate. ] - n: unsigned_int = 2047 - Maximal number of bytes. + [ + n: unsigned_int + Maximal number of bytes. The rest of the line by default. + ] / Return the text of the window as a bytes object. Read from the current cursor position, or from y, x if specified, to -the end of the line, and return the text in the encoding of the -current locale, with attributes and color pairs stripped. At most n -bytes are read. +the end of the line or at most n bytes if n is specified, and return +the text in the encoding of the current locale, with attributes and +color pairs stripped. [clinic start generated code]*/ static PyObject * -_curses_window_instr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n) -/*[clinic end generated code: output=40081f67070132da input=4ece6af75b09346f]*/ +_curses_window_instr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, unsigned int n) +/*[clinic end generated code: output=2428948b44ad10c7 input=9307eca4bd576899]*/ { - return curses_window_instr_bytes(self, group_left_1, y, x, n); + return curses_window_instr_bytes(self, group_right_1, group_right_2, + y, x, n); } /*[clinic input] @@ -3987,44 +4013,45 @@ _curses.window.in_wstr x: int X-coordinate. ] - n: unsigned_int = 2047 - Maximal number of characters. + [ + n: unsigned_int + Maximal number of characters. The rest of the line by default. + ] / Return the text of the window as a str. This is the wide-character variant of instr(). Read from the current cursor position, or from y, x if specified, to the end of -the line, with attributes and color pairs stripped. At most n -characters are read. +the line or at most n characters if n is specified, with attributes +and color pairs stripped. [clinic start generated code]*/ static PyObject * -_curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n) -/*[clinic end generated code: output=e3db72a1f10b9875 input=436737264c54d8d3]*/ +_curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, unsigned int n) +/*[clinic end generated code: output=d8c8bcfe8a26f519 input=5ba908338a94bfc8]*/ { #ifdef HAVE_NCURSESW int rtn; - unsigned int max_buf_size = 2048; - - n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); - n += CURSES_STR_EXTRA; - wchar_t *buf = PyMem_New(wchar_t, n + 1); + unsigned int limit = curses_window_read_limit(self, group_right_1, x, + CURSES_CELL_CHARS); + unsigned int nread = group_right_2 ? Py_MIN(n, limit) : limit; + wchar_t *buf = PyMem_New(wchar_t, nread + CURSES_STR_EXTRA + 1); if (buf == NULL) { return PyErr_NoMemory(); } /* Read again if the library stored more than asked: truncating could separate a combining character from its base. */ - for (unsigned int want = n - CURSES_STR_EXTRA; ; n = want) { - if (group_left_1) { - rtn = mvwinnwstr(self->win, y, x, buf, n); + for (unsigned int ask = nread + CURSES_STR_EXTRA; ; ask = nread) { + if (group_right_1) { + rtn = mvwinnwstr(self->win, y, x, buf, ask); } else { - rtn = winnwstr(self->win, buf, n); + rtn = winnwstr(self->win, buf, ask); } - if (rtn == ERR || (unsigned int)rtn <= want) { + if (rtn == ERR || (unsigned int)rtn <= nread) { break; } } @@ -4039,7 +4066,8 @@ _curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, #else /* Without the wide library, read the bytes as instr() does and decode them with the window's encoding. */ - PyObject *bytes = curses_window_instr_bytes(self, group_left_1, y, x, n); + PyObject *bytes = curses_window_instr_bytes(self, group_right_1, + group_right_2, y, x, n); if (bytes == NULL) { return NULL; } @@ -4060,43 +4088,46 @@ _curses.window.in_wchstr x: int X-coordinate. ] - n: unsigned_int = 2047 - Maximal number of cells. + [ + n: unsigned_int + Maximal number of cells. The rest of the line by default. + ] / Return the styled cells of the window as a complexstr. -Read from the current cursor position, or from y, x if specified, to -the end of the line. Unlike instr() and in_wstr(), each cell keeps -its attributes and color pair, so the result can be written back -unchanged with addstr(). At most n cells are read. +Read from the current cursor position, or from y, x if specified, +to the end of the line or at most n cells if n is specified. +Unlike instr() and in_wstr(), each cell keeps its attributes and +color pair, so the result can be written back unchanged with +addstr(). [clinic start generated code]*/ static PyObject * -_curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n) -/*[clinic end generated code: output=7fb5216f2088835b input=8104e661c3cb7fea]*/ +_curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, + unsigned int n) +/*[clinic end generated code: output=3807a62d51efd44f input=50400321de1db1da]*/ { int rtn; - unsigned int max_buf_size = 2048; - - n = Py_MIN(n, max_buf_size - 1 - CURSES_STR_EXTRA); - n += CURSES_STR_EXTRA; + unsigned int limit = curses_window_read_limit(self, group_right_1, x, 1); + unsigned int nread = group_right_2 ? Py_MIN(n, limit) : limit; + unsigned int ask = nread + CURSES_STR_EXTRA; cursesmodule_state *state = get_cursesmodule_state_by_win(self); /* Zero the cells: reading a cell back through getcchar() relies on the cchar_t text array being NUL-terminated, which some curses libraries only guarantee for the characters they actually write. */ - curses_cell_t *buf = PyMem_Calloc(n + 1, sizeof(curses_cell_t)); + curses_cell_t *buf = PyMem_Calloc(ask + 1, sizeof(curses_cell_t)); if (buf == NULL) { return PyErr_NoMemory(); } #ifdef HAVE_NCURSESW - if (group_left_1) { - rtn = mvwin_wchnstr(self->win, y, x, buf, n); + if (group_right_1) { + rtn = mvwin_wchnstr(self->win, y, x, buf, ask); } else { - rtn = win_wchnstr(self->win, buf, n); + rtn = win_wchnstr(self->win, buf, ask); } if (rtn == ERR) { @@ -4104,12 +4135,11 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, return PyCursesComplexStr_New(state, NULL, 0); } - n -= CURSES_STR_EXTRA; - /* win_wchnstr() stores at most n cells and zero-terminates the array at - the actual count; every real cell holds at least a space, so the first + /* win_wchnstr() stores at most nread cells and zero-terminates the array + at the actual count; every real cell holds at least a space, so the first empty cell marks the end of the run. */ Py_ssize_t count = 0; - while (count < (Py_ssize_t)n) { + while (count < (Py_ssize_t)nread) { wchar_t wstr[CCHARW_MAX + 1]; attr_t attrs; int pair; @@ -4124,12 +4154,12 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, /* winchnstr() is not guaranteed (SVr4) to terminate the array, so pre-zero it and stop at the first empty cell; a painted cell always holds at least a space, never 0. */ - memset(buf, 0, ((size_t)n + 1) * sizeof(curses_cell_t)); - if (group_left_1) { - rtn = mvwinchnstr(self->win, y, x, buf, n); + memset(buf, 0, ((size_t)ask + 1) * sizeof(curses_cell_t)); + if (group_right_1) { + rtn = mvwinchnstr(self->win, y, x, buf, ask); } else { - rtn = winchnstr(self->win, buf, n); + rtn = winchnstr(self->win, buf, ask); } if (rtn == ERR) { @@ -4137,9 +4167,8 @@ _curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, return PyCursesComplexStr_New(state, NULL, 0); } - n -= CURSES_STR_EXTRA; Py_ssize_t count = 0; - while (count < (Py_ssize_t)n && buf[count] != 0) { + while (count < (Py_ssize_t)nread && buf[count] != 0) { count++; } #endif diff --git a/Modules/clinic/_cursesmodule.c.h b/Modules/clinic/_cursesmodule.c.h index 61c324e04c5bdcf..44cb16d55fa330c 100644 --- a/Modules/clinic/_cursesmodule.c.h +++ b/Modules/clinic/_cursesmodule.c.h @@ -1721,7 +1721,7 @@ _curses_window_inch(PyObject *self, PyObject *args) } PyDoc_STRVAR(_curses_window_instr__doc__, -"instr([y, x,] n=2047)\n" +"instr([y, x,] [n])\n" "Return the text of the window as a bytes object.\n" "\n" " y\n" @@ -1729,48 +1729,57 @@ PyDoc_STRVAR(_curses_window_instr__doc__, " x\n" " X-coordinate.\n" " n\n" -" Maximal number of bytes.\n" +" Maximal number of bytes. The rest of the line by default.\n" "\n" "Read from the current cursor position, or from y, x if specified, to\n" -"the end of the line, and return the text in the encoding of the\n" -"current locale, with attributes and color pairs stripped. At most n\n" -"bytes are read."); +"the end of the line or at most n bytes if n is specified, and return\n" +"the text in the encoding of the current locale, with attributes and\n" +"color pairs stripped."); #define _CURSES_WINDOW_INSTR_METHODDEF \ {"instr", (PyCFunction)_curses_window_instr, METH_VARARGS, _curses_window_instr__doc__}, static PyObject * -_curses_window_instr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n); +_curses_window_instr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, unsigned int n); static PyObject * _curses_window_instr(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - int group_left_1 = 0; + int group_right_1 = 0; int y = 0; int x = 0; - unsigned int n = 2047; + int group_right_2 = 0; + unsigned int n = 0; switch (PyTuple_GET_SIZE(args)) { case 0: + break; case 1: - if (!PyArg_ParseTuple(args, "|O&:instr", _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "O&:instr", _PyLong_UnsignedInt_Converter, &n)) { goto exit; } + group_right_2 = 1; break; case 2: + if (!PyArg_ParseTuple(args, "ii:instr", &y, &x)) { + goto exit; + } + group_right_1 = 1; + break; case 3: - if (!PyArg_ParseTuple(args, "ii|O&:instr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "iiO&:instr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { goto exit; } - group_left_1 = 1; + group_right_1 = 1; + group_right_2 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.instr requires 0 to 3 arguments"); goto exit; } - return_value = _curses_window_instr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); + return_value = _curses_window_instr_impl((PyCursesWindowObject *)self, group_right_1, y, x, group_right_2, n); exit: return return_value; @@ -1832,7 +1841,7 @@ _curses_window_get_wstr(PyObject *self, PyObject *args) } PyDoc_STRVAR(_curses_window_in_wstr__doc__, -"in_wstr([y, x,] n=2047)\n" +"in_wstr([y, x,] [n])\n" "Return the text of the window as a str.\n" "\n" " y\n" @@ -1840,55 +1849,64 @@ PyDoc_STRVAR(_curses_window_in_wstr__doc__, " x\n" " X-coordinate.\n" " n\n" -" Maximal number of characters.\n" +" Maximal number of characters. The rest of the line by default.\n" "\n" "This is the wide-character variant of instr(). Read from the\n" "current cursor position, or from y, x if specified, to the end of\n" -"the line, with attributes and color pairs stripped. At most n\n" -"characters are read."); +"the line or at most n characters if n is specified, with attributes\n" +"and color pairs stripped."); #define _CURSES_WINDOW_IN_WSTR_METHODDEF \ {"in_wstr", (PyCFunction)_curses_window_in_wstr, METH_VARARGS, _curses_window_in_wstr__doc__}, static PyObject * -_curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n); +_curses_window_in_wstr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, unsigned int n); static PyObject * _curses_window_in_wstr(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - int group_left_1 = 0; + int group_right_1 = 0; int y = 0; int x = 0; - unsigned int n = 2047; + int group_right_2 = 0; + unsigned int n = 0; switch (PyTuple_GET_SIZE(args)) { case 0: + break; case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wstr", _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "O&:in_wstr", _PyLong_UnsignedInt_Converter, &n)) { goto exit; } + group_right_2 = 1; break; case 2: + if (!PyArg_ParseTuple(args, "ii:in_wstr", &y, &x)) { + goto exit; + } + group_right_1 = 1; + break; case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "iiO&:in_wstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { goto exit; } - group_left_1 = 1; + group_right_1 = 1; + group_right_2 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.in_wstr requires 0 to 3 arguments"); goto exit; } - return_value = _curses_window_in_wstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); + return_value = _curses_window_in_wstr_impl((PyCursesWindowObject *)self, group_right_1, y, x, group_right_2, n); exit: return return_value; } PyDoc_STRVAR(_curses_window_in_wchstr__doc__, -"in_wchstr([y, x,] n=2047)\n" +"in_wchstr([y, x,] [n])\n" "Return the styled cells of the window as a complexstr.\n" "\n" " y\n" @@ -1896,48 +1914,59 @@ PyDoc_STRVAR(_curses_window_in_wchstr__doc__, " x\n" " X-coordinate.\n" " n\n" -" Maximal number of cells.\n" +" Maximal number of cells. The rest of the line by default.\n" "\n" -"Read from the current cursor position, or from y, x if specified, to\n" -"the end of the line. Unlike instr() and in_wstr(), each cell keeps\n" -"its attributes and color pair, so the result can be written back\n" -"unchanged with addstr(). At most n cells are read."); +"Read from the current cursor position, or from y, x if specified,\n" +"to the end of the line or at most n cells if n is specified.\n" +"Unlike instr() and in_wstr(), each cell keeps its attributes and\n" +"color pair, so the result can be written back unchanged with\n" +"addstr()."); #define _CURSES_WINDOW_IN_WCHSTR_METHODDEF \ {"in_wchstr", (PyCFunction)_curses_window_in_wchstr, METH_VARARGS, _curses_window_in_wchstr__doc__}, static PyObject * -_curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_left_1, - int y, int x, unsigned int n); +_curses_window_in_wchstr_impl(PyCursesWindowObject *self, int group_right_1, + int y, int x, int group_right_2, + unsigned int n); static PyObject * _curses_window_in_wchstr(PyObject *self, PyObject *args) { PyObject *return_value = NULL; - int group_left_1 = 0; + int group_right_1 = 0; int y = 0; int x = 0; - unsigned int n = 2047; + int group_right_2 = 0; + unsigned int n = 0; switch (PyTuple_GET_SIZE(args)) { case 0: + break; case 1: - if (!PyArg_ParseTuple(args, "|O&:in_wchstr", _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "O&:in_wchstr", _PyLong_UnsignedInt_Converter, &n)) { goto exit; } + group_right_2 = 1; break; case 2: + if (!PyArg_ParseTuple(args, "ii:in_wchstr", &y, &x)) { + goto exit; + } + group_right_1 = 1; + break; case 3: - if (!PyArg_ParseTuple(args, "ii|O&:in_wchstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { + if (!PyArg_ParseTuple(args, "iiO&:in_wchstr", &y, &x, _PyLong_UnsignedInt_Converter, &n)) { goto exit; } - group_left_1 = 1; + group_right_1 = 1; + group_right_2 = 1; break; default: PyErr_SetString(PyExc_TypeError, "_curses.window.in_wchstr requires 0 to 3 arguments"); goto exit; } - return_value = _curses_window_in_wchstr_impl((PyCursesWindowObject *)self, group_left_1, y, x, n); + return_value = _curses_window_in_wchstr_impl((PyCursesWindowObject *)self, group_right_1, y, x, group_right_2, n); exit: return return_value; @@ -6603,4 +6632,4 @@ _curses_has_extended_color_support(PyObject *module, PyObject *Py_UNUSED(ignored #ifndef _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #define _CURSES_ASSUME_DEFAULT_COLORS_METHODDEF #endif /* !defined(_CURSES_ASSUME_DEFAULT_COLORS_METHODDEF) */ -/*[clinic end generated code: output=5616d0371c2240be input=a9049054013a1b77]*/ +/*[clinic end generated code: output=81cb3f7a7225f920 input=a9049054013a1b77]*/