Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b638aaf

Browse files
committed
Michael Hudson <[email protected]>:
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.
1 parent a8e0827 commit b638aaf

1 file changed

Lines changed: 84 additions & 53 deletions

File tree

Modules/termios.c

Lines changed: 84 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,61 @@
55
#define PyInit_termios inittermios
66

77
#include <termios.h>
8-
/* XXX Some systems need this to get all the symbols, while
9-
this breaks for others.
8+
#include <termio.h>
109
#include <sys/ioctl.h>
11-
*/
10+
11+
#ifdef __BEOS__
12+
#include <unistd.h>
13+
#endif
1214

1315
static char termios__doc__[] = "\
1416
This module provides an interface to the Posix calls for tty I/O control.\n\
1517
For a complete description of these calls, see the Posix or Unix manual\n\
1618
pages. It is only available for those Unix versions that support Posix\n\
17-
termios style tty I/O control (and then only if configured at installation\n\
18-
time).\n\
19+
termios style tty I/O control.\n\
1920
\n\
2021
All functions in this module take a file descriptor fd as their first\n\
21-
argument. This must be an integer file descriptor, such as returned by\n\
22-
sys.stdin.fileno().";
23-
22+
argument. This can be an integer file descriptor, such as returned by\n\
23+
sys.stdin.fileno(), or a file object, such as sys.stdin itself.";
2424

25-
#ifdef __BEOS__
26-
#include <unistd.h>
27-
#endif
25+
static PyObject *TermiosError;
2826

29-
#define BAD "bad termios argument"
27+
static char* fname;
3028

31-
static PyObject *TermiosError;
29+
static int fdconv(PyObject* obj, void* p)
30+
{
31+
int fd;
3232

33-
/* termios = tcgetattr(fd)
34-
termios is
35-
[iflag, oflag, cflag, lflag, ispeed, ospeed, [cc[0], ..., cc[NCCS]]]
33+
fd = PyObject_AsFileDescriptor(obj);
34+
if (fd == -1) {
35+
if (PyInt_Check(obj)) {
36+
fd = PyInt_AS_LONG(obj);
37+
}
38+
else {
39+
char* tname;
40+
41+
if (PyInstance_Check(obj)) {
42+
tname = PyString_AS_STRING(
43+
((PyInstanceObject*)obj)->in_class->cl_name);
44+
}
45+
else {
46+
tname = obj->ob_type->tp_name;
47+
}
48+
49+
PyErr_Format(PyExc_TypeError,
50+
"%s, arg 1: can't extract file descriptor from \"%.500s\"",
51+
fname, tname);
52+
return 0;
53+
}
54+
}
3655

37-
Return the attributes of the terminal device. */
56+
*(int*)p = fd;
57+
return 1;
58+
}
3859

3960
static char termios_tcgetattr__doc__[] = "\
4061
tcgetattr(fd) -> list_of_attrs\n\
62+
\n\
4163
Get the tty attributes for file descriptor fd, as follows:\n\
4264
[iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\
4365
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)
5779
int i;
5880
char ch;
5981

60-
if (!PyArg_Parse(args, "i", &fd))
82+
fname = "tcgetattr";
83+
84+
if (!PyArg_ParseTuple(args, "O&:tcgetattr",
85+
fdconv, (void*)&fd))
6186
return NULL;
6287

6388
if (tcgetattr(fd, &mode) == -1)
@@ -111,11 +136,9 @@ termios_tcgetattr(PyObject *self, PyObject *args)
111136
return NULL;
112137
}
113138

114-
/* tcsetattr(fd, when, termios)
115-
Set the attributes of the terminal device. */
116-
117139
static char termios_tcsetattr__doc__[] = "\
118140
tcsetattr(fd, when, attributes) -> None\n\
141+
\n\
119142
Set the tty attributes for file descriptor fd.\n\
120143
The attributes to be set are taken from the attributes argument, which\n\
121144
is a list like the one returned by tcgetattr(). The when argument\n\
@@ -133,10 +156,14 @@ termios_tcsetattr(PyObject *self, PyObject *args)
133156
PyObject *term, *cc, *v;
134157
int i;
135158

136-
if (!PyArg_Parse(args, "(iiO)", &fd, &when, &term))
159+
fname = "tcsetattr";
160+
161+
if (!PyArg_ParseTuple(args, "O&iO:tcsetattr",
162+
fdconv, &fd, &when, &term))
137163
return NULL;
138164
if (!PyList_Check(term) || PyList_Size(term) != 7) {
139-
PyErr_SetString(PyExc_TypeError, BAD);
165+
PyErr_SetString(PyExc_TypeError,
166+
"tcsetattr, arg 3: must be 7 element list");
140167
return NULL;
141168
}
142169

@@ -154,7 +181,9 @@ termios_tcsetattr(PyObject *self, PyObject *args)
154181
return NULL;
155182

156183
if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
157-
PyErr_SetString(PyExc_TypeError, BAD);
184+
PyErr_Format(PyExc_TypeError,
185+
"tcsetattr: attributes[6] must be %d element list",
186+
NCCS);
158187
return NULL;
159188
}
160189

@@ -166,7 +195,8 @@ termios_tcsetattr(PyObject *self, PyObject *args)
166195
else if (PyInt_Check(v))
167196
mode.c_cc[i] = (cc_t) PyInt_AsLong(v);
168197
else {
169-
PyErr_SetString(PyExc_TypeError, BAD);
198+
PyErr_SetString(PyExc_TypeError,
199+
"tcsetattr: elements of attributes must be characters or integers");
170200
return NULL;
171201
}
172202
}
@@ -182,21 +212,22 @@ termios_tcsetattr(PyObject *self, PyObject *args)
182212
return Py_None;
183213
}
184214

