maint: make update-copyright handle more cases
[coreutils.git] / src / stty.c
blob389ab9eb9075766c5e7a2472bb0758b77b43a2d0
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005, 2007-2009 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 <http://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 #if HAVE_TERMIOS_H
40 # include <termios.h>
41 #endif
42 #if HAVE_STROPTS_H
43 # include <stropts.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 # include <sys/ioctl.h>
47 #endif
49 #ifdef WINSIZE_IN_PTEM
50 # include <sys/stream.h>
51 # include <sys/ptem.h>
52 #endif
53 #ifdef GWINSZ_IN_SYS_PTY
54 # include <sys/tty.h>
55 # include <sys/pty.h>
56 #endif
57 #include <getopt.h>
58 #include <stdarg.h>
60 #include "system.h"
61 #include "error.h"
62 #include "fd-reopen.h"
63 #include "quote.h"
64 #include "xstrtol.h"
66 /* The official name of this program (e.g., no `g' prefix). */
67 #define PROGRAM_NAME "stty"
69 #define AUTHORS proper_name ("David MacKenzie")
71 #ifndef _POSIX_VDISABLE
72 # define _POSIX_VDISABLE 0
73 #endif
75 #define Control(c) ((c) & 0x1f)
76 /* Canonical values for control characters. */
77 #ifndef CINTR
78 # define CINTR Control ('c')
79 #endif
80 #ifndef CQUIT
81 # define CQUIT 28
82 #endif
83 #ifndef CERASE
84 # define CERASE 127
85 #endif
86 #ifndef CKILL
87 # define CKILL Control ('u')
88 #endif
89 #ifndef CEOF
90 # define CEOF Control ('d')
91 #endif
92 #ifndef CEOL
93 # define CEOL _POSIX_VDISABLE
94 #endif
95 #ifndef CSTART
96 # define CSTART Control ('q')
97 #endif
98 #ifndef CSTOP
99 # define CSTOP Control ('s')
100 #endif
101 #ifndef CSUSP
102 # define CSUSP Control ('z')
103 #endif
104 #if defined VEOL2 && !defined CEOL2
105 # define CEOL2 _POSIX_VDISABLE
106 #endif
107 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
108 character is initialized by CSWTCH, if present. */
109 #if defined VSWTC && !defined VSWTCH
110 # define VSWTCH VSWTC
111 #endif
112 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
113 #if defined VSUSP && !defined VSWTCH
114 # define VSWTCH VSUSP
115 # if defined CSUSP && !defined CSWTCH
116 # define CSWTCH CSUSP
117 # endif
118 #endif
119 #if defined VSWTCH && !defined CSWTCH
120 # define CSWTCH _POSIX_VDISABLE
121 #endif
123 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
124 So the default is to disable `swtch.' */
125 #if defined __sparc__ && defined __svr4__
126 # undef CSWTCH
127 # define CSWTCH _POSIX_VDISABLE
128 #endif
130 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
131 # define VWERASE VWERSE
132 #endif
133 #if defined VDSUSP && !defined CDSUSP
134 # define CDSUSP Control ('y')
135 #endif
136 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
137 # define VREPRINT VRPRNT
138 #endif
139 #if defined VREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
141 #endif
142 #if defined CREPRINT && !defined CRPRNT
143 # define CRPRNT Control ('r')
144 #endif
145 #if defined VWERASE && !defined CWERASE
146 # define CWERASE Control ('w')
147 #endif
148 #if defined VLNEXT && !defined CLNEXT
149 # define CLNEXT Control ('v')
150 #endif
151 #if defined VDISCARD && !defined VFLUSHO
152 # define VFLUSHO VDISCARD
153 #endif
154 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
155 # define VFLUSHO VFLUSH
156 #endif
157 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
158 # define ECHOCTL CTLECH
159 #endif
160 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
161 # define ECHOCTL TCTLECH
162 #endif
163 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
164 # define ECHOKE CRTKIL
165 #endif
166 #if defined VFLUSHO && !defined CFLUSHO
167 # define CFLUSHO Control ('o')
168 #endif
169 #if defined VSTATUS && !defined CSTATUS
170 # define CSTATUS Control ('t')
171 #endif
173 /* Which speeds to set. */
174 enum speed_setting
176 input_speed, output_speed, both_speeds
179 /* What to output and how. */
180 enum output_type
182 changed, all, recoverable /* Default, -a, -g. */
185 /* Which member(s) of `struct termios' a mode uses. */
186 enum mode_type
188 control, input, output, local, combination
191 /* Flags for `struct mode_info'. */
192 #define SANE_SET 1 /* Set in `sane' mode. */
193 #define SANE_UNSET 2 /* Unset in `sane' mode. */
194 #define REV 4 /* Can be turned off by prepending `-'. */
195 #define OMIT 8 /* Don't display value. */
197 /* Each mode. */
198 struct mode_info
200 const char *name; /* Name given on command line. */
201 enum mode_type type; /* Which structure element to change. */
202 char flags; /* Setting and display options. */
203 unsigned long bits; /* Bits to set for this mode. */
204 unsigned long mask; /* Other bits to turn off for this mode. */
207 static struct mode_info const mode_info[] =
209 {"parenb", control, REV, PARENB, 0},
210 {"parodd", control, REV, PARODD, 0},
211 {"cs5", control, 0, CS5, CSIZE},
212 {"cs6", control, 0, CS6, CSIZE},
213 {"cs7", control, 0, CS7, CSIZE},
214 {"cs8", control, 0, CS8, CSIZE},
215 {"hupcl", control, REV, HUPCL, 0},
216 {"hup", control, REV | OMIT, HUPCL, 0},
217 {"cstopb", control, REV, CSTOPB, 0},
218 {"cread", control, SANE_SET | REV, CREAD, 0},
219 {"clocal", control, REV, CLOCAL, 0},
220 #ifdef CRTSCTS
221 {"crtscts", control, REV, CRTSCTS, 0},
222 #endif
224 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
225 {"brkint", input, SANE_SET | REV, BRKINT, 0},
226 {"ignpar", input, REV, IGNPAR, 0},
227 {"parmrk", input, REV, PARMRK, 0},
228 {"inpck", input, REV, INPCK, 0},
229 {"istrip", input, REV, ISTRIP, 0},
230 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
231 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
232 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
233 {"ixon", input, REV, IXON, 0},
234 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
235 {"tandem", input, REV | OMIT, IXOFF, 0},
236 #ifdef IUCLC
237 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
238 #endif
239 #ifdef IXANY
240 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
241 #endif
242 #ifdef IMAXBEL
243 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
244 #endif
245 #ifdef IUTF8
246 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
247 #endif
249 {"opost", output, SANE_SET | REV, OPOST, 0},
250 #ifdef OLCUC
251 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
252 #endif
253 #ifdef OCRNL
254 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
255 #endif
256 #ifdef ONLCR
257 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
258 #endif
259 #ifdef ONOCR
260 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
261 #endif
262 #ifdef ONLRET
263 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
264 #endif
265 #ifdef OFILL
266 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
267 #endif
268 #ifdef OFDEL
269 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
270 #endif
271 #ifdef NLDLY
272 {"nl1", output, SANE_UNSET, NL1, NLDLY},
273 {"nl0", output, SANE_SET, NL0, NLDLY},
274 #endif
275 #ifdef CRDLY
276 {"cr3", output, SANE_UNSET, CR3, CRDLY},
277 {"cr2", output, SANE_UNSET, CR2, CRDLY},
278 {"cr1", output, SANE_UNSET, CR1, CRDLY},
279 {"cr0", output, SANE_SET, CR0, CRDLY},
280 #endif
281 #ifdef TABDLY
282 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
283 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
284 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
285 {"tab0", output, SANE_SET, TAB0, TABDLY},
286 #else
287 # ifdef OXTABS
288 {"tab3", output, SANE_UNSET, OXTABS, 0},
289 # endif
290 #endif
291 #ifdef BSDLY
292 {"bs1", output, SANE_UNSET, BS1, BSDLY},
293 {"bs0", output, SANE_SET, BS0, BSDLY},
294 #endif
295 #ifdef VTDLY
296 {"vt1", output, SANE_UNSET, VT1, VTDLY},
297 {"vt0", output, SANE_SET, VT0, VTDLY},
298 #endif
299 #ifdef FFDLY
300 {"ff1", output, SANE_UNSET, FF1, FFDLY},
301 {"ff0", output, SANE_SET, FF0, FFDLY},
302 #endif
304 {"isig", local, SANE_SET | REV, ISIG, 0},
305 {"icanon", local, SANE_SET | REV, ICANON, 0},
306 #ifdef IEXTEN
307 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
308 #endif
309 {"echo", local, SANE_SET | REV, ECHO, 0},
310 {"echoe", local, SANE_SET | REV, ECHOE, 0},
311 {"crterase", local, REV | OMIT, ECHOE, 0},
312 {"echok", local, SANE_SET | REV, ECHOK, 0},
313 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
314 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
315 #ifdef XCASE
316 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
317 #endif
318 #ifdef TOSTOP
319 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
320 #endif
321 #ifdef ECHOPRT
322 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
323 {"prterase", local, REV | OMIT, ECHOPRT, 0},
324 #endif
325 #ifdef ECHOCTL
326 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
327 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
328 #endif
329 #ifdef ECHOKE
330 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
331 {"crtkill", local, REV | OMIT, ECHOKE, 0},
332 #endif
334 {"evenp", combination, REV | OMIT, 0, 0},
335 {"parity", combination, REV | OMIT, 0, 0},
336 {"oddp", combination, REV | OMIT, 0, 0},
337 {"nl", combination, REV | OMIT, 0, 0},
338 {"ek", combination, OMIT, 0, 0},
339 {"sane", combination, OMIT, 0, 0},
340 {"cooked", combination, REV | OMIT, 0, 0},
341 {"raw", combination, REV | OMIT, 0, 0},
342 {"pass8", combination, REV | OMIT, 0, 0},
343 {"litout", combination, REV | OMIT, 0, 0},
344 {"cbreak", combination, REV | OMIT, 0, 0},
345 #ifdef IXANY
346 {"decctlq", combination, REV | OMIT, 0, 0},
347 #endif
348 #if defined TABDLY || defined OXTABS
349 {"tabs", combination, REV | OMIT, 0, 0},
350 #endif
351 #if defined XCASE && defined IUCLC && defined OLCUC
352 {"lcase", combination, REV | OMIT, 0, 0},
353 {"LCASE", combination, REV | OMIT, 0, 0},
354 #endif
355 {"crt", combination, OMIT, 0, 0},
356 {"dec", combination, OMIT, 0, 0},
358 {NULL, control, 0, 0, 0}
361 /* Control character settings. */
362 struct control_info
364 const char *name; /* Name given on command line. */
365 cc_t saneval; /* Value to set for `stty sane'. */
366 size_t offset; /* Offset in c_cc. */
369 /* Control characters. */
371 static struct control_info const control_info[] =
373 {"intr", CINTR, VINTR},
374 {"quit", CQUIT, VQUIT},
375 {"erase", CERASE, VERASE},
376 {"kill", CKILL, VKILL},
377 {"eof", CEOF, VEOF},
378 {"eol", CEOL, VEOL},
379 #ifdef VEOL2
380 {"eol2", CEOL2, VEOL2},
381 #endif
382 #ifdef VSWTCH
383 {"swtch", CSWTCH, VSWTCH},
384 #endif
385 {"start", CSTART, VSTART},
386 {"stop", CSTOP, VSTOP},
387 {"susp", CSUSP, VSUSP},
388 #ifdef VDSUSP
389 {"dsusp", CDSUSP, VDSUSP},
390 #endif
391 #ifdef VREPRINT
392 {"rprnt", CRPRNT, VREPRINT},
393 #else
394 # ifdef CREPRINT /* HPUX 10.20 needs this */
395 {"rprnt", CRPRNT, CREPRINT},
396 # endif
397 #endif
398 #ifdef VWERASE
399 {"werase", CWERASE, VWERASE},
400 #endif
401 #ifdef VLNEXT
402 {"lnext", CLNEXT, VLNEXT},
403 #endif
404 #ifdef VFLUSHO
405 {"flush", CFLUSHO, VFLUSHO},
406 #endif
407 #ifdef VSTATUS
408 {"status", CSTATUS, VSTATUS},
409 #endif
411 /* These must be last because of the display routines. */
412 {"min", 1, VMIN},
413 {"time", 0, VTIME},
414 {NULL, 0, 0}
417 static char const *visible (cc_t ch);
418 static unsigned long int baud_to_value (speed_t speed);
419 static bool recover_mode (char const *arg, struct termios *mode);
420 static int screen_columns (void);
421 static bool set_mode (struct mode_info const *info, bool reversed,
422 struct termios *mode);
423 static unsigned long int integer_arg (const char *s, unsigned long int max);
424 static speed_t string_to_baud (const char *arg);
425 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
426 static void display_all (struct termios *mode, char const *device_name);
427 static void display_changed (struct termios *mode);
428 static void display_recoverable (struct termios *mode);
429 static void display_settings (enum output_type output_type,
430 struct termios *mode,
431 const char *device_name);
432 static void display_speed (struct termios *mode, bool fancy);
433 static void display_window_size (bool fancy, char const *device_name);
434 static void sane_mode (struct termios *mode);
435 static void set_control_char (struct control_info const *info,
436 const char *arg,
437 struct termios *mode);
438 static void set_speed (enum speed_setting type, const char *arg,
439 struct termios *mode);
440 static void set_window_size (int rows, int cols, char const *device_name);
442 /* The width of the screen, for output wrapping. */
443 static int max_col;
445 /* Current position, to know when to wrap. */
446 static int current_col;
448 static struct option const longopts[] =
450 {"all", no_argument, NULL, 'a'},
451 {"save", no_argument, NULL, 'g'},
452 {"file", required_argument, NULL, 'F'},
453 {GETOPT_HELP_OPTION_DECL},
454 {GETOPT_VERSION_OPTION_DECL},
455 {NULL, 0, NULL, 0}
458 static void wrapf (const char *message, ...)
459 __attribute__ ((__format__ (__printf__, 1, 2)));
461 /* Print format string MESSAGE and optional args.
462 Wrap to next line first if it won't fit.
463 Print a space first unless MESSAGE will start a new line. */
465 static void
466 wrapf (const char *message,...)
468 va_list args;
469 char *buf;
470 int buflen;
472 va_start (args, message);
473 buflen = vasprintf (&buf, message, args);
474 va_end (args);
476 if (buflen < 0)
477 xalloc_die ();
479 if (0 < current_col)
481 if (max_col - current_col < buflen)
483 putchar ('\n');
484 current_col = 0;
486 else
488 putchar (' ');
489 current_col++;
493 fputs (buf, stdout);
494 free (buf);
495 current_col += buflen;
498 void
499 usage (int status)
501 if (status != EXIT_SUCCESS)
502 fprintf (stderr, _("Try `%s --help' for more information.\n"),
503 program_name);
504 else
506 printf (_("\
507 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
508 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
509 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
511 program_name, program_name, program_name);
512 fputs (_("\
513 Print or change terminal characteristics.\n\
515 -a, --all print all current settings in human-readable form\n\
516 -g, --save print all current settings in a stty-readable form\n\
517 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
518 "), stdout);
519 fputs (HELP_OPTION_DESCRIPTION, stdout);
520 fputs (VERSION_OPTION_DESCRIPTION, stdout);
521 fputs (_("\
523 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
524 settings. The underlying system defines which settings are available.\n\
525 "), stdout);
526 fputs (_("\
528 Special characters:\n\
529 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
530 eof CHAR CHAR will send an end of file (terminate the input)\n\
531 eol CHAR CHAR will end the line\n\
532 "), stdout);
533 fputs (_("\
534 * eol2 CHAR alternate CHAR for ending the line\n\
535 erase CHAR CHAR will erase the last character typed\n\
536 intr CHAR CHAR will send an interrupt signal\n\
537 kill CHAR CHAR will erase the current line\n\
538 "), stdout);
539 fputs (_("\
540 * lnext CHAR CHAR will enter the next character quoted\n\
541 quit CHAR CHAR will send a quit signal\n\
542 * rprnt CHAR CHAR will redraw the current line\n\
543 start CHAR CHAR will restart the output after stopping it\n\
544 "), stdout);
545 fputs (_("\
546 stop CHAR CHAR will stop the output\n\
547 susp CHAR CHAR will send a terminal stop signal\n\
548 * swtch CHAR CHAR will switch to a different shell layer\n\
549 * werase CHAR CHAR will erase the last word typed\n\
550 "), stdout);
551 fputs (_("\
553 Special settings:\n\
554 N set the input and output speeds to N bauds\n\
555 * cols N tell the kernel that the terminal has N columns\n\
556 * columns N same as cols N\n\
557 "), stdout);
558 fputs (_("\
559 ispeed N set the input speed to N\n\
560 * line N use line discipline N\n\
561 min N with -icanon, set N characters minimum for a completed read\n\
562 ospeed N set the output speed to N\n\
563 "), stdout);
564 fputs (_("\
565 * rows N tell the kernel that the terminal has N rows\n\
566 * size print the number of rows and columns according to the kernel\n\
567 speed print the terminal speed\n\
568 time N with -icanon, set read timeout of N tenths of a second\n\
569 "), stdout);
570 fputs (_("\
572 Control settings:\n\
573 [-]clocal disable modem control signals\n\
574 [-]cread allow input to be received\n\
575 * [-]crtscts enable RTS/CTS handshaking\n\
576 csN set character size to N bits, N in [5..8]\n\
577 "), stdout);
578 fputs (_("\
579 [-]cstopb use two stop bits per character (one with `-')\n\
580 [-]hup send a hangup signal when the last process closes the tty\n\
581 [-]hupcl same as [-]hup\n\
582 [-]parenb generate parity bit in output and expect parity bit in input\n\
583 [-]parodd set odd parity (even with `-')\n\
584 "), stdout);
585 fputs (_("\
587 Input settings:\n\
588 [-]brkint breaks cause an interrupt signal\n\
589 [-]icrnl translate carriage return to newline\n\
590 [-]ignbrk ignore break characters\n\
591 [-]igncr ignore carriage return\n\
592 "), stdout);
593 fputs (_("\
594 [-]ignpar ignore characters with parity errors\n\
595 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
596 [-]inlcr translate newline to carriage return\n\
597 [-]inpck enable input parity checking\n\
598 [-]istrip clear high (8th) bit of input characters\n\
599 "), stdout);
600 fputs (_("\
601 * [-]iutf8 assume input characters are UTF-8 encoded\n\
602 "), stdout);
603 fputs (_("\
604 * [-]iuclc translate uppercase characters to lowercase\n\
605 * [-]ixany let any character restart output, not only start character\n\
606 [-]ixoff enable sending of start/stop characters\n\
607 [-]ixon enable XON/XOFF flow control\n\
608 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
609 [-]tandem same as [-]ixoff\n\
610 "), stdout);
611 fputs (_("\
613 Output settings:\n\
614 * bsN backspace delay style, N in [0..1]\n\
615 * crN carriage return delay style, N in [0..3]\n\
616 * ffN form feed delay style, N in [0..1]\n\
617 * nlN newline delay style, N in [0..1]\n\
618 "), stdout);
619 fputs (_("\
620 * [-]ocrnl translate carriage return to newline\n\
621 * [-]ofdel use delete characters for fill instead of null characters\n\
622 * [-]ofill use fill (padding) characters instead of timing for delays\n\
623 * [-]olcuc translate lowercase characters to uppercase\n\
624 * [-]onlcr translate newline to carriage return-newline\n\
625 * [-]onlret newline performs a carriage return\n\
626 "), stdout);
627 fputs (_("\
628 * [-]onocr do not print carriage returns in the first column\n\
629 [-]opost postprocess output\n\
630 * tabN horizontal tab delay style, N in [0..3]\n\
631 * tabs same as tab0\n\
632 * -tabs same as tab3\n\
633 * vtN vertical tab delay style, N in [0..1]\n\
634 "), stdout);
635 fputs (_("\
637 Local settings:\n\
638 [-]crterase echo erase characters as backspace-space-backspace\n\
639 * crtkill kill all line by obeying the echoprt and echoe settings\n\
640 * -crtkill kill all line by obeying the echoctl and echok settings\n\
641 "), stdout);
642 fputs (_("\
643 * [-]ctlecho echo control characters in hat notation (`^c')\n\
644 [-]echo echo input characters\n\
645 * [-]echoctl same as [-]ctlecho\n\
646 [-]echoe same as [-]crterase\n\
647 [-]echok echo a newline after a kill character\n\
648 "), stdout);
649 fputs (_("\
650 * [-]echoke same as [-]crtkill\n\
651 [-]echonl echo newline even if not echoing other characters\n\
652 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
653 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
654 [-]iexten enable non-POSIX special characters\n\
655 "), stdout);
656 fputs (_("\
657 [-]isig enable interrupt, quit, and suspend special characters\n\
658 [-]noflsh disable flushing after interrupt and quit special characters\n\
659 * [-]prterase same as [-]echoprt\n\
660 * [-]tostop stop background jobs that try to write to the terminal\n\
661 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
662 "), stdout);
663 fputs (_("\
665 Combination settings:\n\
666 * [-]LCASE same as [-]lcase\n\
667 cbreak same as -icanon\n\
668 -cbreak same as icanon\n\
669 "), stdout);
670 fputs (_("\
671 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
672 icanon, eof and eol characters to their default values\n\
673 -cooked same as raw\n\
674 crt same as echoe echoctl echoke\n\
675 "), stdout);
676 fputs (_("\
677 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
678 kill ^u\n\
679 * [-]decctlq same as [-]ixany\n\
680 ek erase and kill characters to their default values\n\
681 evenp same as parenb -parodd cs7\n\
682 "), stdout);
683 fputs (_("\
684 -evenp same as -parenb cs8\n\
685 * [-]lcase same as xcase iuclc olcuc\n\
686 litout same as -parenb -istrip -opost cs8\n\
687 -litout same as parenb istrip opost cs7\n\
688 nl same as -icrnl -onlcr\n\
689 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
690 "), stdout);
691 fputs (_("\
692 oddp same as parenb parodd cs7\n\
693 -oddp same as -parenb cs8\n\
694 [-]parity same as [-]evenp\n\
695 pass8 same as -parenb -istrip cs8\n\
696 -pass8 same as parenb istrip cs7\n\
697 "), stdout);
698 fputs (_("\
699 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
700 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
701 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
702 -raw same as cooked\n\
703 "), stdout);
704 fputs (_("\
705 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
706 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
707 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
708 isig icanon iexten echo echoe echok -echonl -noflsh\n\
709 -xcase -tostop -echoprt echoctl echoke, all special\n\
710 characters to their default values\n\
711 "), stdout);
712 fputs (_("\
714 Handle the tty line connected to standard input. Without arguments,\n\
715 prints baud rate, line discipline, and deviations from stty sane. In\n\
716 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
717 127; special values ^- or undef used to disable special characters.\n\
718 "), stdout);
719 emit_bug_reporting_address ();
721 exit (status);
725 main (int argc, char **argv)
727 /* Initialize to all zeroes so there is no risk memcmp will report a
728 spurious difference in an uninitialized portion of the structure. */
729 DECLARE_ZEROED_AGGREGATE (struct termios, mode);
731 enum output_type output_type;
732 int optc;
733 int argi = 0;
734 int opti = 1;
735 bool require_set_attr;
736 bool speed_was_set;
737 bool verbose_output;
738 bool recoverable_output;
739 int k;
740 bool noargs = true;
741 char *file_name = NULL;
742 const char *device_name;
744 initialize_main (&argc, &argv);
745 set_program_name (argv[0]);
746 setlocale (LC_ALL, "");
747 bindtextdomain (PACKAGE, LOCALEDIR);
748 textdomain (PACKAGE);
750 atexit (close_stdout);
752 output_type = changed;
753 verbose_output = false;
754 recoverable_output = false;
756 /* Don't print error messages for unrecognized options. */
757 opterr = 0;
759 /* If any new options are ever added to stty, the short options MUST
760 NOT allow any ambiguity with the stty settings. For example, the
761 stty setting "-gagFork" would not be feasible, since it will be
762 parsed as "-g -a -g -F ork". If you change anything about how
763 stty parses options, be sure it still works with combinations of
764 short and long options, --, POSIXLY_CORRECT, etc. */
766 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
767 longopts, NULL))
768 != -1)
770 switch (optc)
772 case 'a':
773 verbose_output = true;
774 output_type = all;
775 break;
777 case 'g':
778 recoverable_output = true;
779 output_type = recoverable;
780 break;
782 case 'F':
783 if (file_name)
784 error (EXIT_FAILURE, 0, _("only one device may be specified"));
785 file_name = optarg;
786 break;
788 case_GETOPT_HELP_CHAR;
790 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
792 default:
793 noargs = false;
795 /* Skip the argument containing this unrecognized option;
796 the 2nd pass will analyze it. */
797 argi += opti;
799 /* Restart getopt_long from the first unskipped argument. */
800 opti = 1;
801 optind = 0;
803 break;
806 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
807 while (opti < optind)
808 argv[argi + opti++] = NULL;
811 /* Specifying both -a and -g gets an error. */
812 if (verbose_output & recoverable_output)
813 error (EXIT_FAILURE, 0,
814 _("the options for verbose and stty-readable output styles are\n"
815 "mutually exclusive"));
817 /* Specifying any other arguments with -a or -g gets an error. */
818 if (!noargs && (verbose_output | recoverable_output))
819 error (EXIT_FAILURE, 0,
820 _("when specifying an output style, modes may not be set"));
822 /* FIXME: it'd be better not to open the file until we've verified
823 that all arguments are valid. Otherwise, we could end up doing
824 only some of the requested operations and then failing, probably
825 leaving things in an undesirable state. */
827 if (file_name)
829 int fdflags;
830 device_name = file_name;
831 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
832 error (EXIT_FAILURE, errno, "%s", device_name);
833 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
834 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
835 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
836 device_name);
838 else
839 device_name = _("standard input");
841 if (tcgetattr (STDIN_FILENO, &mode))
842 error (EXIT_FAILURE, errno, "%s", device_name);
844 if (verbose_output | recoverable_output | noargs)
846 max_col = screen_columns ();
847 current_col = 0;
848 display_settings (output_type, &mode, device_name);
849 exit (EXIT_SUCCESS);
852 speed_was_set = false;
853 require_set_attr = false;
854 for (k = 1; k < argc; k++)
856 char const *arg = argv[k];
857 bool match_found = false;
858 bool reversed = false;
859 int i;
861 if (! arg)
862 continue;
864 if (arg[0] == '-')
866 ++arg;
867 reversed = true;
869 for (i = 0; mode_info[i].name != NULL; ++i)
871 if (STREQ (arg, mode_info[i].name))
873 match_found = set_mode (&mode_info[i], reversed, &mode);
874 require_set_attr = true;
875 break;
878 if (!match_found & reversed)
880 error (0, 0, _("invalid argument %s"), quote (arg - 1));
881 usage (EXIT_FAILURE);
883 if (!match_found)
885 for (i = 0; control_info[i].name != NULL; ++i)
887 if (STREQ (arg, control_info[i].name))
889 if (k == argc - 1)
891 error (0, 0, _("missing argument to %s"), quote (arg));
892 usage (EXIT_FAILURE);
894 match_found = true;
895 ++k;
896 set_control_char (&control_info[i], argv[k], &mode);
897 require_set_attr = true;
898 break;
902 if (!match_found)
904 if (STREQ (arg, "ispeed"))
906 if (k == argc - 1)
908 error (0, 0, _("missing argument to %s"), quote (arg));
909 usage (EXIT_FAILURE);
911 ++k;
912 set_speed (input_speed, argv[k], &mode);
913 speed_was_set = true;
914 require_set_attr = true;
916 else if (STREQ (arg, "ospeed"))
918 if (k == argc - 1)
920 error (0, 0, _("missing argument to %s"), quote (arg));
921 usage (EXIT_FAILURE);
923 ++k;
924 set_speed (output_speed, argv[k], &mode);
925 speed_was_set = true;
926 require_set_attr = true;
928 #ifdef TIOCGWINSZ
929 else if (STREQ (arg, "rows"))
931 if (k == argc - 1)
933 error (0, 0, _("missing argument to %s"), quote (arg));
934 usage (EXIT_FAILURE);
936 ++k;
937 set_window_size (integer_arg (argv[k], INT_MAX), -1,
938 device_name);
940 else if (STREQ (arg, "cols")
941 || STREQ (arg, "columns"))
943 if (k == argc - 1)
945 error (0, 0, _("missing argument to %s"), quote (arg));
946 usage (EXIT_FAILURE);
948 ++k;
949 set_window_size (-1, integer_arg (argv[k], INT_MAX),
950 device_name);
952 else if (STREQ (arg, "size"))
954 max_col = screen_columns ();
955 current_col = 0;
956 display_window_size (false, device_name);
958 #endif
959 #ifdef HAVE_C_LINE
960 else if (STREQ (arg, "line"))
962 unsigned long int value;
963 if (k == argc - 1)
965 error (0, 0, _("missing argument to %s"), quote (arg));
966 usage (EXIT_FAILURE);
968 ++k;
969 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
970 if (mode.c_line != value)
971 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
972 require_set_attr = true;
974 #endif
975 else if (STREQ (arg, "speed"))
977 max_col = screen_columns ();
978 display_speed (&mode, false);
980 else if (string_to_baud (arg) != (speed_t) -1)
982 set_speed (both_speeds, arg, &mode);
983 speed_was_set = true;
984 require_set_attr = true;
986 else
988 if (! recover_mode (arg, &mode))
990 error (0, 0, _("invalid argument %s"), quote (arg));
991 usage (EXIT_FAILURE);
993 require_set_attr = true;
998 if (require_set_attr)
1000 /* Initialize to all zeroes so there is no risk memcmp will report a
1001 spurious difference in an uninitialized portion of the structure. */
1002 DECLARE_ZEROED_AGGREGATE (struct termios, new_mode);
1004 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1005 error (EXIT_FAILURE, errno, "%s", device_name);
1007 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1008 it performs *any* of the requested operations. This means it
1009 can report `success' when it has actually failed to perform
1010 some proper subset of the requested operations. To detect
1011 this partial failure, get the current terminal attributes and
1012 compare them to the requested ones. */
1014 if (tcgetattr (STDIN_FILENO, &new_mode))
1015 error (EXIT_FAILURE, errno, "%s", device_name);
1017 /* Normally, one shouldn't use memcmp to compare structures that
1018 may have `holes' containing uninitialized data, but we have been
1019 careful to initialize the storage of these two variables to all
1020 zeroes. One might think it more efficient simply to compare the
1021 modified fields, but that would require enumerating those fields --
1022 and not all systems have the same fields in this structure. */
1024 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1026 #ifdef CIBAUD
1027 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1028 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1029 sometimes (m1 != m2). The only difference is in the four bits
1030 of the c_cflag field corresponding to the baud rate. To save
1031 Sun users a little confusion, don't report an error if this
1032 happens. But suppress the error only if we haven't tried to
1033 set the baud rate explicitly -- otherwise we'd never give an
1034 error for a true failure to set the baud rate. */
1036 new_mode.c_cflag &= (~CIBAUD);
1037 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1038 #endif
1040 error (EXIT_FAILURE, 0,
1041 _("%s: unable to perform all requested operations"),
1042 device_name);
1043 #ifdef TESTING
1045 size_t i;
1046 printf ("new_mode: mode\n");
1047 for (i = 0; i < sizeof (new_mode); i++)
1048 printf ("0x%02x: 0x%02x\n",
1049 *(((unsigned char *) &new_mode) + i),
1050 *(((unsigned char *) &mode) + i));
1052 #endif
1057 exit (EXIT_SUCCESS);
1060 /* Return false if not applied because not reversible; otherwise
1061 return true. */
1063 static bool
1064 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1066 tcflag_t *bitsp;
1068 if (reversed && (info->flags & REV) == 0)
1069 return false;
1071 bitsp = mode_type_flag (info->type, mode);
1073 if (bitsp == NULL)
1075 /* Combination mode. */
1076 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1078 if (reversed)
1079 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1080 else
1081 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1083 else if (STREQ (info->name, "oddp"))
1085 if (reversed)
1086 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1087 else
1088 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1090 else if (STREQ (info->name, "nl"))
1092 if (reversed)
1094 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1095 mode->c_oflag = (mode->c_oflag
1096 #ifdef ONLCR
1097 | ONLCR
1098 #endif
1100 #ifdef OCRNL
1101 & ~OCRNL
1102 #endif
1103 #ifdef ONLRET
1104 & ~ONLRET
1105 #endif
1108 else
1110 mode->c_iflag = mode->c_iflag & ~ICRNL;
1111 #ifdef ONLCR
1112 mode->c_oflag = mode->c_oflag & ~ONLCR;
1113 #endif
1116 else if (STREQ (info->name, "ek"))
1118 mode->c_cc[VERASE] = CERASE;
1119 mode->c_cc[VKILL] = CKILL;
1121 else if (STREQ (info->name, "sane"))
1122 sane_mode (mode);
1123 else if (STREQ (info->name, "cbreak"))
1125 if (reversed)
1126 mode->c_lflag |= ICANON;
1127 else
1128 mode->c_lflag &= ~ICANON;
1130 else if (STREQ (info->name, "pass8"))
1132 if (reversed)
1134 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1135 mode->c_iflag |= ISTRIP;
1137 else
1139 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1140 mode->c_iflag &= ~ISTRIP;
1143 else if (STREQ (info->name, "litout"))
1145 if (reversed)
1147 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1148 mode->c_iflag |= ISTRIP;
1149 mode->c_oflag |= OPOST;
1151 else
1153 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1154 mode->c_iflag &= ~ISTRIP;
1155 mode->c_oflag &= ~OPOST;
1158 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1160 if ((info->name[0] == 'r' && reversed)
1161 || (info->name[0] == 'c' && !reversed))
1163 /* Cooked mode. */
1164 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1165 mode->c_oflag |= OPOST;
1166 mode->c_lflag |= ISIG | ICANON;
1167 #if VMIN == VEOF
1168 mode->c_cc[VEOF] = CEOF;
1169 #endif
1170 #if VTIME == VEOL
1171 mode->c_cc[VEOL] = CEOL;
1172 #endif
1174 else
1176 /* Raw mode. */
1177 mode->c_iflag = 0;
1178 mode->c_oflag &= ~OPOST;
1179 mode->c_lflag &= ~(ISIG | ICANON
1180 #ifdef XCASE
1181 | XCASE
1182 #endif
1184 mode->c_cc[VMIN] = 1;
1185 mode->c_cc[VTIME] = 0;
1188 #ifdef IXANY
1189 else if (STREQ (info->name, "decctlq"))
1191 if (reversed)
1192 mode->c_iflag |= IXANY;
1193 else
1194 mode->c_iflag &= ~IXANY;
1196 #endif
1197 #ifdef TABDLY
1198 else if (STREQ (info->name, "tabs"))
1200 if (reversed)
1201 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1202 else
1203 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1205 #else
1206 # ifdef OXTABS
1207 else if (STREQ (info->name, "tabs"))
1209 if (reversed)
1210 mode->c_oflag = mode->c_oflag | OXTABS;
1211 else
1212 mode->c_oflag = mode->c_oflag & ~OXTABS;
1214 # endif
1215 #endif
1216 #if defined XCASE && defined IUCLC && defined OLCUC
1217 else if (STREQ (info->name, "lcase")
1218 || STREQ (info->name, "LCASE"))
1220 if (reversed)
1222 mode->c_lflag &= ~XCASE;
1223 mode->c_iflag &= ~IUCLC;
1224 mode->c_oflag &= ~OLCUC;
1226 else
1228 mode->c_lflag |= XCASE;
1229 mode->c_iflag |= IUCLC;
1230 mode->c_oflag |= OLCUC;
1233 #endif
1234 else if (STREQ (info->name, "crt"))
1235 mode->c_lflag |= ECHOE
1236 #ifdef ECHOCTL
1237 | ECHOCTL
1238 #endif
1239 #ifdef ECHOKE
1240 | ECHOKE
1241 #endif
1243 else if (STREQ (info->name, "dec"))
1245 mode->c_cc[VINTR] = 3; /* ^C */
1246 mode->c_cc[VERASE] = 127; /* DEL */
1247 mode->c_cc[VKILL] = 21; /* ^U */
1248 mode->c_lflag |= ECHOE
1249 #ifdef ECHOCTL
1250 | ECHOCTL
1251 #endif
1252 #ifdef ECHOKE
1253 | ECHOKE
1254 #endif
1256 #ifdef IXANY
1257 mode->c_iflag &= ~IXANY;
1258 #endif
1261 else if (reversed)
1262 *bitsp = *bitsp & ~info->mask & ~info->bits;
1263 else
1264 *bitsp = (*bitsp & ~info->mask) | info->bits;
1266 return true;
1269 static void
1270 set_control_char (struct control_info const *info, const char *arg,
1271 struct termios *mode)
1273 unsigned long int value;
1275 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1276 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1277 else if (arg[0] == '\0' || arg[1] == '\0')
1278 value = to_uchar (arg[0]);
1279 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1280 value = _POSIX_VDISABLE;
1281 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1283 if (arg[1] == '?')
1284 value = 127;
1285 else
1286 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1288 else
1289 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1290 mode->c_cc[info->offset] = value;
1293 static void
1294 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1296 speed_t baud;
1298 baud = string_to_baud (arg);
1299 if (type == input_speed || type == both_speeds)
1300 cfsetispeed (mode, baud);
1301 if (type == output_speed || type == both_speeds)
1302 cfsetospeed (mode, baud);
1305 #ifdef TIOCGWINSZ
1307 static int
1308 get_win_size (int fd, struct winsize *win)
1310 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1311 return err;
1314 static void
1315 set_window_size (int rows, int cols, char const *device_name)
1317 struct winsize win;
1319 if (get_win_size (STDIN_FILENO, &win))
1321 if (errno != EINVAL)
1322 error (EXIT_FAILURE, errno, "%s", device_name);
1323 memset (&win, 0, sizeof (win));
1326 if (rows >= 0)
1327 win.ws_row = rows;
1328 if (cols >= 0)
1329 win.ws_col = cols;
1331 # ifdef TIOCSSIZE
1332 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1333 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1334 This comment from sys/ttold.h describes Sun's twisted logic - a better
1335 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1336 At any rate, the problem is gone in Solaris 2.x.
1338 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1339 but they can be disambiguated by checking whether a "struct ttysize"
1340 structure's "ts_lines" field is greater than 64K or not. If so,
1341 it's almost certainly a "struct winsize" instead.
1343 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1344 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1345 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1346 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1347 "stty cols 0 rows 0" would do the right thing. On a little-endian
1348 machine like the sun386i, the problem is the same, but for ws_col == 0.
1350 The workaround is to do the ioctl once with row and col = 1 to set the
1351 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1353 if (win.ws_row == 0 || win.ws_col == 0)
1355 struct ttysize ttysz;
1357 ttysz.ts_lines = win.ws_row;
1358 ttysz.ts_cols = win.ws_col;
1360 win.ws_row = 1;
1361 win.ws_col = 1;
1363 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1364 error (EXIT_FAILURE, errno, "%s", device_name);
1366 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1367 error (EXIT_FAILURE, errno, "%s", device_name);
1368 return;
1370 # endif
1372 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1373 error (EXIT_FAILURE, errno, "%s", device_name);
1376 static void
1377 display_window_size (bool fancy, char const *device_name)
1379 struct winsize win;
1381 if (get_win_size (STDIN_FILENO, &win))
1383 if (errno != EINVAL)
1384 error (EXIT_FAILURE, errno, "%s", device_name);
1385 if (!fancy)
1386 error (EXIT_FAILURE, 0,
1387 _("%s: no size information for this device"), device_name);
1389 else
1391 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1392 win.ws_row, win.ws_col);
1393 if (!fancy)
1394 current_col = 0;
1397 #endif
1399 static int
1400 screen_columns (void)
1402 #ifdef TIOCGWINSZ
1403 struct winsize win;
1405 /* With Solaris 2.[123], this ioctl fails and errno is set to
1406 EINVAL for telnet (but not rlogin) sessions.
1407 On ISC 3.0, it fails for the console and the serial port
1408 (but it works for ptys).
1409 It can also fail on any system when stdout isn't a tty.
1410 In case of any failure, just use the default. */
1411 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1412 return win.ws_col;
1413 #endif
1415 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1416 char *col_string = getenv ("COLUMNS");
1417 long int n_columns;
1418 if (!(col_string != NULL
1419 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1420 && 0 < n_columns
1421 && n_columns <= INT_MAX))
1422 n_columns = 80;
1423 return n_columns;
1427 static tcflag_t *
1428 mode_type_flag (enum mode_type type, struct termios *mode)
1430 switch (type)
1432 case control:
1433 return &mode->c_cflag;
1435 case input:
1436 return &mode->c_iflag;
1438 case output:
1439 return &mode->c_oflag;
1441 case local:
1442 return &mode->c_lflag;
1444 case combination:
1445 return NULL;
1447 default:
1448 abort ();
1452 static void
1453 display_settings (enum output_type output_type, struct termios *mode,
1454 char const *device_name)
1456 switch (output_type)
1458 case changed:
1459 display_changed (mode);
1460 break;
1462 case all:
1463 display_all (mode, device_name);
1464 break;
1466 case recoverable:
1467 display_recoverable (mode);
1468 break;
1472 static void
1473 display_changed (struct termios *mode)
1475 int i;
1476 bool empty_line;
1477 tcflag_t *bitsp;
1478 unsigned long mask;
1479 enum mode_type prev_type = control;
1481 display_speed (mode, true);
1482 #ifdef HAVE_C_LINE
1483 wrapf ("line = %d;", mode->c_line);
1484 #endif
1485 putchar ('\n');
1486 current_col = 0;
1488 empty_line = true;
1489 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1491 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1492 continue;
1493 /* If swtch is the same as susp, don't print both. */
1494 #if VSWTCH == VSUSP
1495 if (STREQ (control_info[i].name, "swtch"))
1496 continue;
1497 #endif
1498 /* If eof uses the same slot as min, only print whichever applies. */
1499 #if VEOF == VMIN
1500 if ((mode->c_lflag & ICANON) == 0
1501 && (STREQ (control_info[i].name, "eof")
1502 || STREQ (control_info[i].name, "eol")))
1503 continue;
1504 #endif
1506 empty_line = false;
1507 wrapf ("%s = %s;", control_info[i].name,
1508 visible (mode->c_cc[control_info[i].offset]));
1510 if ((mode->c_lflag & ICANON) == 0)
1512 wrapf ("min = %lu; time = %lu;\n",
1513 (unsigned long int) mode->c_cc[VMIN],
1514 (unsigned long int) mode->c_cc[VTIME]);
1516 else if (!empty_line)
1517 putchar ('\n');
1518 current_col = 0;
1520 empty_line = true;
1521 for (i = 0; mode_info[i].name != NULL; ++i)
1523 if (mode_info[i].flags & OMIT)
1524 continue;
1525 if (mode_info[i].type != prev_type)
1527 if (!empty_line)
1529 putchar ('\n');
1530 current_col = 0;
1531 empty_line = true;
1533 prev_type = mode_info[i].type;
1536 bitsp = mode_type_flag (mode_info[i].type, mode);
1537 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1538 if ((*bitsp & mask) == mode_info[i].bits)
1540 if (mode_info[i].flags & SANE_UNSET)
1542 wrapf ("%s", mode_info[i].name);
1543 empty_line = false;
1546 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1548 wrapf ("-%s", mode_info[i].name);
1549 empty_line = false;
1552 if (!empty_line)
1553 putchar ('\n');
1554 current_col = 0;
1557 static void
1558 display_all (struct termios *mode, char const *device_name)
1560 int i;
1561 tcflag_t *bitsp;
1562 unsigned long mask;
1563 enum mode_type prev_type = control;
1565 display_speed (mode, true);
1566 #ifdef TIOCGWINSZ
1567 display_window_size (true, device_name);
1568 #endif
1569 #ifdef HAVE_C_LINE
1570 wrapf ("line = %d;", mode->c_line);
1571 #endif
1572 putchar ('\n');
1573 current_col = 0;
1575 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1577 /* If swtch is the same as susp, don't print both. */
1578 #if VSWTCH == VSUSP
1579 if (STREQ (control_info[i].name, "swtch"))
1580 continue;
1581 #endif
1582 /* If eof uses the same slot as min, only print whichever applies. */
1583 #if VEOF == VMIN
1584 if ((mode->c_lflag & ICANON) == 0
1585 && (STREQ (control_info[i].name, "eof")
1586 || STREQ (control_info[i].name, "eol")))
1587 continue;
1588 #endif
1589 wrapf ("%s = %s;", control_info[i].name,
1590 visible (mode->c_cc[control_info[i].offset]));
1592 #if VEOF == VMIN
1593 if ((mode->c_lflag & ICANON) == 0)
1594 #endif
1595 wrapf ("min = %lu; time = %lu;",
1596 (unsigned long int) mode->c_cc[VMIN],
1597 (unsigned long int) mode->c_cc[VTIME]);
1598 if (current_col != 0)
1599 putchar ('\n');
1600 current_col = 0;
1602 for (i = 0; mode_info[i].name != NULL; ++i)
1604 if (mode_info[i].flags & OMIT)
1605 continue;
1606 if (mode_info[i].type != prev_type)
1608 putchar ('\n');
1609 current_col = 0;
1610 prev_type = mode_info[i].type;
1613 bitsp = mode_type_flag (mode_info[i].type, mode);
1614 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1615 if ((*bitsp & mask) == mode_info[i].bits)
1616 wrapf ("%s", mode_info[i].name);
1617 else if (mode_info[i].flags & REV)
1618 wrapf ("-%s", mode_info[i].name);
1620 putchar ('\n');
1621 current_col = 0;
1624 static void
1625 display_speed (struct termios *mode, bool fancy)
1627 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1628 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1629 baud_to_value (cfgetospeed (mode)));
1630 else
1631 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1632 baud_to_value (cfgetispeed (mode)),
1633 baud_to_value (cfgetospeed (mode)));
1634 if (!fancy)
1635 current_col = 0;
1638 static void
1639 display_recoverable (struct termios *mode)
1641 size_t i;
1643 printf ("%lx:%lx:%lx:%lx",
1644 (unsigned long int) mode->c_iflag,
1645 (unsigned long int) mode->c_oflag,
1646 (unsigned long int) mode->c_cflag,
1647 (unsigned long int) mode->c_lflag);
1648 for (i = 0; i < NCCS; ++i)
1649 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1650 putchar ('\n');
1653 /* NOTE: identical to below, modulo use of tcflag_t */
1654 static int
1655 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1656 char delim)
1658 unsigned long ul;
1659 errno = 0;
1660 ul = strtoul (s, p, base);
1661 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1662 return -1;
1663 *result = ul;
1664 return 0;
1667 /* NOTE: identical to above, modulo use of cc_t */
1668 static int
1669 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1671 unsigned long ul;
1672 errno = 0;
1673 ul = strtoul (s, p, base);
1674 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1675 return -1;
1676 *result = ul;
1677 return 0;
1680 /* Parse the output of display_recoverable.
1681 Return false if any part of it is invalid. */
1682 static bool
1683 recover_mode (char const *arg, struct termios *mode)
1685 tcflag_t flag[4];
1686 char const *s = arg;
1687 size_t i;
1688 for (i = 0; i < 4; i++)
1690 char *p;
1691 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1692 return false;
1693 s = p + 1;
1695 mode->c_iflag = flag[0];
1696 mode->c_oflag = flag[1];
1697 mode->c_cflag = flag[2];
1698 mode->c_lflag = flag[3];
1700 for (i = 0; i < NCCS; ++i)
1702 char *p;
1703 char delim = i < NCCS - 1 ? ':' : '\0';
1704 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1705 return false;
1706 s = p + 1;
1709 return true;
1712 struct speed_map
1714 const char *string; /* ASCII representation. */
1715 speed_t speed; /* Internal form. */
1716 unsigned long int value; /* Numeric value. */
1719 static struct speed_map const speeds[] =
1721 {"0", B0, 0},
1722 {"50", B50, 50},
1723 {"75", B75, 75},
1724 {"110", B110, 110},
1725 {"134", B134, 134},
1726 {"134.5", B134, 134},
1727 {"150", B150, 150},
1728 {"200", B200, 200},
1729 {"300", B300, 300},
1730 {"600", B600, 600},
1731 {"1200", B1200, 1200},
1732 {"1800", B1800, 1800},
1733 {"2400", B2400, 2400},
1734 {"4800", B4800, 4800},
1735 {"9600", B9600, 9600},
1736 {"19200", B19200, 19200},
1737 {"38400", B38400, 38400},
1738 {"exta", B19200, 19200},
1739 {"extb", B38400, 38400},
1740 #ifdef B57600
1741 {"57600", B57600, 57600},
1742 #endif
1743 #ifdef B115200
1744 {"115200", B115200, 115200},
1745 #endif
1746 #ifdef B230400
1747 {"230400", B230400, 230400},
1748 #endif
1749 #ifdef B460800
1750 {"460800", B460800, 460800},
1751 #endif
1752 #ifdef B500000
1753 {"500000", B500000, 500000},
1754 #endif
1755 #ifdef B576000
1756 {"576000", B576000, 576000},
1757 #endif
1758 #ifdef B921600
1759 {"921600", B921600, 921600},
1760 #endif
1761 #ifdef B1000000
1762 {"1000000", B1000000, 1000000},
1763 #endif
1764 #ifdef B1152000
1765 {"1152000", B1152000, 1152000},
1766 #endif
1767 #ifdef B1500000
1768 {"1500000", B1500000, 1500000},
1769 #endif
1770 #ifdef B2000000
1771 {"2000000", B2000000, 2000000},
1772 #endif
1773 #ifdef B2500000
1774 {"2500000", B2500000, 2500000},
1775 #endif
1776 #ifdef B3000000
1777 {"3000000", B3000000, 3000000},
1778 #endif
1779 #ifdef B3500000
1780 {"3500000", B3500000, 3500000},
1781 #endif
1782 #ifdef B4000000
1783 {"4000000", B4000000, 4000000},
1784 #endif
1785 {NULL, 0, 0}
1788 static speed_t
1789 string_to_baud (const char *arg)
1791 int i;
1793 for (i = 0; speeds[i].string != NULL; ++i)
1794 if (STREQ (arg, speeds[i].string))
1795 return speeds[i].speed;
1796 return (speed_t) -1;
1799 static unsigned long int
1800 baud_to_value (speed_t speed)
1802 int i;
1804 for (i = 0; speeds[i].string != NULL; ++i)
1805 if (speed == speeds[i].speed)
1806 return speeds[i].value;
1807 return 0;
1810 static void
1811 sane_mode (struct termios *mode)
1813 int i;
1814 tcflag_t *bitsp;
1816 for (i = 0; control_info[i].name; ++i)
1818 #if VMIN == VEOF
1819 if (STREQ (control_info[i].name, "min"))
1820 break;
1821 #endif
1822 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1825 for (i = 0; mode_info[i].name != NULL; ++i)
1827 if (mode_info[i].flags & SANE_SET)
1829 bitsp = mode_type_flag (mode_info[i].type, mode);
1830 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1832 else if (mode_info[i].flags & SANE_UNSET)
1834 bitsp = mode_type_flag (mode_info[i].type, mode);
1835 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1840 /* Return a string that is the printable representation of character CH. */
1841 /* Adapted from `cat' by Torbjorn Granlund. */
1843 static const char *
1844 visible (cc_t ch)
1846 static char buf[10];
1847 char *bpout = buf;
1849 if (ch == _POSIX_VDISABLE)
1850 return "<undef>";
1852 if (ch >= 32)
1854 if (ch < 127)
1855 *bpout++ = ch;
1856 else if (ch == 127)
1858 *bpout++ = '^';
1859 *bpout++ = '?';
1861 else
1863 *bpout++ = 'M';
1864 *bpout++ = '-';
1865 if (ch >= 128 + 32)
1867 if (ch < 128 + 127)
1868 *bpout++ = ch - 128;
1869 else
1871 *bpout++ = '^';
1872 *bpout++ = '?';
1875 else
1877 *bpout++ = '^';
1878 *bpout++ = ch - 128 + 64;
1882 else
1884 *bpout++ = '^';
1885 *bpout++ = ch + 64;
1887 *bpout = '\0';
1888 return (const char *) buf;
1891 /* Parse string S as an integer, using decimal radix by default,
1892 but allowing octal and hex numbers as in C. Reject values
1893 larger than MAXVAL. */
1895 static unsigned long int
1896 integer_arg (const char *s, unsigned long int maxval)
1898 unsigned long int value;
1899 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1901 error (0, 0, _("invalid integer argument %s"), quote (s));
1902 usage (EXIT_FAILURE);
1904 return value;