Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-41818: Add termios.tcgetwinsize(), termios.tcsetwinsize(). Update docs. #23686

Merged
merged 9 commits into from
Aug 27, 2021
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
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
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)
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
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 ().

Copy link
Contributor Author

@8vasu 8vasu Aug 12, 2021

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
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().
[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