[Python-checkins] bpo-41818: Add termios.tcgetwinsize(), termios.tcsetwinsize(). (GH-23686)

gpshead webhook-mailer at python.org
Thu Aug 26 22:56:34 EDT 2021


https://github.com/python/cpython/commit/ae224bb566301d3602e9b090e37c1dcf5a48c914
commit: ae224bb566301d3602e9b090e37c1dcf5a48c914
branch: main
author: Soumendra Ganguly <67527439+8vasu at users.noreply.github.com>
committer: gpshead <greg at krypto.org>
date: 2021-08-26T19:56:26-07:00
summary:

bpo-41818: Add termios.tcgetwinsize(), termios.tcsetwinsize(). (GH-23686)

* Add termios.tcgetwinsize(), termios.tcsetwinsize(). Update docs.
* Add TIOCGSIZE support to termios.tcgetwinsize()
* Add TIOCSSIZE support to termios.tcsetwinsize()

Authored-by: Soumendra Ganguly <soumendraganguly at gmail.com>

* termios.tcgetwinsize() and termios.tcsetwinsize() should return/accept two-item tuples instead of lists.
* Refactor tcsetwinsize to share common code and accept any two item sequence, with overflow checking.

Co-authored-by: Gregory P. Smith <greg at krypto.org> [Google]

files:
A Misc/NEWS.d/next/Library/2020-12-08-01-08-58.bpo-41818.zO8vV7.rst
M Doc/library/termios.rst
M Modules/clinic/termios.c.h
M Modules/termios.c

diff --git a/Doc/library/termios.rst b/Doc/library/termios.rst
index d75a87c55a46e..8ced0bbbd7757 100644
--- a/Doc/library/termios.rst
+++ b/Doc/library/termios.rst
@@ -74,6 +74,22 @@ The module defines the following functions:
    output, :const:`TCIOFF` to suspend input, or :const:`TCION` to restart input.
 
 
+.. function:: tcgetwinsize(fd)
+
+   Return a tuple ``(ws_row, ws_col)`` containing the tty window size for file
+   descriptor *fd*. Requires :const:`termios.TIOCGWINSZ` or
+   :const:`termios.TIOCGSIZE`.
+
+
+.. function:: tcsetwinsize(fd, winsize)
+
+    Set the tty window size for file descriptor *fd* from *winsize*, which is
+    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.
+
+
 .. seealso::
 
    Module :mod:`tty`
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 0000000000000..e8d6063d4b5e7
--- /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 a45c1f64262f8..b4d179abbe490 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 tuple (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 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__},
+
+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=db808d31296f6643 input=a9049054013a1b77]*/
diff --git a/Modules/termios.c b/Modules/termios.c
index fdfe589eb80c1..38573e25f51dd 100644
--- a/Modules/termios.c
+++ b/Modules/termios.c
@@ -315,6 +315,156 @@ 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 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=5706c379d7fd984d]*/
+{
+#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 = PyTuple_New(2))) {
+        return NULL;
+    }
+
+    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;
+    }
+    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 = PyTuple_New(2))) {
+        return NULL;
+    }
+
+    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;
+    }
+    return v;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "requires termios.TIOCGWINSZ and/or termios.TIOCGSIZE");
+    return NULL;
+#endif /* defined(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 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=4a06424465b24aee]*/
+{
+    if (!PySequence_Check(winsz) || PySequence_Size(winsz) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+                     "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. */
+    if (ioctl(fd, TIOCGWINSZ, &w) == -1) {
+        return PyErr_SetFromErrno(state->TermiosError);
+    }
+
+    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;
+    }
+
+    if (ioctl(fd, TIOCSWINSZ, &w) == -1) {
+        return PyErr_SetFromErrno(state->TermiosError);
+    }
+
+    Py_RETURN_NONE;
+#elif defined(TIOCGSIZE) && defined(TIOCSSIZE)
+    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) 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;
+    }
+
+    if (ioctl(fd, TIOCSSIZE, &s) == -1) {
+        return PyErr_SetFromErrno(state->TermiosError);
+    }
+
+    Py_RETURN_NONE;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "requires termios.TIOCGWINSZ, termios.TIOCSWINSZ and/or termios.TIOCGSIZE, termios.TIOCSSIZE");
+    return NULL;
+#endif /* defined(TIOCGWINSZ) && defined(TIOCSWINSZ) */
+}
+
 static PyMethodDef termios_methods[] =
 {
     TERMIOS_TCGETATTR_METHODDEF
@@ -323,6 +473,8 @@ static PyMethodDef termios_methods[] =
     TERMIOS_TCDRAIN_METHODDEF
     TERMIOS_TCFLUSH_METHODDEF
     TERMIOS_TCFLOW_METHODDEF
+    TERMIOS_TCGETWINSIZE_METHODDEF
+    TERMIOS_TCSETWINSIZE_METHODDEF
     {NULL, NULL}
 };
 
@@ -841,6 +993,9 @@ static struct constant {
 #ifdef TIOCGSERIAL
     {"TIOCGSERIAL", TIOCGSERIAL},
 #endif
+#ifdef TIOCGSIZE
+    {"TIOCGSIZE", TIOCGSIZE},
+#endif
 #ifdef TIOCGSOFTCAR
     {"TIOCGSOFTCAR", TIOCGSOFTCAR},
 #endif
@@ -973,6 +1128,9 @@ static struct constant {
 #ifdef TIOCSSERIAL
     {"TIOCSSERIAL", TIOCSSERIAL},
 #endif
+#ifdef TIOCSSIZE
+    {"TIOCSSIZE", TIOCSSIZE},
+#endif
 #ifdef TIOCSSOFTCAR
     {"TIOCSSOFTCAR", TIOCSSOFTCAR},
 #endif



More information about the Python-checkins mailing list