gh-156230: Bound a curses window read by the window, not by 2047 (GH-156282)
serhiy-storchaka <[email protected]>
| Newsgroups | gmane.comp.python.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/python/cpython/commit/ca79981cc08f23990e2f00d78d84681e40f369bd commit: ca79981cc08f23990e2f00d78d84681e40f369bd branch: main author: Serhiy Storchaka <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-08-23T19:53:59+03:00 summary: 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. files: A Misc/NEWS.d/next/Library/2026-08-22-14-12-40.gh-issue-156230.Lt9wQd.rst M Doc/library/curses.rst M Lib/test/test_curses.py M Modules/_cursesmodule.c M Modules/clinic/_cursesmodule.c.h diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index d6bccbb730f8b4..858371f927f4fa 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 ea2dcd76b585a9..630de544a457f4 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 00000000000000..3b9b41c389580e --- /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 45ba6476bbc4a6..12d7664b395967 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 61c324e04c5bdc..44cb16d55fa330 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]*/ _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]