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]

Reply via email to