Skip to content
13 changes: 13 additions & 0 deletions Doc/library/termios.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one follow up PR as I forgot to fix it up here, these need versionadded tags. I'll take care of it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpshead Thank you for making the improvements!


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.TIOCGWINSZ` and :const:`termios.TIOCSWINSZ`.


.. seealso::

Module :mod:`tty`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Soumendra Ganguly: add termios.tcgetwinsize(), termios.tcsetwinsize().
66 changes: 65 additions & 1 deletion Modules/clinic/termios.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions Modules/termios.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,96 @@ 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)
Comment thread
gpshead marked this conversation as resolved.
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))) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When returning a constant number of values, it is more typical to use a tuple than a list. PyTuple_New and equivalent item setting calls. also update the docstrings in the comment above and on the next function to mention "two item tuple" and use ().

@8vasu 8vasu Aug 12, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpshead Sir, thank you for the review. I should mention that I used PyList_New() instead of PyTuple_New() because I wanted this function to resemble the other low level function termios.tcgetattr(), which also returns a list. Do you confirm this change?

Added: I should have been more specific: termios.tcgetattr() also returns a list of fixed length, and that cannot (?) be changed (backward compatibility?). I was wondering if termios.tcgetwinsize() should also behave similarly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up making the changes!

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 /* 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 list like the one returned by tcgetwinsize().
Comment thread
gpshead marked this conversation as resolved.
Outdated
[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(TIOCGWINSZ) && 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;
/* 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));
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.TIOCGWINSZ and/or termios.TIOCSWINSZ undefined");
return NULL;
#endif /* defined(TIOCGWINSZ) && defined(TIOCSWINSZ) */
}

static PyMethodDef termios_methods[] =
{
TERMIOS_TCGETATTR_METHODDEF
Expand All @@ -323,6 +413,8 @@ static PyMethodDef termios_methods[] =
TERMIOS_TCDRAIN_METHODDEF
TERMIOS_TCFLUSH_METHODDEF
TERMIOS_TCFLOW_METHODDEF
TERMIOS_TCGETWINSIZE_METHODDEF
TERMIOS_TCSETWINSIZE_METHODDEF
{NULL, NULL}
};

Expand Down