blob: d7afeaec685334b6d9b040afd3c650710b888974 [file] [log] [blame]
Guido van Rossum9adae8e1994-09-12 10:41:22 +00001/* termiosmodule.c -- POSIX terminal I/O module implementation. */
2
Guido van Rossum602099a1994-09-14 13:32:22 +00003#include <Python.h>
Guido van Rossum9adae8e1994-09-12 10:41:22 +00004
5#define PyInit_termios inittermios
6
Guido van Rossum9adae8e1994-09-12 10:41:22 +00007#include <termios.h>
8
Guido van Rossum1aca4d81998-03-03 22:10:18 +00009static char termios__doc__[] = "\
10This module provides an interface to the Posix calls for tty I/O control.\n\
11For a complete description of these calls, see the Posix or Unix manual\n\
12pages. It is only available for those Unix versions that support Posix\n\
13termios style tty I/O control (and then only if configured at installation\n\
14time).\n\
15\n\
16All functions in this module take a file descriptor fd as their first\n\
17argument. This must be an integer file descriptor, such as returned by\n\
18sys.stdin.fileno().\n\
19\n\
20This module should be used in conjunction with the TERMIOS module,\n\
21which defines the relevant symbolic constants.";
22
23
Guido van Rossum9adae8e1994-09-12 10:41:22 +000024#define BAD "bad termios argument"
25
26static PyObject *TermiosError;
27
28/* termios = tcgetattr(fd)
29 termios is
30 [iflag, oflag, cflag, lflag, ispeed, ospeed, [cc[0], ..., cc[NCCS]]]
31
32 Return the attributes of the terminal device. */
33
Guido van Rossum1aca4d81998-03-03 22:10:18 +000034static char termios_tcgetattr__doc__[] = "\
35tcgetattr(fd) -> list_of_attrs\n\
36Get the tty attributes for file descriptor fd, as follows:\n\
37[iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\
38of the tty special characters (each a string of length 1, except the items\n\
39with indices VMIN and VTIME, which are integers when these fields are\n\
40defined). The interpretation of the flags and the speeds as well as the\n\
41indexing in the cc array must be done using the symbolic constants defined\n\
42in the TERMIOS module.";
43
Guido van Rossum9adae8e1994-09-12 10:41:22 +000044static PyObject *
45termios_tcgetattr(self, args)
46 PyObject *self;
47 PyObject *args;
48{
49 int fd;
50 struct termios mode;
51 PyObject *cc;
52 speed_t ispeed, ospeed;
53 PyObject *v;
54 int i;
55 char ch;
56
57 if (!PyArg_Parse(args, "i", &fd))
58 return NULL;
59
60 if (tcgetattr(fd, &mode) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +000061 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +000062
63 ispeed = cfgetispeed(&mode);
64 ospeed = cfgetospeed(&mode);
65
66 cc = PyList_New(NCCS);
67 if (cc == NULL)
68 return NULL;
69 for (i = 0; i < NCCS; i++) {
70 ch = (char)mode.c_cc[i];
71 v = PyString_FromStringAndSize(&ch, 1);
72 if (v == NULL)
Barry Warsaw5709dcf1997-01-10 18:42:18 +000073 goto err;
Guido van Rossum9adae8e1994-09-12 10:41:22 +000074 PyList_SetItem(cc, i, v);
75 }
76
77 /* Convert the MIN and TIME slots to integer. On some systems, the
78 MIN and TIME slots are the same as the EOF and EOL slots. So we
79 only do this in noncanonical input mode. */
Guido van Rossum36dd0d21996-12-10 15:23:00 +000080 if ((mode.c_lflag & ICANON) == 0) {
Guido van Rossum9adae8e1994-09-12 10:41:22 +000081 v = PyInt_FromLong((long)mode.c_cc[VMIN]);
82 if (v == NULL)
Barry Warsaw5709dcf1997-01-10 18:42:18 +000083 goto err;
Guido van Rossum9adae8e1994-09-12 10:41:22 +000084 PyList_SetItem(cc, VMIN, v);
85 v = PyInt_FromLong((long)mode.c_cc[VTIME]);
86 if (v == NULL)
Barry Warsaw5709dcf1997-01-10 18:42:18 +000087 goto err;
Guido van Rossum9adae8e1994-09-12 10:41:22 +000088 PyList_SetItem(cc, VTIME, v);
89 }
90
Barry Warsaw5709dcf1997-01-10 18:42:18 +000091 if (!(v = PyList_New(7)))
92 goto err;
93
Guido van Rossum9adae8e1994-09-12 10:41:22 +000094 PyList_SetItem(v, 0, PyInt_FromLong((long)mode.c_iflag));
95 PyList_SetItem(v, 1, PyInt_FromLong((long)mode.c_oflag));
96 PyList_SetItem(v, 2, PyInt_FromLong((long)mode.c_cflag));
97 PyList_SetItem(v, 3, PyInt_FromLong((long)mode.c_lflag));
98 PyList_SetItem(v, 4, PyInt_FromLong((long)ispeed));
99 PyList_SetItem(v, 5, PyInt_FromLong((long)ospeed));
100 PyList_SetItem(v, 6, cc);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000101 if (PyErr_Occurred()){
102 Py_DECREF(v);
103 goto err;
104 }
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000105 return v;
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000106 err:
107 Py_DECREF(cc);
108 return NULL;
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000109}
110
111/* tcsetattr(fd, when, termios)
112 Set the attributes of the terminal device. */
113
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000114static char termios_tcsetattr__doc__[] = "\
115tcsetattr(fd, when, attributes) -> None\n\
116Set the tty attributes for file descriptor fd.\n\
117The attributes to be set are taken from the attributes argument, which\n\
118is a list like the one returned by tcgetattr(). The when argument\n\
119determines when the attributes are changed: TERMIOS.TCSANOW to\n\
120change immediately, TERMIOS.TCSADRAIN to change after transmitting all\n\
121queued output, or TERMIOS.TCSAFLUSH to change after transmitting all\n\
122queued output and discarding all queued input. ";
123
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000124static PyObject *
125termios_tcsetattr(self, args)
126 PyObject *self;
127 PyObject *args;
128{
129 int fd, when;
130 struct termios mode;
131 speed_t ispeed, ospeed;
132 PyObject *term, *cc, *v;
133 int i;
134
135 if (!PyArg_Parse(args, "(iiO)", &fd, &when, &term))
136 return NULL;
137 if (!PyList_Check(term) || PyList_Size(term) != 7) {
138 PyErr_SetString(PyExc_TypeError, BAD);
139 return NULL;
140 }
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000141
Guido van Rossume7c41931998-06-12 14:26:18 +0000142 /* Get the old mode, in case there are any hidden fields... */
143 if (tcgetattr(fd, &mode) == -1)
144 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000145 mode.c_iflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 0));
146 mode.c_oflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 1));
147 mode.c_cflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 2));
148 mode.c_lflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 3));
149 ispeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 4));
150 ospeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 5));
151 cc = PyList_GetItem(term, 6);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000152 if (PyErr_Occurred())
153 return NULL;
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000154
155 if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
156 PyErr_SetString(PyExc_TypeError, BAD);
157 return NULL;
158 }
159
160 for (i = 0; i < NCCS; i++) {
161 v = PyList_GetItem(cc, i);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000162
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000163 if (PyString_Check(v) && PyString_Size(v) == 1)
164 mode.c_cc[i] = (cc_t) * PyString_AsString(v);
165 else if (PyInt_Check(v))
166 mode.c_cc[i] = (cc_t) PyInt_AsLong(v);
167 else {
168 PyErr_SetString(PyExc_TypeError, BAD);
169 return NULL;
170 }
171 }
172
173 if (cfsetispeed(&mode, (speed_t) ispeed) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000174 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000175 if (cfsetospeed(&mode, (speed_t) ospeed) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000176 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000177 if (tcsetattr(fd, when, &mode) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000178 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000179
180 Py_INCREF(Py_None);
181 return Py_None;
182}
183
184/* tcsendbreak(fd, duration)
185 Generate a break condition. */
186
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000187static char termios_tcsendbreak__doc__[] = "\
188tcsendbreak(fd, duration) -> None\n\
189Send a break on file descriptor fd.\n\
190A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration \n\
191has a system dependent meaning. ";
192
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000193static PyObject *
194termios_tcsendbreak(self, args)
195 PyObject *self;
196 PyObject *args;
197{
198 int fd, duration;
199
200 if (!PyArg_Parse(args, "(ii)", &fd, &duration))
201 return NULL;
202 if (tcsendbreak(fd, duration) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000203 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000204
205 Py_INCREF(Py_None);
206 return Py_None;
207}
208
209/* tcdrain(fd)
210 Wait until all queued output to the terminal has been
211 transmitted. */
212
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000213static char termios_tcdrain__doc__[] = "\
214tcdrain(fd) -> None\n\
215Wait until all output written to file descriptor fd has been transmitted. ";
216
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000217static PyObject *
218termios_tcdrain(self, args)
219 PyObject *self;
220 PyObject *args;
221{
222 int fd;
223
224 if (!PyArg_Parse(args, "i", &fd))
225 return NULL;
226 if (tcdrain(fd) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000227 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000228
229 Py_INCREF(Py_None);
230 return Py_None;
231}
232
233/* tcflush(fd, queue)
234 Clear the input and/or output queues associated with
235 the terminal. */
236
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000237static char termios_tcflush__doc__[] = "\
238tcflush(fd, queue) -> None\n\
239Discard queued data on file descriptor fd.\n\
240The queue selector specifies which queue: TERMIOS.TCIFLUSH for the input\n\
241queue, TERMIOS.TCOFLUSH for the output queue, or TERMIOS.TCIOFLUSH for\n\
242both queues. ";
243
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000244static PyObject *
245termios_tcflush(self, args)
246 PyObject *self;
247 PyObject *args;
248{
249 int fd, queue;
250
251 if (!PyArg_Parse(args, "(ii)", &fd, &queue))
252 return NULL;
253 if (tcflush(fd, queue) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000254 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000255
256 Py_INCREF(Py_None);
257 return Py_None;
258}
259
260/* tcflow(fd, action)
261 Perform operations relating to XON/XOFF flow control on
262 the terminal. */
263
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000264static char termios_tcflow__doc__[] = "\
265tcflow(fd, action) -> None\n\
266Suspend or resume input or output on file descriptor fd.\n\
267The action argument can be TERMIOS.TCOOFF to suspend output,\n\
268TERMIOS.TCOON to restart output, TERMIOS.TCIOFF to suspend input,\n\
269or TERMIOS.TCION to restart input. ";
270
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000271static PyObject *
272termios_tcflow(self, args)
273 PyObject *self;
274 PyObject *args;
275{
276 int fd, action;
277
278 if (!PyArg_Parse(args, "(ii)", &fd, &action))
279 return NULL;
280 if (tcflow(fd, action) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000281 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000282
283 Py_INCREF(Py_None);
284 return Py_None;
285}
286
287static PyMethodDef termios_methods[] =
288{
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000289 {"tcgetattr", termios_tcgetattr, 0, termios_tcgetattr__doc__},
290 {"tcsetattr", termios_tcsetattr, 0, termios_tcsetattr__doc__},
291 {"tcsendbreak", termios_tcsendbreak, 0, termios_tcsendbreak__doc__},
292 {"tcdrain", termios_tcdrain, 0, termios_tcdrain__doc__},
293 {"tcflush", termios_tcflush, 0, termios_tcflush__doc__},
294 {"tcflow", termios_tcflow, 0, termios_tcflow__doc__},
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000295 {NULL, NULL}
296};
297
298void
299PyInit_termios()
300{
301 PyObject *m, *d;
302
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000303 m = Py_InitModule4("termios", termios_methods, termios__doc__,
304 (PyObject *)NULL, PYTHON_API_VERSION);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000305
306 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000307 TermiosError = PyErr_NewException("termios.error", NULL, NULL);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000308 PyDict_SetItemString(d, "error", TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000309}