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