185-
/* tcsendbreak(fd, duration)
186-
Generate a break condition. */
187-
188215
static char termios_tcsendbreak__doc__[] = "\
189216
tcsendbreak(fd, duration) -> None\n\
217+
\n\
190218
Send a break on file descriptor fd.\n\
191-
A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration \n\
192-
has a system dependent meaning. ";
219+
A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration\n\
220+
has a system dependent meaning.";
193221

194222
static PyObject *
195223
termios_tcsendbreak(PyObject *self, PyObject *args)
196224
{
197225
int fd, duration;
198226

199-
if (!PyArg_Parse(args, "(ii)", &fd, &duration))
227+
fname = "tcsendbreak";
228+
229+
if (!PyArg_ParseTuple(args, "O&i:tcsendbreak",
230+
fdconv, &fd, &duration))
200231
return NULL;
201232
if (tcsendbreak(fd, duration) == -1)
202233
return PyErr_SetFromErrno(TermiosError);
@@ -205,20 +236,20 @@ termios_tcsendbreak(PyObject *self, PyObject *args)
205236
return Py_None;
206237
}
207238

208-
/* tcdrain(fd)
209-
Wait until all queued output to the terminal has been
210-
transmitted. */
211-
212239
static char termios_tcdrain__doc__[] = "\
213240
tcdrain(fd) -> None\n\
214-
Wait until all output written to file descriptor fd has been transmitted. ";
241+
\n\
242+
Wait until all output written to file descriptor fd has been transmitted.";
215243

216244
static PyObject *
217245
termios_tcdrain(PyObject *self, PyObject *args)
218246
{
219247
int fd;
220248

221-
if (!PyArg_Parse(args, "i", &fd))
249+
fname = "tcdrain";
250+
251+
if (!PyArg_ParseTuple(args, "O&:tcdrain",
252+
fdconv, &fd))
222253
return NULL;
223254
if (tcdrain(fd) == -1)
224255
return PyErr_SetFromErrno(TermiosError);
@@ -227,12 +258,9 @@ termios_tcdrain(PyObject *self, PyObject *args)
227258
return Py_None;
228259
}
229260

230-
/* tcflush(fd, queue)
231-
Clear the input and/or output queues associated with
232-
the terminal. */
233-
234261
static char termios_tcflush__doc__[] = "\
235262
tcflush(fd, queue) -> None\n\
263+
\n\
236264
Discard queued data on file descriptor fd.\n\
237265
The queue selector specifies which queue: termios.TCIFLUSH for the input\n\
238266
queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for\n\
@@ -243,7 +271,10 @@ termios_tcflush(PyObject *self, PyObject *args)
243271
{
244272
int fd, queue;
245273

246-
if (!PyArg_Parse(args, "(ii)", &fd, &queue))
274+
fname = "tcflush";
275+
276+
if (!PyArg_ParseTuple(args, "O&i:tcflush",
277+
fdconv, &fd, &queue))
247278
return NULL;
248279
if (tcflush(fd, queue) == -1)
249280
return PyErr_SetFromErrno(TermiosError);
@@ -252,12 +283,9 @@ termios_tcflush(PyObject *self, PyObject *args)
252283
return Py_None;
253284
}
254285

255-
/* tcflow(fd, action)
256-
Perform operations relating to XON/XOFF flow control on
257-
the terminal. */
258-
259286
static char termios_tcflow__doc__[] = "\
260287
tcflow(fd, action) -> None\n\
288+
\n\
261289
Suspend or resume input or output on file descriptor fd.\n\
262290
The action argument can be termios.TCOOFF to suspend output,\n\
263291
termios.TCOON to restart output, termios.TCIOFF to suspend input,\n\
@@ -268,7 +296,10 @@ termios_tcflow(PyObject *self, PyObject *args)
268296
{
269297
int fd, action;
270298

271-
if (!PyArg_Parse(args, "(ii)", &fd, &action))
299+
fname = "tcflow";
300+
301+
if (!PyArg_ParseTuple(args, "O&i:tcflow",
302+
fdconv, &fd, &action))
272303
return NULL;
273304
if (tcflow(fd, action) == -1)
274305
return PyErr_SetFromErrno(TermiosError);
@@ -280,17 +311,17 @@ termios_tcflow(PyObject *self, PyObject *args)
280311
static PyMethodDef termios_methods[] =
281312
{
282313
{"tcgetattr", termios_tcgetattr,
283-
METH_OLDARGS, termios_tcgetattr__doc__},
314+
METH_VARARGS, termios_tcgetattr__doc__},
284315
{"tcsetattr", termios_tcsetattr,
285-
METH_OLDARGS, termios_tcsetattr__doc__},
316+
METH_VARARGS, termios_tcsetattr__doc__},
286317
{"tcsendbreak", termios_tcsendbreak,
287-
METH_OLDARGS, termios_tcsendbreak__doc__},
318+
METH_VARARGS, termios_tcsendbreak__doc__},
288319
{"tcdrain", termios_tcdrain,
289-
METH_OLDARGS, termios_tcdrain__doc__},
320+
METH_VARARGS, termios_tcdrain__doc__},
290321
{"tcflush", termios_tcflush,
291-
METH_OLDARGS, termios_tcflush__doc__},
322+
METH_VARARGS, termios_tcflush__doc__},
292323
{"tcflow", termios_tcflow,
293-
METH_OLDARGS, termios_tcflow__doc__},
324+
METH_VARARGS, termios_tcflow__doc__},
294325
{NULL, NULL}
295326
};
296327

0 commit comments

Comments
 (0)