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

158 changes: 158 additions & 0 deletions Modules/termios.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
gpshead marked this conversation as resolved.
Show resolved Hide resolved
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
Expand All @@ -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}
};

Expand Down Expand Up @@ -841,6 +993,9 @@ static struct constant {
#ifdef TIOCGSERIAL
{"TIOCGSERIAL", TIOCGSERIAL},
#endif
#ifdef TIOCGSIZE
{"TIOCGSIZE", TIOCGSIZE},
#endif
#ifdef TIOCGSOFTCAR
{"TIOCGSOFTCAR", TIOCGSOFTCAR},
#endif
Expand Down Expand Up @@ -973,6 +1128,9 @@ static struct constant {
#ifdef TIOCSSERIAL
{"TIOCSSERIAL", TIOCSSERIAL},
#endif
#ifdef TIOCSSIZE
{"TIOCSSIZE", TIOCSSIZE},
#endif
#ifdef TIOCSSOFTCAR
{"TIOCSSOFTCAR", TIOCSSOFTCAR},
#endif
Expand Down