blob: aab6b8a71c4e1020ef6512f1880c761e45acac34 [file] [log] [blame]
Guido van Rossum9adae8e1994-09-12 10:41:22 +00001/* termiosmodule.c -- POSIX terminal I/O module implementation. */
2
Guido van Rossumca6954a1999-01-14 19:31:42 +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 Rossumbcc20741998-08-04 22:53:56 +000024#ifdef __BEOS__
25#include <unistd.h>
26#endif
27
Guido van Rossum9adae8e1994-09-12 10:41:22 +000028#define BAD "bad termios argument"
29
30static PyObject *TermiosError;
31
32/* termios = tcgetattr(fd)
33 termios is
34 [iflag, oflag, cflag, lflag, ispeed, ospeed, [cc[0], ..., cc[NCCS]]]
35
36 Return the attributes of the terminal device. */
37
Guido van Rossum1aca4d81998-03-03 22:10:18 +000038static char termios_tcgetattr__doc__[] = "\
39tcgetattr(fd) -> list_of_attrs\n\
40Get the tty attributes for file descriptor fd, as follows:\n\
41[iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\
42of the tty special characters (each a string of length 1, except the items\n\
43with indices VMIN and VTIME, which are integers when these fields are\n\
44defined). The interpretation of the flags and the speeds as well as the\n\
45indexing in the cc array must be done using the symbolic constants defined\n\
46in the TERMIOS module.";
47
Guido van Rossum9adae8e1994-09-12 10:41:22 +000048static PyObject *
49termios_tcgetattr(self, args)
50 PyObject *self;
51 PyObject *args;
52{
53 int fd;
54 struct termios mode;
55 PyObject *cc;
56 speed_t ispeed, ospeed;
57 PyObject *v;
58 int i;
59 char ch;
60
61 if (!PyArg_Parse(args, "i", &fd))
62 return NULL;
63
64 if (tcgetattr(fd, &mode) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +000065 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +000066
67 ispeed = cfgetispeed(&mode);
68 ospeed = cfgetospeed(&mode);
69
70 cc = PyList_New(NCCS);
71 if (cc == NULL)
72 return NULL;
73 for (i = 0; i < NCCS; i++) {
74 ch = (char)mode.c_cc[i];
75 v = PyString_FromStringAndSize(&ch, 1);
76 if (v == NULL)
Barry Warsaw5709dcf1997-01-10 18:42:18 +000077 goto err;
Guido van Rossum9adae8e1994-09-12 10:41:22 +000078 PyList_SetItem(cc, i, v);
79 }
80
81 /* Convert the MIN and TIME slots to integer. On some systems, the
82 MIN and TIME slots are the same as the EOF and EOL slots. So we
83 only do this in noncanonical input mode. */
Guido van Rossum36dd0d21996-12-10 15:23:00 +000084 if ((mode.c_lflag & ICANON) == 0) {
Guido van Rossum9adae8e1994-09-12 10:41:22 +000085 v = PyInt_FromLong((long)mode.c_cc[VMIN]);
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, VMIN, v);
89 v = PyInt_FromLong((long)mode.c_cc[VTIME]);
90 if (v == NULL)
Barry Warsaw5709dcf1997-01-10 18:42:18 +000091 goto err;
Guido van Rossum9adae8e1994-09-12 10:41:22 +000092 PyList_SetItem(cc, VTIME, v);
93 }
94
Barry Warsaw5709dcf1997-01-10 18:42:18 +000095 if (!(v = PyList_New(7)))
96 goto err;
97
Guido van Rossum9adae8e1994-09-12 10:41:22 +000098 PyList_SetItem(v, 0, PyInt_FromLong((long)mode.c_iflag));
99 PyList_SetItem(v, 1, PyInt_FromLong((long)mode.c_oflag));
100 PyList_SetItem(v, 2, PyInt_FromLong((long)mode.c_cflag));
101 PyList_SetItem(v, 3, PyInt_FromLong((long)mode.c_lflag));
102 PyList_SetItem(v, 4, PyInt_FromLong((long)ispeed));
103 PyList_SetItem(v, 5, PyInt_FromLong((long)ospeed));
104 PyList_SetItem(v, 6, cc);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000105 if (PyErr_Occurred()){
106 Py_DECREF(v);
107 goto err;
108 }
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000109 return v;
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000110 err:
111 Py_DECREF(cc);
112 return NULL;
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000113}
114
115/* tcsetattr(fd, when, termios)
116 Set the attributes of the terminal device. */
117
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000118static char termios_tcsetattr__doc__[] = "\
119tcsetattr(fd, when, attributes) -> None\n\
120Set the tty attributes for file descriptor fd.\n\
121The attributes to be set are taken from the attributes argument, which\n\
122is a list like the one returned by tcgetattr(). The when argument\n\
123determines when the attributes are changed: TERMIOS.TCSANOW to\n\
124change immediately, TERMIOS.TCSADRAIN to change after transmitting all\n\
125queued output, or TERMIOS.TCSAFLUSH to change after transmitting all\n\
126queued output and discarding all queued input. ";
127
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000128static PyObject *
129termios_tcsetattr(self, args)
130 PyObject *self;
131 PyObject *args;
132{
133 int fd, when;
134 struct termios mode;
135 speed_t ispeed, ospeed;
136 PyObject *term, *cc, *v;
137 int i;
138
139 if (!PyArg_Parse(args, "(iiO)", &fd, &when, &term))
140 return NULL;
141 if (!PyList_Check(term) || PyList_Size(term) != 7) {
142 PyErr_SetString(PyExc_TypeError, BAD);
143 return NULL;
144 }
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000145
Guido van Rossume7c41931998-06-12 14:26:18 +0000146 /* Get the old mode, in case there are any hidden fields... */
147 if (tcgetattr(fd, &mode) == -1)
148 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000149 mode.c_iflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 0));
150 mode.c_oflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 1));
151 mode.c_cflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 2));
152 mode.c_lflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 3));
153 ispeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 4));
154 ospeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 5));
155 cc = PyList_GetItem(term, 6);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000156 if (PyErr_Occurred())
157 return NULL;
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000158
159 if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
160 PyErr_SetString(PyExc_TypeError, BAD);
161 return NULL;
162 }
163
164 for (i = 0; i < NCCS; i++) {
165 v = PyList_GetItem(cc, i);
Barry Warsaw5709dcf1997-01-10 18:42:18 +0000166
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000167 if (PyString_Check(v) && PyString_Size(v) == 1)
168 mode.c_cc[i] = (cc_t) * PyString_AsString(v);
169 else if (PyInt_Check(v))
170 mode.c_cc[i] = (cc_t) PyInt_AsLong(v);
171 else {
172 PyErr_SetString(PyExc_TypeError, BAD);
173 return NULL;
174 }
175 }
176
177 if (cfsetispeed(&mode, (speed_t) ispeed) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000178 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000179 if (cfsetospeed(&mode, (speed_t) ospeed) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000180 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000181 if (tcsetattr(fd, when, &mode) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000182 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000183
184 Py_INCREF(Py_None);
185 return Py_None;
186}
187
188/* tcsendbreak(fd, duration)
189 Generate a break condition. */
190
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000191static char termios_tcsendbreak__doc__[] = "\
192tcsendbreak(fd, duration) -> None\n\
193Send a break on file descriptor fd.\n\
194A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration \n\
195has a system dependent meaning. ";
196
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000197static PyObject *
198termios_tcsendbreak(self, args)
199 PyObject *self;
200 PyObject *args;
201{
202 int fd, duration;
203
204 if (!PyArg_Parse(args, "(ii)", &fd, &duration))
205 return NULL;
206 if (tcsendbreak(fd, duration) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000207 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000208
209 Py_INCREF(Py_None);
210 return Py_None;
211}
212
213/* tcdrain(fd)
214 Wait until all queued output to the terminal has been
215 transmitted. */
216
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000217static char termios_tcdrain__doc__[] = "\
218tcdrain(fd) -> None\n\
219Wait until all output written to file descriptor fd has been transmitted. ";
220
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000221static PyObject *
222termios_tcdrain(self, args)
223 PyObject *self;
224 PyObject *args;
225{
226 int fd;
227
228 if (!PyArg_Parse(args, "i", &fd))
229 return NULL;
230 if (tcdrain(fd) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000231 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000232
233 Py_INCREF(Py_None);
234 return Py_None;
235}
236
237/* tcflush(fd, queue)
238 Clear the input and/or output queues associated with
239 the terminal. */
240
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000241static char termios_tcflush__doc__[] = "\
242tcflush(fd, queue) -> None\n\
243Discard queued data on file descriptor fd.\n\
244The queue selector specifies which queue: TERMIOS.TCIFLUSH for the input\n\
245queue, TERMIOS.TCOFLUSH for the output queue, or TERMIOS.TCIOFLUSH for\n\
246both queues. ";
247
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000248static PyObject *
249termios_tcflush(self, args)
250 PyObject *self;
251 PyObject *args;
252{
253 int fd, queue;
254
255 if (!PyArg_Parse(args, "(ii)", &fd, &queue))
256 return NULL;
257 if (tcflush(fd, queue) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000258 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000259
260 Py_INCREF(Py_None);
261 return Py_None;
262}
263
264/* tcflow(fd, action)
265 Perform operations relating to XON/XOFF flow control on
266 the terminal. */
267
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000268static char termios_tcflow__doc__[] = "\
269tcflow(fd, action) -> None\n\
270Suspend or resume input or output on file descriptor fd.\n\
271The action argument can be TERMIOS.TCOOFF to suspend output,\n\
272TERMIOS.TCOON to restart output, TERMIOS.TCIOFF to suspend input,\n\
273or TERMIOS.TCION to restart input. ";
274
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000275static PyObject *
276termios_tcflow(self, args)
277 PyObject *self;
278 PyObject *args;
279{
280 int fd, action;
281
282 if (!PyArg_Parse(args, "(ii)", &fd, &action))
283 return NULL;
284 if (tcflow(fd, action) == -1)
Guido van Rossumb8ad0241997-07-17 22:55:06 +0000285 return PyErr_SetFromErrno(TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000286
287 Py_INCREF(Py_None);
288 return Py_None;
289}
290
291static PyMethodDef termios_methods[] =
292{
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000293 {"tcgetattr", termios_tcgetattr, 0, termios_tcgetattr__doc__},
294 {"tcsetattr", termios_tcsetattr, 0, termios_tcsetattr__doc__},
295 {"tcsendbreak", termios_tcsendbreak, 0, termios_tcsendbreak__doc__},
296 {"tcdrain", termios_tcdrain, 0, termios_tcdrain__doc__},
297 {"tcflush", termios_tcflush, 0, termios_tcflush__doc__},
298 {"tcflow", termios_tcflow, 0, termios_tcflow__doc__},
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000299 {NULL, NULL}
300};
301
Guido van Rossum3886bb61998-12-04 18:50:17 +0000302DL_EXPORT(void)
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000303PyInit_termios()
304{
305 PyObject *m, *d;
306
Guido van Rossum1aca4d81998-03-03 22:10:18 +0000307 m = Py_InitModule4("termios", termios_methods, termios__doc__,
308 (PyObject *)NULL, PYTHON_API_VERSION);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000309
310 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000311 TermiosError = PyErr_NewException("termios.error", NULL, NULL);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000312 PyDict_SetItemString(d, "error", TermiosError);
Guido van Rossum9adae8e1994-09-12 10:41:22 +0000313}