doc: sort: be more descriptive than 'manual'
[coreutils.git] / src / stty.c
blob95091744aa48eae51f7b19b910ee7cda319e9cdb
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
19 Options:
20 -a, --all Write all current settings to stdout in human-readable form.
21 -g, --save Write all current settings to stdout in stty-readable form.
22 -F, --file Open and use the specified device instead of stdin
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on the specified device, or stdin if none was specified.
28 David MacKenzie <djm@gnu.ai.mit.edu> */
30 #include <config.h>
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
34 #endif
36 #include <stdio.h>
37 #include <sys/types.h>
39 #include <termios.h>
40 #if HAVE_STROPTS_H
41 # include <stropts.h>
42 #endif
43 #include <sys/ioctl.h>
45 #ifdef WINSIZE_IN_PTEM
46 # include <sys/stream.h>
47 # include <sys/ptem.h>
48 #endif
49 #ifdef GWINSZ_IN_SYS_PTY
50 # include <sys/tty.h>
51 # include <sys/pty.h>
52 #endif
53 #include <getopt.h>
54 #include <stdarg.h>
56 #include "system.h"
57 #include "assure.h"
58 #include "fd-reopen.h"
59 #include "quote.h"
60 #include "xdectoint.h"
61 #include "xstrtol.h"
63 /* The official name of this program (e.g., no 'g' prefix). */
64 #define PROGRAM_NAME "stty"
66 #define AUTHORS proper_name ("David MacKenzie")
68 #ifndef _POSIX_VDISABLE
69 # define _POSIX_VDISABLE 0
70 #endif
72 #define Control(c) ((c) & 0x1f)
73 /* Canonical values for control characters. */
74 #ifndef CINTR
75 # define CINTR Control ('c')
76 #endif
77 #ifndef CQUIT
78 # define CQUIT 28
79 #endif
80 #ifndef CERASE
81 # define CERASE 127
82 #endif
83 #ifndef CKILL
84 # define CKILL Control ('u')
85 #endif
86 #ifndef CEOF
87 # define CEOF Control ('d')
88 #endif
89 #ifndef CEOL
90 # define CEOL _POSIX_VDISABLE
91 #endif
92 #ifndef CSTART
93 # define CSTART Control ('q')
94 #endif
95 #ifndef CSTOP
96 # define CSTOP Control ('s')
97 #endif
98 #ifndef CSUSP
99 # define CSUSP Control ('z')
100 #endif
101 #if defined VEOL2 && !defined CEOL2
102 # define CEOL2 _POSIX_VDISABLE
103 #endif
104 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
105 character is initialized by CSWTCH, if present. */
106 #if defined VSWTC && !defined VSWTCH
107 # define VSWTCH VSWTC
108 #endif
109 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
110 #if defined VSUSP && !defined VSWTCH
111 # define VSWTCH VSUSP
112 # if defined CSUSP && !defined CSWTCH
113 # define CSWTCH CSUSP
114 # endif
115 #endif
116 #if defined VSWTCH && !defined CSWTCH
117 # define CSWTCH _POSIX_VDISABLE
118 #endif
120 /* SunOS >= 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
121 So the default is to disable 'swtch.' */
122 #if defined __sun
123 # undef CSWTCH
124 # define CSWTCH _POSIX_VDISABLE
125 #endif
127 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
128 # define VWERASE VWERSE
129 #endif
130 #if defined VDSUSP && !defined CDSUSP
131 # define CDSUSP Control ('y')
132 #endif
133 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
134 # define VREPRINT VRPRNT
135 #endif
136 #if defined VREPRINT && !defined CRPRNT
137 # define CRPRNT Control ('r')
138 #endif
139 #if defined CREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
141 #endif
142 #if defined VWERASE && !defined CWERASE
143 # define CWERASE Control ('w')
144 #endif
145 #if defined VLNEXT && !defined CLNEXT
146 # define CLNEXT Control ('v')
147 #endif
148 #if defined VDISCARD && !defined VFLUSHO
149 # define VFLUSHO VDISCARD
150 #endif
151 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
152 # define VFLUSHO VFLUSH
153 #endif
154 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
155 # define ECHOCTL CTLECH
156 #endif
157 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
158 # define ECHOCTL TCTLECH
159 #endif
160 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
161 # define ECHOKE CRTKIL
162 #endif
163 #if defined VFLUSHO && !defined CFLUSHO
164 # define CFLUSHO Control ('o')
165 #endif
166 #if defined VSTATUS && !defined CSTATUS
167 # define CSTATUS Control ('t')
168 #endif
170 /* Which speeds to set. */
171 enum speed_setting
173 input_speed, output_speed, both_speeds
176 /* What to output and how. */
177 enum output_type
179 changed, all, recoverable /* Default, -a, -g. */
182 /* Which member(s) of 'struct termios' a mode uses. */
183 enum mode_type
185 control, input, output, local, combination
188 /* Flags for 'struct mode_info'. */
189 #define SANE_SET 1 /* Set in 'sane' mode. */
190 #define SANE_UNSET 2 /* Unset in 'sane' mode. */
191 #define REV 4 /* Can be turned off by prepending '-'. */
192 #define OMIT 8 /* Don't display value. */
193 #define NO_SETATTR 16 /* tcsetattr not used to set mode bits. */
195 /* Each mode. */
196 struct mode_info
198 char const *name; /* Name given on command line. */
199 enum mode_type type; /* Which structure element to change. */
200 char flags; /* Setting and display options. */
201 unsigned long bits; /* Bits to set for this mode. */
202 unsigned long mask; /* Other bits to turn off for this mode. */
205 static struct mode_info const mode_info[] =
207 {"parenb", control, REV, PARENB, 0},
208 {"parodd", control, REV, PARODD, 0},
209 #ifdef CMSPAR
210 {"cmspar", control, REV, CMSPAR, 0},
211 #endif
212 {"cs5", control, 0, CS5, CSIZE},
213 {"cs6", control, 0, CS6, CSIZE},
214 {"cs7", control, 0, CS7, CSIZE},
215 {"cs8", control, 0, CS8, CSIZE},
216 {"hupcl", control, REV, HUPCL, 0},
217 {"hup", control, REV | OMIT, HUPCL, 0},
218 {"cstopb", control, REV, CSTOPB, 0},
219 {"cread", control, SANE_SET | REV, CREAD, 0},
220 {"clocal", control, REV, CLOCAL, 0},
221 #ifdef CRTSCTS
222 {"crtscts", control, REV, CRTSCTS, 0},
223 #endif
224 #ifdef CDTRDSR
225 {"cdtrdsr", control, REV, CDTRDSR, 0},
226 #endif
228 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
229 {"brkint", input, SANE_SET | REV, BRKINT, 0},
230 {"ignpar", input, REV, IGNPAR, 0},
231 {"parmrk", input, REV, PARMRK, 0},
232 {"inpck", input, REV, INPCK, 0},
233 {"istrip", input, REV, ISTRIP, 0},
234 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
235 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
236 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
237 {"ixon", input, REV, IXON, 0},
238 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
239 {"tandem", input, REV | OMIT, IXOFF, 0},
240 #ifdef IUCLC
241 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
242 #endif
243 #ifdef IXANY
244 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
245 #endif
246 #ifdef IMAXBEL
247 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
248 #endif
249 #ifdef IUTF8
250 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
251 #endif
253 {"opost", output, SANE_SET | REV, OPOST, 0},
254 #ifdef OLCUC
255 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
256 #endif
257 #ifdef OCRNL
258 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
259 #endif
260 #ifdef ONLCR
261 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
262 #endif
263 #ifdef ONOCR
264 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
265 #endif
266 #ifdef ONLRET
267 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
268 #endif
269 #ifdef OFILL
270 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
271 #endif
272 #ifdef OFDEL
273 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
274 #endif
275 #ifdef NLDLY
276 {"nl1", output, SANE_UNSET, NL1, NLDLY},
277 {"nl0", output, SANE_SET, NL0, NLDLY},
278 #endif
279 #ifdef CRDLY
280 {"cr3", output, SANE_UNSET, CR3, CRDLY},
281 {"cr2", output, SANE_UNSET, CR2, CRDLY},
282 {"cr1", output, SANE_UNSET, CR1, CRDLY},
283 {"cr0", output, SANE_SET, CR0, CRDLY},
284 #endif
285 #ifdef TABDLY
286 # ifdef TAB3
287 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
288 # endif
289 # ifdef TAB2
290 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
291 # endif
292 # ifdef TAB1
293 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
294 # endif
295 # ifdef TAB0
296 {"tab0", output, SANE_SET, TAB0, TABDLY},
297 # endif
298 #else
299 # ifdef OXTABS
300 {"tab3", output, SANE_UNSET, OXTABS, 0},
301 # endif
302 #endif
303 #ifdef BSDLY
304 {"bs1", output, SANE_UNSET, BS1, BSDLY},
305 {"bs0", output, SANE_SET, BS0, BSDLY},
306 #endif
307 #ifdef VTDLY
308 {"vt1", output, SANE_UNSET, VT1, VTDLY},
309 {"vt0", output, SANE_SET, VT0, VTDLY},
310 #endif
311 #ifdef FFDLY
312 {"ff1", output, SANE_UNSET, FF1, FFDLY},
313 {"ff0", output, SANE_SET, FF0, FFDLY},
314 #endif
316 {"isig", local, SANE_SET | REV, ISIG, 0},
317 {"icanon", local, SANE_SET | REV, ICANON, 0},
318 #ifdef IEXTEN
319 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
320 #endif
321 {"echo", local, SANE_SET | REV, ECHO, 0},
322 {"echoe", local, SANE_SET | REV, ECHOE, 0},
323 {"crterase", local, REV | OMIT, ECHOE, 0},
324 {"echok", local, SANE_SET | REV, ECHOK, 0},
325 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
326 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
327 #ifdef XCASE
328 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
329 #endif
330 #ifdef TOSTOP
331 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
332 #endif
333 #ifdef ECHOPRT
334 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
335 {"prterase", local, REV | OMIT, ECHOPRT, 0},
336 #endif
337 #ifdef ECHOCTL
338 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
339 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
340 #endif
341 #ifdef ECHOKE
342 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
343 {"crtkill", local, REV | OMIT, ECHOKE, 0},
344 #endif
345 #ifdef FLUSHO
346 {"flusho", local, SANE_UNSET | REV, FLUSHO, 0},
347 #endif
348 #if defined TIOCEXT
349 {"extproc", local, SANE_UNSET | REV | NO_SETATTR, EXTPROC, 0},
350 #elif defined EXTPROC
351 {"extproc", local, SANE_UNSET | REV, EXTPROC, 0},
352 #endif
354 {"evenp", combination, REV | OMIT, 0, 0},
355 {"parity", combination, REV | OMIT, 0, 0},
356 {"oddp", combination, REV | OMIT, 0, 0},
357 {"nl", combination, REV | OMIT, 0, 0},
358 {"ek", combination, OMIT, 0, 0},
359 {"sane", combination, OMIT, 0, 0},
360 {"cooked", combination, REV | OMIT, 0, 0},
361 {"raw", combination, REV | OMIT, 0, 0},
362 {"pass8", combination, REV | OMIT, 0, 0},
363 {"litout", combination, REV | OMIT, 0, 0},
364 {"cbreak", combination, REV | OMIT, 0, 0},
365 #ifdef IXANY
366 {"decctlq", combination, REV | OMIT, 0, 0},
367 #endif
368 #if defined TABDLY || defined OXTABS
369 {"tabs", combination, REV | OMIT, 0, 0},
370 #endif
371 #if defined XCASE && defined IUCLC && defined OLCUC
372 {"lcase", combination, REV | OMIT, 0, 0},
373 {"LCASE", combination, REV | OMIT, 0, 0},
374 #endif
375 {"crt", combination, OMIT, 0, 0},
376 {"dec", combination, OMIT, 0, 0},
378 {nullptr, control, 0, 0, 0}
381 /* Control character settings. */
382 struct control_info
384 char const *name; /* Name given on command line. */
385 cc_t saneval; /* Value to set for 'stty sane'. */
386 size_t offset; /* Offset in c_cc. */
389 /* Control characters. */
391 static struct control_info const control_info[] =
393 {"intr", CINTR, VINTR},
394 {"quit", CQUIT, VQUIT},
395 {"erase", CERASE, VERASE},
396 {"kill", CKILL, VKILL},
397 {"eof", CEOF, VEOF},
398 {"eol", CEOL, VEOL},
399 #ifdef VEOL2
400 {"eol2", CEOL2, VEOL2},
401 #endif
402 #ifdef VSWTCH
403 {"swtch", CSWTCH, VSWTCH},
404 #endif
405 {"start", CSTART, VSTART},
406 {"stop", CSTOP, VSTOP},
407 {"susp", CSUSP, VSUSP},
408 #ifdef VDSUSP
409 {"dsusp", CDSUSP, VDSUSP},
410 #endif
411 #ifdef VREPRINT
412 {"rprnt", CRPRNT, VREPRINT},
413 #else
414 # ifdef CREPRINT /* HPUX 10.20 needs this */
415 {"rprnt", CRPRNT, CREPRINT},
416 # endif
417 #endif
418 #ifdef VWERASE
419 {"werase", CWERASE, VWERASE},
420 #endif
421 #ifdef VLNEXT
422 {"lnext", CLNEXT, VLNEXT},
423 #endif
424 #ifdef VFLUSHO
425 {"flush", CFLUSHO, VFLUSHO}, /* deprecated compat option. */
426 {"discard", CFLUSHO, VFLUSHO},
427 #endif
428 #ifdef VSTATUS
429 {"status", CSTATUS, VSTATUS},
430 #endif
432 /* These must be last because of the display routines. */
433 {"min", 1, VMIN},
434 {"time", 0, VTIME},
435 {nullptr, 0, 0}
438 static char const *visible (cc_t ch);
439 static unsigned long int baud_to_value (speed_t speed);
440 static bool recover_mode (char const *arg, struct termios *mode);
441 static int screen_columns (void);
442 static bool set_mode (struct mode_info const *info, bool reversed,
443 struct termios *mode);
444 static bool eq_mode (struct termios *mode1, struct termios *mode2);
445 static uintmax_t integer_arg (char const *s, uintmax_t max);
446 static speed_t string_to_baud (char const *arg);
447 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
448 static void display_all (struct termios *mode, char const *device_name);
449 static void display_changed (struct termios *mode);
450 static void display_recoverable (struct termios *mode);
451 static void display_settings (enum output_type output_type,
452 struct termios *mode,
453 char const *device_name);
454 static void check_speed (struct termios *mode);
455 static void display_speed (struct termios *mode, bool fancy);
456 static void display_window_size (bool fancy, char const *device_name);
457 static void sane_mode (struct termios *mode);
458 static void set_control_char (struct control_info const *info,
459 char const *arg,
460 struct termios *mode);
461 static void set_speed (enum speed_setting type, char const *arg,
462 struct termios *mode);
463 static void set_window_size (int rows, int cols, char const *device_name);
465 /* The width of the screen, for output wrapping. */
466 static int max_col;
468 /* Current position, to know when to wrap. */
469 static int current_col;
471 /* Default "drain" mode for tcsetattr. */
472 static int tcsetattr_options = TCSADRAIN;
474 /* Extra info to aid stty development. */
475 static bool dev_debug;
477 /* Record last speed set for correlation. */
478 static speed_t last_ibaud = (speed_t) -1;
479 static speed_t last_obaud = (speed_t) -1;
481 /* For long options that have no equivalent short option, use a
482 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
483 enum
485 DEV_DEBUG_OPTION = CHAR_MAX + 1,
488 static struct option const longopts[] =
490 {"all", no_argument, nullptr, 'a'},
491 {"save", no_argument, nullptr, 'g'},
492 {"file", required_argument, nullptr, 'F'},
493 {"-debug", no_argument, nullptr, DEV_DEBUG_OPTION},
494 {GETOPT_HELP_OPTION_DECL},
495 {GETOPT_VERSION_OPTION_DECL},
496 {nullptr, 0, nullptr, 0}
499 /* Print format string MESSAGE and optional args.
500 Wrap to next line first if it won't fit.
501 Print a space first unless MESSAGE will start a new line. */
503 ATTRIBUTE_FORMAT ((printf, 1, 2))
504 static void
505 wrapf (char const *message,...)
507 va_list args;
508 char *buf;
509 int buflen;
511 va_start (args, message);
512 buflen = vasprintf (&buf, message, args);
513 va_end (args);
515 if (buflen < 0)
516 xalloc_die ();
518 if (0 < current_col)
520 if (max_col - current_col <= buflen)
522 putchar ('\n');
523 current_col = 0;
525 else
527 putchar (' ');
528 current_col++;
532 fputs (buf, stdout);
533 free (buf);
534 current_col += buflen;
537 void
538 usage (int status)
540 if (status != EXIT_SUCCESS)
541 emit_try_help ();
542 else
544 printf (_("\
545 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
546 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
547 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
549 program_name, program_name, program_name);
550 fputs (_("\
551 Print or change terminal characteristics.\n\
552 "), stdout);
554 emit_mandatory_arg_note ();
556 fputs (_("\
557 -a, --all print all current settings in human-readable form\n\
558 -g, --save print all current settings in a stty-readable form\n\
559 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
560 "), stdout);
561 fputs (HELP_OPTION_DESCRIPTION, stdout);
562 fputs (VERSION_OPTION_DESCRIPTION, stdout);
563 fputs (_("\
565 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
566 settings. The underlying system defines which settings are available.\n\
567 "), stdout);
568 fputs (_("\
570 Special characters:\n"), stdout);
571 #ifdef VFLUSHO
572 fputs (_("\
573 * discard CHAR CHAR will toggle discarding of output\n\
574 "), stdout);
575 #endif
576 #ifdef VDSUSP
577 fputs (_("\
578 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
579 "), stdout);
580 #endif
581 fputs (_("\
582 eof CHAR CHAR will send an end of file (terminate the input)\n\
583 eol CHAR CHAR will end the line\n\
584 "), stdout);
585 #ifdef VEOL2
586 fputs (_("\
587 * eol2 CHAR alternate CHAR for ending the line\n\
588 "), stdout);
589 #endif
590 fputs (_("\
591 erase CHAR CHAR will erase the last character typed\n\
592 intr CHAR CHAR will send an interrupt signal\n\
593 kill CHAR CHAR will erase the current line\n\
594 "), stdout);
595 #ifdef VLNEXT
596 fputs (_("\
597 * lnext CHAR CHAR will enter the next character quoted\n\
598 "), stdout);
599 #endif
600 #ifdef VSTATUS
601 fputs (_("\
602 * status CHAR CHAR will send an info signal\n\
603 "), stdout);
604 #endif
605 fputs (_("\
606 quit CHAR CHAR will send a quit signal\n\
607 "), stdout);
608 #if defined CREPRINT || defined VREPRINT
609 fputs (_("\
610 * rprnt CHAR CHAR will redraw the current line\n\
611 "), stdout);
612 #endif
613 fputs (_("\
614 start CHAR CHAR will restart the output after stopping it\n\
615 stop CHAR CHAR will stop the output\n\
616 susp CHAR CHAR will send a terminal stop signal\n\
617 "), stdout);
618 #ifdef VSWTCH
619 fputs (_("\
620 * swtch CHAR CHAR will switch to a different shell layer\n\
621 "), stdout);
622 #endif
623 #ifdef VWERASE
624 fputs (_("\
625 * werase CHAR CHAR will erase the last word typed\n\
626 "), stdout);
627 #endif
628 fputs (_("\
630 Special settings:\n\
631 N set the input and output speeds to N bauds\n\
632 "), stdout);
633 #ifdef TIOCGWINSZ
634 fputs (_("\
635 * cols N tell the kernel that the terminal has N columns\n\
636 * columns N same as cols N\n\
637 "), stdout);
638 #endif
639 printf (_("\
640 * [-]drain wait for transmission before applying settings (%s by default)\
641 \n"), tcsetattr_options == TCSADRAIN ? _("on") : _("off"));
642 fputs (_("\
643 ispeed N set the input speed to N\n\
644 "), stdout);
645 #ifdef HAVE_C_LINE
646 fputs (_("\
647 * line N use line discipline N\n\
648 "), stdout);
649 #endif
650 fputs (_("\
651 min N with -icanon, set N characters minimum for a completed read\n\
652 ospeed N set the output speed to N\n\
653 "), stdout);
654 #ifdef TIOCGWINSZ
655 fputs (_("\
656 * rows N tell the kernel that the terminal has N rows\n\
657 * size print the number of rows and columns according to the kernel\n\
658 "), stdout);
659 #endif
660 fputs (_("\
661 speed print the terminal speed\n\
662 time N with -icanon, set read timeout of N tenths of a second\n\
663 "), stdout);
664 fputs (_("\
666 Control settings:\n\
667 [-]clocal disable modem control signals\n\
668 [-]cread allow input to be received\n\
669 "), stdout);
670 #ifdef CRTSCTS
671 fputs (_("\
672 * [-]crtscts enable RTS/CTS handshaking\n\
673 "), stdout);
674 #endif
675 #ifdef CDTRDSR
676 fputs (_("\
677 * [-]cdtrdsr enable DTR/DSR handshaking\n\
678 "), stdout);
679 #endif
680 fputs (_("\
681 csN set character size to N bits, N in [5..8]\n\
682 "), stdout);
683 fputs (_("\
684 [-]cstopb use two stop bits per character (one with '-')\n\
685 [-]hup send a hangup signal when the last process closes the tty\n\
686 [-]hupcl same as [-]hup\n\
687 [-]parenb generate parity bit in output and expect parity bit in input\n\
688 [-]parodd set odd parity (or even parity with '-')\n\
689 "), stdout);
690 #ifdef CMSPAR
691 fputs (_("\
692 * [-]cmspar use \"stick\" (mark/space) parity\n\
693 "), stdout);
694 #endif
695 fputs (_("\
697 Input settings:\n\
698 [-]brkint breaks cause an interrupt signal\n\
699 [-]icrnl translate carriage return to newline\n\
700 [-]ignbrk ignore break characters\n\
701 [-]igncr ignore carriage return\n\
702 [-]ignpar ignore characters with parity errors\n\
703 "), stdout);
704 #ifdef IMAXBEL
705 fputs (_("\
706 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
707 "), stdout);
708 #endif
709 fputs (_("\
710 [-]inlcr translate newline to carriage return\n\
711 [-]inpck enable input parity checking\n\
712 [-]istrip clear high (8th) bit of input characters\n\
713 "), stdout);
714 #ifdef IUTF8
715 fputs (_("\
716 * [-]iutf8 assume input characters are UTF-8 encoded\n\
717 "), stdout);
718 #endif
719 #ifdef IUCLC
720 fputs (_("\
721 * [-]iuclc translate uppercase characters to lowercase\n\
722 "), stdout);
723 #endif
724 #ifdef IXANY
725 fputs (_("\
726 * [-]ixany let any character restart output, not only start character\n\
727 "), stdout);
728 #endif
729 fputs (_("\
730 [-]ixoff enable sending of start/stop characters\n\
731 [-]ixon enable XON/XOFF flow control\n\
732 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
733 [-]tandem same as [-]ixoff\n\
734 "), stdout);
735 fputs (_("\
737 Output settings:\n\
738 "), stdout);
739 #ifdef BSDLY
740 fputs (_("\
741 * bsN backspace delay style, N in [0..1]\n\
742 "), stdout);
743 #endif
744 #ifdef CRDLY
745 fputs (_("\
746 * crN carriage return delay style, N in [0..3]\n\
747 "), stdout);
748 #endif
749 #ifdef FFDLY
750 fputs (_("\
751 * ffN form feed delay style, N in [0..1]\n\
752 "), stdout);
753 #endif
754 #ifdef NLDLY
755 fputs (_("\
756 * nlN newline delay style, N in [0..1]\n\
757 "), stdout);
758 #endif
759 #ifdef OCRNL
760 fputs (_("\
761 * [-]ocrnl translate carriage return to newline\n\
762 "), stdout);
763 #endif
764 #ifdef OFDEL
765 fputs (_("\
766 * [-]ofdel use delete characters for fill instead of NUL characters\n\
767 "), stdout);
768 #endif
769 #ifdef OFILL
770 fputs (_("\
771 * [-]ofill use fill (padding) characters instead of timing for delays\n\
772 "), stdout);
773 #endif
774 #ifdef OLCUC
775 fputs (_("\
776 * [-]olcuc translate lowercase characters to uppercase\n\
777 "), stdout);
778 #endif
779 #ifdef ONLCR
780 fputs (_("\
781 * [-]onlcr translate newline to carriage return-newline\n\
782 "), stdout);
783 #endif
784 #ifdef ONLRET
785 fputs (_("\
786 * [-]onlret newline performs a carriage return\n\
787 "), stdout);
788 #endif
789 #ifdef ONOCR
790 fputs (_("\
791 * [-]onocr do not print carriage returns in the first column\n\
792 "), stdout);
793 #endif
794 fputs (_("\
795 [-]opost postprocess output\n\
796 "), stdout);
797 #if defined TABDLY || defined OXTABS
798 fputs (_("\
799 * tabN horizontal tab delay style, N in [0..3]\n\
800 * tabs same as tab0\n\
801 * -tabs same as tab3\n\
802 "), stdout);
803 #endif
804 #ifdef VTDLY
805 fputs (_("\
806 * vtN vertical tab delay style, N in [0..1]\n\
807 "), stdout);
808 #endif
809 fputs (_("\
811 Local settings:\n\
812 [-]crterase echo erase characters as backspace-space-backspace\n\
813 "), stdout);
814 #ifdef ECHOKE
815 fputs (_("\
816 * crtkill kill all line by obeying the echoprt and echoe settings\n\
817 * -crtkill kill all line by obeying the echoctl and echok settings\n\
818 "), stdout);
819 #endif
820 #ifdef ECHOCTL
821 fputs (_("\
822 * [-]ctlecho echo control characters in hat notation ('^c')\n\
823 "), stdout);
824 #endif
825 fputs (_("\
826 [-]echo echo input characters\n\
827 "), stdout);
828 #ifdef ECHOCTL
829 fputs (_("\
830 * [-]echoctl same as [-]ctlecho\n\
831 "), stdout);
832 #endif
833 fputs (_("\
834 [-]echoe same as [-]crterase\n\
835 [-]echok echo a newline after a kill character\n\
836 "), stdout);
837 #ifdef ECHOKE
838 fputs (_("\
839 * [-]echoke same as [-]crtkill\n\
840 "), stdout);
841 #endif
842 fputs (_("\
843 [-]echonl echo newline even if not echoing other characters\n\
844 "), stdout);
845 #ifdef ECHOPRT
846 fputs (_("\
847 * [-]echoprt echo erased characters backward, between '\\' and '/'\n\
848 "), stdout);
849 #endif
850 #if defined EXTPROC || defined TIOCEXT
851 fputs (_("\
852 * [-]extproc enable \"LINEMODE\"; useful with high latency links\n\
853 "), stdout);
854 #endif
855 #if defined FLUSHO
856 fputs (_("\
857 * [-]flusho discard output\n\
858 "), stdout);
859 #endif
860 printf (_("\
861 [-]icanon enable special characters: %s\n\
862 [-]iexten enable non-POSIX special characters\n\
863 "), "erase, kill"
864 #ifdef VWERASE
865 ", werase"
866 #endif
867 #if defined CREPRINT || defined VREPRINT
868 ", rprnt"
869 #endif
871 fputs (_("\
872 [-]isig enable interrupt, quit, and suspend special characters\n\
873 [-]noflsh disable flushing after interrupt and quit special characters\n\
874 "), stdout);
875 #ifdef ECHOPRT
876 fputs (_("\
877 * [-]prterase same as [-]echoprt\n\
878 "), stdout);
879 #endif
880 #ifdef TOSTOP
881 fputs (_("\
882 * [-]tostop stop background jobs that try to write to the terminal\n\
883 "), stdout);
884 #endif
885 #ifdef XCASE
886 fputs (_("\
887 * [-]xcase with icanon, escape with '\\' for uppercase characters\n\
888 "), stdout);
889 #endif
890 fputs (_("\
892 Combination settings:\n\
893 "), stdout);
894 #if defined XCASE && defined IUCLC && defined OLCUC
895 fputs (_("\
896 * [-]LCASE same as [-]lcase\n\
897 "), stdout);
898 #endif
899 fputs (_("\
900 cbreak same as -icanon\n\
901 -cbreak same as icanon\n\
902 "), stdout);
903 fputs (_("\
904 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
905 icanon, eof and eol characters to their default values\n\
906 -cooked same as raw\n\
907 "), stdout);
908 printf (_("\
909 crt same as %s\n\
910 "), "echoe"
911 #ifdef ECHOCTL
912 " echoctl"
913 #endif
914 #ifdef ECHOKE
915 " echoke"
916 #endif
918 printf (_("\
919 dec same as %s intr ^c erase 0177\n\
920 kill ^u\n\
921 "), "echoe"
922 #ifdef ECHOCTL
923 " echoctl"
924 #endif
925 #ifdef ECHOKE
926 " echoke"
927 #endif
928 #ifdef IXANY
929 " -ixany"
930 #endif
932 #ifdef IXANY
933 fputs (_("\
934 * [-]decctlq same as [-]ixany\n\
935 "), stdout);
936 #endif
937 fputs (_("\
938 ek erase and kill characters to their default values\n\
939 evenp same as parenb -parodd cs7\n\
940 -evenp same as -parenb cs8\n\
941 "), stdout);
942 #if defined XCASE && defined IUCLC && defined OLCUC
943 fputs (_("\
944 * [-]lcase same as xcase iuclc olcuc\n\
945 "), stdout);
946 #endif
947 fputs (_("\
948 litout same as -parenb -istrip -opost cs8\n\
949 -litout same as parenb istrip opost cs7\n\
950 "), stdout);
951 printf (_("\
952 nl same as %s\n\
953 -nl same as %s\n\
954 "), "-icrnl"
955 #ifdef ONLCR
956 " -onlcr"
957 #endif
958 , "icrnl -inlcr -igncr"
959 #ifdef ONLCR
960 " onlcr"
961 #endif
962 #ifdef OCRNL
963 " -ocrnl"
964 #endif
965 #ifdef ONLRET
966 " -onlret"
967 #endif
969 fputs (_("\
970 oddp same as parenb parodd cs7\n\
971 -oddp same as -parenb cs8\n\
972 [-]parity same as [-]evenp\n\
973 pass8 same as -parenb -istrip cs8\n\
974 -pass8 same as parenb istrip cs7\n\
975 "), stdout);
976 printf (_("\
977 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
978 -inlcr -igncr -icrnl -ixon -ixoff -icanon -opost\n\
979 -isig%s min 1 time 0\n\
980 -raw same as cooked\n\
982 #ifdef IUCLC
983 " -iuclc"
984 #endif
985 #ifdef IXANY
986 " -ixany"
987 #endif
988 #ifdef IMAXBEL
989 " -imaxbel"
990 #endif
991 #ifdef XCASE
992 " -xcase"
993 #endif
995 printf (_("\
996 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
997 icanon iexten echo echoe echok -echonl -noflsh\n\
998 %s\n\
999 %s\n\
1000 %s,\n\
1001 all special characters to their default values\n\
1003 "-ixoff"
1004 #ifdef IUTF8
1005 " -iutf8"
1006 #endif
1007 #ifdef IUCLC
1008 " -iuclc"
1009 #endif
1010 #ifdef IXANY
1011 " -ixany"
1012 #endif
1013 #ifdef IMAXBEL
1014 " imaxbel"
1015 #endif
1016 #ifdef XCASE
1017 " -xcase"
1018 #endif
1019 #ifdef OLCUC
1020 " -olcuc"
1021 #endif
1022 #ifdef OCRNL
1023 " -ocrnl"
1024 #endif
1026 , "opost"
1027 #ifdef OFILL
1028 " -ofill"
1029 #endif
1030 #ifdef ONLCR
1031 " onlcr"
1032 #endif
1033 #ifdef ONOCR
1034 " -onocr"
1035 #endif
1036 #ifdef ONLRET
1037 " -onlret"
1038 #endif
1039 #ifdef NLDLY
1040 " nl0"
1041 #endif
1042 #ifdef CRDLY
1043 " cr0"
1044 #endif
1045 #ifdef TAB0
1046 " tab0"
1047 #endif
1048 #ifdef BSDLY
1049 " bs0"
1050 #endif
1051 #ifdef VTDLY
1052 " vt0"
1053 #endif
1054 #ifdef FFDLY
1055 " ff0"
1056 #endif
1058 , "isig"
1059 #ifdef TOSTOP
1060 " -tostop"
1061 #endif
1062 #ifdef OFDEL
1063 " -ofdel"
1064 #endif
1065 #ifdef ECHOPRT
1066 " -echoprt"
1067 #endif
1068 #ifdef ECHOCTL
1069 " echoctl"
1070 #endif
1071 #ifdef ECHOKE
1072 " echoke"
1073 #endif
1074 #ifdef EXTPROC
1075 " -extproc"
1076 #endif
1077 #ifdef FLUSHO
1078 " -flusho"
1079 #endif
1081 fputs (_("\
1083 Handle the tty line connected to standard input. Without arguments,\n\
1084 prints baud rate, line discipline, and deviations from stty sane. In\n\
1085 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
1086 127; special values ^- or undef used to disable special characters.\n\
1087 "), stdout);
1088 emit_ancillary_info (PROGRAM_NAME);
1090 exit (status);
1094 /* Apply specified settings to MODE and REQUIRE_SET_ATTR as required.
1095 If CHECKING is true, this function doesn't interact
1096 with a device, and only validates specified settings. */
1098 static void
1099 apply_settings (bool checking, char const *device_name,
1100 char * const *settings, int n_settings,
1101 struct termios *mode, bool *require_set_attr)
1103 #define check_argument(arg) \
1104 do \
1106 if (k == n_settings - 1 || ! settings[k + 1]) \
1108 error (0, 0, _("missing argument to %s"), quote (arg)); \
1109 usage (EXIT_FAILURE); \
1112 while (0)
1114 for (int k = 1; k < n_settings; k++)
1116 char const *arg = settings[k];
1117 bool match_found = false;
1118 bool not_set_attr = false;
1119 bool reversed = false;
1120 int i;
1122 if (! arg)
1123 continue;
1125 if (arg[0] == '-')
1127 ++arg;
1128 reversed = true;
1130 if (STREQ (arg, "drain"))
1132 tcsetattr_options = reversed ? TCSANOW : TCSADRAIN;
1133 continue;
1135 for (i = 0; mode_info[i].name != nullptr; ++i)
1137 if (STREQ (arg, mode_info[i].name))
1139 if ((mode_info[i].flags & NO_SETATTR) == 0)
1141 match_found = set_mode (&mode_info[i], reversed, mode);
1142 *require_set_attr = true;
1144 else
1145 match_found = not_set_attr = true;
1146 break;
1149 if (!match_found && reversed)
1151 error (0, 0, _("invalid argument %s"), quote (arg - 1));
1152 usage (EXIT_FAILURE);
1154 if (!match_found)
1156 for (i = 0; control_info[i].name != nullptr; ++i)
1158 if (STREQ (arg, control_info[i].name))
1160 check_argument (arg);
1161 match_found = true;
1162 ++k;
1163 set_control_char (&control_info[i], settings[k], mode);
1164 *require_set_attr = true;
1165 break;
1169 if (!match_found || not_set_attr)
1171 if (STREQ (arg, "ispeed"))
1173 check_argument (arg);
1174 ++k;
1175 if (string_to_baud (settings[k]) == (speed_t) -1)
1177 error (0, 0, _("invalid ispeed %s"), quote (settings[k]));
1178 usage (EXIT_FAILURE);
1180 set_speed (input_speed, settings[k], mode);
1181 if (checking)
1182 continue;
1183 *require_set_attr = true;
1185 else if (STREQ (arg, "ospeed"))
1187 check_argument (arg);
1188 ++k;
1189 if (string_to_baud (settings[k]) == (speed_t) -1)
1191 error (0, 0, _("invalid ospeed %s"), quote (settings[k]));
1192 usage (EXIT_FAILURE);
1194 set_speed (output_speed, settings[k], mode);
1195 if (checking)
1196 continue;
1197 *require_set_attr = true;
1199 #ifdef TIOCEXT
1200 /* This is the BSD interface to "extproc".
1201 Even though it's an lflag, an ioctl is used to set it. */
1202 else if (STREQ (arg, "extproc"))
1204 int val = ! reversed;
1206 if (checking)
1207 continue;
1209 if (ioctl (STDIN_FILENO, TIOCEXT, &val) != 0)
1210 error (EXIT_FAILURE, errno, _("%s: error setting %s"),
1211 quotef_n (0, device_name), quote_n (1, arg));
1213 #endif
1214 #ifdef TIOCGWINSZ
1215 else if (STREQ (arg, "rows"))
1217 check_argument (arg);
1218 ++k;
1219 if (checking)
1220 continue;
1221 set_window_size (integer_arg (settings[k], INT_MAX), -1,
1222 device_name);
1224 else if (STREQ (arg, "cols")
1225 || STREQ (arg, "columns"))
1227 check_argument (arg);
1228 ++k;
1229 if (checking)
1230 continue;
1231 set_window_size (-1, integer_arg (settings[k], INT_MAX),
1232 device_name);
1234 else if (STREQ (arg, "size"))
1236 if (checking)
1237 continue;
1238 max_col = screen_columns ();
1239 current_col = 0;
1240 display_window_size (false, device_name);
1242 #endif
1243 #ifdef HAVE_C_LINE
1244 else if (STREQ (arg, "line"))
1246 check_argument (arg);
1247 ++k;
1248 uintmax_t value = integer_arg (settings[k], UINTMAX_MAX);
1249 if (ckd_add (&mode->c_line, value, 0))
1250 error (0, EOVERFLOW, _("invalid line discipline %s"),
1251 quote (settings[k]));
1252 *require_set_attr = true;
1254 #endif
1255 else if (STREQ (arg, "speed"))
1257 if (checking)
1258 continue;
1259 max_col = screen_columns ();
1260 display_speed (mode, false);
1262 else if (string_to_baud (arg) != (speed_t) -1)
1264 set_speed (both_speeds, arg, mode);
1265 if (checking)
1266 continue;
1267 *require_set_attr = true;
1269 else
1271 if (! recover_mode (arg, mode))
1273 error (0, 0, _("invalid argument %s"), quote (arg));
1274 usage (EXIT_FAILURE);
1276 *require_set_attr = true;
1281 if (checking)
1282 check_speed (mode);
1286 main (int argc, char **argv)
1288 /* Initialize to all zeroes so there is no risk memcmp will report a
1289 spurious difference in an uninitialized portion of the structure. */
1290 static struct termios mode;
1292 enum output_type output_type;
1293 int optc;
1294 int argi = 0;
1295 int opti = 1;
1296 bool require_set_attr;
1297 bool verbose_output;
1298 bool recoverable_output;
1299 bool noargs = true;
1300 char *file_name = nullptr;
1301 char const *device_name;
1303 initialize_main (&argc, &argv);
1304 set_program_name (argv[0]);
1305 setlocale (LC_ALL, "");
1306 bindtextdomain (PACKAGE, LOCALEDIR);
1307 textdomain (PACKAGE);
1309 atexit (close_stdout);
1311 output_type = changed;
1312 verbose_output = false;
1313 recoverable_output = false;
1315 /* Don't print error messages for unrecognized options. */
1316 opterr = 0;
1318 /* If any new options are ever added to stty, the short options MUST
1319 NOT allow any ambiguity with the stty settings. For example, the
1320 stty setting "-gagFork" would not be feasible, since it will be
1321 parsed as "-g -a -g -F ork". If you change anything about how
1322 stty parses options, be sure it still works with combinations of
1323 short and long options, --, POSIXLY_CORRECT, etc. */
1325 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
1326 longopts, nullptr))
1327 != -1)
1329 switch (optc)
1331 case 'a':
1332 verbose_output = true;
1333 output_type = all;
1334 break;
1336 case 'g':
1337 recoverable_output = true;
1338 output_type = recoverable;
1339 break;
1341 case 'F':
1342 if (file_name)
1343 error (EXIT_FAILURE, 0, _("only one device may be specified"));
1344 file_name = optarg;
1345 break;
1347 case DEV_DEBUG_OPTION:
1348 dev_debug = true;
1349 break;
1351 case_GETOPT_HELP_CHAR;
1353 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1355 default:
1356 /* Consider "drain" as an option rather than a setting,
1357 to support: alias stty='stty -drain' etc. */
1358 if (! STREQ (argv[argi + opti], "-drain")
1359 && ! STREQ (argv[argi + opti], "drain"))
1360 noargs = false;
1362 /* Skip the argument containing this unrecognized option;
1363 the 2nd pass will analyze it. */
1364 argi += opti;
1366 /* Restart getopt_long from the first unskipped argument. */
1367 opti = 1;
1368 optind = 0;
1370 break;
1373 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
1374 while (opti < optind)
1375 argv[argi + opti++] = nullptr;
1378 /* Specifying both -a and -g gets an error. */
1379 if (verbose_output && recoverable_output)
1380 error (EXIT_FAILURE, 0,
1381 _("the options for verbose and stty-readable output styles are\n"
1382 "mutually exclusive"));
1384 /* Specifying any other arguments with -a or -g gets an error. */
1385 if (!noargs && (verbose_output || recoverable_output))
1386 error (EXIT_FAILURE, 0,
1387 _("when specifying an output style, modes may not be set"));
1389 device_name = file_name ? file_name : _("standard input");
1391 if (!noargs && !verbose_output && !recoverable_output)
1393 static struct termios check_mode;
1394 apply_settings (/* checking= */ true, device_name, argv, argc,
1395 &check_mode, &require_set_attr);
1398 if (file_name)
1400 int fdflags;
1401 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
1402 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1403 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
1404 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
1405 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
1406 quotef (device_name));
1409 if (tcgetattr (STDIN_FILENO, &mode))
1410 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1412 if (verbose_output || recoverable_output || noargs)
1414 max_col = screen_columns ();
1415 current_col = 0;
1416 display_settings (output_type, &mode, device_name);
1417 return EXIT_SUCCESS;
1420 require_set_attr = false;
1421 apply_settings (/* checking= */ false, device_name, argv, argc,
1422 &mode, &require_set_attr);
1424 if (require_set_attr)
1426 /* Initialize to all zeroes so there is no risk memcmp will report a
1427 spurious difference in an uninitialized portion of the structure. */
1428 static struct termios new_mode;
1430 if (tcsetattr (STDIN_FILENO, tcsetattr_options, &mode))
1431 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1433 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1434 it performs *any* of the requested operations. This means it
1435 can report 'success' when it has actually failed to perform
1436 some proper subset of the requested operations. To detect
1437 this partial failure, get the current terminal attributes and
1438 compare them to the requested ones. */
1440 if (tcgetattr (STDIN_FILENO, &new_mode))
1441 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1443 if (! eq_mode (&mode, &new_mode))
1445 if (dev_debug)
1447 error (0, 0, _("indx: mode: actual mode"));
1448 for (unsigned int i = 0; i < sizeof (new_mode); i++)
1450 unsigned int newc = *(((unsigned char *) &new_mode) + i);
1451 unsigned int oldc = *(((unsigned char *) &mode) + i);
1452 error (0, 0, "0x%02x, 0x%02x: 0x%02x%s", i, oldc, newc,
1453 newc == oldc ? "" : " *");
1457 error (EXIT_FAILURE, 0,
1458 _("%s: unable to perform all requested operations"),
1459 quotef (device_name));
1463 return EXIT_SUCCESS;
1466 /* Return true if modes are equivalent. */
1468 static bool
1469 eq_mode (struct termios *mode1, struct termios *mode2)
1471 return mode1->c_iflag == mode2->c_iflag
1472 && mode1->c_oflag == mode2->c_oflag
1473 && mode1->c_cflag == mode2->c_cflag
1474 && mode1->c_lflag == mode2->c_lflag
1475 #ifdef HAVE_C_LINE
1476 && mode1->c_line == mode2->c_line
1477 #endif
1478 && memcmp (mode1->c_cc, mode2->c_cc, sizeof (mode1->c_cc)) == 0
1479 && cfgetispeed (mode1) == cfgetispeed (mode2)
1480 && cfgetospeed (mode1) == cfgetospeed (mode2);
1483 /* Return false if not applied because not reversible; otherwise
1484 return true. */
1486 static bool
1487 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1489 tcflag_t *bitsp;
1491 if (reversed && (info->flags & REV) == 0)
1492 return false;
1494 bitsp = mode_type_flag (info->type, mode);
1496 if (bitsp == nullptr)
1498 /* Combination mode. */
1499 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1501 if (reversed)
1502 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1503 else
1504 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1506 else if (STREQ (info->name, "oddp"))
1508 if (reversed)
1509 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1510 else
1511 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1513 else if (STREQ (info->name, "nl"))
1515 if (reversed)
1517 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1518 mode->c_oflag = (mode->c_oflag
1519 #ifdef ONLCR
1520 | ONLCR
1521 #endif
1523 #ifdef OCRNL
1524 & ~OCRNL
1525 #endif
1526 #ifdef ONLRET
1527 & ~ONLRET
1528 #endif
1531 else
1533 mode->c_iflag = mode->c_iflag & ~ICRNL;
1534 #ifdef ONLCR
1535 mode->c_oflag = mode->c_oflag & ~ONLCR;
1536 #endif
1539 else if (STREQ (info->name, "ek"))
1541 mode->c_cc[VERASE] = CERASE;
1542 mode->c_cc[VKILL] = CKILL;
1544 else if (STREQ (info->name, "sane"))
1545 sane_mode (mode);
1546 else if (STREQ (info->name, "cbreak"))
1548 if (reversed)
1549 mode->c_lflag |= ICANON;
1550 else
1551 mode->c_lflag &= ~ICANON;
1553 else if (STREQ (info->name, "pass8"))
1555 if (reversed)
1557 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1558 mode->c_iflag |= ISTRIP;
1560 else
1562 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1563 mode->c_iflag &= ~ISTRIP;
1566 else if (STREQ (info->name, "litout"))
1568 if (reversed)
1570 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1571 mode->c_iflag |= ISTRIP;
1572 mode->c_oflag |= OPOST;
1574 else
1576 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1577 mode->c_iflag &= ~ISTRIP;
1578 mode->c_oflag &= ~OPOST;
1581 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1583 if ((info->name[0] == 'r' && reversed)
1584 || (info->name[0] == 'c' && !reversed))
1586 /* Cooked mode. */
1587 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1588 mode->c_oflag |= OPOST;
1589 mode->c_lflag |= ISIG | ICANON;
1590 #if VMIN == VEOF
1591 mode->c_cc[VEOF] = CEOF;
1592 #endif
1593 #if VTIME == VEOL
1594 mode->c_cc[VEOL] = CEOL;
1595 #endif
1597 else
1599 /* Raw mode. */
1600 mode->c_iflag = 0;
1601 mode->c_oflag &= ~OPOST;
1602 mode->c_lflag &= ~(ISIG | ICANON
1603 #ifdef XCASE
1604 | XCASE
1605 #endif
1607 mode->c_cc[VMIN] = 1;
1608 mode->c_cc[VTIME] = 0;
1611 #ifdef IXANY
1612 else if (STREQ (info->name, "decctlq"))
1614 if (reversed)
1615 mode->c_iflag |= IXANY;
1616 else
1617 mode->c_iflag &= ~IXANY;
1619 #endif
1620 #ifdef TABDLY
1621 else if (STREQ (info->name, "tabs"))
1623 if (reversed)
1624 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1625 else
1626 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1628 #else
1629 # ifdef OXTABS
1630 else if (STREQ (info->name, "tabs"))
1632 if (reversed)
1633 mode->c_oflag = mode->c_oflag | OXTABS;
1634 else
1635 mode->c_oflag = mode->c_oflag & ~OXTABS;
1637 # endif
1638 #endif
1639 #if defined XCASE && defined IUCLC && defined OLCUC
1640 else if (STREQ (info->name, "lcase")
1641 || STREQ (info->name, "LCASE"))
1643 if (reversed)
1645 mode->c_lflag &= ~XCASE;
1646 mode->c_iflag &= ~IUCLC;
1647 mode->c_oflag &= ~OLCUC;
1649 else
1651 mode->c_lflag |= XCASE;
1652 mode->c_iflag |= IUCLC;
1653 mode->c_oflag |= OLCUC;
1656 #endif
1657 else if (STREQ (info->name, "crt"))
1658 mode->c_lflag |= ECHOE
1659 #ifdef ECHOCTL
1660 | ECHOCTL
1661 #endif
1662 #ifdef ECHOKE
1663 | ECHOKE
1664 #endif
1666 else if (STREQ (info->name, "dec"))
1668 mode->c_cc[VINTR] = 3; /* ^C */
1669 mode->c_cc[VERASE] = 127; /* DEL */
1670 mode->c_cc[VKILL] = 21; /* ^U */
1671 mode->c_lflag |= ECHOE
1672 #ifdef ECHOCTL
1673 | ECHOCTL
1674 #endif
1675 #ifdef ECHOKE
1676 | ECHOKE
1677 #endif
1679 #ifdef IXANY
1680 mode->c_iflag &= ~IXANY;
1681 #endif
1684 else if (reversed)
1685 *bitsp = *bitsp & ~info->mask & ~info->bits;
1686 else
1687 *bitsp = (*bitsp & ~info->mask) | info->bits;
1689 return true;
1692 static void
1693 set_control_char (struct control_info const *info, char const *arg,
1694 struct termios *mode)
1696 unsigned long int value;
1698 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1699 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1700 else if (arg[0] == '\0' || arg[1] == '\0')
1701 value = to_uchar (arg[0]);
1702 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1703 value = _POSIX_VDISABLE;
1704 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1706 if (arg[1] == '?')
1707 value = 127;
1708 else
1709 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1711 else
1712 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1713 mode->c_cc[info->offset] = value;
1716 static void
1717 set_speed (enum speed_setting type, char const *arg, struct termios *mode)
1719 /* Note cfset[io]speed(), do not check with the device,
1720 and only check whether the system logic supports the specified speed.
1721 Therefore we don't report the device name in any errors. */
1723 speed_t baud = string_to_baud (arg);
1724 affirm (baud != (speed_t) -1);
1726 if (type == input_speed || type == both_speeds)
1728 last_ibaud = baud;
1729 if (cfsetispeed (mode, baud))
1730 error (EXIT_FAILURE, 0, _("unsupported ispeed %s"), quoteaf (arg));
1732 if (type == output_speed || type == both_speeds)
1734 last_obaud = baud;
1735 if (cfsetospeed (mode, baud))
1736 error (EXIT_FAILURE, 0, _("unsupported ospeed %s"), quoteaf (arg));
1740 #ifdef TIOCGWINSZ
1742 static int
1743 get_win_size (int fd, struct winsize *win)
1745 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1746 return err;
1749 static void
1750 set_window_size (int rows, int cols, char const *device_name)
1752 struct winsize win;
1754 if (get_win_size (STDIN_FILENO, &win))
1756 if (errno != EINVAL)
1757 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1758 memset (&win, 0, sizeof (win));
1761 if (rows >= 0)
1762 win.ws_row = rows;
1763 if (cols >= 0)
1764 win.ws_col = cols;
1766 # ifdef TIOCSSIZE
1767 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1768 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1769 This comment from sys/ttold.h describes Sun's twisted logic - a better
1770 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1771 At any rate, the problem is gone in Solaris 2.x.
1773 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1774 but they can be disambiguated by checking whether a "struct ttysize"
1775 structure's "ts_lines" field is greater than 64K or not. If so,
1776 it's almost certainly a "struct winsize" instead.
1778 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1779 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16)
1780 + ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1781 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1782 "stty cols 0 rows 0" would do the right thing. On a little-endian
1783 machine like the sun386i, the problem is the same, but for ws_col == 0.
1785 The workaround is to do the ioctl once with row and col = 1 to set the
1786 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1788 if (win.ws_row == 0 || win.ws_col == 0)
1790 struct ttysize ttysz;
1792 ttysz.ts_lines = win.ws_row;
1793 ttysz.ts_cols = win.ws_col;
1795 win.ws_row = 1;
1796 win.ws_col = 1;
1798 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1799 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1801 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1802 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1803 return;
1805 # endif
1807 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1808 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1811 static void
1812 display_window_size (bool fancy, char const *device_name)
1814 struct winsize win;
1816 if (get_win_size (STDIN_FILENO, &win))
1818 if (errno != EINVAL)
1819 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1820 if (!fancy)
1821 error (EXIT_FAILURE, 0,
1822 _("%s: no size information for this device"),
1823 quotef (device_name));
1825 else
1827 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1828 win.ws_row, win.ws_col);
1829 if (!fancy)
1830 current_col = 0;
1833 #endif
1835 static int
1836 screen_columns (void)
1838 #ifdef TIOCGWINSZ
1839 struct winsize win;
1841 /* With Solaris 2.[123], this ioctl fails and errno is set to
1842 EINVAL for telnet (but not rlogin) sessions.
1843 On ISC 3.0, it fails for the console and the serial port
1844 (but it works for ptys).
1845 It can also fail on any system when stdout isn't a tty.
1846 In case of any failure, just use the default. */
1847 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1848 return win.ws_col;
1849 #endif
1851 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1852 char *col_string = getenv ("COLUMNS");
1853 long int n_columns;
1854 if (!(col_string != nullptr
1855 && xstrtol (col_string, nullptr, 0, &n_columns, "") == LONGINT_OK
1856 && 0 < n_columns
1857 && n_columns <= INT_MAX))
1858 n_columns = 80;
1859 return n_columns;
1863 ATTRIBUTE_PURE
1864 static tcflag_t *
1865 mode_type_flag (enum mode_type type, struct termios *mode)
1867 switch (type)
1869 case control:
1870 return &mode->c_cflag;
1872 case input:
1873 return &mode->c_iflag;
1875 case output:
1876 return &mode->c_oflag;
1878 case local:
1879 return &mode->c_lflag;
1881 case combination:
1882 return nullptr;
1884 default:
1885 unreachable ();
1889 static void
1890 display_settings (enum output_type output_type, struct termios *mode,
1891 char const *device_name)
1893 switch (output_type)
1895 case changed:
1896 display_changed (mode);
1897 break;
1899 case all:
1900 display_all (mode, device_name);
1901 break;
1903 case recoverable:
1904 display_recoverable (mode);
1905 break;
1909 static void
1910 display_changed (struct termios *mode)
1912 int i;
1913 bool empty_line;
1914 tcflag_t *bitsp;
1915 unsigned long mask;
1916 enum mode_type prev_type = control;
1918 display_speed (mode, true);
1919 #ifdef HAVE_C_LINE
1920 wrapf ("line = %d;", mode->c_line);
1921 #endif
1922 putchar ('\n');
1923 current_col = 0;
1925 empty_line = true;
1926 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1928 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1929 continue;
1931 #ifdef VFLUSHO
1932 /* 'flush' is the deprecated equivalent of 'discard'. */
1933 if (STREQ (control_info[i].name, "flush"))
1934 continue;
1935 #endif
1936 /* If swtch is the same as susp, don't print both. */
1937 #if VSWTCH == VSUSP
1938 if (STREQ (control_info[i].name, "swtch"))
1939 continue;
1940 #endif
1941 /* If eof uses the same slot as min, only print whichever applies. */
1942 #if VEOF == VMIN
1943 if ((mode->c_lflag & ICANON) == 0
1944 && (STREQ (control_info[i].name, "eof")
1945 || STREQ (control_info[i].name, "eol")))
1946 continue;
1947 #endif
1949 empty_line = false;
1950 wrapf ("%s = %s;", control_info[i].name,
1951 visible (mode->c_cc[control_info[i].offset]));
1953 if ((mode->c_lflag & ICANON) == 0)
1955 wrapf ("min = %lu; time = %lu;\n",
1956 (unsigned long int) mode->c_cc[VMIN],
1957 (unsigned long int) mode->c_cc[VTIME]);
1959 else if (!empty_line)
1960 putchar ('\n');
1961 current_col = 0;
1963 empty_line = true;
1964 for (i = 0; mode_info[i].name != nullptr; ++i)
1966 if (mode_info[i].flags & OMIT)
1967 continue;
1968 if (mode_info[i].type != prev_type)
1970 if (!empty_line)
1972 putchar ('\n');
1973 current_col = 0;
1974 empty_line = true;
1976 prev_type = mode_info[i].type;
1979 bitsp = mode_type_flag (mode_info[i].type, mode);
1980 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1981 if ((*bitsp & mask) == mode_info[i].bits)
1983 if (mode_info[i].flags & SANE_UNSET)
1985 wrapf ("%s", mode_info[i].name);
1986 empty_line = false;
1989 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1991 wrapf ("-%s", mode_info[i].name);
1992 empty_line = false;
1995 if (!empty_line)
1996 putchar ('\n');
1997 current_col = 0;
2000 static void
2001 display_all (struct termios *mode, char const *device_name)
2003 int i;
2004 tcflag_t *bitsp;
2005 unsigned long mask;
2006 enum mode_type prev_type = control;
2008 display_speed (mode, true);
2009 #ifdef TIOCGWINSZ
2010 display_window_size (true, device_name);
2011 #endif
2012 #ifdef HAVE_C_LINE
2013 wrapf ("line = %d;", mode->c_line);
2014 #endif
2015 putchar ('\n');
2016 current_col = 0;
2018 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
2020 #ifdef VFLUSHO
2021 /* 'flush' is the deprecated equivalent of 'discard'. */
2022 if (STREQ (control_info[i].name, "flush"))
2023 continue;
2024 #endif
2025 /* If swtch is the same as susp, don't print both. */
2026 #if VSWTCH == VSUSP
2027 if (STREQ (control_info[i].name, "swtch"))
2028 continue;
2029 #endif
2030 /* If eof uses the same slot as min, only print whichever applies. */
2031 #if VEOF == VMIN
2032 if ((mode->c_lflag & ICANON) == 0
2033 && (STREQ (control_info[i].name, "eof")
2034 || STREQ (control_info[i].name, "eol")))
2035 continue;
2036 #endif
2037 wrapf ("%s = %s;", control_info[i].name,
2038 visible (mode->c_cc[control_info[i].offset]));
2040 #if VEOF == VMIN
2041 if ((mode->c_lflag & ICANON) == 0)
2042 #endif
2043 wrapf ("min = %lu; time = %lu;",
2044 (unsigned long int) mode->c_cc[VMIN],
2045 (unsigned long int) mode->c_cc[VTIME]);
2046 if (current_col != 0)
2047 putchar ('\n');
2048 current_col = 0;
2050 for (i = 0; mode_info[i].name != nullptr; ++i)
2052 if (mode_info[i].flags & OMIT)
2053 continue;
2054 if (mode_info[i].type != prev_type)
2056 putchar ('\n');
2057 current_col = 0;
2058 prev_type = mode_info[i].type;
2061 bitsp = mode_type_flag (mode_info[i].type, mode);
2062 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
2063 if ((*bitsp & mask) == mode_info[i].bits)
2064 wrapf ("%s", mode_info[i].name);
2065 else if (mode_info[i].flags & REV)
2066 wrapf ("-%s", mode_info[i].name);
2068 putchar ('\n');
2069 current_col = 0;
2072 /* Verify requested asymmetric speeds are supported.
2073 Note we don't flag the case where only ispeed or
2074 ospeed is set, when that would set both. */
2076 static void
2077 check_speed (struct termios *mode)
2079 if (last_ibaud != -1 && last_obaud != -1)
2081 if (cfgetispeed (mode) != last_ibaud
2082 || cfgetospeed (mode) != last_obaud)
2083 error (EXIT_FAILURE, 0,
2084 _("asymmetric input (%lu), output (%lu) speeds not supported"),
2085 baud_to_value (last_ibaud), baud_to_value (last_obaud));
2089 static void
2090 display_speed (struct termios *mode, bool fancy)
2092 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
2093 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
2094 baud_to_value (cfgetospeed (mode)));
2095 else
2096 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
2097 baud_to_value (cfgetispeed (mode)),
2098 baud_to_value (cfgetospeed (mode)));
2099 if (!fancy)
2100 current_col = 0;
2103 static void
2104 display_recoverable (struct termios *mode)
2106 printf ("%lx:%lx:%lx:%lx",
2107 (unsigned long int) mode->c_iflag,
2108 (unsigned long int) mode->c_oflag,
2109 (unsigned long int) mode->c_cflag,
2110 (unsigned long int) mode->c_lflag);
2111 for (size_t i = 0; i < NCCS; ++i)
2112 printf (":%lx", (unsigned long int) mode->c_cc[i]);
2113 putchar ('\n');
2116 /* NOTE: identical to below, modulo use of tcflag_t */
2117 static int
2118 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
2119 char delim)
2121 unsigned long ul;
2122 errno = 0;
2123 ul = strtoul (s, p, base);
2124 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
2125 return -1;
2126 *result = ul;
2127 return 0;
2130 /* NOTE: identical to above, modulo use of cc_t */
2131 static int
2132 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
2134 unsigned long ul;
2135 errno = 0;
2136 ul = strtoul (s, p, base);
2137 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
2138 return -1;
2139 *result = ul;
2140 return 0;
2143 /* Parse the output of display_recoverable.
2144 Return false if any part of it is invalid. */
2145 static bool
2146 recover_mode (char const *arg, struct termios *mode)
2148 tcflag_t flag[4];
2149 char const *s = arg;
2150 size_t i;
2151 for (i = 0; i < 4; i++)
2153 char *p;
2154 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
2155 return false;
2156 s = p + 1;
2158 mode->c_iflag = flag[0];
2159 mode->c_oflag = flag[1];
2160 mode->c_cflag = flag[2];
2161 mode->c_lflag = flag[3];
2163 for (i = 0; i < NCCS; ++i)
2165 char *p;
2166 char delim = i < NCCS - 1 ? ':' : '\0';
2167 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
2168 return false;
2169 s = p + 1;
2172 return true;
2175 struct speed_map
2177 char const *string; /* ASCII representation. */
2178 speed_t speed; /* Internal form. */
2179 unsigned long int value; /* Numeric value. */
2182 static struct speed_map const speeds[] =
2184 {"0", B0, 0},
2185 {"50", B50, 50},
2186 {"75", B75, 75},
2187 {"110", B110, 110},
2188 {"134", B134, 134},
2189 {"134.5", B134, 134},
2190 {"150", B150, 150},
2191 {"200", B200, 200},
2192 {"300", B300, 300},
2193 {"600", B600, 600},
2194 {"1200", B1200, 1200},
2195 {"1800", B1800, 1800},
2196 {"2400", B2400, 2400},
2197 {"4800", B4800, 4800},
2198 {"9600", B9600, 9600},
2199 {"19200", B19200, 19200},
2200 {"38400", B38400, 38400},
2201 {"exta", B19200, 19200},
2202 {"extb", B38400, 38400},
2203 #ifdef B57600
2204 {"57600", B57600, 57600},
2205 #endif
2206 #ifdef B115200
2207 {"115200", B115200, 115200},
2208 #endif
2209 #ifdef B230400
2210 {"230400", B230400, 230400},
2211 #endif
2212 #ifdef B460800
2213 {"460800", B460800, 460800},
2214 #endif
2215 #ifdef B500000
2216 {"500000", B500000, 500000},
2217 #endif
2218 #ifdef B576000
2219 {"576000", B576000, 576000},
2220 #endif
2221 #ifdef B921600
2222 {"921600", B921600, 921600},
2223 #endif
2224 #ifdef B1000000
2225 {"1000000", B1000000, 1000000},
2226 #endif
2227 #ifdef B1152000
2228 {"1152000", B1152000, 1152000},
2229 #endif
2230 #ifdef B1500000
2231 {"1500000", B1500000, 1500000},
2232 #endif
2233 #ifdef B2000000
2234 {"2000000", B2000000, 2000000},
2235 #endif
2236 #ifdef B2500000
2237 {"2500000", B2500000, 2500000},
2238 #endif
2239 #ifdef B3000000
2240 {"3000000", B3000000, 3000000},
2241 #endif
2242 #ifdef B3500000
2243 {"3500000", B3500000, 3500000},
2244 #endif
2245 #ifdef B4000000
2246 {"4000000", B4000000, 4000000},
2247 #endif
2248 {nullptr, 0, 0}
2251 ATTRIBUTE_PURE
2252 static speed_t
2253 string_to_baud (char const *arg)
2255 for (int i = 0; speeds[i].string != nullptr; ++i)
2256 if (STREQ (arg, speeds[i].string))
2257 return speeds[i].speed;
2258 return (speed_t) -1;
2261 ATTRIBUTE_PURE
2262 static unsigned long int
2263 baud_to_value (speed_t speed)
2265 for (int i = 0; speeds[i].string != nullptr; ++i)
2266 if (speed == speeds[i].speed)
2267 return speeds[i].value;
2268 return 0;
2271 static void
2272 sane_mode (struct termios *mode)
2274 int i;
2275 tcflag_t *bitsp;
2277 for (i = 0; control_info[i].name; ++i)
2279 #if VMIN == VEOF
2280 if (STREQ (control_info[i].name, "min"))
2281 break;
2282 #endif
2283 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
2286 for (i = 0; mode_info[i].name != nullptr; ++i)
2288 if (mode_info[i].flags & NO_SETATTR)
2289 continue;
2291 if (mode_info[i].flags & SANE_SET)
2293 bitsp = mode_type_flag (mode_info[i].type, mode);
2294 assume (bitsp); /* combination modes will not have SANE_SET. */
2295 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
2297 else if (mode_info[i].flags & SANE_UNSET)
2299 bitsp = mode_type_flag (mode_info[i].type, mode);
2300 assume (bitsp); /* combination modes will not have SANE_UNSET. */
2301 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
2306 /* Return a string that is the printable representation of character CH. */
2307 /* Adapted from 'cat' by Torbjörn Granlund. */
2309 static char const *
2310 visible (cc_t ch)
2312 static char buf[10];
2313 char *bpout = buf;
2315 if (ch == _POSIX_VDISABLE)
2316 return "<undef>";
2318 if (ch >= 32)
2320 if (ch < 127)
2321 *bpout++ = ch;
2322 else if (ch == 127)
2324 *bpout++ = '^';
2325 *bpout++ = '?';
2327 else
2329 *bpout++ = 'M';
2330 *bpout++ = '-';
2331 if (ch >= 128 + 32)
2333 if (ch < 128 + 127)
2334 *bpout++ = ch - 128;
2335 else
2337 *bpout++ = '^';
2338 *bpout++ = '?';
2341 else
2343 *bpout++ = '^';
2344 *bpout++ = ch - 128 + 64;
2348 else
2350 *bpout++ = '^';
2351 *bpout++ = ch + 64;
2353 *bpout = '\0';
2354 return (char const *) buf;
2357 /* Parse string S as an integer, using decimal radix by default,
2358 but allowing octal and hex numbers as in C. Reject values
2359 larger than MAXVAL. */
2361 static uintmax_t
2362 integer_arg (char const *s, uintmax_t maxval)
2364 return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"),
2365 0, 0);