• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* termios.c -- POSIX terminal I/O module implementation.  */
2 
3 // Need limited C API version 3.13 for PyLong_AsInt()
4 // in code generated by Argument Clinic.
5 #include "pyconfig.h"   // Py_GIL_DISABLED
6 #ifndef Py_GIL_DISABLED
7 #  define Py_LIMITED_API 0x030d0000
8 #endif
9 
10 #include "Python.h"
11 
12 #include <string.h>               // memset()
13 #include <sys/ioctl.h>
14 #include <termios.h>
15 #include <unistd.h>               // _POSIX_VDISABLE
16 
17 // On QNX 6, struct termio must be declared by including sys/termio.h
18 // if TCGETA, TCSETA, TCSETAW, or TCSETAF are used. sys/termio.h must
19 // be included before termios.h or it will generate an error.
20 #if defined(HAVE_SYS_TERMIO_H) && !defined(__hpux)
21 #  include <sys/termio.h>
22 #endif
23 
24 // Apparently, on SGI, termios.h won't define CTRL if _XOPEN_SOURCE
25 // is defined, so we define it here.
26 #if defined(__sgi)
27 #  define CTRL(c) ((c)&037)
28 #endif
29 
30 // We could do better. Check bpo-32660
31 #if defined(__sun)
32 #  include <sys/filio.h>
33 #  include <sys/sockio.h>
34 #endif
35 
36 /* HP-UX requires that this be included to pick up MDCD, MCTS, MDSR,
37  * MDTR, MRI, and MRTS (apparently used internally by some things
38  * defined as macros; these are not used here directly).
39  */
40 #ifdef HAVE_SYS_MODEM_H
41 #  include <sys/modem.h>
42 #endif
43 
44 /* HP-UX requires that this be included to pick up TIOCGPGRP and friends */
45 #ifdef HAVE_SYS_BSDTTY_H
46 #  include <sys/bsdtty.h>
47 #endif
48 
49 
50 /*[clinic input]
51 module termios
52 [clinic start generated code]*/
53 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=01105c85d0ca7252]*/
54 
55 #include "clinic/termios.c.h"
56 
57 PyDoc_STRVAR(termios__doc__,
58 "This module provides an interface to the Posix calls for tty I/O control.\n\
59 For a complete description of these calls, see the Posix or Unix manual\n\
60 pages. It is only available for those Unix versions that support Posix\n\
61 termios style tty I/O control.\n\
62 \n\
63 All functions in this module take a file descriptor fd as their first\n\
64 argument. This can be an integer file descriptor, such as returned by\n\
65 sys.stdin.fileno(), or a file object, such as sys.stdin itself.");
66 
67 typedef struct {
68   PyObject *TermiosError;
69 } termiosmodulestate;
70 
71 static inline termiosmodulestate*
get_termios_state(PyObject * module)72 get_termios_state(PyObject *module)
73 {
74     void *state = PyModule_GetState(module);
75     assert(state != NULL);
76     return (termiosmodulestate *)state;
77 }
78 
79 static struct PyModuleDef termiosmodule;
80 
81 /*[clinic input]
82 termios.tcgetattr
83 
84     fd: fildes
85     /
86 
87 Get the tty attributes for file descriptor fd.
88 
89 Returns a list [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
90 where cc is a list of the tty special characters (each a string of
91 length 1, except the items with indices VMIN and VTIME, which are
92 integers when these fields are defined).  The interpretation of the
93 flags and the speeds as well as the indexing in the cc array must be
94 done using the symbolic constants defined in this module.
95 [clinic start generated code]*/
96 
97 static PyObject *
termios_tcgetattr_impl(PyObject * module,int fd)98 termios_tcgetattr_impl(PyObject *module, int fd)
99 /*[clinic end generated code: output=2b3da39db870e629 input=54dad9779ebe74b1]*/
100 {
101     termiosmodulestate *state = PyModule_GetState(module);
102     struct termios mode;
103     int r;
104 
105     /* Alpine Linux can leave some fields uninitialized. */
106     memset(&mode, 0, sizeof(mode));
107     Py_BEGIN_ALLOW_THREADS
108     r = tcgetattr(fd, &mode);
109     Py_END_ALLOW_THREADS
110     if (r == -1) {
111         return PyErr_SetFromErrno(state->TermiosError);
112     }
113 
114     speed_t ispeed = cfgetispeed(&mode);
115     speed_t ospeed = cfgetospeed(&mode);
116 
117     PyObject *cc = PyList_New(NCCS);
118     if (cc == NULL) {
119         return NULL;
120     }
121 
122     PyObject *v;
123     int i;
124     for (i = 0; i < NCCS; i++) {
125         char ch = (char)mode.c_cc[i];
126         v = PyBytes_FromStringAndSize(&ch, 1);
127         if (v == NULL)
128             goto err;
129         PyList_SetItem(cc, i, v);
130     }
131 
132     /* Convert the MIN and TIME slots to integer.  On some systems, the
133        MIN and TIME slots are the same as the EOF and EOL slots.  So we
134        only do this in noncanonical input mode.  */
135     if ((mode.c_lflag & ICANON) == 0) {
136         v = PyLong_FromLong((long)mode.c_cc[VMIN]);
137         if (v == NULL) {
138             goto err;
139         }
140         if (PyList_SetItem(cc, VMIN, v) < 0) {
141             goto err;
142         }
143         v = PyLong_FromLong((long)mode.c_cc[VTIME]);
144         if (v == NULL) {
145             goto err;
146         }
147         if (PyList_SetItem(cc, VTIME, v) < 0) {
148             goto err;
149         }
150     }
151 
152     if (!(v = PyList_New(7))) {
153         goto err;
154     }
155 
156 #define ADD_LONG_ITEM(index, val) \
157     do { \
158         PyObject *l = PyLong_FromLong((long)val); \
159         if (l == NULL) { \
160             Py_DECREF(v); \
161             goto err; \
162         } \
163         PyList_SetItem(v, index, l); \
164     } while (0)
165 
166     ADD_LONG_ITEM(0, mode.c_iflag);
167     ADD_LONG_ITEM(1, mode.c_oflag);
168     ADD_LONG_ITEM(2, mode.c_cflag);
169     ADD_LONG_ITEM(3, mode.c_lflag);
170     ADD_LONG_ITEM(4, ispeed);
171     ADD_LONG_ITEM(5, ospeed);
172 #undef ADD_LONG_ITEM
173 
174     PyList_SetItem(v, 6, cc);
175     return v;
176   err:
177     Py_DECREF(cc);
178     return NULL;
179 }
180 
181 /*[clinic input]
182 termios.tcsetattr
183 
184     fd: fildes
185     when: int
186     attributes as term: object
187     /
188 
189 Set the tty attributes for file descriptor fd.
190 
191 The attributes to be set are taken from the attributes argument, which
192 is a list like the one returned by tcgetattr(). The when argument
193 determines when the attributes are changed: termios.TCSANOW to
194 change immediately, termios.TCSADRAIN to change after transmitting all
195 queued output, or termios.TCSAFLUSH to change after transmitting all
196 queued output and discarding all queued input.
197 [clinic start generated code]*/
198 
199 static PyObject *
termios_tcsetattr_impl(PyObject * module,int fd,int when,PyObject * term)200 termios_tcsetattr_impl(PyObject *module, int fd, int when, PyObject *term)
201 /*[clinic end generated code: output=bcd2b0a7b98a4bf5 input=5dafabdd5a08f018]*/
202 {
203     if (!PyList_Check(term) || PyList_Size(term) != 7) {
204         PyErr_SetString(PyExc_TypeError,
205                      "tcsetattr, arg 3: must be 7 element list");
206         return NULL;
207     }
208 
209     /* Get the old mode, in case there are any hidden fields... */
210     termiosmodulestate *state = PyModule_GetState(module);
211     struct termios mode;
212     int r;
213 
214     Py_BEGIN_ALLOW_THREADS
215     r = tcgetattr(fd, &mode);
216     Py_END_ALLOW_THREADS
217     if (r == -1) {
218         return PyErr_SetFromErrno(state->TermiosError);
219     }
220 
221     speed_t ispeed, ospeed;
222 #define SET_FROM_LIST(TYPE, VAR, LIST, N) do {  \
223     PyObject *item = PyList_GetItem(LIST, N);  \
224     long num = PyLong_AsLong(item);             \
225     if (num == -1 && PyErr_Occurred()) {        \
226         return NULL;                            \
227     }                                           \
228     VAR = (TYPE)num;                            \
229 } while (0)
230 
231     SET_FROM_LIST(tcflag_t, mode.c_iflag, term, 0);
232     SET_FROM_LIST(tcflag_t, mode.c_oflag, term, 1);
233     SET_FROM_LIST(tcflag_t, mode.c_cflag, term, 2);
234     SET_FROM_LIST(tcflag_t, mode.c_lflag, term, 3);
235     SET_FROM_LIST(speed_t, ispeed, term, 4);
236     SET_FROM_LIST(speed_t, ospeed, term, 5);
237 #undef SET_FROM_LIST
238 
239     PyObject *cc = PyList_GetItem(term, 6);
240     if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) {
241         PyErr_Format(PyExc_TypeError,
242             "tcsetattr: attributes[6] must be %d element list",
243                  NCCS);
244         return NULL;
245     }
246 
247     int i;
248     PyObject *v;
249     for (i = 0; i < NCCS; i++) {
250         v = PyList_GetItem(cc, i);
251 
252         if (PyBytes_Check(v) && PyBytes_Size(v) == 1)
253             mode.c_cc[i] = (cc_t) * PyBytes_AsString(v);
254         else if (PyLong_Check(v)) {
255             long num = PyLong_AsLong(v);
256             if (num == -1 && PyErr_Occurred()) {
257                 return NULL;
258             }
259             mode.c_cc[i] = (cc_t)num;
260         }
261         else {
262             PyErr_SetString(PyExc_TypeError,
263      "tcsetattr: elements of attributes must be characters or integers");
264                         return NULL;
265                 }
266     }
267 
268     if (cfsetispeed(&mode, (speed_t) ispeed) == -1)
269         return PyErr_SetFromErrno(state->TermiosError);
270     if (cfsetospeed(&mode, (speed_t) ospeed) == -1)
271         return PyErr_SetFromErrno(state->TermiosError);
272 
273     Py_BEGIN_ALLOW_THREADS
274     r = tcsetattr(fd, when, &mode);
275     Py_END_ALLOW_THREADS
276 
277     if (r == -1)
278         return PyErr_SetFromErrno(state->TermiosError);
279 
280     Py_RETURN_NONE;
281 }
282 
283 /*[clinic input]
284 termios.tcsendbreak
285 
286     fd: fildes
287     duration: int
288     /
289 
290 Send a break on file descriptor fd.
291 
292 A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration
293 has a system dependent meaning.
294 [clinic start generated code]*/
295 
296 static PyObject *
termios_tcsendbreak_impl(PyObject * module,int fd,int duration)297 termios_tcsendbreak_impl(PyObject *module, int fd, int duration)
298 /*[clinic end generated code: output=5945f589b5d3ac66 input=dc2f32417691f8ed]*/
299 {
300     termiosmodulestate *state = PyModule_GetState(module);
301     int r;
302 
303     Py_BEGIN_ALLOW_THREADS
304     r = tcsendbreak(fd, duration);
305     Py_END_ALLOW_THREADS
306 
307     if (r == -1) {
308         return PyErr_SetFromErrno(state->TermiosError);
309     }
310 
311     Py_RETURN_NONE;
312 }
313 
314 /*[clinic input]
315 termios.tcdrain
316 
317     fd: fildes
318     /
319 
320 Wait until all output written to file descriptor fd has been transmitted.
321 [clinic start generated code]*/
322 
323 static PyObject *
termios_tcdrain_impl(PyObject * module,int fd)324 termios_tcdrain_impl(PyObject *module, int fd)
325 /*[clinic end generated code: output=5fd86944c6255955 input=c99241b140b32447]*/
326 {
327     termiosmodulestate *state = PyModule_GetState(module);
328     int r;
329 
330     Py_BEGIN_ALLOW_THREADS
331     r = tcdrain(fd);
332     Py_END_ALLOW_THREADS
333 
334     if (r == -1) {
335         return PyErr_SetFromErrno(state->TermiosError);
336     }
337 
338     Py_RETURN_NONE;
339 }
340 
341 /*[clinic input]
342 termios.tcflush
343 
344     fd: fildes
345     queue: int
346     /
347 
348 Discard queued data on file descriptor fd.
349 
350 The queue selector specifies which queue: termios.TCIFLUSH for the input
351 queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for
352 both queues.
353 [clinic start generated code]*/
354 
355 static PyObject *
termios_tcflush_impl(PyObject * module,int fd,int queue)356 termios_tcflush_impl(PyObject *module, int fd, int queue)
357 /*[clinic end generated code: output=2424f80312ec2f21 input=0f7d08122ddc07b5]*/
358 {
359     termiosmodulestate *state = PyModule_GetState(module);
360     int r;
361 
362     Py_BEGIN_ALLOW_THREADS
363     r = tcflush(fd, queue);
364     Py_END_ALLOW_THREADS
365 
366     if (r == -1) {
367         return PyErr_SetFromErrno(state->TermiosError);
368     }
369 
370     Py_RETURN_NONE;
371 }
372 
373 /*[clinic input]
374 termios.tcflow
375 
376     fd: fildes
377     action: int
378     /
379 
380 Suspend or resume input or output on file descriptor fd.
381 
382 The action argument can be termios.TCOOFF to suspend output,
383 termios.TCOON to restart output, termios.TCIOFF to suspend input,
384 or termios.TCION to restart input.
385 [clinic start generated code]*/
386 
387 static PyObject *
termios_tcflow_impl(PyObject * module,int fd,int action)388 termios_tcflow_impl(PyObject *module, int fd, int action)
389 /*[clinic end generated code: output=afd10928e6ea66eb input=c6aff0640b6efd9c]*/
390 {
391     termiosmodulestate *state = PyModule_GetState(module);
392     int r;
393 
394     Py_BEGIN_ALLOW_THREADS
395     r = tcflow(fd, action);
396     Py_END_ALLOW_THREADS
397 
398     if (r == -1) {
399         return PyErr_SetFromErrno(state->TermiosError);
400     }
401 
402     Py_RETURN_NONE;
403 }
404 
405 /*[clinic input]
406 termios.tcgetwinsize
407 
408     fd: fildes
409     /
410 
411 Get the tty winsize for file descriptor fd.
412 
413 Returns a tuple (ws_row, ws_col).
414 [clinic start generated code]*/
415 
416 static PyObject *
termios_tcgetwinsize_impl(PyObject * module,int fd)417 termios_tcgetwinsize_impl(PyObject *module, int fd)
418 /*[clinic end generated code: output=31825977d5325fb6 input=5706c379d7fd984d]*/
419 {
420 #if defined(TIOCGWINSZ)
421     termiosmodulestate *state = PyModule_GetState(module);
422     struct winsize w;
423     int r;
424 
425     Py_BEGIN_ALLOW_THREADS
426     r = ioctl(fd, TIOCGWINSZ, &w);
427     Py_END_ALLOW_THREADS
428 
429     if (r == -1) {
430         return PyErr_SetFromErrno(state->TermiosError);
431     }
432 
433     PyObject *v;
434     if (!(v = PyTuple_New(2))) {
435         return NULL;
436     }
437 
438     PyTuple_SetItem(v, 0, PyLong_FromLong((long)w.ws_row));
439     PyTuple_SetItem(v, 1, PyLong_FromLong((long)w.ws_col));
440     if (PyErr_Occurred()) {
441         Py_DECREF(v);
442         return NULL;
443     }
444     return v;
445 #elif defined(TIOCGSIZE)
446     termiosmodulestate *state = PyModule_GetState(module);
447     struct ttysize s;
448     int r;
449 
450     Py_BEGIN_ALLOW_THREADS
451     r = ioctl(fd, TIOCGSIZE, &s);
452     Py_END_ALLOW_THREADS
453     if (r == -1) {
454         return PyErr_SetFromErrno(state->TermiosError);
455     }
456 
457     PyObject *v;
458     if (!(v = PyTuple_New(2))) {
459         return NULL;
460     }
461 
462     PyTuple_SetItem(v, 0, PyLong_FromLong((long)s.ts_lines));
463     PyTuple_SetItem(v, 1, PyLong_FromLong((long)s.ts_cols));
464     if (PyErr_Occurred()) {
465         Py_DECREF(v);
466         return NULL;
467     }
468     return v;
469 #else
470     PyErr_SetString(PyExc_NotImplementedError,
471                     "requires termios.TIOCGWINSZ and/or termios.TIOCGSIZE");
472     return NULL;
473 #endif /* defined(TIOCGWINSZ) */
474 }
475 
476 /*[clinic input]
477 termios.tcsetwinsize
478 
479     fd: fildes
480     winsize as winsz: object
481     /
482 
483 Set the tty winsize for file descriptor fd.
484 
485 The winsize to be set is taken from the winsize argument, which
486 is a two-item tuple (ws_row, ws_col) like the one returned by tcgetwinsize().
487 [clinic start generated code]*/
488 
489 static PyObject *
termios_tcsetwinsize_impl(PyObject * module,int fd,PyObject * winsz)490 termios_tcsetwinsize_impl(PyObject *module, int fd, PyObject *winsz)
491 /*[clinic end generated code: output=2ac3c9bb6eda83e1 input=4a06424465b24aee]*/
492 {
493     if (!PySequence_Check(winsz) || PySequence_Size(winsz) != 2) {
494         PyErr_SetString(PyExc_TypeError,
495                      "tcsetwinsize, arg 2: must be a two-item sequence");
496         return NULL;
497     }
498 
499     PyObject *tmp_item;
500     long winsz_0, winsz_1;
501     tmp_item = PySequence_GetItem(winsz, 0);
502     winsz_0 = PyLong_AsLong(tmp_item);
503     if (winsz_0 == -1 && PyErr_Occurred()) {
504         Py_XDECREF(tmp_item);
505         return NULL;
506     }
507     Py_XDECREF(tmp_item);
508     tmp_item = PySequence_GetItem(winsz, 1);
509     winsz_1 = PyLong_AsLong(tmp_item);
510     if (winsz_1 == -1 && PyErr_Occurred()) {
511         Py_XDECREF(tmp_item);
512         return NULL;
513     }
514     Py_XDECREF(tmp_item);
515 
516     termiosmodulestate *state = PyModule_GetState(module);
517 
518 #if defined(TIOCGWINSZ) && defined(TIOCSWINSZ)
519     struct winsize w;
520     /* Get the old winsize because it might have
521        more fields such as xpixel, ypixel. */
522     if (ioctl(fd, TIOCGWINSZ, &w) == -1) {
523         return PyErr_SetFromErrno(state->TermiosError);
524     }
525 
526     w.ws_row = (unsigned short) winsz_0;
527     w.ws_col = (unsigned short) winsz_1;
528     if ((((long)w.ws_row) != winsz_0) || (((long)w.ws_col) != winsz_1)) {
529         PyErr_SetString(PyExc_OverflowError,
530                         "winsize value(s) out of range.");
531         return NULL;
532     }
533 
534     int r;
535     Py_BEGIN_ALLOW_THREADS
536     r = ioctl(fd, TIOCSWINSZ, &w);
537     Py_END_ALLOW_THREADS
538 
539     if (r == -1) {
540         return PyErr_SetFromErrno(state->TermiosError);
541     }
542 
543     Py_RETURN_NONE;
544 #elif defined(TIOCGSIZE) && defined(TIOCSSIZE)
545     struct ttysize s;
546     int r;
547     /* Get the old ttysize because it might have more fields. */
548     Py_BEGIN_ALLOW_THREADS
549     r = ioctl(fd, TIOCGSIZE, &s);
550     Py_END_ALLOW_THREADS
551 
552     if (r == -1) {
553         return PyErr_SetFromErrno(state->TermiosError);
554     }
555 
556     s.ts_lines = (int) winsz_0;
557     s.ts_cols = (int) winsz_1;
558     if ((((long)s.ts_lines) != winsz_0) || (((long)s.ts_cols) != winsz_1)) {
559         PyErr_SetString(PyExc_OverflowError,
560                         "winsize value(s) out of range.");
561         return NULL;
562     }
563 
564     Py_BEGIN_ALLOW_THREADS
565     r = ioctl(fd, TIOCSSIZE, &s);
566     Py_END_ALLOW_THREADS
567 
568     if (r == -1) {
569         return PyErr_SetFromErrno(state->TermiosError);
570     }
571 
572     Py_RETURN_NONE;
573 #else
574     PyErr_SetString(PyExc_NotImplementedError,
575                     "requires termios.TIOCGWINSZ, termios.TIOCSWINSZ and/or termios.TIOCGSIZE, termios.TIOCSSIZE");
576     return NULL;
577 #endif /* defined(TIOCGWINSZ) && defined(TIOCSWINSZ) */
578 }
579 
580 static PyMethodDef termios_methods[] =
581 {
582     TERMIOS_TCGETATTR_METHODDEF
583     TERMIOS_TCSETATTR_METHODDEF
584     TERMIOS_TCSENDBREAK_METHODDEF
585     TERMIOS_TCDRAIN_METHODDEF
586     TERMIOS_TCFLUSH_METHODDEF
587     TERMIOS_TCFLOW_METHODDEF
588     TERMIOS_TCGETWINSIZE_METHODDEF
589     TERMIOS_TCSETWINSIZE_METHODDEF
590     {NULL, NULL}
591 };
592 
593 
594 #if defined(VSWTCH) && !defined(VSWTC)
595 #define VSWTC VSWTCH
596 #endif
597 
598 #if defined(VSWTC) && !defined(VSWTCH)
599 #define VSWTCH VSWTC
600 #endif
601 
602 static struct constant {
603     char *name;
604     long value;
605 } termios_constants[] = {
606     /* cfgetospeed(), cfsetospeed() constants */
607     {"B0", B0},
608     {"B50", B50},
609     {"B75", B75},
610     {"B110", B110},
611     {"B134", B134},
612     {"B150", B150},
613     {"B200", B200},
614     {"B300", B300},
615     {"B600", B600},
616     {"B1200", B1200},
617     {"B1800", B1800},
618     {"B2400", B2400},
619     {"B4800", B4800},
620     {"B9600", B9600},
621     {"B19200", B19200},
622     {"B38400", B38400},
623 #ifdef B57600
624     {"B57600", B57600},
625 #endif
626 #ifdef B115200
627     {"B115200", B115200},
628 #endif
629 #ifdef B230400
630     {"B230400", B230400},
631 #endif
632 #ifdef B460800
633     {"B460800", B460800},
634 #endif
635 #ifdef B500000
636     {"B500000", B500000},
637 #endif
638 #ifdef B576000
639     {"B576000", B576000},
640 #endif
641 #ifdef B921600
642     {"B921600", B921600},
643 #endif
644 #ifdef B1000000
645     {"B1000000", B1000000},
646 #endif
647 #ifdef B1152000
648     {"B1152000", B1152000},
649 #endif
650 #ifdef B1500000
651     {"B1500000", B1500000},
652 #endif
653 #ifdef B2000000
654     {"B2000000", B2000000},
655 #endif
656 #ifdef B2500000
657     {"B2500000", B2500000},
658 #endif
659 #ifdef B3000000
660     {"B3000000", B3000000},
661 #endif
662 #ifdef B3500000
663     {"B3500000", B3500000},
664 #endif
665 #ifdef B4000000
666     {"B4000000", B4000000},
667 #endif
668 
669 #ifdef CBAUDEX
670     {"CBAUDEX", CBAUDEX},
671 #endif
672 
673     /* tcsetattr() constants */
674     {"TCSANOW", TCSANOW},
675     {"TCSADRAIN", TCSADRAIN},
676     {"TCSAFLUSH", TCSAFLUSH},
677 #ifdef TCSASOFT
678     {"TCSASOFT", TCSASOFT},
679 #endif
680 
681     /* tcflush() constants */
682     {"TCIFLUSH", TCIFLUSH},
683     {"TCOFLUSH", TCOFLUSH},
684     {"TCIOFLUSH", TCIOFLUSH},
685 
686     /* tcflow() constants */
687     {"TCOOFF", TCOOFF},
688     {"TCOON", TCOON},
689     {"TCIOFF", TCIOFF},
690     {"TCION", TCION},
691 
692     /* struct termios.c_iflag constants */
693     {"IGNBRK", IGNBRK},
694     {"BRKINT", BRKINT},
695     {"IGNPAR", IGNPAR},
696     {"PARMRK", PARMRK},
697     {"INPCK", INPCK},
698     {"ISTRIP", ISTRIP},
699     {"INLCR", INLCR},
700     {"IGNCR", IGNCR},
701     {"ICRNL", ICRNL},
702 #ifdef IUCLC
703     {"IUCLC", IUCLC},
704 #endif
705     {"IXON", IXON},
706     {"IXANY", IXANY},
707     {"IXOFF", IXOFF},
708 #ifdef IMAXBEL
709     {"IMAXBEL", IMAXBEL},
710 #endif
711 #ifdef IUTF8
712     {"IUTF8", IUTF8},
713 #endif
714 
715     /* struct termios.c_oflag constants */
716     {"OPOST", OPOST},
717 #ifdef OLCUC
718     {"OLCUC", OLCUC},
719 #endif
720 #ifdef ONLCR
721     {"ONLCR", ONLCR},
722 #endif
723 #ifdef OCRNL
724     {"OCRNL", OCRNL},
725 #endif
726 #ifdef ONOCR
727     {"ONOCR", ONOCR},
728 #endif
729 #ifdef ONLRET
730     {"ONLRET", ONLRET},
731 #endif
732 #ifdef OFILL
733     {"OFILL", OFILL},
734 #endif
735 #ifdef OFDEL
736     {"OFDEL", OFDEL},
737 #endif
738 #ifdef OXTABS
739     {"OXTABS", OXTABS},
740 #endif
741 #ifdef ONOEOT
742     {"ONOEOT", ONOEOT},
743 #endif
744 #ifdef NLDLY
745     {"NLDLY", NLDLY},
746 #endif
747 #ifdef CRDLY
748     {"CRDLY", CRDLY},
749 #endif
750 #ifdef TABDLY
751     {"TABDLY", TABDLY},
752 #endif
753 #ifdef BSDLY
754     {"BSDLY", BSDLY},
755 #endif
756 #ifdef VTDLY
757     {"VTDLY", VTDLY},
758 #endif
759 #ifdef FFDLY
760     {"FFDLY", FFDLY},
761 #endif
762 
763     /* struct termios.c_oflag-related values (delay mask) */
764 #ifdef NL0
765     {"NL0", NL0},
766 #endif
767 #ifdef NL1
768     {"NL1", NL1},
769 #endif
770 #ifdef NL2
771     {"NL2", NL2},
772 #endif
773 #ifdef NL3
774     {"NL3", NL3},
775 #endif
776 #ifdef CR0
777     {"CR0", CR0},
778 #endif
779 #ifdef CR1
780     {"CR1", CR1},
781 #endif
782 #ifdef CR2
783     {"CR2", CR2},
784 #endif
785 #ifdef CR3
786     {"CR3", CR3},
787 #endif
788 #ifdef TAB0
789     {"TAB0", TAB0},
790 #endif
791 #ifdef TAB1
792     {"TAB1", TAB1},
793 #endif
794 #ifdef TAB2
795     {"TAB2", TAB2},
796 #endif
797 #ifdef TAB3
798     {"TAB3", TAB3},
799 #endif
800 #ifdef XTABS
801     {"XTABS", XTABS},
802 #endif
803 #ifdef BS0
804     {"BS0", BS0},
805 #endif
806 #ifdef BS1
807     {"BS1", BS1},
808 #endif
809 #ifdef VT0
810     {"VT0", VT0},
811 #endif
812 #ifdef VT1
813     {"VT1", VT1},
814 #endif
815 #ifdef FF0
816     {"FF0", FF0},
817 #endif
818 #ifdef FF1
819     {"FF1", FF1},
820 #endif
821 
822     /* struct termios.c_cflag constants */
823 #ifdef CIGNORE
824     {"CIGNORE", CIGNORE},
825 #endif
826     {"CSIZE", CSIZE},
827     {"CSTOPB", CSTOPB},
828     {"CREAD", CREAD},
829     {"PARENB", PARENB},
830     {"PARODD", PARODD},
831     {"HUPCL", HUPCL},
832     {"CLOCAL", CLOCAL},
833 #ifdef CIBAUD
834     {"CIBAUD", CIBAUD},
835 #endif
836 #ifdef CRTSCTS
837     {"CRTSCTS", (long)CRTSCTS},
838 #endif
839 
840 #ifdef CRTS_IFLOW
841     {"CRTS_IFLOW", CRTS_IFLOW},
842 #endif
843 #ifdef CDTR_IFLOW
844     {"CDTR_IFLOW", CDTR_IFLOW},
845 #endif
846 #ifdef CDSR_OFLOW
847     {"CDSR_OFLOW", CDSR_OFLOW},
848 #endif
849 #ifdef CCTS_OFLOW
850     {"CCTS_OFLOW", CCTS_OFLOW},
851 #endif
852 #ifdef CCAR_OFLOW
853     {"CCAR_OFLOW", CCAR_OFLOW},
854 #endif
855 #ifdef MDMBUF
856     {"MDMBUF", MDMBUF},
857 #endif
858 
859     /* struct termios.c_cflag-related values (character size) */
860     {"CS5", CS5},
861     {"CS6", CS6},
862     {"CS7", CS7},
863     {"CS8", CS8},
864 
865     /* struct termios.c_lflag constants */
866 #ifdef ALTWERASE
867     {"ALTWERASE", ALTWERASE},
868 #endif
869     {"ISIG", ISIG},
870     {"ICANON", ICANON},
871 #ifdef XCASE
872     {"XCASE", XCASE},
873 #endif
874     {"ECHO", ECHO},
875     {"ECHOE", ECHOE},
876     {"ECHOK", ECHOK},
877     {"ECHONL", ECHONL},
878 #ifdef ECHOCTL
879     {"ECHOCTL", ECHOCTL},
880 #endif
881 #ifdef ECHOPRT
882     {"ECHOPRT", ECHOPRT},
883 #endif
884 #ifdef ECHOKE
885     {"ECHOKE", ECHOKE},
886 #endif
887 #ifdef FLUSHO
888     {"FLUSHO", FLUSHO},
889 #endif
890 #ifdef NOKERNINFO
891     {"NOKERNINFO", NOKERNINFO},
892 #endif
893     {"NOFLSH", NOFLSH},
894     {"TOSTOP", TOSTOP},
895 #ifdef PENDIN
896     {"PENDIN", PENDIN},
897 #endif
898     {"IEXTEN", IEXTEN},
899 #ifdef EXTPROC
900     {"EXTPROC", EXTPROC},
901 #endif
902 
903     /* indexes into the control chars array returned by tcgetattr() */
904     {"VINTR", VINTR},
905     {"VQUIT", VQUIT},
906     {"VERASE", VERASE},
907     {"VKILL", VKILL},
908     {"VEOF", VEOF},
909     {"VTIME", VTIME},
910 #ifdef VSTATUS
911     {"VSTATUS", VSTATUS},
912 #endif
913     {"VMIN", VMIN},
914 #ifdef VSWTC
915     /* The #defines above ensure that if either is defined, both are,
916      * but both may be omitted by the system headers.  ;-(  */
917     {"VSWTC", VSWTC},
918     {"VSWTCH", VSWTCH},
919 #endif
920     {"VSTART", VSTART},
921     {"VSTOP", VSTOP},
922     {"VSUSP", VSUSP},
923 #ifdef VDSUSP
924     {"VDSUSP", VDSUSP},
925 #endif
926     {"VEOL", VEOL},
927 #ifdef VREPRINT
928     {"VREPRINT", VREPRINT},
929 #endif
930 #ifdef VDISCARD
931     {"VDISCARD", VDISCARD},
932 #endif
933 #ifdef VWERASE
934     {"VWERASE", VWERASE},
935 #endif
936 #ifdef VLNEXT
937     {"VLNEXT", VLNEXT},
938 #endif
939 #ifdef VEOL2
940     {"VEOL2", VEOL2},
941 #endif
942 
943 
944 #ifdef B7200
945     {"B7200", B7200},
946 #endif
947 #ifdef B14400
948     {"B14400", B14400},
949 #endif
950 #ifdef B28800
951     {"B28800", B28800},
952 #endif
953 #ifdef B76800
954     {"B76800", B76800},
955 #endif
956 #ifdef B460800
957     {"B460800", B460800},
958 #endif
959 #ifdef B500000
960     {"B500000", B500000},
961 #endif
962 #ifdef B576000
963     { "B576000", B576000},
964 #endif
965 #ifdef B921600
966     { "B921600", B921600},
967 #endif
968 #ifdef B1000000
969     { "B1000000", B1000000},
970 #endif
971 #ifdef B1152000
972     { "B1152000", B1152000},
973 #endif
974 #ifdef B1500000
975     { "B1500000", B1500000},
976 #endif
977 #ifdef B2000000
978     { "B2000000", B2000000},
979 #endif
980 #ifdef B2500000
981     { "B2500000", B2500000},
982 #endif
983 #ifdef B3000000
984     { "B3000000", B3000000},
985 #endif
986 #ifdef B3500000
987     { "B3500000", B3500000},
988 #endif
989 #ifdef B4000000
990     { "B4000000", B4000000},
991 #endif
992 #ifdef CBAUD
993     {"CBAUD", CBAUD},
994 #endif
995 #ifdef CDEL
996     {"CDEL", CDEL},
997 #endif
998 #ifdef CDSUSP
999     {"CDSUSP", CDSUSP},
1000 #endif
1001 #ifdef CEOF
1002     {"CEOF", CEOF},
1003 #endif
1004 #ifdef CEOL
1005     {"CEOL", CEOL},
1006 #endif
1007 #ifdef CEOL2
1008     {"CEOL2", CEOL2},
1009 #endif
1010 #ifdef CEOT
1011     {"CEOT", CEOT},
1012 #endif
1013 #ifdef CERASE
1014     {"CERASE", CERASE},
1015 #endif
1016 #ifdef CESC
1017     {"CESC", CESC},
1018 #endif
1019 #ifdef CFLUSH
1020     {"CFLUSH", CFLUSH},
1021 #endif
1022 #ifdef CINTR
1023     {"CINTR", CINTR},
1024 #endif
1025 #ifdef CKILL
1026     {"CKILL", CKILL},
1027 #endif
1028 #ifdef CLNEXT
1029     {"CLNEXT", CLNEXT},
1030 #endif
1031 #ifdef CNUL
1032     {"CNUL", CNUL},
1033 #endif
1034 #ifdef COMMON
1035     {"COMMON", COMMON},
1036 #endif
1037 #ifdef CQUIT
1038     {"CQUIT", CQUIT},
1039 #endif
1040 #ifdef CRPRNT
1041     {"CRPRNT", CRPRNT},
1042 #endif
1043 #ifdef CSTART
1044     {"CSTART", CSTART},
1045 #endif
1046 #ifdef CSTOP
1047     {"CSTOP", CSTOP},
1048 #endif
1049 #ifdef CSUSP
1050     {"CSUSP", CSUSP},
1051 #endif
1052 #ifdef CSWTCH
1053     {"CSWTCH", CSWTCH},
1054 #endif
1055 #ifdef CWERASE
1056     {"CWERASE", CWERASE},
1057 #endif
1058 #ifdef EXTA
1059     {"EXTA", EXTA},
1060 #endif
1061 #ifdef EXTB
1062     {"EXTB", EXTB},
1063 #endif
1064 #ifdef FIOASYNC
1065     {"FIOASYNC", FIOASYNC},
1066 #endif
1067 #ifdef FIOCLEX
1068     {"FIOCLEX", FIOCLEX},
1069 #endif
1070 #ifdef FIONBIO
1071     {"FIONBIO", FIONBIO},
1072 #endif
1073 #ifdef FIONCLEX
1074     {"FIONCLEX", FIONCLEX},
1075 #endif
1076 #ifdef FIONREAD
1077     {"FIONREAD", FIONREAD},
1078 #endif
1079 #ifdef IBSHIFT
1080     {"IBSHIFT", IBSHIFT},
1081 #endif
1082 #ifdef INIT_C_CC
1083     {"INIT_C_CC", INIT_C_CC},
1084 #endif
1085 #ifdef IOCSIZE_MASK
1086     {"IOCSIZE_MASK", IOCSIZE_MASK},
1087 #endif
1088 #ifdef IOCSIZE_SHIFT
1089     {"IOCSIZE_SHIFT", IOCSIZE_SHIFT},
1090 #endif
1091 #ifdef NCC
1092     {"NCC", NCC},
1093 #endif
1094 #ifdef NCCS
1095     {"NCCS", NCCS},
1096 #endif
1097 #ifdef NSWTCH
1098     {"NSWTCH", NSWTCH},
1099 #endif
1100 #ifdef N_MOUSE
1101     {"N_MOUSE", N_MOUSE},
1102 #endif
1103 #ifdef N_PPP
1104     {"N_PPP", N_PPP},
1105 #endif
1106 #ifdef N_SLIP
1107     {"N_SLIP", N_SLIP},
1108 #endif
1109 #ifdef N_STRIP
1110     {"N_STRIP", N_STRIP},
1111 #endif
1112 #ifdef N_TTY
1113     {"N_TTY", N_TTY},
1114 #endif
1115 #ifdef TCFLSH
1116     {"TCFLSH", TCFLSH},
1117 #endif
1118 #ifdef TCGETA
1119     {"TCGETA", TCGETA},
1120 #endif
1121 #ifdef TCGETS
1122     {"TCGETS", TCGETS},
1123 #endif
1124 #ifdef TCSBRK
1125     {"TCSBRK", TCSBRK},
1126 #endif
1127 #ifdef TCSBRKP
1128     {"TCSBRKP", TCSBRKP},
1129 #endif
1130 #ifdef TCSETA
1131     {"TCSETA", TCSETA},
1132 #endif
1133 #ifdef TCSETAF
1134     {"TCSETAF", TCSETAF},
1135 #endif
1136 #ifdef TCSETAW
1137     {"TCSETAW", TCSETAW},
1138 #endif
1139 #ifdef TCSETS
1140     {"TCSETS", TCSETS},
1141 #endif
1142 #ifdef TCSETSF
1143     {"TCSETSF", TCSETSF},
1144 #endif
1145 #ifdef TCSETSW
1146     {"TCSETSW", TCSETSW},
1147 #endif
1148 #ifdef TCXONC
1149     {"TCXONC", TCXONC},
1150 #endif
1151 #ifdef TIOCCONS
1152     {"TIOCCONS", TIOCCONS},
1153 #endif
1154 #ifdef TIOCEXCL
1155     {"TIOCEXCL", TIOCEXCL},
1156 #endif
1157 #ifdef TIOCGETD
1158     {"TIOCGETD", TIOCGETD},
1159 #endif
1160 #ifdef TIOCGICOUNT
1161     {"TIOCGICOUNT", TIOCGICOUNT},
1162 #endif
1163 #ifdef TIOCGLCKTRMIOS
1164     {"TIOCGLCKTRMIOS", TIOCGLCKTRMIOS},
1165 #endif
1166 #ifdef TIOCGPGRP
1167     {"TIOCGPGRP", TIOCGPGRP},
1168 #endif
1169 #ifdef TIOCGSERIAL
1170     {"TIOCGSERIAL", TIOCGSERIAL},
1171 #endif
1172 #ifdef TIOCGSIZE
1173     {"TIOCGSIZE", TIOCGSIZE},
1174 #endif
1175 #ifdef TIOCGSOFTCAR
1176     {"TIOCGSOFTCAR", TIOCGSOFTCAR},
1177 #endif
1178 #ifdef TIOCGWINSZ
1179     {"TIOCGWINSZ", TIOCGWINSZ},
1180 #endif
1181 #ifdef TIOCINQ
1182     {"TIOCINQ", TIOCINQ},
1183 #endif
1184 #ifdef TIOCLINUX
1185     {"TIOCLINUX", TIOCLINUX},
1186 #endif
1187 #ifdef TIOCMBIC
1188     {"TIOCMBIC", TIOCMBIC},
1189 #endif
1190 #ifdef TIOCMBIS
1191     {"TIOCMBIS", TIOCMBIS},
1192 #endif
1193 #ifdef TIOCMGET
1194     {"TIOCMGET", TIOCMGET},
1195 #endif
1196 #ifdef TIOCMIWAIT
1197     {"TIOCMIWAIT", TIOCMIWAIT},
1198 #endif
1199 #ifdef TIOCMSET
1200     {"TIOCMSET", TIOCMSET},
1201 #endif
1202 #ifdef TIOCM_CAR
1203     {"TIOCM_CAR", TIOCM_CAR},
1204 #endif
1205 #ifdef TIOCM_CD
1206     {"TIOCM_CD", TIOCM_CD},
1207 #endif
1208 #ifdef TIOCM_CTS
1209     {"TIOCM_CTS", TIOCM_CTS},
1210 #endif
1211 #ifdef TIOCM_DSR
1212     {"TIOCM_DSR", TIOCM_DSR},
1213 #endif
1214 #ifdef TIOCM_DTR
1215     {"TIOCM_DTR", TIOCM_DTR},
1216 #endif
1217 #ifdef TIOCM_LE
1218     {"TIOCM_LE", TIOCM_LE},
1219 #endif
1220 #ifdef TIOCM_RI
1221     {"TIOCM_RI", TIOCM_RI},
1222 #endif
1223 #ifdef TIOCM_RNG
1224     {"TIOCM_RNG", TIOCM_RNG},
1225 #endif
1226 #ifdef TIOCM_RTS
1227     {"TIOCM_RTS", TIOCM_RTS},
1228 #endif
1229 #ifdef TIOCM_SR
1230     {"TIOCM_SR", TIOCM_SR},
1231 #endif
1232 #ifdef TIOCM_ST
1233     {"TIOCM_ST", TIOCM_ST},
1234 #endif
1235 #ifdef TIOCNOTTY
1236     {"TIOCNOTTY", TIOCNOTTY},
1237 #endif
1238 #ifdef TIOCNXCL
1239     {"TIOCNXCL", TIOCNXCL},
1240 #endif
1241 #ifdef TIOCOUTQ
1242     {"TIOCOUTQ", TIOCOUTQ},
1243 #endif
1244 #ifdef TIOCPKT
1245     {"TIOCPKT", TIOCPKT},
1246 #endif
1247 #ifdef TIOCPKT_DATA
1248     {"TIOCPKT_DATA", TIOCPKT_DATA},
1249 #endif
1250 #ifdef TIOCPKT_DOSTOP
1251     {"TIOCPKT_DOSTOP", TIOCPKT_DOSTOP},
1252 #endif
1253 #ifdef TIOCPKT_FLUSHREAD
1254     {"TIOCPKT_FLUSHREAD", TIOCPKT_FLUSHREAD},
1255 #endif
1256 #ifdef TIOCPKT_FLUSHWRITE
1257     {"TIOCPKT_FLUSHWRITE", TIOCPKT_FLUSHWRITE},
1258 #endif
1259 #ifdef TIOCPKT_NOSTOP
1260     {"TIOCPKT_NOSTOP", TIOCPKT_NOSTOP},
1261 #endif
1262 #ifdef TIOCPKT_START
1263     {"TIOCPKT_START", TIOCPKT_START},
1264 #endif
1265 #ifdef TIOCPKT_STOP
1266     {"TIOCPKT_STOP", TIOCPKT_STOP},
1267 #endif
1268 #ifdef TIOCSCTTY
1269     {"TIOCSCTTY", TIOCSCTTY},
1270 #endif
1271 #ifdef TIOCSERCONFIG
1272     {"TIOCSERCONFIG", TIOCSERCONFIG},
1273 #endif
1274 #ifdef TIOCSERGETLSR
1275     {"TIOCSERGETLSR", TIOCSERGETLSR},
1276 #endif
1277 #ifdef TIOCSERGETMULTI
1278     {"TIOCSERGETMULTI", TIOCSERGETMULTI},
1279 #endif
1280 #ifdef TIOCSERGSTRUCT
1281     {"TIOCSERGSTRUCT", TIOCSERGSTRUCT},
1282 #endif
1283 #ifdef TIOCSERGWILD
1284     {"TIOCSERGWILD", TIOCSERGWILD},
1285 #endif
1286 #ifdef TIOCSERSETMULTI
1287     {"TIOCSERSETMULTI", TIOCSERSETMULTI},
1288 #endif
1289 #ifdef TIOCSERSWILD
1290     {"TIOCSERSWILD", TIOCSERSWILD},
1291 #endif
1292 #ifdef TIOCSER_TEMT
1293     {"TIOCSER_TEMT", TIOCSER_TEMT},
1294 #endif
1295 #ifdef TIOCSETD
1296     {"TIOCSETD", TIOCSETD},
1297 #endif
1298 #ifdef TIOCSLCKTRMIOS
1299     {"TIOCSLCKTRMIOS", TIOCSLCKTRMIOS},
1300 #endif
1301 #ifdef TIOCSPGRP
1302     {"TIOCSPGRP", TIOCSPGRP},
1303 #endif
1304 #ifdef TIOCSSERIAL
1305     {"TIOCSSERIAL", TIOCSSERIAL},
1306 #endif
1307 #ifdef TIOCSSIZE
1308     {"TIOCSSIZE", TIOCSSIZE},
1309 #endif
1310 #ifdef TIOCSSOFTCAR
1311     {"TIOCSSOFTCAR", TIOCSSOFTCAR},
1312 #endif
1313 #ifdef TIOCSTI
1314     {"TIOCSTI", TIOCSTI},
1315 #endif
1316 #ifdef TIOCSWINSZ
1317     {"TIOCSWINSZ", TIOCSWINSZ},
1318 #endif
1319 #ifdef TIOCTTYGSTRUCT
1320     {"TIOCTTYGSTRUCT", TIOCTTYGSTRUCT},
1321 #endif
1322 #ifdef _POSIX_VDISABLE
1323     {"_POSIX_VDISABLE", _POSIX_VDISABLE},
1324 #endif
1325 
1326     /* sentinel */
1327     {NULL, 0}
1328 };
1329 
termiosmodule_traverse(PyObject * m,visitproc visit,void * arg)1330 static int termiosmodule_traverse(PyObject *m, visitproc visit, void *arg) {
1331     Py_VISIT(get_termios_state(m)->TermiosError);
1332     return 0;
1333 }
1334 
termiosmodule_clear(PyObject * m)1335 static int termiosmodule_clear(PyObject *m) {
1336     Py_CLEAR(get_termios_state(m)->TermiosError);
1337     return 0;
1338 }
1339 
termiosmodule_free(void * m)1340 static void termiosmodule_free(void *m) {
1341     termiosmodule_clear((PyObject *)m);
1342 }
1343 
1344 static int
termios_exec(PyObject * mod)1345 termios_exec(PyObject *mod)
1346 {
1347     struct constant *constant = termios_constants;
1348     termiosmodulestate *state = get_termios_state(mod);
1349     state->TermiosError = PyErr_NewException("termios.error", NULL, NULL);
1350     if (PyModule_AddObjectRef(mod, "error", state->TermiosError) < 0) {
1351         return -1;
1352     }
1353 
1354     while (constant->name != NULL) {
1355         if (PyModule_AddIntConstant(
1356             mod, constant->name, constant->value) < 0) {
1357             return -1;
1358         }
1359         ++constant;
1360     }
1361     return 0;
1362 }
1363 
1364 static PyModuleDef_Slot termios_slots[] = {
1365     {Py_mod_exec, termios_exec},
1366     {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
1367     {Py_mod_gil, Py_MOD_GIL_NOT_USED},
1368     {0, NULL}
1369 };
1370 
1371 static struct PyModuleDef termiosmodule = {
1372     PyModuleDef_HEAD_INIT,
1373     .m_name = "termios",
1374     .m_doc = termios__doc__,
1375     .m_size = sizeof(termiosmodulestate),
1376     .m_methods = termios_methods,
1377     .m_slots = termios_slots,
1378     .m_traverse = termiosmodule_traverse,
1379     .m_clear = termiosmodule_clear,
1380     .m_free = termiosmodule_free,
1381 };
1382 
PyInit_termios(void)1383 PyMODINIT_FUNC PyInit_termios(void)
1384 {
1385     return PyModuleDef_Init(&termiosmodule);
1386 }
1387