summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 8b2b211..0553c76 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -125,6 +125,18 @@ corresponding Unix manual entries for more information on calls.");
#include <dlfcn.h>
#endif
+#if defined(MS_WINDOWS)
+# define TERMSIZE_USE_CONIO
+#elif defined(HAVE_SYS_IOCTL_H)
+# include <sys/ioctl.h>
+# if defined(HAVE_TERMIOS_H)
+# include <termios.h>
+# endif
+# if defined(TIOCGWINSZ)
+# define TERMSIZE_USE_IOCTL
+# endif
+#endif /* MS_WINDOWS */
+
/* Various compilers have only certain posix functions */
/* XXX Gosh I wish these were all moved into pyconfig.h */
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
@@ -10477,6 +10489,114 @@ posix_flistxattr(PyObject *self, PyObject *args)
#endif /* USE_XATTRS */
+
+/* Terminal size querying */
+
+static PyTypeObject TerminalSizeType;
+
+PyDoc_STRVAR(TerminalSize_docstring,
+ "A tuple of (columns, lines) for holding terminal window size");
+
+static PyStructSequence_Field TerminalSize_fields[] = {
+ {"columns", "width of the terminal window in characters"},
+ {"lines", "height of the terminal window in characters"},
+ {NULL, NULL}
+};
+
+static PyStructSequence_Desc TerminalSize_desc = {
+ "os.terminal_size",
+ TerminalSize_docstring,
+ TerminalSize_fields,
+ 2,
+};
+
+#if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
+PyDoc_STRVAR(termsize__doc__,
+ "Return the size of the terminal window as (columns, lines).\n" \
+ "\n" \
+ "The optional argument fd (default standard output) specifies\n" \
+ "which file descriptor should be queried.\n" \
+ "\n" \
+ "If the file descriptor is not connected to a terminal, an OSError\n" \
+ "is thrown.\n" \
+ "\n" \
+ "This function will only be defined if an implementation is\n" \
+ "available for this system.\n" \
+ "\n" \
+ "shutil.get_terminal_size is the high-level function which should \n" \
+ "normally be used, os.get_terminal_size is the low-level implementation.");
+
+static PyObject*
+get_terminal_size(PyObject *self, PyObject *args)
+{
+ int columns, lines;
+ PyObject *termsize;
+
+ int fd = fileno(stdout);
+ /* Under some conditions stdout may not be connected and
+ * fileno(stdout) may point to an invalid file descriptor. For example
+ * GUI apps don't have valid standard streams by default.
+ *
+ * If this happens, and the optional fd argument is not present,
+ * the ioctl below will fail returning EBADF. This is what we want.
+ */
+
+ if (!PyArg_ParseTuple(args, "|i", &fd))
+ return NULL;
+
+#ifdef TERMSIZE_USE_IOCTL
+ {
+ struct winsize w;
+ if (ioctl(fd, TIOCGWINSZ, &w))
+ return PyErr_SetFromErrno(PyExc_OSError);
+ columns = w.ws_col;
+ lines = w.ws_row;
+ }
+#endif /* TERMSIZE_USE_IOCTL */
+
+#ifdef TERMSIZE_USE_CONIO
+ {
+ DWORD nhandle;
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ switch (fd) {
+ case 0: nhandle = STD_INPUT_HANDLE;
+ break;
+ case 1: nhandle = STD_OUTPUT_HANDLE;
+ break;
+ case 2: nhandle = STD_ERROR_HANDLE;
+ break;
+ default:
+ return PyErr_Format(PyExc_ValueError, "bad file descriptor");
+ }
+ handle = GetStdHandle(nhandle);
+ if (handle == NULL)
+ return PyErr_Format(PyExc_OSError, "handle cannot be retrieved");
+ if (handle == INVALID_HANDLE_VALUE)
+ return PyErr_SetFromWindowsErr(0);
+
+ if (!GetConsoleScreenBufferInfo(handle, &csbi))
+ return PyErr_SetFromWindowsErr(0);
+
+ columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ lines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+ }
+#endif /* TERMSIZE_USE_CONIO */
+
+ termsize = PyStructSequence_New(&TerminalSizeType);
+ if (termsize == NULL)
+ return NULL;
+ PyStructSequence_SET_ITEM(termsize, 0, PyLong_FromLong(columns));
+ PyStructSequence_SET_ITEM(termsize, 1, PyLong_FromLong(lines));
+ if (PyErr_Occurred()) {
+ Py_DECREF(termsize);
+ return NULL;
+ }
+ return termsize;
+}
+#endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */
+
+
static PyMethodDef posix_methods[] = {
{"access", posix_access, METH_VARARGS, posix_access__doc__},
#ifdef HAVE_TTYNAME
@@ -10945,6 +11065,9 @@ static PyMethodDef posix_methods[] = {
{"llistxattr", posix_llistxattr, METH_VARARGS, posix_llistxattr__doc__},
{"flistxattr", posix_flistxattr, METH_VARARGS, posix_flistxattr__doc__},
#endif
+#if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL)
+ {"get_terminal_size", get_terminal_size, METH_VARARGS, termsize__doc__},
+#endif
{NULL, NULL} /* Sentinel */
};
@@ -11539,6 +11662,10 @@ INITFUNC(void)
PyStructSequence_InitType(&SchedParamType, &sched_param_desc);
SchedParamType.tp_new = sched_param_new;
#endif
+
+ /* initialize TerminalSize_info */
+ PyStructSequence_InitType(&TerminalSizeType, &TerminalSize_desc);
+ Py_INCREF(&TerminalSizeType);
}
#if defined(HAVE_WAITID) && !defined(__APPLE__)
Py_INCREF((PyObject*) &WaitidResultType);
@@ -11593,6 +11720,9 @@ INITFUNC(void)
#endif /* __APPLE__ */
+
+ PyModule_AddObject(m, "terminal_size", (PyObject*) &TerminalSizeType);
+
return m;
}