From 78aaac7ab140c034a2c8ee99fb7163f74229b0a1 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Mon, 7 Dec 2020 18:58:53 -0600 Subject: [PATCH 1/9] Add termios.tcgetwinsize(), termios.tcsetwinsize(). Update docs. Signed-off-by: Soumendra Ganguly --- Doc/library/termios.rst | 13 +++++++ Modules/termios.c | 86 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index d75a87c55a46ec..27c253e757c0bd 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -74,6 +74,19 @@ The module defines the following functions: output, :const:`TCIOFF` to suspend input, or :const:`TCION` to restart input. +.. function:: tcgetwinsize(fd) + + Return a list ``[ws_row, ws_col]`` containing the tty window size for file + descriptor *fd*. Requires :const:`termios.TIOCGWINSZ`. + + +.. function:: tcsetwinsize(fd, winsize) + + Set the tty window size for file descriptor *fd* from *winsize*, which is + a list like the one returned by :func:`tcgetwinsize`. Requires + :const:`termios.TIOCSWINSZ`. + + .. seealso:: Module :mod:`tty` diff --git a/Modules/termios.c b/Modules/termios.c index a6649598ec1710..ef9b141c15bbd6 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -315,6 +315,90 @@ termios_tcflow_impl(PyObject *module, int fd, int action) Py_RETURN_NONE; } +/*[clinic input] +termios.tcgetwinsize + + fd: fildes + / + +Get the tty winsize for file descriptor fd. + +Returns a list [ws_row, ws_col]. +[clinic start generated code]*/ + +static PyObject * +termios_tcgetwinsize_impl(PyObject *module, int fd) +/*[clinic end generated code: output=31825977d5325fb6 input=c7ed8aa957d108c0]*/ +{ +#if defined(TIOCGWINSZ) + termiosmodulestate *state = PyModule_GetState(module); + struct winsize w; + if (ioctl(fd, TIOCGWINSZ, &w) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } + + PyObject *v; + if (!(v = PyList_New(2))) { + return NULL; + } + + PyList_SetItem(v, 0, PyLong_FromLong((long)w.ws_row)); + PyList_SetItem(v, 1, PyLong_FromLong((long)w.ws_col)); + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + return v; +#else + PyErr_SetString(PyExc_NotImplementedError, "termios.TIOCGWINSZ undefined"); + return NULL; +#endif /* TIOCGWINSZ */ +} + +/*[clinic input] +termios.tcsetwinsize + + fd: fildes + winsize as winsz: object + / + +Set the tty winsize for file descriptor fd. + +The winsize to be set is taken from the winsize argument, which +is a list like the one returned by tcgetwinsize(). +[clinic start generated code]*/ + +static PyObject * +termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) +/*[clinic end generated code: output=2ac3c9bb6eda83e1 input=c495180b2b932a30]*/ +{ +#if defined(TIOCSWINSZ) + if (!PyList_Check(winsz) || PyList_Size(winsz) != 2) { + PyErr_SetString(PyExc_TypeError, + "tcsetwinsize, arg 2: must be 2 element list"); + return NULL; + } + + termiosmodulestate *state = PyModule_GetState(module); + struct winsize w; + + w.ws_row = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 0)); + w.ws_col = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 1)); + if (PyErr_Occurred()) { + return NULL; + } + + if (ioctl(fd, TIOCSWINSZ, &w) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } + + Py_RETURN_NONE; +#else + PyErr_SetString(PyExc_NotImplementedError, "termios.TIOCSWINSZ undefined"); + return NULL; +#endif /* TIOCSWINSZ */ +} + static PyMethodDef termios_methods[] = { TERMIOS_TCGETATTR_METHODDEF @@ -323,6 +407,8 @@ static PyMethodDef termios_methods[] = TERMIOS_TCDRAIN_METHODDEF TERMIOS_TCFLUSH_METHODDEF TERMIOS_TCFLOW_METHODDEF + TERMIOS_TCGETWINSIZE_METHODDEF + TERMIOS_TCSETWINSIZE_METHODDEF {NULL, NULL} }; From 0553063d77dcd4ddd19406e664bff1757c9af913 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Mon, 7 Dec 2020 19:14:03 -0600 Subject: [PATCH 2/9] Add news, clinic generated code. Signed-off-by: Soumendra Ganguly --- .../2020-12-08-01-08-58.bpo-41818.zO8vV7.rst | 1 + Modules/clinic/termios.c.h | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-08-01-08-58.bpo-41818.zO8vV7.rst diff --git a/Misc/NEWS.d/next/Library/2020-12-08-01-08-58.bpo-41818.zO8vV7.rst b/Misc/NEWS.d/next/Library/2020-12-08-01-08-58.bpo-41818.zO8vV7.rst new file mode 100644 index 00000000000000..e8d6063d4b5e79 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-08-01-08-58.bpo-41818.zO8vV7.rst @@ -0,0 +1 @@ +Soumendra Ganguly: add termios.tcgetwinsize(), termios.tcsetwinsize(). \ No newline at end of file diff --git a/Modules/clinic/termios.c.h b/Modules/clinic/termios.c.h index a45c1f64262f8c..d57283350d83c2 100644 --- a/Modules/clinic/termios.c.h +++ b/Modules/clinic/termios.c.h @@ -222,4 +222,68 @@ termios_tcflow(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=a129179f1e2545cc input=a9049054013a1b77]*/ + +PyDoc_STRVAR(termios_tcgetwinsize__doc__, +"tcgetwinsize($module, fd, /)\n" +"--\n" +"\n" +"Get the tty winsize for file descriptor fd.\n" +"\n" +"Returns a list [ws_row, ws_col]."); + +#define TERMIOS_TCGETWINSIZE_METHODDEF \ + {"tcgetwinsize", (PyCFunction)termios_tcgetwinsize, METH_O, termios_tcgetwinsize__doc__}, + +static PyObject * +termios_tcgetwinsize_impl(PyObject *module, int fd); + +static PyObject * +termios_tcgetwinsize(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int fd; + + if (!_PyLong_FileDescriptor_Converter(arg, &fd)) { + goto exit; + } + return_value = termios_tcgetwinsize_impl(module, fd); + +exit: + return return_value; +} + +PyDoc_STRVAR(termios_tcsetwinsize__doc__, +"tcsetwinsize($module, fd, winsize, /)\n" +"--\n" +"\n" +"Set the tty winsize for file descriptor fd.\n" +"\n" +"The winsize to be set is taken from the winsize argument, which\n" +"is a list like the one returned by tcgetwinsize()."); + +#define TERMIOS_TCSETWINSIZE_METHODDEF \ + {"tcsetwinsize", (PyCFunction)(void(*)(void))termios_tcsetwinsize, METH_FASTCALL, termios_tcsetwinsize__doc__}, + +static PyObject * +termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz); + +static PyObject * +termios_tcsetwinsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + int fd; + PyObject *winsz; + + if (!_PyArg_CheckPositional("tcsetwinsize", nargs, 2, 2)) { + goto exit; + } + if (!_PyLong_FileDescriptor_Converter(args[0], &fd)) { + goto exit; + } + winsz = args[1]; + return_value = termios_tcsetwinsize_impl(module, fd, winsz); + +exit: + return return_value; +} +/*[clinic end generated code: output=c71166c2d959710d input=a9049054013a1b77]*/ From 0d2d35bd8e5d094881505d5b68f460831d113bac Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Thu, 10 Dec 2020 15:17:52 -0600 Subject: [PATCH 3/9] Improve termios.tcsetwinsize(). Signed-off-by: Soumendra Ganguly --- Doc/library/termios.rst | 2 +- Modules/termios.c | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index 27c253e757c0bd..70c6b4d50555d8 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -84,7 +84,7 @@ The module defines the following functions: Set the tty window size for file descriptor *fd* from *winsize*, which is a list like the one returned by :func:`tcgetwinsize`. Requires - :const:`termios.TIOCSWINSZ`. + :const:`termios.TIOCGWINSZ` and :const:`termios.TIOCSWINSZ`. .. seealso:: diff --git a/Modules/termios.c b/Modules/termios.c index ef9b141c15bbd6..7ffe1f0a4601ac 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -352,7 +352,7 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) #else PyErr_SetString(PyExc_NotImplementedError, "termios.TIOCGWINSZ undefined"); return NULL; -#endif /* TIOCGWINSZ */ +#endif /* defined(TIOCGWINSZ) */ } /*[clinic input] @@ -372,7 +372,7 @@ static PyObject * termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) /*[clinic end generated code: output=2ac3c9bb6eda83e1 input=c495180b2b932a30]*/ { -#if defined(TIOCSWINSZ) +#if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) if (!PyList_Check(winsz) || PyList_Size(winsz) != 2) { PyErr_SetString(PyExc_TypeError, "tcsetwinsize, arg 2: must be 2 element list"); @@ -381,6 +381,11 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) termiosmodulestate *state = PyModule_GetState(module); struct winsize w; + /* Get the old winsize, in case there are + more fields such as xpixel, ypixel */ + if (ioctl(fd, TIOCGWINSZ, &w) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } w.ws_row = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 0)); w.ws_col = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 1)); @@ -394,9 +399,10 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) Py_RETURN_NONE; #else - PyErr_SetString(PyExc_NotImplementedError, "termios.TIOCSWINSZ undefined"); + PyErr_SetString(PyExc_NotImplementedError, + "termios.TIOCGWINSZ and/or termios.TIOCSWINSZ undefined"); return NULL; -#endif /* TIOCSWINSZ */ +#endif /* defined(TIOCGWINSZ) && defined(TIOCSWINSZ) */ } static PyMethodDef termios_methods[] = From 628b7dcc32efe8d1bc5a52bf167547f4092412a0 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Sun, 13 Dec 2020 22:15:16 -0600 Subject: [PATCH 4/9] Add TIOCGSIZE support to termios.tcgetwinsize() Signed-off-by: Soumendra Ganguly --- Doc/library/termios.rst | 3 ++- Modules/termios.c | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index 70c6b4d50555d8..473dbe667b5c97 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -77,7 +77,8 @@ The module defines the following functions: .. function:: tcgetwinsize(fd) Return a list ``[ws_row, ws_col]`` containing the tty window size for file - descriptor *fd*. Requires :const:`termios.TIOCGWINSZ`. + descriptor *fd*. Requires :const:`termios.TIOCGWINSZ` or + :const:`termios.TIOCGSIZE`. .. function:: tcsetwinsize(fd, winsize) diff --git a/Modules/termios.c b/Modules/termios.c index 7ffe1f0a4601ac..509126206e9409 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -349,8 +349,28 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) return NULL; } return v; +#elif defined(TIOCGSIZE) + termiosmodulestate *state = PyModule_GetState(module); + struct ttysize s; + if (ioctl(fd, TIOCGSIZE, &s) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } + + PyObject *v; + if (!(v = PyList_New(2))) { + return NULL; + } + + PyList_SetItem(v, 0, PyLong_FromLong((long)s.ts_lines)); + PyList_SetItem(v, 1, PyLong_FromLong((long)s.ts_cols)); + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + return v; #else - PyErr_SetString(PyExc_NotImplementedError, "termios.TIOCGWINSZ undefined"); + PyErr_SetString(PyExc_NotImplementedError, + "termios.TIOCGWINSZ and termios.TIOCGSIZE undefined"); return NULL; #endif /* defined(TIOCGWINSZ) */ } @@ -933,6 +953,9 @@ static struct constant { #ifdef TIOCGSERIAL {"TIOCGSERIAL", TIOCGSERIAL}, #endif +#ifdef TIOCGSIZE + {"TIOCGSIZE", TIOCGSIZE}, +#endif #ifdef TIOCGSOFTCAR {"TIOCGSOFTCAR", TIOCGSOFTCAR}, #endif From 6ef8a2921c65f30b9e11f414565e3d27bbfbe8c3 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Sun, 13 Dec 2020 23:36:30 -0600 Subject: [PATCH 5/9] Add TIOCSSIZE support to termios.tcsetwinsize() Signed-off-by: Soumendra Ganguly --- Doc/library/termios.rst | 5 +++-- Modules/termios.c | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index 473dbe667b5c97..c4a83385ca4144 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -84,8 +84,9 @@ The module defines the following functions: .. function:: tcsetwinsize(fd, winsize) Set the tty window size for file descriptor *fd* from *winsize*, which is - a list like the one returned by :func:`tcgetwinsize`. Requires - :const:`termios.TIOCGWINSZ` and :const:`termios.TIOCSWINSZ`. + a list like the one returned by :func:`tcgetwinsize`. Requires at least + one of the pairs (:const:`termios.TIOCGWINSZ`, :const:`termios.TIOCSWINSZ`); + (:const:`termios.TIOCGSIZE`, :const:`termios.TIOCSSIZE`) to be defined. .. seealso:: diff --git a/Modules/termios.c b/Modules/termios.c index 509126206e9409..34cf600a2839f7 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -370,7 +370,7 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) return v; #else PyErr_SetString(PyExc_NotImplementedError, - "termios.TIOCGWINSZ and termios.TIOCGSIZE undefined"); + "requires termios.TIOCGWINSZ and/or termios.TIOCGSIZE"); return NULL; #endif /* defined(TIOCGWINSZ) */ } @@ -401,8 +401,8 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) termiosmodulestate *state = PyModule_GetState(module); struct winsize w; - /* Get the old winsize, in case there are - more fields such as xpixel, ypixel */ + /* Get the old winsize because it might have + more fields such as xpixel, ypixel. */ if (ioctl(fd, TIOCGWINSZ, &w) == -1) { return PyErr_SetFromErrno(state->TermiosError); } @@ -417,10 +417,35 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) return PyErr_SetFromErrno(state->TermiosError); } + Py_RETURN_NONE; +#elif defined(TIOCGSIZE) && defined(TIOCSSIZE) + if (!PyList_Check(winsz) || PyList_Size(winsz) != 2) { + PyErr_SetString(PyExc_TypeError, + "tcsetwinsize, arg 2: must be 2 element list"); + return NULL; + } + + termiosmodulestate *state = PyModule_GetState(module); + struct ttysize s; + /* Get the old ttysize because it might have more fields. */ + if (ioctl(fd, TIOCGSIZE, &s) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } + + s.ts_lines = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 0)); + s.ts_cols = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 1)); + if (PyErr_Occurred()) { + return NULL; + } + + if (ioctl(fd, TIOCSSIZE, &s) == -1) { + return PyErr_SetFromErrno(state->TermiosError); + } + Py_RETURN_NONE; #else PyErr_SetString(PyExc_NotImplementedError, - "termios.TIOCGWINSZ and/or termios.TIOCSWINSZ undefined"); + "requires termios.TIOCGWINSZ, termios.TIOCSWINSZ and/or termios.TIOCGSIZE, termios.TIOCSSIZE"); return NULL; #endif /* defined(TIOCGWINSZ) && defined(TIOCSWINSZ) */ } @@ -1088,6 +1113,9 @@ static struct constant { #ifdef TIOCSSERIAL {"TIOCSSERIAL", TIOCSSERIAL}, #endif +#ifdef TIOCSSIZE + {"TIOCSSIZE", TIOCSSIZE}, +#endif #ifdef TIOCSSOFTCAR {"TIOCSSOFTCAR", TIOCSSOFTCAR}, #endif From 91374ea95146bf80edacfa743a3f7bc8c4d6e76f Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Tue, 15 Dec 2020 05:42:20 -0600 Subject: [PATCH 6/9] The SunOS struct ttysize had fields of type "int"; update termios.tcgetwinsize(). Signed-off-by: Soumendra Ganguly --- Modules/termios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/termios.c b/Modules/termios.c index 34cf600a2839f7..aff4beb04c4b5a 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -432,8 +432,8 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) return PyErr_SetFromErrno(state->TermiosError); } - s.ts_lines = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 0)); - s.ts_cols = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 1)); + s.ts_lines = (int) PyLong_AsLong(PyList_GetItem(winsz, 0)); + s.ts_cols = (int) PyLong_AsLong(PyList_GetItem(winsz, 1)); if (PyErr_Occurred()) { return NULL; } From bb0b2b16daf01650f001295e470ec28d28a78470 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Sat, 14 Aug 2021 01:06:12 -0500 Subject: [PATCH 7/9] termios.tcgetwinsize() and termios.tcsetwinsize() should return/accept two-item tuples instead of lists. --- Doc/library/termios.rst | 7 ++++--- Modules/clinic/termios.c.h | 6 +++--- Modules/termios.c | 36 ++++++++++++++++++------------------ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst index c4a83385ca4144..8ced0bbbd7757e 100644 --- a/Doc/library/termios.rst +++ b/Doc/library/termios.rst @@ -76,7 +76,7 @@ The module defines the following functions: .. function:: tcgetwinsize(fd) - Return a list ``[ws_row, ws_col]`` containing the tty window size for file + Return a tuple ``(ws_row, ws_col)`` containing the tty window size for file descriptor *fd*. Requires :const:`termios.TIOCGWINSZ` or :const:`termios.TIOCGSIZE`. @@ -84,8 +84,9 @@ The module defines the following functions: .. function:: tcsetwinsize(fd, winsize) Set the tty window size for file descriptor *fd* from *winsize*, which is - a list like the one returned by :func:`tcgetwinsize`. Requires at least - one of the pairs (:const:`termios.TIOCGWINSZ`, :const:`termios.TIOCSWINSZ`); + a two-item tuple ``(ws_row, ws_col)`` like the one returned by + :func:`tcgetwinsize`. Requires at least one of the pairs + (:const:`termios.TIOCGWINSZ`, :const:`termios.TIOCSWINSZ`); (:const:`termios.TIOCGSIZE`, :const:`termios.TIOCSSIZE`) to be defined. diff --git a/Modules/clinic/termios.c.h b/Modules/clinic/termios.c.h index d57283350d83c2..b4d179abbe4903 100644 --- a/Modules/clinic/termios.c.h +++ b/Modules/clinic/termios.c.h @@ -229,7 +229,7 @@ PyDoc_STRVAR(termios_tcgetwinsize__doc__, "\n" "Get the tty winsize for file descriptor fd.\n" "\n" -"Returns a list [ws_row, ws_col]."); +"Returns a tuple (ws_row, ws_col)."); #define TERMIOS_TCGETWINSIZE_METHODDEF \ {"tcgetwinsize", (PyCFunction)termios_tcgetwinsize, METH_O, termios_tcgetwinsize__doc__}, @@ -259,7 +259,7 @@ PyDoc_STRVAR(termios_tcsetwinsize__doc__, "Set the tty winsize for file descriptor fd.\n" "\n" "The winsize to be set is taken from the winsize argument, which\n" -"is a list like the one returned by tcgetwinsize()."); +"is a two-item tuple (ws_row, ws_col) like the one returned by tcgetwinsize()."); #define TERMIOS_TCSETWINSIZE_METHODDEF \ {"tcsetwinsize", (PyCFunction)(void(*)(void))termios_tcsetwinsize, METH_FASTCALL, termios_tcsetwinsize__doc__}, @@ -286,4 +286,4 @@ termios_tcsetwinsize(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=c71166c2d959710d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=db808d31296f6643 input=a9049054013a1b77]*/ diff --git a/Modules/termios.c b/Modules/termios.c index aff4beb04c4b5a..2a32990cc1fbb1 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -323,12 +323,12 @@ termios.tcgetwinsize Get the tty winsize for file descriptor fd. -Returns a list [ws_row, ws_col]. +Returns a tuple (ws_row, ws_col). [clinic start generated code]*/ static PyObject * termios_tcgetwinsize_impl(PyObject *module, int fd) -/*[clinic end generated code: output=31825977d5325fb6 input=c7ed8aa957d108c0]*/ +/*[clinic end generated code: output=31825977d5325fb6 input=5706c379d7fd984d]*/ { #if defined(TIOCGWINSZ) termiosmodulestate *state = PyModule_GetState(module); @@ -338,12 +338,12 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) } PyObject *v; - if (!(v = PyList_New(2))) { + if (!(v = PyTuple_New(2))) { return NULL; } - PyList_SetItem(v, 0, PyLong_FromLong((long)w.ws_row)); - PyList_SetItem(v, 1, PyLong_FromLong((long)w.ws_col)); + PyTuple_SetItem(v, 0, PyLong_FromLong((long)w.ws_row)); + PyTuple_SetItem(v, 1, PyLong_FromLong((long)w.ws_col)); if (PyErr_Occurred()) { Py_DECREF(v); return NULL; @@ -357,12 +357,12 @@ termios_tcgetwinsize_impl(PyObject *module, int fd) } PyObject *v; - if (!(v = PyList_New(2))) { + if (!(v = PyTuple_New(2))) { return NULL; } - PyList_SetItem(v, 0, PyLong_FromLong((long)s.ts_lines)); - PyList_SetItem(v, 1, PyLong_FromLong((long)s.ts_cols)); + PyTuple_SetItem(v, 0, PyLong_FromLong((long)s.ts_lines)); + PyTuple_SetItem(v, 1, PyLong_FromLong((long)s.ts_cols)); if (PyErr_Occurred()) { Py_DECREF(v); return NULL; @@ -385,17 +385,17 @@ termios.tcsetwinsize Set the tty winsize for file descriptor fd. The winsize to be set is taken from the winsize argument, which -is a list like the one returned by tcgetwinsize(). +is a two-item tuple (ws_row, ws_col) like the one returned by tcgetwinsize(). [clinic start generated code]*/ static PyObject * termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) -/*[clinic end generated code: output=2ac3c9bb6eda83e1 input=c495180b2b932a30]*/ +/*[clinic end generated code: output=2ac3c9bb6eda83e1 input=4a06424465b24aee]*/ { #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) - if (!PyList_Check(winsz) || PyList_Size(winsz) != 2) { + if (!PyTuple_Check(winsz) || PyTuple_Size(winsz) != 2) { PyErr_SetString(PyExc_TypeError, - "tcsetwinsize, arg 2: must be 2 element list"); + "tcsetwinsize, arg 2: must be a two-item tuple"); return NULL; } @@ -407,8 +407,8 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) return PyErr_SetFromErrno(state->TermiosError); } - w.ws_row = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 0)); - w.ws_col = (unsigned short) PyLong_AsLong(PyList_GetItem(winsz, 1)); + w.ws_row = (unsigned short) PyLong_AsLong(PyTuple_GetItem(winsz, 0)); + w.ws_col = (unsigned short) PyLong_AsLong(PyTuple_GetItem(winsz, 1)); if (PyErr_Occurred()) { return NULL; } @@ -419,9 +419,9 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) Py_RETURN_NONE; #elif defined(TIOCGSIZE) && defined(TIOCSSIZE) - if (!PyList_Check(winsz) || PyList_Size(winsz) != 2) { + if (!PyTuple_Check(winsz) || PyTuple_Size(winsz) != 2) { PyErr_SetString(PyExc_TypeError, - "tcsetwinsize, arg 2: must be 2 element list"); + "tcsetwinsize, arg 2: must be a two-item tuple"); return NULL; } @@ -432,8 +432,8 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) return PyErr_SetFromErrno(state->TermiosError); } - s.ts_lines = (int) PyLong_AsLong(PyList_GetItem(winsz, 0)); - s.ts_cols = (int) PyLong_AsLong(PyList_GetItem(winsz, 1)); + s.ts_lines = (int) PyLong_AsLong(PyTuple_GetItem(winsz, 0)); + s.ts_cols = (int) PyLong_AsLong(PyTuple_GetItem(winsz, 1)); if (PyErr_Occurred()) { return NULL; } From eb0be0934ecba171b86fdbc72c0689936a3eb54f Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 26 Aug 2021 17:57:47 -0700 Subject: [PATCH 8/9] Refactor tcsetwinsize to share common code and accept any two item sequence, with overflow checking. --- Modules/termios.c | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/Modules/termios.c b/Modules/termios.c index 2a32990cc1fbb1..7fb420f1e38f31 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -392,14 +392,32 @@ static PyObject * termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) /*[clinic end generated code: output=2ac3c9bb6eda83e1 input=4a06424465b24aee]*/ { -#if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) - if (!PyTuple_Check(winsz) || PyTuple_Size(winsz) != 2) { + if (!PySequence_Check(winsz) || PySequence_Size(winsz) != 2) { PyErr_SetString(PyExc_TypeError, - "tcsetwinsize, arg 2: must be a two-item tuple"); + "tcsetwinsize, arg 2: must be a two-item sequence"); + return NULL; + } + + PyObject *tmp_item; + long winsz_0, winsz_1; + tmp_item = PySequence_GetItem(winsz, 0); + winsz_0 = PyLong_AsLong(tmp_item); + if (winsz_0 == -1 && PyErr_Occurred()) { + Py_XDECREF(tmp_item); return NULL; } + Py_XDECREF(tmp_item); + tmp_item = PySequence_GetItem(winsz, 1); + winsz_1 = PyLong_AsLong(tmp_item); + if (winsz_1 == -1 && PyErr_Occurred()) { + Py_XDECREF(tmp_item); + return NULL; + } + Py_XDECREF(tmp_item); termiosmodulestate *state = PyModule_GetState(module); + +#if defined(TIOCGWINSZ) && defined(TIOCSWINSZ) struct winsize w; /* Get the old winsize because it might have more fields such as xpixel, ypixel. */ @@ -407,9 +425,11 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) return PyErr_SetFromErrno(state->TermiosError); } - w.ws_row = (unsigned short) PyLong_AsLong(PyTuple_GetItem(winsz, 0)); - w.ws_col = (unsigned short) PyLong_AsLong(PyTuple_GetItem(winsz, 1)); - if (PyErr_Occurred()) { + w.ws_row = (unsigned short) winsz_0; + w.ws_col = (unsigned short) winsz_1; + if (((long)w.ws_row) != winsz_0) || (((long)w.ws_col) != winsz_1) { + PyErr_SetString(PyExc_OverflowError, + "winsize value(s) out of range."); return NULL; } @@ -419,22 +439,17 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) Py_RETURN_NONE; #elif defined(TIOCGSIZE) && defined(TIOCSSIZE) - if (!PyTuple_Check(winsz) || PyTuple_Size(winsz) != 2) { - PyErr_SetString(PyExc_TypeError, - "tcsetwinsize, arg 2: must be a two-item tuple"); - return NULL; - } - - termiosmodulestate *state = PyModule_GetState(module); struct ttysize s; /* Get the old ttysize because it might have more fields. */ if (ioctl(fd, TIOCGSIZE, &s) == -1) { return PyErr_SetFromErrno(state->TermiosError); } - s.ts_lines = (int) PyLong_AsLong(PyTuple_GetItem(winsz, 0)); - s.ts_cols = (int) PyLong_AsLong(PyTuple_GetItem(winsz, 1)); - if (PyErr_Occurred()) { + s.ts_lines = (int) winsz_0; + s.ts_cols = (int) winsz_1; + if (((long)s.ts_lines) != winsz_0) || (((long)s.ts_cols) != winsz_1) { + PyErr_SetString(PyExc_OverflowError, + "winsize value(s) out of range."); return NULL; } From 5ab0d4c804aa79b12185a9609f094fc17bd4cdba Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 26 Aug 2021 18:03:11 -0700 Subject: [PATCH 9/9] parenthesis on my if statements :) --- Modules/termios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/termios.c b/Modules/termios.c index 7fb420f1e38f31..863259066aafd9 100644 --- a/Modules/termios.c +++ b/Modules/termios.c @@ -427,7 +427,7 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) w.ws_row = (unsigned short) winsz_0; w.ws_col = (unsigned short) winsz_1; - if (((long)w.ws_row) != winsz_0) || (((long)w.ws_col) != winsz_1) { + if ((((long)w.ws_row) != winsz_0) || (((long)w.ws_col) != winsz_1)) { PyErr_SetString(PyExc_OverflowError, "winsize value(s) out of range."); return NULL; @@ -447,7 +447,7 @@ termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz) s.ts_lines = (int) winsz_0; s.ts_cols = (int) winsz_1; - if (((long)s.ts_lines) != winsz_0) || (((long)s.ts_cols) != winsz_1) { + if ((((long)s.ts_lines) != winsz_0) || (((long)s.ts_cols) != winsz_1)) { PyErr_SetString(PyExc_OverflowError, "winsize value(s) out of range."); return NULL;