Michael Hudson <mwh21@cam.ac.uk>:

This patch does several things to termios:

(1) changes all functions to be METH_VARARGS
(2) changes all functions to be able to take a file object as the
    first parameter, as per

http://mail.python.org/pipermail/python-dev/2001-February/012701.html

(3) give better error messages
(4) removes a bunch of comments that just repeat the docstrings
(5) #includes <termio.h> before #including <sys/ioctl.h> so more
    #constants are actually #defined.
(6) a couple of docstring tweaks

I have tested this minimally (i.e. it builds, and
doesn't blow up too embarassingly) on OSF1/alpha and
on one of the sf compile farm's solaris boxes, and
rather more comprehansively on my linux/x86 box.

It still needs to be tested on all the other platforms
we build termios on.


This closes the code portion of SF patch #417081.
This commit is contained in:
Fred Drake 2001-05-07 17:55:35 +00:00
parent a8e0827614
commit b638aafef2
1 changed files with 87 additions and 56 deletions

View File

@ -5,39 +5,61 @@
#define PyInit_termios inittermios #define PyInit_termios inittermios
#include <termios.h> #include <termios.h>
/* XXX Some systems need this to get all the symbols, while #include <termio.h>
this breaks for others.
#include <sys/ioctl.h> #include <sys/ioctl.h>
*/
static char termios__doc__[] = "\
This module provides an interface to the Posix calls for tty I/O control.\n\
For a complete description of these calls, see the Posix or Unix manual\n\
pages. It is only available for those Unix versions that support Posix\n\
termios style tty I/O control (and then only if configured at installation\n\
time).\n\
\n\
All functions in this module take a file descriptor fd as their first\n\
argument. This must be an integer file descriptor, such as returned by\n\
sys.stdin.fileno().";
#ifdef __BEOS__ #ifdef __BEOS__
#include <unistd.h> #include <unistd.h>
#endif #endif
#define BAD "bad termios argument" static char termios__doc__[] = "\
This module provides an interface to the Posix calls for tty I/O control.\n\
For a complete description of these calls, see the Posix or Unix manual\n\
pages. It is only available for those Unix versions that support Posix\n\
termios style tty I/O control.\n\
\n\
All functions in this module take a file descriptor fd as their first\n\
argument. This can be an integer file descriptor, such as returned by\n\
sys.stdin.fileno(), or a file object, such as sys.stdin itself.";
static PyObject *TermiosError; static PyObject *TermiosError;
/* termios = tcgetattr(fd) static char* fname;
termios is
[iflag, oflag, cflag, lflag, ispeed, ospeed, [cc[0], ..., cc[NCCS]]]
Return the attributes of the terminal device. */ static int fdconv(PyObject* obj, void* p)
{
int fd;
fd = PyObject_AsFileDescriptor(obj);
if (fd == -1) {
if (PyInt_Check(obj)) {
fd = PyInt_AS_LONG(obj);
}
else {
char* tname;
if (PyInstance_Check(obj)) {
tname = PyString_AS_STRING(
((PyInstanceObject*)obj)->in_class->cl_name);
}
else {
tname = obj->ob_type->tp_name;
}
PyErr_Format(PyExc_TypeError,
"%s, arg 1: can't extract file descriptor from \"%.500s\"",
fname, tname);
return 0;
}
}
*(int*)p = fd;
return 1;
}
static char termios_tcgetattr__doc__[] = "\ static char termios_tcgetattr__doc__[] = "\
tcgetattr(fd) -> list_of_attrs\n\ tcgetattr(fd) -> list_of_attrs\n\
\n\
Get the tty attributes for file descriptor fd, as follows:\n\ Get the tty attributes for file descriptor fd, as follows:\n\
[iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\ [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\
of the tty special characters (each a string of length 1, except the items\n\ of the tty special characters (each a string of length 1, except the items\n\
@ -57,7 +79,10 @@ termios_tcgetattr(PyObject *self, PyObject *args)
int i; int i;
char ch; char ch;
if (!PyArg_Parse(args, "i", &fd)) fname = "tcgetattr";
if (!PyArg_ParseTuple(args, "O&:tcgetattr",
fdconv, (void*)&fd))
return NULL; return NULL;
if (tcgetattr(fd, &mode) == -1) if (tcgetattr(fd, &mode) == -1)
@ -111,11 +136,9 @@ termios_tcgetattr(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
/* tcsetattr(fd, when, termios)
Set the attributes of the terminal device. */
static char termios_tcsetattr__doc__[] = "\ static char termios_tcsetattr__doc__[] = "\
tcsetattr(fd, when, attributes) -> None\n\ tcsetattr(fd, when, attributes) -> None\n\
\n\
Set the tty attributes for file descriptor fd.\n\ Set the tty attributes for file descriptor fd.\n\
The attributes to be set are taken from the attributes argument, which\n\ The attributes to be set are taken from the attributes argument, which\n\
is a list like the one returned by tcgetattr(). The when argument\n\ is a list like the one returned by tcgetattr(). The when argument\n\
@ -133,10 +156,14 @@ termios_tcsetattr(PyObject *self, PyObject *args)
PyObject *term, *cc, *v; PyObject *term, *cc, *v;
int i; int i;
if (!PyArg_Parse(args, "(iiO)", &fd, &when, &term)) fname = "tcsetattr";
if (!PyArg_ParseTuple(args, "O&iO:tcsetattr",
fdconv, &fd, &when, &term))
return NULL; return NULL;
if (!PyList_Check(term) || PyList_Size(term) != 7) { if (!PyList_Check(term) || PyList_Size(term) != 7) {
PyErr_SetString(PyExc_TypeError, BAD); PyErr_SetString(PyExc_TypeError,
"tcsetattr, arg 3: must be 7 element list");
return NULL; return NULL;
} }
@ -154,7 +181,9 @@ termios_tcsetattr(PyObject *self, PyObject *args)
return NULL; return NULL;
if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) { if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
PyErr_SetString(PyExc_TypeError, BAD); PyErr_Format(PyExc_TypeError,
"tcsetattr: attributes[6] must be %d element list",
NCCS);
return NULL; return NULL;
} }
@ -166,7 +195,8 @@ termios_tcsetattr(PyObject *self, PyObject *args)
else if (PyInt_Check(v)) else if (PyInt_Check(v))
mode.c_cc[i] = (cc_t) PyInt_AsLong(v); mode.c_cc[i] = (cc_t) PyInt_AsLong(v);
else { else {
PyErr_SetString(PyExc_TypeError, BAD); PyErr_SetString(PyExc_TypeError,
"tcsetattr: elements of attributes must be characters or integers");
return NULL; return NULL;
} }
} }
@ -182,21 +212,22 @@ termios_tcsetattr(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
/* tcsendbreak(fd, duration)
Generate a break condition. */
static char termios_tcsendbreak__doc__[] = "\ static char termios_tcsendbreak__doc__[] = "\
tcsendbreak(fd, duration) -> None\n\ tcsendbreak(fd, duration) -> None\n\
\n\
Send a break on file descriptor fd.\n\ Send a break on file descriptor fd.\n\
A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration \n\ A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration\n\
has a system dependent meaning. "; has a system dependent meaning.";
static PyObject * static PyObject *
termios_tcsendbreak(PyObject *self, PyObject *args) termios_tcsendbreak(PyObject *self, PyObject *args)
{ {
int fd, duration; int fd, duration;
if (!PyArg_Parse(args, "(ii)", &fd, &duration)) fname = "tcsendbreak";
if (!PyArg_ParseTuple(args, "O&i:tcsendbreak",
fdconv, &fd, &duration))
return NULL; return NULL;
if (tcsendbreak(fd, duration) == -1) if (tcsendbreak(fd, duration) == -1)
return PyErr_SetFromErrno(TermiosError); return PyErr_SetFromErrno(TermiosError);
@ -205,20 +236,20 @@ termios_tcsendbreak(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
/* tcdrain(fd)
Wait until all queued output to the terminal has been
transmitted. */
static char termios_tcdrain__doc__[] = "\ static char termios_tcdrain__doc__[] = "\
tcdrain(fd) -> None\n\ tcdrain(fd) -> None\n\
Wait until all output written to file descriptor fd has been transmitted. "; \n\
Wait until all output written to file descriptor fd has been transmitted.";
static PyObject * static PyObject *
termios_tcdrain(PyObject *self, PyObject *args) termios_tcdrain(PyObject *self, PyObject *args)
{ {
int fd; int fd;
if (!PyArg_Parse(args, "i", &fd)) fname = "tcdrain";
if (!PyArg_ParseTuple(args, "O&:tcdrain",
fdconv, &fd))
return NULL; return NULL;
if (tcdrain(fd) == -1) if (tcdrain(fd) == -1)
return PyErr_SetFromErrno(TermiosError); return PyErr_SetFromErrno(TermiosError);
@ -227,12 +258,9 @@ termios_tcdrain(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
/* tcflush(fd, queue)
Clear the input and/or output queues associated with
the terminal. */
static char termios_tcflush__doc__[] = "\ static char termios_tcflush__doc__[] = "\
tcflush(fd, queue) -> None\n\ tcflush(fd, queue) -> None\n\
\n\
Discard queued data on file descriptor fd.\n\ Discard queued data on file descriptor fd.\n\
The queue selector specifies which queue: termios.TCIFLUSH for the input\n\ The queue selector specifies which queue: termios.TCIFLUSH for the input\n\
queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for\n\ queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for\n\
@ -243,7 +271,10 @@ termios_tcflush(PyObject *self, PyObject *args)
{ {
int fd, queue; int fd, queue;
if (!PyArg_Parse(args, "(ii)", &fd, &queue)) fname = "tcflush";
if (!PyArg_ParseTuple(args, "O&i:tcflush",
fdconv, &fd, &queue))
return NULL; return NULL;
if (tcflush(fd, queue) == -1) if (tcflush(fd, queue) == -1)
return PyErr_SetFromErrno(TermiosError); return PyErr_SetFromErrno(TermiosError);
@ -252,12 +283,9 @@ termios_tcflush(PyObject *self, PyObject *args)
return Py_None; return Py_None;
} }
/* tcflow(fd, action)
Perform operations relating to XON/XOFF flow control on
the terminal. */
static char termios_tcflow__doc__[] = "\ static char termios_tcflow__doc__[] = "\
tcflow(fd, action) -> None\n\ tcflow(fd, action) -> None\n\
\n\
Suspend or resume input or output on file descriptor fd.\n\ Suspend or resume input or output on file descriptor fd.\n\
The action argument can be termios.TCOOFF to suspend output,\n\ The action argument can be termios.TCOOFF to suspend output,\n\
termios.TCOON to restart output, termios.TCIOFF to suspend input,\n\ termios.TCOON to restart output, termios.TCIOFF to suspend input,\n\
@ -268,7 +296,10 @@ termios_tcflow(PyObject *self, PyObject *args)
{ {
int fd, action; int fd, action;
if (!PyArg_Parse(args, "(ii)", &fd, &action)) fname = "tcflow";
if (!PyArg_ParseTuple(args, "O&i:tcflow",
fdconv, &fd, &action))
return NULL; return NULL;
if (tcflow(fd, action) == -1) if (tcflow(fd, action) == -1)
return PyErr_SetFromErrno(TermiosError); return PyErr_SetFromErrno(TermiosError);
@ -280,17 +311,17 @@ termios_tcflow(PyObject *self, PyObject *args)
static PyMethodDef termios_methods[] = static PyMethodDef termios_methods[] =
{ {
{"tcgetattr", termios_tcgetattr, {"tcgetattr", termios_tcgetattr,
METH_OLDARGS, termios_tcgetattr__doc__}, METH_VARARGS, termios_tcgetattr__doc__},
{"tcsetattr", termios_tcsetattr, {"tcsetattr", termios_tcsetattr,
METH_OLDARGS, termios_tcsetattr__doc__}, METH_VARARGS, termios_tcsetattr__doc__},
{"tcsendbreak", termios_tcsendbreak, {"tcsendbreak", termios_tcsendbreak,
METH_OLDARGS, termios_tcsendbreak__doc__}, METH_VARARGS, termios_tcsendbreak__doc__},
{"tcdrain", termios_tcdrain, {"tcdrain", termios_tcdrain,
METH_OLDARGS, termios_tcdrain__doc__}, METH_VARARGS, termios_tcdrain__doc__},
{"tcflush", termios_tcflush, {"tcflush", termios_tcflush,
METH_OLDARGS, termios_tcflush__doc__}, METH_VARARGS, termios_tcflush__doc__},
{"tcflow", termios_tcflow, {"tcflow", termios_tcflow,
METH_OLDARGS, termios_tcflow__doc__}, METH_VARARGS, termios_tcflow__doc__},
{NULL, NULL} {NULL, NULL}
}; };