1use crate::backend::c;
2use crate::backend::termios::types;
3#[cfg(target_os = "nto")]
4use crate::ffi;
5use crate::{backend, io};
6use bitflags::bitflags;
7
8/// `struct termios` for use with [`tcgetattr`] and [`tcsetattr`].
9///
10/// [`tcgetattr`]: crate::termios::tcgetattr
11/// [`tcsetattr`]: crate::termios::tcsetattr
12#[repr(C)]
13#[derive(Clone)]
14pub struct Termios {
15 /// How is input interpreted?
16 #[doc(alias = "c_iflag")]
17 pub input_modes: InputModes,
18
19 /// How is output translated?
20 #[doc(alias = "c_oflag")]
21 pub output_modes: OutputModes,
22
23 /// Low-level configuration flags.
24 #[doc(alias = "c_cflag")]
25 pub control_modes: ControlModes,
26
27 /// High-level configuration flags.
28 #[doc(alias = "c_lflag")]
29 pub local_modes: LocalModes,
30
31 /// Line discipline.
32 #[doc(alias = "c_line")]
33 #[cfg(not(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64"))))]
34 #[cfg(any(
35 linux_like,
36 target_env = "newlib",
37 target_os = "fuchsia",
38 target_os = "haiku",
39 target_os = "redox"
40 ))]
41 pub line_discipline: u8,
42
43 /// How are various special control codes handled?
44 #[doc(alias = "c_cc")]
45 #[cfg(not(target_os = "haiku"))]
46 pub special_codes: SpecialCodes,
47
48 #[cfg(target_os = "nto")]
49 pub(crate) __reserved: [ffi::c_uint; 3],
50
51 /// Line discipline.
52 // On PowerPC, this field comes after `c_cc`.
53 #[doc(alias = "c_line")]
54 #[cfg(all(linux_raw, any(target_arch = "powerpc", target_arch = "powerpc64")))]
55 pub line_discipline: c::cc_t,
56
57 /// See the `input_speed` and `set_input_seed` functions.
58 ///
59 /// On Linux and BSDs, this is the arbitrary integer speed value. On all
60 /// other platforms, this is the encoded speed value.
61 #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))]
62 pub(crate) input_speed: c::speed_t,
63
64 /// See the `output_speed` and `set_output_seed` functions.
65 ///
66 /// On Linux and BSDs, this is the integer speed value. On all other
67 /// platforms, this is the encoded speed value.
68 #[cfg(not(any(solarish, all(libc, target_env = "newlib"), target_os = "aix")))]
69 pub(crate) output_speed: c::speed_t,
70
71 /// How are various special control codes handled?
72 #[doc(alias = "c_cc")]
73 #[cfg(target_os = "haiku")]
74 pub special_codes: SpecialCodes,
75}
76
77impl Termios {
78 /// `cfmakeraw(self)`—Set a `Termios` value to the settings for “raw” mode.
79 ///
80 /// In raw mode, input is available a byte at a time, echoing is disabled,
81 /// and special terminal input and output codes are disabled.
82 #[cfg(not(target_os = "nto"))]
83 #[doc(alias = "cfmakeraw")]
84 #[inline]
85 pub fn make_raw(&mut self) {
86 backend::termios::syscalls::cfmakeraw(self)
87 }
88
89 /// Return the input communication speed.
90 ///
91 /// Unlike the `c_ispeed` field in glibc and others, this returns the
92 /// integer value of the speed, rather than the `B*` encoded constant
93 /// value.
94 #[doc(alias = "c_ispeed")]
95 #[doc(alias = "cfgetispeed")]
96 #[doc(alias = "cfgetspeed")]
97 #[inline]
98 pub fn input_speed(&self) -> u32 {
99 // On Linux and BSDs, `input_speed` is the arbitrary integer speed.
100 #[cfg(any(linux_kernel, bsd))]
101 {
102 debug_assert!(u32::try_from(self.input_speed).is_ok());
103 self.input_speed as u32
104 }
105
106 // On illumos, `input_speed` is not present.
107 #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))]
108 unsafe {
109 speed::decode(c::cfgetispeed(crate::utils::as_ptr(self).cast())).unwrap()
110 }
111
112 // On other platforms, it's the encoded speed.
113 #[cfg(not(any(
114 linux_kernel,
115 bsd,
116 solarish,
117 all(libc, target_env = "newlib"),
118 target_os = "aix"
119 )))]
120 {
121 speed::decode(self.input_speed).unwrap()
122 }
123 }
124
125 /// Return the output communication speed.
126 ///
127 /// Unlike the `c_ospeed` field in glibc and others, this returns the
128 /// arbitrary integer value of the speed, rather than the `B*` encoded
129 /// constant value.
130 #[inline]
131 pub fn output_speed(&self) -> u32 {
132 // On Linux and BSDs, `output_speed` is the arbitrary integer speed.
133 #[cfg(any(linux_kernel, bsd))]
134 {
135 debug_assert!(u32::try_from(self.output_speed).is_ok());
136 self.output_speed as u32
137 }
138
139 // On illumos, `output_speed` is not present.
140 #[cfg(any(solarish, all(libc, target_env = "newlib"), target_os = "aix"))]
141 unsafe {
142 speed::decode(c::cfgetospeed(crate::utils::as_ptr(self).cast())).unwrap()
143 }
144
145 // On other platforms, it's the encoded speed.
146 #[cfg(not(any(
147 linux_kernel,
148 bsd,
149 solarish,
150 all(libc, target_env = "newlib"),
151 target_os = "aix"
152 )))]
153 {
154 speed::decode(self.output_speed).unwrap()
155 }
156 }
157
158 /// Set the input and output communication speeds.
159 ///
160 /// Unlike the `c_ispeed` and `c_ospeed` fields in glibc and others, this
161 /// takes the arbitrary integer value of the speed, rather than the `B*`
162 /// encoded constant value. Not all implementations support all integer
163 /// values; use the constants in the [`speed`] module for likely-supported
164 /// speeds.
165 #[cfg(not(target_os = "nto"))]
166 #[doc(alias = "cfsetspeed")]
167 #[doc(alias = "CBAUD")]
168 #[doc(alias = "CBAUDEX")]
169 #[doc(alias = "CIBAUD")]
170 #[doc(alias = "CIBAUDEX")]
171 #[inline]
172 pub fn set_speed(&mut self, new_speed: u32) -> io::Result<()> {
173 backend::termios::syscalls::set_speed(self, new_speed)
174 }
175
176 /// Set the input communication speed.
177 ///
178 /// Unlike the `c_ispeed` field in glibc and others, this takes the
179 /// arbitrary integer value of the speed, rather than the `B*` encoded
180 /// constant value. Not all implementations support all integer values; use
181 /// the constants in the [`speed`] module for known-supported speeds.
182 ///
183 /// On some platforms, changing the input speed changes the output speed to
184 /// the same speed.
185 #[doc(alias = "c_ispeed")]
186 #[doc(alias = "cfsetispeed")]
187 #[doc(alias = "CIBAUD")]
188 #[doc(alias = "CIBAUDEX")]
189 #[inline]
190 pub fn set_input_speed(&mut self, new_speed: u32) -> io::Result<()> {
191 backend::termios::syscalls::set_input_speed(self, new_speed)
192 }
193
194 /// Set the output communication speed.
195 ///
196 /// Unlike the `c_ospeed` field in glibc and others, this takes the
197 /// arbitrary integer value of the speed, rather than the `B*` encoded
198 /// constant value. Not all implementations support all integer values; use
199 /// the constants in the [`speed`] module for known-supported speeds.
200 ///
201 /// On some platforms, changing the output speed changes the input speed to
202 /// the same speed.
203 #[doc(alias = "c_ospeed")]
204 #[doc(alias = "cfsetospeed")]
205 #[doc(alias = "CBAUD")]
206 #[doc(alias = "CBAUDEX")]
207 #[inline]
208 pub fn set_output_speed(&mut self, new_speed: u32) -> io::Result<()> {
209 backend::termios::syscalls::set_output_speed(self, new_speed)
210 }
211}
212
213impl core::fmt::Debug for Termios {
214 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215 let mut d = f.debug_struct("Termios");
216 d.field("input_modes", &self.input_modes);
217 d.field("output_modes", &self.output_modes);
218
219 // This includes any bits set in the `CBAUD` and `CIBAUD` ranges, which
220 // is a little ugly, because we also decode those bits for the speeds
221 // below. However, it seems better to print them here than to hide
222 // them, because hiding them would make the `Termios` debug output
223 // appear to disagree with the `ControlModes` debug output for the same
224 // value, which could be confusing.
225 d.field("control_modes", &self.control_modes);
226
227 d.field("local_modes", &self.local_modes);
228 #[cfg(any(
229 linux_like,
230 target_env = "newlib",
231 target_os = "fuchsia",
232 target_os = "haiku",
233 target_os = "redox"
234 ))]
235 {
236 d.field("line_discipline", &SpecialCode(self.line_discipline));
237 }
238 d.field("special_codes", &self.special_codes);
239 d.field("input_speed", &self.input_speed());
240 d.field("output_speed", &self.output_speed());
241 d.finish()
242 }
243}
244
245bitflags! {
246 /// Flags controlling terminal input.
247 #[repr(transparent)]
248 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
249 pub struct InputModes: types::tcflag_t {
250 /// `IGNBRK`
251 const IGNBRK = c::IGNBRK;
252
253 /// `BRKINT`
254 const BRKINT = c::BRKINT;
255
256 /// `IGNPAR`
257 const IGNPAR = c::IGNPAR;
258
259 /// `PARMRK`
260 const PARMRK = c::PARMRK;
261
262 /// `INPCK`
263 const INPCK = c::INPCK;
264
265 /// `ISTRIP`
266 const ISTRIP = c::ISTRIP;
267
268 /// `INLCR`
269 const INLCR = c::INLCR;
270
271 /// `IGNCR`
272 const IGNCR = c::IGNCR;
273
274 /// `ICRNL`
275 const ICRNL = c::ICRNL;
276
277 /// `IUCLC`
278 #[cfg(any(linux_kernel, solarish, target_os = "aix", target_os = "haiku", target_os = "nto"))]
279 const IUCLC = c::IUCLC;
280
281 /// `IXON`
282 const IXON = c::IXON;
283
284 /// `IXANY`
285 #[cfg(not(target_os = "redox"))]
286 const IXANY = c::IXANY;
287
288 /// `IXOFF`
289 const IXOFF = c::IXOFF;
290
291 /// `IMAXBEL`
292 #[cfg(not(any(target_os = "haiku", target_os = "redox")))]
293 const IMAXBEL = c::IMAXBEL;
294
295 /// `IUTF8`
296 #[cfg(not(any(
297 freebsdlike,
298 netbsdlike,
299 solarish,
300 target_os = "aix",
301 target_os = "emscripten",
302 target_os = "haiku",
303 target_os = "hurd",
304 target_os = "redox",
305 )))]
306 const IUTF8 = c::IUTF8;
307
308 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
309 const _ = !0;
310 }
311}
312
313bitflags! {
314 /// Flags controlling terminal output.
315 #[repr(transparent)]
316 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
317 pub struct OutputModes: types::tcflag_t {
318 /// `OPOST`
319 const OPOST = c::OPOST;
320
321 /// `OLCUC`
322 #[cfg(not(any(
323 apple,
324 freebsdlike,
325 target_os = "aix",
326 target_os = "netbsd",
327 target_os = "redox",
328 )))]
329 const OLCUC = c::OLCUC;
330
331 /// `ONLCR`
332 const ONLCR = c::ONLCR;
333
334 /// `OCRNL`
335 const OCRNL = c::OCRNL;
336
337 /// `ONOCR`
338 const ONOCR = c::ONOCR;
339
340 /// `ONLRET`
341 const ONLRET = c::ONLRET;
342
343 /// `OFILL`
344 #[cfg(not(bsd))]
345 const OFILL = c::OFILL;
346
347 /// `OFDEL`
348 #[cfg(not(bsd))]
349 const OFDEL = c::OFDEL;
350
351 /// `NLDLY`
352 #[cfg(not(any(bsd, solarish, target_os = "redox")))]
353 const NLDLY = c::NLDLY;
354
355 /// `NL0`
356 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
357 const NL0 = c::NL0;
358
359 /// `NL1`
360 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
361 const NL1 = c::NL1;
362
363 /// `CRDLY`
364 #[cfg(not(any(bsd, solarish, target_os = "redox")))]
365 const CRDLY = c::CRDLY;
366
367 /// `CR0`
368 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
369 const CR0 = c::CR0;
370
371 /// `CR1`
372 #[cfg(not(any(
373 target_env = "musl",
374 bsd,
375 solarish,
376 target_os = "emscripten",
377 target_os = "fuchsia",
378 target_os = "redox",
379 )))]
380 const CR1 = c::CR1;
381
382 /// `CR2`
383 #[cfg(not(any(
384 target_env = "musl",
385 bsd,
386 solarish,
387 target_os = "emscripten",
388 target_os = "fuchsia",
389 target_os = "redox",
390 )))]
391 const CR2 = c::CR2;
392
393 /// `CR3`
394 #[cfg(not(any(
395 target_env = "musl",
396 bsd,
397 solarish,
398 target_os = "emscripten",
399 target_os = "fuchsia",
400 target_os = "redox",
401 )))]
402 const CR3 = c::CR3;
403
404 /// `TABDLY`
405 #[cfg(not(any(
406 netbsdlike,
407 solarish,
408 target_os = "dragonfly",
409 target_os = "redox",
410 )))]
411 const TABDLY = c::TABDLY;
412
413 /// `TAB0`
414 #[cfg(not(any(
415 netbsdlike,
416 solarish,
417 target_os = "dragonfly",
418 target_os = "fuchsia",
419 target_os = "redox",
420 )))]
421 const TAB0 = c::TAB0;
422
423 /// `TAB1`
424 #[cfg(not(any(
425 target_env = "musl",
426 bsd,
427 solarish,
428 target_os = "emscripten",
429 target_os = "fuchsia",
430 target_os = "redox",
431 )))]
432 const TAB1 = c::TAB1;
433
434 /// `TAB2`
435 #[cfg(not(any(
436 target_env = "musl",
437 bsd,
438 solarish,
439 target_os = "emscripten",
440 target_os = "fuchsia",
441 target_os = "redox",
442 )))]
443 const TAB2 = c::TAB2;
444
445 /// `TAB3`
446 #[cfg(not(any(
447 target_env = "musl",
448 bsd,
449 solarish,
450 target_os = "emscripten",
451 target_os = "fuchsia",
452 target_os = "redox",
453 )))]
454 const TAB3 = c::TAB3;
455
456 /// `XTABS`
457 #[cfg(not(any(
458 bsd,
459 solarish,
460 target_os = "aix",
461 target_os = "haiku",
462 target_os = "redox",
463 )))]
464 const XTABS = c::XTABS;
465
466 /// `BSDLY`
467 #[cfg(not(any(bsd, solarish, target_os = "redox")))]
468 const BSDLY = c::BSDLY;
469
470 /// `BS0`
471 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
472 const BS0 = c::BS0;
473
474 /// `BS1`
475 #[cfg(not(any(
476 target_env = "musl",
477 bsd,
478 solarish,
479 target_os = "emscripten",
480 target_os = "fuchsia",
481 target_os = "redox",
482 )))]
483 const BS1 = c::BS1;
484
485 /// `FFDLY`
486 #[cfg(not(any(bsd, solarish, target_os = "redox")))]
487 const FFDLY = c::FFDLY;
488
489 /// `FF0`
490 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
491 const FF0 = c::FF0;
492
493 /// `FF1`
494 #[cfg(not(any(
495 target_env = "musl",
496 bsd,
497 solarish,
498 target_os = "emscripten",
499 target_os = "fuchsia",
500 target_os = "redox",
501 )))]
502 const FF1 = c::FF1;
503
504 /// `VTDLY`
505 #[cfg(not(any(bsd, solarish, target_os = "redox")))]
506 const VTDLY = c::VTDLY;
507
508 /// `VT0`
509 #[cfg(not(any(bsd, solarish, target_os = "fuchsia", target_os = "redox")))]
510 const VT0 = c::VT0;
511
512 /// `VT1`
513 #[cfg(not(any(
514 target_env = "musl",
515 bsd,
516 solarish,
517 target_os = "emscripten",
518 target_os = "fuchsia",
519 target_os = "redox",
520 )))]
521 const VT1 = c::VT1;
522
523 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
524 const _ = !0;
525 }
526}
527
528bitflags! {
529 /// Flags controlling special terminal modes.
530 ///
531 /// `CBAUD`, `CBAUDEX`, `CIBAUD`, `CIBAUDEX`, and various `B*` speed
532 /// constants are often included in the control modes, however rustix
533 /// handles them separately, in [`Termios::set_speed`] and related
534 /// functions. If you see extra bits in the `Debug` output, they're
535 /// probably these flags.
536 #[repr(transparent)]
537 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
538 pub struct ControlModes: types::tcflag_t {
539 /// `CSIZE`
540 const CSIZE = c::CSIZE;
541
542 /// `CS5`
543 const CS5 = c::CS5;
544
545 /// `CS6`
546 const CS6 = c::CS6;
547
548 /// `CS7`
549 const CS7 = c::CS7;
550
551 /// `CS8`
552 const CS8 = c::CS8;
553
554 /// `CSTOPB`
555 const CSTOPB = c::CSTOPB;
556
557 /// `CREAD`
558 const CREAD = c::CREAD;
559
560 /// `PARENB`
561 const PARENB = c::PARENB;
562
563 /// `PARODD`
564 const PARODD = c::PARODD;
565
566 /// `HUPCL`
567 const HUPCL = c::HUPCL;
568
569 /// `CLOCAL`
570 const CLOCAL = c::CLOCAL;
571
572 /// `CRTSCTS`
573 #[cfg(not(any(target_os = "aix", target_os = "nto", target_os = "redox")))]
574 const CRTSCTS = c::CRTSCTS;
575
576 /// `CMSPAR`
577 #[cfg(not(any(
578 bsd,
579 solarish,
580 target_os = "aix",
581 target_os = "emscripten",
582 target_os = "haiku",
583 target_os = "hurd",
584 target_os = "nto",
585 target_os = "redox",
586 )))]
587 const CMSPAR = c::CMSPAR;
588
589 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
590 const _ = !0;
591 }
592}
593
594bitflags! {
595 /// Flags controlling “local” terminal modes.
596 #[repr(transparent)]
597 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
598 pub struct LocalModes: types::tcflag_t {
599 /// `XCASE`
600 #[cfg(any(linux_kernel, target_arch = "s390x", target_os = "haiku"))]
601 const XCASE = c::XCASE;
602
603 /// `ECHOCTL`
604 #[cfg(not(target_os = "redox"))]
605 const ECHOCTL = c::ECHOCTL;
606
607 /// `ECHOPRT`
608 #[cfg(not(any(target_os = "cygwin", target_os = "nto", target_os = "redox")))]
609 const ECHOPRT = c::ECHOPRT;
610
611 /// `ECHOKE`
612 #[cfg(not(target_os = "redox"))]
613 const ECHOKE = c::ECHOKE;
614
615 /// `FLUSHO`
616 #[cfg(not(any(target_os = "nto", target_os = "redox")))]
617 const FLUSHO = c::FLUSHO;
618
619 /// `PENDIN`
620 #[cfg(not(any(target_os = "cygwin", target_os = "nto", target_os = "redox")))]
621 const PENDIN = c::PENDIN;
622
623 /// `EXTPROC`
624 #[cfg(not(any(
625 target_os = "aix",
626 target_os = "cygwin",
627 target_os = "haiku",
628 target_os = "nto",
629 target_os = "redox",
630 )))]
631 const EXTPROC = c::EXTPROC;
632
633 /// `ISIG`
634 const ISIG = c::ISIG;
635
636 /// `ICANON`—A flag for the `c_lflag` field of [`Termios`] indicating
637 /// canonical mode.
638 const ICANON = c::ICANON;
639
640 /// `ECHO`
641 const ECHO = c::ECHO;
642
643 /// `ECHOE`
644 const ECHOE = c::ECHOE;
645
646 /// `ECHOK`
647 const ECHOK = c::ECHOK;
648
649 /// `ECHONL`
650 const ECHONL = c::ECHONL;
651
652 /// `NOFLSH`
653 const NOFLSH = c::NOFLSH;
654
655 /// `TOSTOP`
656 const TOSTOP = c::TOSTOP;
657
658 /// `IEXTEN`
659 const IEXTEN = c::IEXTEN;
660
661 /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
662 const _ = !0;
663 }
664}
665
666/// Speeds for use with [`Termios::set_speed`], [`Termios::set_input_speed`],
667/// and [`Termios::set_output_speed`].
668///
669/// Unlike in some platforms' libc APIs, these always have the same numerical
670/// value as their names; for example, `B50` has the value `50`, and so on.
671/// Consequently, it's not necessary to use them. They are provided here
672/// because they help identify speeds which are likely to be supported, on
673/// platforms and devices which don't support arbitrary speeds.
674pub mod speed {
675 #[cfg(not(bsd))]
676 use crate::backend::c;
677
678 /// `B0`
679 pub const B0: u32 = 0;
680
681 /// `B50`
682 pub const B50: u32 = 50;
683
684 /// `B75`
685 pub const B75: u32 = 75;
686
687 /// `B110`
688 pub const B110: u32 = 110;
689
690 /// `B134`
691 pub const B134: u32 = 134;
692
693 /// `B150`
694 pub const B150: u32 = 150;
695
696 /// `B200`
697 pub const B200: u32 = 200;
698
699 /// `B300`
700 pub const B300: u32 = 300;
701
702 /// `B600`
703 pub const B600: u32 = 600;
704
705 /// `B1200`
706 pub const B1200: u32 = 1200;
707
708 /// `B1800`
709 pub const B1800: u32 = 1800;
710
711 /// `B2400`
712 pub const B2400: u32 = 2400;
713
714 /// `B4800`
715 pub const B4800: u32 = 4800;
716
717 /// `B9600`
718 pub const B9600: u32 = 9600;
719
720 /// `B19200`
721 #[doc(alias = "EXTA")]
722 pub const B19200: u32 = 19200;
723
724 /// `B38400`
725 #[doc(alias = "EXTB")]
726 pub const B38400: u32 = 38400;
727
728 /// `B57600`
729 #[cfg(not(target_os = "aix"))]
730 pub const B57600: u32 = 57600;
731
732 /// `B115200`
733 #[cfg(not(target_os = "aix"))]
734 pub const B115200: u32 = 115_200;
735
736 /// `B230400`
737 #[cfg(not(target_os = "aix"))]
738 pub const B230400: u32 = 230_400;
739
740 /// `B460800`
741 #[cfg(not(any(
742 apple,
743 target_os = "aix",
744 target_os = "dragonfly",
745 target_os = "haiku",
746 target_os = "openbsd"
747 )))]
748 pub const B460800: u32 = 460_800;
749
750 /// `B500000`
751 #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
752 pub const B500000: u32 = 500_000;
753
754 /// `B576000`
755 #[cfg(not(any(bsd, solarish, target_os = "aix", target_os = "haiku")))]
756 pub const B576000: u32 = 576_000;
757
758 /// `B921600`
759 #[cfg(not(any(
760 apple,
761 target_os = "aix",
762 target_os = "dragonfly",
763 target_os = "haiku",
764 target_os = "openbsd"
765 )))]
766 pub const B921600: u32 = 921_600;
767
768 /// `B1000000`
769 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
770 pub const B1000000: u32 = 1_000_000;
771
772 /// `B1152000`
773 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
774 pub const B1152000: u32 = 1_152_000;
775
776 /// `B1500000`
777 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
778 pub const B1500000: u32 = 1_500_000;
779
780 /// `B2000000`
781 #[cfg(not(any(bsd, target_os = "aix", target_os = "haiku", target_os = "solaris")))]
782 pub const B2000000: u32 = 2_000_000;
783
784 /// `B2500000`
785 #[cfg(not(any(
786 target_arch = "sparc",
787 target_arch = "sparc64",
788 bsd,
789 target_os = "aix",
790 target_os = "haiku",
791 target_os = "solaris",
792 )))]
793 pub const B2500000: u32 = 2_500_000;
794
795 /// `B3000000`
796 #[cfg(not(any(
797 target_arch = "sparc",
798 target_arch = "sparc64",
799 bsd,
800 target_os = "aix",
801 target_os = "haiku",
802 target_os = "solaris",
803 )))]
804 pub const B3000000: u32 = 3_000_000;
805
806 /// `B3500000`
807 #[cfg(not(any(
808 target_arch = "sparc",
809 target_arch = "sparc64",
810 bsd,
811 target_os = "aix",
812 target_os = "haiku",
813 target_os = "solaris",
814 )))]
815 pub const B3500000: u32 = 3_500_000;
816
817 /// `B4000000`
818 #[cfg(not(any(
819 target_arch = "sparc",
820 target_arch = "sparc64",
821 bsd,
822 target_os = "aix",
823 target_os = "haiku",
824 target_os = "solaris",
825 )))]
826 pub const B4000000: u32 = 4_000_000;
827
828 /// Translate from a `c::speed_t` code to an arbitrary integer speed value
829 /// `u32`.
830 ///
831 /// On BSD platforms, integer speed values are already the same as their
832 /// encoded values.
833 ///
834 /// On Linux on PowerPC, `TCGETS`/`TCSETS` support the `c_ispeed` and
835 /// `c_ospeed` fields.
836 ///
837 /// On Linux on architectures other than PowerPC, `TCGETS`/`TCSETS` don't
838 /// support the `c_ispeed` and `c_ospeed` fields, so we have to fall back
839 /// to `TCGETS2`/`TCSETS2` to support them.
840 #[cfg(not(any(
841 bsd,
842 all(linux_kernel, any(target_arch = "powerpc", target_arch = "powerpc64"))
843 )))]
844 pub(crate) const fn decode(encoded_speed: c::speed_t) -> Option<u32> {
845 match encoded_speed {
846 c::B0 => Some(0),
847 c::B50 => Some(50),
848 c::B75 => Some(75),
849 c::B110 => Some(110),
850 c::B134 => Some(134),
851 c::B150 => Some(150),
852 c::B200 => Some(200),
853 c::B300 => Some(300),
854 c::B600 => Some(600),
855 c::B1200 => Some(1200),
856 c::B1800 => Some(1800),
857 c::B2400 => Some(2400),
858 c::B4800 => Some(4800),
859 c::B9600 => Some(9600),
860 c::B19200 => Some(19200),
861 c::B38400 => Some(38400),
862 #[cfg(not(target_os = "aix"))]
863 c::B57600 => Some(57600),
864 #[cfg(not(target_os = "aix"))]
865 c::B115200 => Some(115_200),
866 #[cfg(not(any(target_os = "aix", target_os = "nto")))]
867 c::B230400 => Some(230_400),
868 #[cfg(not(any(
869 apple,
870 target_os = "aix",
871 target_os = "dragonfly",
872 target_os = "haiku",
873 target_os = "nto",
874 target_os = "openbsd"
875 )))]
876 c::B460800 => Some(460_800),
877 #[cfg(not(any(
878 bsd,
879 solarish,
880 target_os = "aix",
881 target_os = "haiku",
882 target_os = "nto"
883 )))]
884 c::B500000 => Some(500_000),
885 #[cfg(not(any(
886 bsd,
887 solarish,
888 target_os = "aix",
889 target_os = "haiku",
890 target_os = "nto"
891 )))]
892 c::B576000 => Some(576_000),
893 #[cfg(not(any(
894 apple,
895 target_os = "aix",
896 target_os = "dragonfly",
897 target_os = "haiku",
898 target_os = "nto",
899 target_os = "openbsd"
900 )))]
901 c::B921600 => Some(921_600),
902 #[cfg(not(any(
903 bsd,
904 target_os = "aix",
905 target_os = "haiku",
906 target_os = "nto",
907 target_os = "solaris"
908 )))]
909 c::B1000000 => Some(1_000_000),
910 #[cfg(not(any(
911 bsd,
912 target_os = "aix",
913 target_os = "haiku",
914 target_os = "nto",
915 target_os = "solaris"
916 )))]
917 c::B1152000 => Some(1_152_000),
918 #[cfg(not(any(
919 bsd,
920 target_os = "aix",
921 target_os = "haiku",
922 target_os = "nto",
923 target_os = "solaris"
924 )))]
925 c::B1500000 => Some(1_500_000),
926 #[cfg(not(any(
927 bsd,
928 target_os = "aix",
929 target_os = "haiku",
930 target_os = "nto",
931 target_os = "solaris"
932 )))]
933 c::B2000000 => Some(2_000_000),
934 #[cfg(not(any(
935 target_arch = "sparc",
936 target_arch = "sparc64",
937 bsd,
938 target_os = "aix",
939 target_os = "haiku",
940 target_os = "nto",
941 target_os = "solaris",
942 )))]
943 c::B2500000 => Some(2_500_000),
944 #[cfg(not(any(
945 target_arch = "sparc",
946 target_arch = "sparc64",
947 bsd,
948 target_os = "aix",
949 target_os = "haiku",
950 target_os = "nto",
951 target_os = "solaris",
952 )))]
953 c::B3000000 => Some(3_000_000),
954 #[cfg(not(any(
955 target_arch = "sparc",
956 target_arch = "sparc64",
957 bsd,
958 target_os = "aix",
959 target_os = "cygwin",
960 target_os = "haiku",
961 target_os = "nto",
962 target_os = "solaris",
963 )))]
964 c::B3500000 => Some(3_500_000),
965 #[cfg(not(any(
966 target_arch = "sparc",
967 target_arch = "sparc64",
968 bsd,
969 target_os = "aix",
970 target_os = "cygwin",
971 target_os = "haiku",
972 target_os = "nto",
973 target_os = "solaris",
974 )))]
975 c::B4000000 => Some(4_000_000),
976 _ => None,
977 }
978 }
979
980 /// Translate from an arbitrary `u32` arbitrary integer speed value to a
981 /// `c::speed_t` code.
982 #[cfg(not(bsd))]
983 pub(crate) const fn encode(speed: u32) -> Option<c::speed_t> {
984 match speed {
985 0 => Some(c::B0),
986 50 => Some(c::B50),
987 75 => Some(c::B75),
988 110 => Some(c::B110),
989 134 => Some(c::B134),
990 150 => Some(c::B150),
991 200 => Some(c::B200),
992 300 => Some(c::B300),
993 600 => Some(c::B600),
994 1200 => Some(c::B1200),
995 1800 => Some(c::B1800),
996 2400 => Some(c::B2400),
997 4800 => Some(c::B4800),
998 9600 => Some(c::B9600),
999 19200 => Some(c::B19200),
1000 38400 => Some(c::B38400),
1001 #[cfg(not(target_os = "aix"))]
1002 57600 => Some(c::B57600),
1003 #[cfg(not(target_os = "aix"))]
1004 115_200 => Some(c::B115200),
1005 #[cfg(not(any(target_os = "aix", target_os = "nto")))]
1006 230_400 => Some(c::B230400),
1007 #[cfg(not(any(
1008 apple,
1009 target_os = "aix",
1010 target_os = "dragonfly",
1011 target_os = "haiku",
1012 target_os = "nto",
1013 target_os = "openbsd",
1014 )))]
1015 460_800 => Some(c::B460800),
1016 #[cfg(not(any(
1017 bsd,
1018 solarish,
1019 target_os = "aix",
1020 target_os = "haiku",
1021 target_os = "nto"
1022 )))]
1023 500_000 => Some(c::B500000),
1024 #[cfg(not(any(
1025 bsd,
1026 solarish,
1027 target_os = "aix",
1028 target_os = "haiku",
1029 target_os = "nto"
1030 )))]
1031 576_000 => Some(c::B576000),
1032 #[cfg(not(any(
1033 apple,
1034 target_os = "aix",
1035 target_os = "dragonfly",
1036 target_os = "haiku",
1037 target_os = "nto",
1038 target_os = "openbsd"
1039 )))]
1040 921_600 => Some(c::B921600),
1041 #[cfg(not(any(
1042 bsd,
1043 target_os = "aix",
1044 target_os = "haiku",
1045 target_os = "nto",
1046 target_os = "solaris"
1047 )))]
1048 1_000_000 => Some(c::B1000000),
1049 #[cfg(not(any(
1050 bsd,
1051 target_os = "aix",
1052 target_os = "haiku",
1053 target_os = "nto",
1054 target_os = "solaris"
1055 )))]
1056 1_152_000 => Some(c::B1152000),
1057 #[cfg(not(any(
1058 bsd,
1059 target_os = "aix",
1060 target_os = "haiku",
1061 target_os = "nto",
1062 target_os = "solaris"
1063 )))]
1064 1_500_000 => Some(c::B1500000),
1065 #[cfg(not(any(
1066 bsd,
1067 target_os = "aix",
1068 target_os = "haiku",
1069 target_os = "nto",
1070 target_os = "solaris"
1071 )))]
1072 2_000_000 => Some(c::B2000000),
1073 #[cfg(not(any(
1074 target_arch = "sparc",
1075 target_arch = "sparc64",
1076 bsd,
1077 target_os = "aix",
1078 target_os = "haiku",
1079 target_os = "nto",
1080 target_os = "solaris",
1081 )))]
1082 2_500_000 => Some(c::B2500000),
1083 #[cfg(not(any(
1084 target_arch = "sparc",
1085 target_arch = "sparc64",
1086 bsd,
1087 target_os = "aix",
1088 target_os = "haiku",
1089 target_os = "nto",
1090 target_os = "solaris",
1091 )))]
1092 3_000_000 => Some(c::B3000000),
1093 #[cfg(not(any(
1094 target_arch = "sparc",
1095 target_arch = "sparc64",
1096 bsd,
1097 target_os = "aix",
1098 target_os = "cygwin",
1099 target_os = "haiku",
1100 target_os = "nto",
1101 target_os = "solaris",
1102 )))]
1103 3_500_000 => Some(c::B3500000),
1104 #[cfg(not(any(
1105 target_arch = "sparc",
1106 target_arch = "sparc64",
1107 bsd,
1108 target_os = "aix",
1109 target_os = "cygwin",
1110 target_os = "haiku",
1111 target_os = "nto",
1112 target_os = "solaris",
1113 )))]
1114 4_000_000 => Some(c::B4000000),
1115 _ => None,
1116 }
1117 }
1118}
1119
1120/// An array indexed by [`SpecialCodeIndex`] indicating the current values of
1121/// various special control codes.
1122#[repr(transparent)]
1123#[derive(Clone)]
1124pub struct SpecialCodes(pub(crate) [c::cc_t; c::NCCS as usize]);
1125
1126impl core::ops::Index<SpecialCodeIndex> for SpecialCodes {
1127 type Output = u8;
1128
1129 fn index(&self, index: SpecialCodeIndex) -> &Self::Output {
1130 &self.0[index.0]
1131 }
1132}
1133
1134impl core::ops::IndexMut<SpecialCodeIndex> for SpecialCodes {
1135 fn index_mut(&mut self, index: SpecialCodeIndex) -> &mut Self::Output {
1136 &mut self.0[index.0]
1137 }
1138}
1139
1140impl core::fmt::Debug for SpecialCodes {
1141 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1142 write!(f, "SpecialCodes {{")?;
1143 let mut first: bool = true;
1144 for i: usize in 0..self.0.len() {
1145 if first {
1146 write!(f, " ")?;
1147 } else {
1148 write!(f, ", ")?;
1149 }
1150 first = false;
1151 let index: SpecialCodeIndex = SpecialCodeIndex(i);
1152 write!(f, "{:?}: {:?}", index, SpecialCode(self[index]))?;
1153 }
1154 if !first {
1155 write!(f, " ")?;
1156 }
1157 write!(f, "}}")
1158 }
1159}
1160
1161/// A newtype for pretty printing.
1162struct SpecialCode(u8);
1163
1164impl core::fmt::Debug for SpecialCode {
1165 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1166 if self.0 == 0 {
1167 write!(f, "<undef>")
1168 } else if self.0 < 0x20 {
1169 write!(f, "^{}", (self.0 + 0x40) as char)
1170 } else if self.0 == 0x7f {
1171 write!(f, "^?")
1172 } else if self.0 >= 0x80 {
1173 write!(f, "M-")?;
1174 SpecialCode(self.0 - 0x80).fmt(f)
1175 } else {
1176 write!(f, "{}", (self.0 as char))
1177 }
1178 }
1179}
1180
1181/// Indices for use with [`Termios::special_codes`].
1182#[derive(Copy, Clone, Eq, PartialEq, Hash)]
1183pub struct SpecialCodeIndex(usize);
1184
1185#[rustfmt::skip]
1186impl SpecialCodeIndex {
1187 /// `VINTR`
1188 pub const VINTR: Self = Self(c::VINTR as usize);
1189
1190 /// `VQUIT`
1191 pub const VQUIT: Self = Self(c::VQUIT as usize);
1192
1193 /// `VERASE`
1194 pub const VERASE: Self = Self(c::VERASE as usize);
1195
1196 /// `VKILL`
1197 pub const VKILL: Self = Self(c::VKILL as usize);
1198
1199 /// `VEOF`
1200 pub const VEOF: Self = Self(c::VEOF as usize);
1201
1202 /// `VTIME`
1203 pub const VTIME: Self = Self(c::VTIME as usize);
1204
1205 /// `VMIN`
1206 pub const VMIN: Self = Self(c::VMIN as usize);
1207
1208 /// `VSWTC`
1209 #[cfg(not(any(
1210 bsd,
1211 solarish,
1212 target_os = "aix",
1213 target_os = "haiku",
1214 target_os = "hurd",
1215 target_os = "nto",
1216 )))]
1217 pub const VSWTC: Self = Self(c::VSWTC as usize);
1218
1219 /// `VSTART`
1220 pub const VSTART: Self = Self(c::VSTART as usize);
1221
1222 /// `VSTOP`
1223 pub const VSTOP: Self = Self(c::VSTOP as usize);
1224
1225 /// `VSUSP`
1226 pub const VSUSP: Self = Self(c::VSUSP as usize);
1227
1228 /// `VEOL`
1229 pub const VEOL: Self = Self(c::VEOL as usize);
1230
1231 /// `VREPRINT`
1232 #[cfg(not(target_os = "haiku"))]
1233 pub const VREPRINT: Self = Self(c::VREPRINT as usize);
1234
1235 /// `VDISCARD`
1236 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1237 pub const VDISCARD: Self = Self(c::VDISCARD as usize);
1238
1239 /// `VWERASE`
1240 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1241 pub const VWERASE: Self = Self(c::VWERASE as usize);
1242
1243 /// `VLNEXT`
1244 #[cfg(not(target_os = "haiku"))]
1245 pub const VLNEXT: Self = Self(c::VLNEXT as usize);
1246
1247 /// `VEOL2`
1248 pub const VEOL2: Self = Self(c::VEOL2 as usize);
1249
1250 /// `VSWTCH`
1251 #[cfg(any(solarish, target_os = "haiku", target_os = "nto"))]
1252 pub const VSWTCH: Self = Self(c::VSWTCH as usize);
1253
1254 /// `VDSUSP`
1255 #[cfg(any(
1256 bsd,
1257 solarish,
1258 target_os = "aix",
1259 target_os = "hurd",
1260 target_os = "nto"
1261 ))]
1262 pub const VDSUSP: Self = Self(c::VDSUSP as usize);
1263
1264 /// `VSTATUS`
1265 #[cfg(any(bsd, target_os = "hurd", target_os = "illumos"))]
1266 pub const VSTATUS: Self = Self(c::VSTATUS as usize);
1267
1268 /// `VERASE2`
1269 #[cfg(any(freebsdlike, target_os = "illumos"))]
1270 pub const VERASE2: Self = Self(c::VERASE2 as usize);
1271}
1272
1273impl core::fmt::Debug for SpecialCodeIndex {
1274 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1275 match *self {
1276 Self::VINTR => write!(f, "VINTR"),
1277 Self::VQUIT => write!(f, "VQUIT"),
1278 Self::VERASE => write!(f, "VERASE"),
1279 Self::VKILL => write!(f, "VKILL"),
1280 #[cfg(not(any(
1281 solarish,
1282 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1283 target_os = "aix",
1284 target_os = "haiku",
1285 )))]
1286 Self::VEOF => write!(f, "VEOF"),
1287 #[cfg(not(any(
1288 solarish,
1289 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1290 target_os = "aix",
1291 target_os = "haiku",
1292 )))]
1293 Self::VTIME => write!(f, "VTIME"),
1294 #[cfg(not(any(
1295 solarish,
1296 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1297 target_os = "aix",
1298 target_os = "haiku",
1299 )))]
1300 Self::VMIN => write!(f, "VMIN"),
1301
1302 // On Solarish platforms, Linux on SPARC, AIX, and Haiku, `VMIN`
1303 // and `VTIME` have the same value as `VEOF` and `VEOL`.
1304 #[cfg(any(
1305 solarish,
1306 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1307 target_os = "aix",
1308 target_os = "haiku",
1309 ))]
1310 Self::VMIN => write!(f, "VMIN/VEOF"),
1311 #[cfg(any(
1312 solarish,
1313 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1314 target_os = "aix",
1315 target_os = "haiku",
1316 ))]
1317 Self::VTIME => write!(f, "VTIME/VEOL"),
1318
1319 #[cfg(not(any(
1320 bsd,
1321 solarish,
1322 target_os = "aix",
1323 target_os = "haiku",
1324 target_os = "hurd",
1325 target_os = "nto",
1326 )))]
1327 Self::VSWTC => write!(f, "VSWTC"),
1328 Self::VSTART => write!(f, "VSTART"),
1329 Self::VSTOP => write!(f, "VSTOP"),
1330 Self::VSUSP => write!(f, "VSUSP"),
1331 #[cfg(not(any(
1332 solarish,
1333 all(linux_kernel, any(target_arch = "sparc", target_arch = "sparc64")),
1334 target_os = "aix",
1335 target_os = "haiku",
1336 )))]
1337 Self::VEOL => write!(f, "VEOL"),
1338 #[cfg(not(target_os = "haiku"))]
1339 Self::VREPRINT => write!(f, "VREPRINT"),
1340 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1341 Self::VDISCARD => write!(f, "VDISCARD"),
1342 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
1343 Self::VWERASE => write!(f, "VWERASE"),
1344 #[cfg(not(target_os = "haiku"))]
1345 Self::VLNEXT => write!(f, "VLNEXT"),
1346 Self::VEOL2 => write!(f, "VEOL2"),
1347 #[cfg(any(solarish, target_os = "haiku", target_os = "nto"))]
1348 Self::VSWTCH => write!(f, "VSWTCH"),
1349 #[cfg(any(
1350 bsd,
1351 solarish,
1352 target_os = "aix",
1353 target_os = "hurd",
1354 target_os = "nto"
1355 ))]
1356 Self::VDSUSP => write!(f, "VDSUSP"),
1357 #[cfg(any(bsd, target_os = "hurd", target_os = "illumos"))]
1358 Self::VSTATUS => write!(f, "VSTATUS"),
1359 #[cfg(any(freebsdlike, target_os = "illumos"))]
1360 Self::VERASE2 => write!(f, "VERASE2"),
1361
1362 _ => write!(f, "unknown"),
1363 }
1364 }
1365}
1366
1367/// `TCSA*` values for use with [`tcsetattr`].
1368///
1369/// [`tcsetattr`]: crate::termios::tcsetattr
1370#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1371#[repr(u32)]
1372pub enum OptionalActions {
1373 /// `TCSANOW`—Make the change immediately.
1374 #[doc(alias = "TCSANOW")]
1375 Now = c::TCSANOW as u32,
1376
1377 /// `TCSADRAIN`—Make the change after all output has been transmitted.
1378 #[doc(alias = "TCSADRAIN")]
1379 Drain = c::TCSADRAIN as u32,
1380
1381 /// `TCSAFLUSH`—Discard any pending input and then make the change
1382 /// after all output has been transmitted.
1383 #[doc(alias = "TCSAFLUSH")]
1384 Flush = c::TCSAFLUSH as u32,
1385}
1386
1387/// `TC*` values for use with [`tcflush`].
1388///
1389/// [`tcflush`]: crate::termios::tcflush
1390#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1391#[repr(u32)]
1392pub enum QueueSelector {
1393 /// `TCIFLUSH`—Flush data received but not read.
1394 #[doc(alias = "TCIFLUSH")]
1395 IFlush = c::TCIFLUSH as u32,
1396
1397 /// `TCOFLUSH`—Flush data written but not transmitted.
1398 #[doc(alias = "TCOFLUSH")]
1399 OFlush = c::TCOFLUSH as u32,
1400
1401 /// `TCIOFLUSH`—`IFlush` and `OFlush` combined.
1402 #[doc(alias = "TCIOFLUSH")]
1403 IOFlush = c::TCIOFLUSH as u32,
1404}
1405
1406/// `TC*` values for use with [`tcflow`].
1407///
1408/// [`tcflow`]: crate::termios::tcflow
1409#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
1410#[repr(u32)]
1411pub enum Action {
1412 /// `TCOOFF`—Suspend output.
1413 #[doc(alias = "TCOOFF")]
1414 OOff = c::TCOOFF as u32,
1415
1416 /// `TCOON`—Restart suspended output.
1417 #[doc(alias = "TCOON")]
1418 OOn = c::TCOON as u32,
1419
1420 /// `TCIOFF`—Transmits a STOP byte.
1421 #[doc(alias = "TCIOFF")]
1422 IOff = c::TCIOFF as u32,
1423
1424 /// `TCION`—Transmits a START byte.
1425 #[doc(alias = "TCION")]
1426 IOn = c::TCION as u32,
1427}
1428
1429/// `struct winsize` for use with [`tcgetwinsize`].
1430///
1431/// [`tcgetwinsize`]: crate::termios::tcgetwinsize
1432#[doc(alias = "winsize")]
1433#[repr(C)]
1434#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
1435#[allow(missing_docs)]
1436pub struct Winsize {
1437 /// The number of rows the terminal has.
1438 pub ws_row: u16,
1439 /// The number of columns the terminal has.
1440 pub ws_col: u16,
1441
1442 pub ws_xpixel: u16,
1443 pub ws_ypixel: u16,
1444}
1445
1446#[cfg(test)]
1447mod tests {
1448 use super::*;
1449
1450 #[test]
1451 fn termios_layouts() {
1452 check_renamed_type!(InputModes, tcflag_t);
1453 check_renamed_type!(OutputModes, tcflag_t);
1454 check_renamed_type!(ControlModes, tcflag_t);
1455 check_renamed_type!(LocalModes, tcflag_t);
1456 assert_eq_size!(u8, libc::cc_t);
1457 assert_eq_size!(types::tcflag_t, libc::tcflag_t);
1458
1459 check_renamed_struct!(Winsize, winsize, ws_row, ws_col, ws_xpixel, ws_ypixel);
1460
1461 // On platforms with a termios/termios2 split, check `termios`.
1462 #[cfg(linux_raw)]
1463 {
1464 check_renamed_type!(Termios, termios2);
1465 check_renamed_struct_renamed_field!(Termios, termios2, input_modes, c_iflag);
1466 check_renamed_struct_renamed_field!(Termios, termios2, output_modes, c_oflag);
1467 check_renamed_struct_renamed_field!(Termios, termios2, control_modes, c_cflag);
1468 check_renamed_struct_renamed_field!(Termios, termios2, local_modes, c_lflag);
1469 check_renamed_struct_renamed_field!(Termios, termios2, line_discipline, c_line);
1470 check_renamed_struct_renamed_field!(Termios, termios2, special_codes, c_cc);
1471 check_renamed_struct_renamed_field!(Termios, termios2, input_speed, c_ispeed);
1472 check_renamed_struct_renamed_field!(Termios, termios2, output_speed, c_ospeed);
1473
1474 // We assume that `termios` has the same layout as `termios2` minus the
1475 // `c_ispeed` and `c_ospeed` fields.
1476 check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1477 check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1478 check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1479 check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1480 check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1481
1482 // On everything except PowerPC, `termios` matches `termios2` except
1483 // for the addition of `c_ispeed` and `c_ospeed`.
1484 #[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
1485 const_assert_eq!(
1486 memoffset::offset_of!(Termios, input_speed),
1487 core::mem::size_of::<c::termios>()
1488 );
1489
1490 // On PowerPC, `termios2` is `termios`.
1491 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
1492 assert_eq_size!(c::termios2, c::termios);
1493 }
1494
1495 #[cfg(not(linux_raw))]
1496 {
1497 // On MIPS, SPARC, and Android, the libc lacks the ospeed and ispeed
1498 // fields.
1499 #[cfg(all(
1500 not(all(
1501 target_env = "gnu",
1502 any(
1503 target_arch = "mips",
1504 target_arch = "mips32r6",
1505 target_arch = "mips64",
1506 target_arch = "mips64r6",
1507 target_arch = "sparc",
1508 target_arch = "sparc64"
1509 )
1510 )),
1511 not(all(libc, target_os = "android"))
1512 ))]
1513 check_renamed_type!(Termios, termios);
1514 #[cfg(not(all(
1515 not(all(
1516 target_env = "gnu",
1517 any(
1518 target_arch = "mips",
1519 target_arch = "mips32r6",
1520 target_arch = "mips64",
1521 target_arch = "mips64r6",
1522 target_arch = "sparc",
1523 target_arch = "sparc64"
1524 )
1525 )),
1526 not(all(libc, target_os = "android"))
1527 )))]
1528 const_assert!(core::mem::size_of::<Termios>() >= core::mem::size_of::<c::termios>());
1529
1530 check_renamed_struct_renamed_field!(Termios, termios, input_modes, c_iflag);
1531 check_renamed_struct_renamed_field!(Termios, termios, output_modes, c_oflag);
1532 check_renamed_struct_renamed_field!(Termios, termios, control_modes, c_cflag);
1533 check_renamed_struct_renamed_field!(Termios, termios, local_modes, c_lflag);
1534 #[cfg(any(
1535 linux_like,
1536 target_env = "newlib",
1537 target_os = "fuchsia",
1538 target_os = "haiku",
1539 target_os = "redox"
1540 ))]
1541 check_renamed_struct_renamed_field!(Termios, termios, line_discipline, c_line);
1542 check_renamed_struct_renamed_field!(Termios, termios, special_codes, c_cc);
1543 #[cfg(not(any(
1544 linux_kernel,
1545 solarish,
1546 target_os = "emscripten",
1547 target_os = "fuchsia"
1548 )))]
1549 {
1550 check_renamed_struct_renamed_field!(Termios, termios, input_speed, c_ispeed);
1551 check_renamed_struct_renamed_field!(Termios, termios, output_speed, c_ospeed);
1552 }
1553 #[cfg(any(target_env = "musl", target_os = "fuchsia"))]
1554 {
1555 check_renamed_struct_renamed_field!(Termios, termios, input_speed, __c_ispeed);
1556 check_renamed_struct_renamed_field!(Termios, termios, output_speed, __c_ospeed);
1557 }
1558 }
1559
1560 check_renamed_type!(OptionalActions, c_int);
1561 check_renamed_type!(QueueSelector, c_int);
1562 check_renamed_type!(Action, c_int);
1563 }
1564
1565 #[test]
1566 #[cfg(not(any(
1567 solarish,
1568 target_os = "cygwin",
1569 target_os = "emscripten",
1570 target_os = "haiku",
1571 target_os = "redox",
1572 )))]
1573 fn termios_legacy() {
1574 // Check that our doc aliases above are correct.
1575 const_assert_eq!(c::EXTA, c::B19200);
1576 const_assert_eq!(c::EXTB, c::B38400);
1577 }
1578
1579 #[cfg(bsd)]
1580 #[test]
1581 fn termios_bsd() {
1582 // On BSD platforms we can assume that the `B*` constants have their
1583 // arbitrary integer speed value. Confirm this.
1584 const_assert_eq!(c::B0, 0);
1585 const_assert_eq!(c::B50, 50);
1586 const_assert_eq!(c::B19200, 19200);
1587 const_assert_eq!(c::B38400, 38400);
1588 }
1589
1590 #[test]
1591 #[cfg(not(bsd))]
1592 fn termios_speed_encoding() {
1593 assert_eq!(speed::encode(0), Some(c::B0));
1594 assert_eq!(speed::encode(50), Some(c::B50));
1595 assert_eq!(speed::encode(19200), Some(c::B19200));
1596 assert_eq!(speed::encode(38400), Some(c::B38400));
1597 assert_eq!(speed::encode(1), None);
1598 assert_eq!(speed::encode(!0), None);
1599
1600 #[cfg(not(linux_kernel))]
1601 {
1602 assert_eq!(speed::decode(c::B0), Some(0));
1603 assert_eq!(speed::decode(c::B50), Some(50));
1604 assert_eq!(speed::decode(c::B19200), Some(19200));
1605 assert_eq!(speed::decode(c::B38400), Some(38400));
1606 }
1607 }
1608
1609 #[cfg(linux_kernel)]
1610 #[test]
1611 fn termios_ioctl_contiguity() {
1612 // When using `termios2`, we assume that we can add the optional actions
1613 // value to the ioctl request code. Test this assumption.
1614
1615 const_assert_eq!(c::TCSETS2, c::TCSETS2 + 0);
1616 const_assert_eq!(c::TCSETSW2, c::TCSETS2 + 1);
1617 const_assert_eq!(c::TCSETSF2, c::TCSETS2 + 2);
1618
1619 const_assert_eq!(c::TCSANOW - c::TCSANOW, 0);
1620 const_assert_eq!(c::TCSADRAIN - c::TCSANOW, 1);
1621 const_assert_eq!(c::TCSAFLUSH - c::TCSANOW, 2);
1622
1623 // MIPS is different here.
1624 #[cfg(any(
1625 target_arch = "mips",
1626 target_arch = "mips32r6",
1627 target_arch = "mips64",
1628 target_arch = "mips64r6"
1629 ))]
1630 {
1631 assert_eq!(i128::from(c::TCSANOW) - i128::from(c::TCSETS), 0);
1632 assert_eq!(i128::from(c::TCSADRAIN) - i128::from(c::TCSETS), 1);
1633 assert_eq!(i128::from(c::TCSAFLUSH) - i128::from(c::TCSETS), 2);
1634 }
1635 #[cfg(not(any(
1636 target_arch = "mips",
1637 target_arch = "mips32r6",
1638 target_arch = "mips64",
1639 target_arch = "mips64r6"
1640 )))]
1641 {
1642 const_assert_eq!(c::TCSANOW, 0);
1643 const_assert_eq!(c::TCSADRAIN, 1);
1644 const_assert_eq!(c::TCSAFLUSH, 2);
1645 }
1646 }
1647
1648 #[cfg(linux_kernel)]
1649 #[test]
1650 fn termios_cibaud() {
1651 // Test an assumption.
1652 const_assert_eq!(c::CIBAUD, c::CBAUD << c::IBSHIFT);
1653 }
1654}
1655