*** empty log message ***
[coreutils.git] / src / stty.c
blob33a821d25b8cb2a36332edafdd79fdb0f936980a
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005 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 2, or (at your option)
7 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
20 Options:
21 -a, --all Write all current settings to stdout in human-readable form.
22 -g, --save Write all current settings to stdout in stty-readable form.
23 -F, --file Open and use the specified device instead of stdin
25 If no args are given, write to stdout the baud rate and settings that
26 have been changed from their defaults. Mode reading and changes
27 are done on the specified device, or stdin if none was specified.
29 David MacKenzie <djm@gnu.ai.mit.edu> */
31 #include <config.h>
33 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
34 # define _XOPEN_SOURCE
35 #endif
37 #include <stdio.h>
38 #include <sys/types.h>
40 #if HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
43 #if HAVE_STROPTS_H
44 # include <stropts.h>
45 #endif
46 #ifdef HAVE_SYS_IOCTL_H
47 # include <sys/ioctl.h>
48 #endif
50 #ifdef WINSIZE_IN_PTEM
51 # include <sys/stream.h>
52 # include <sys/ptem.h>
53 #endif
54 #ifdef GWINSZ_IN_SYS_PTY
55 # include <sys/tty.h>
56 # include <sys/pty.h>
57 #endif
58 #include <getopt.h>
59 #include <stdarg.h>
61 #include "system.h"
62 #include "error.h"
63 #include "fd-reopen.h"
64 #include "quote.h"
65 #include "vasprintf.h"
66 #include "xstrtol.h"
68 /* The official name of this program (e.g., no `g' prefix). */
69 #define PROGRAM_NAME "stty"
71 #define AUTHORS "David MacKenzie"
73 #ifndef _POSIX_VDISABLE
74 # define _POSIX_VDISABLE 0
75 #endif
77 #define Control(c) ((c) & 0x1f)
78 /* Canonical values for control characters. */
79 #ifndef CINTR
80 # define CINTR Control ('c')
81 #endif
82 #ifndef CQUIT
83 # define CQUIT 28
84 #endif
85 #ifndef CERASE
86 # define CERASE 127
87 #endif
88 #ifndef CKILL
89 # define CKILL Control ('u')
90 #endif
91 #ifndef CEOF
92 # define CEOF Control ('d')
93 #endif
94 #ifndef CEOL
95 # define CEOL _POSIX_VDISABLE
96 #endif
97 #ifndef CSTART
98 # define CSTART Control ('q')
99 #endif
100 #ifndef CSTOP
101 # define CSTOP Control ('s')
102 #endif
103 #ifndef CSUSP
104 # define CSUSP Control ('z')
105 #endif
106 #if defined VEOL2 && !defined CEOL2
107 # define CEOL2 _POSIX_VDISABLE
108 #endif
109 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
110 character is initialized by CSWTCH, if present. */
111 #if defined VSWTC && !defined VSWTCH
112 # define VSWTCH VSWTC
113 #endif
114 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
115 #if defined VSUSP && !defined VSWTCH
116 # define VSWTCH VSUSP
117 # if defined CSUSP && !defined CSWTCH
118 # define CSWTCH CSUSP
119 # endif
120 #endif
121 #if defined VSWTCH && !defined CSWTCH
122 # define CSWTCH _POSIX_VDISABLE
123 #endif
125 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
126 So the default is to disable `swtch.' */
127 #if defined __sparc__ && defined __svr4__
128 # undef CSWTCH
129 # define CSWTCH _POSIX_VDISABLE
130 #endif
132 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
133 # define VWERASE VWERSE
134 #endif
135 #if defined VDSUSP && !defined CDSUSP
136 # define CDSUSP Control ('y')
137 #endif
138 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
139 # define VREPRINT VRPRNT
140 #endif
141 #if defined VREPRINT && !defined CRPRNT
142 # define CRPRNT Control ('r')
143 #endif
144 #if defined CREPRINT && !defined CRPRNT
145 # define CRPRNT Control ('r')
146 #endif
147 #if defined VWERASE && !defined CWERASE
148 # define CWERASE Control ('w')
149 #endif
150 #if defined VLNEXT && !defined CLNEXT
151 # define CLNEXT Control ('v')
152 #endif
153 #if defined VDISCARD && !defined VFLUSHO
154 # define VFLUSHO VDISCARD
155 #endif
156 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
157 # define VFLUSHO VFLUSH
158 #endif
159 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
160 # define ECHOCTL CTLECH
161 #endif
162 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
163 # define ECHOCTL TCTLECH
164 #endif
165 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
166 # define ECHOKE CRTKIL
167 #endif
168 #if defined VFLUSHO && !defined CFLUSHO
169 # define CFLUSHO Control ('o')
170 #endif
171 #if defined VSTATUS && !defined CSTATUS
172 # define CSTATUS Control ('t')
173 #endif
175 /* Which speeds to set. */
176 enum speed_setting
178 input_speed, output_speed, both_speeds
181 /* What to output and how. */
182 enum output_type
184 changed, all, recoverable /* Default, -a, -g. */
187 /* Which member(s) of `struct termios' a mode uses. */
188 enum mode_type
190 control, input, output, local, combination
193 /* Flags for `struct mode_info'. */
194 #define SANE_SET 1 /* Set in `sane' mode. */
195 #define SANE_UNSET 2 /* Unset in `sane' mode. */
196 #define REV 4 /* Can be turned off by prepending `-'. */
197 #define OMIT 8 /* Don't display value. */
199 /* Each mode. */
200 struct mode_info
202 const char *name; /* Name given on command line. */
203 enum mode_type type; /* Which structure element to change. */
204 char flags; /* Setting and display options. */
205 unsigned long bits; /* Bits to set for this mode. */
206 unsigned long mask; /* Other bits to turn off for this mode. */
209 static struct mode_info mode_info[] =
211 {"parenb", control, REV, PARENB, 0},
212 {"parodd", control, REV, PARODD, 0},
213 {"cs5", control, 0, CS5, CSIZE},
214 {"cs6", control, 0, CS6, CSIZE},
215 {"cs7", control, 0, CS7, CSIZE},
216 {"cs8", control, 0, CS8, CSIZE},
217 {"hupcl", control, REV, HUPCL, 0},
218 {"hup", control, REV | OMIT, HUPCL, 0},
219 {"cstopb", control, REV, CSTOPB, 0},
220 {"cread", control, SANE_SET | REV, CREAD, 0},
221 {"clocal", control, REV, CLOCAL, 0},
222 #ifdef CRTSCTS
223 {"crtscts", control, REV, CRTSCTS, 0},
224 #endif
226 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
227 {"brkint", input, SANE_SET | REV, BRKINT, 0},
228 {"ignpar", input, REV, IGNPAR, 0},
229 {"parmrk", input, REV, PARMRK, 0},
230 {"inpck", input, REV, INPCK, 0},
231 {"istrip", input, REV, ISTRIP, 0},
232 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
233 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
234 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
235 {"ixon", input, REV, IXON, 0},
236 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
237 {"tandem", input, REV | OMIT, IXOFF, 0},
238 #ifdef IUCLC
239 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
240 #endif
241 #ifdef IXANY
242 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
243 #endif
244 #ifdef IMAXBEL
245 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
246 #endif
247 #ifdef IUTF8
248 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
249 #endif
251 {"opost", output, SANE_SET | REV, OPOST, 0},
252 #ifdef OLCUC
253 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
254 #endif
255 #ifdef OCRNL
256 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
257 #endif
258 #ifdef ONLCR
259 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
260 #endif
261 #ifdef ONOCR
262 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
263 #endif
264 #ifdef ONLRET
265 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
266 #endif
267 #ifdef OFILL
268 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
269 #endif
270 #ifdef OFDEL
271 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
272 #endif
273 #ifdef NLDLY
274 {"nl1", output, SANE_UNSET, NL1, NLDLY},
275 {"nl0", output, SANE_SET, NL0, NLDLY},
276 #endif
277 #ifdef CRDLY
278 {"cr3", output, SANE_UNSET, CR3, CRDLY},
279 {"cr2", output, SANE_UNSET, CR2, CRDLY},
280 {"cr1", output, SANE_UNSET, CR1, CRDLY},
281 {"cr0", output, SANE_SET, CR0, CRDLY},
282 #endif
283 #ifdef TABDLY
284 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
285 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
286 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
287 {"tab0", output, SANE_SET, TAB0, TABDLY},
288 #else
289 # ifdef OXTABS
290 {"tab3", output, SANE_UNSET, OXTABS, 0},
291 # endif
292 #endif
293 #ifdef BSDLY
294 {"bs1", output, SANE_UNSET, BS1, BSDLY},
295 {"bs0", output, SANE_SET, BS0, BSDLY},
296 #endif
297 #ifdef VTDLY
298 {"vt1", output, SANE_UNSET, VT1, VTDLY},
299 {"vt0", output, SANE_SET, VT0, VTDLY},
300 #endif
301 #ifdef FFDLY
302 {"ff1", output, SANE_UNSET, FF1, FFDLY},
303 {"ff0", output, SANE_SET, FF0, FFDLY},
304 #endif
306 {"isig", local, SANE_SET | REV, ISIG, 0},
307 {"icanon", local, SANE_SET | REV, ICANON, 0},
308 #ifdef IEXTEN
309 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
310 #endif
311 {"echo", local, SANE_SET | REV, ECHO, 0},
312 {"echoe", local, SANE_SET | REV, ECHOE, 0},
313 {"crterase", local, REV | OMIT, ECHOE, 0},
314 {"echok", local, SANE_SET | REV, ECHOK, 0},
315 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
316 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
317 #ifdef XCASE
318 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
319 #endif
320 #ifdef TOSTOP
321 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
322 #endif
323 #ifdef ECHOPRT
324 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
325 {"prterase", local, REV | OMIT, ECHOPRT, 0},
326 #endif
327 #ifdef ECHOCTL
328 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
329 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
330 #endif
331 #ifdef ECHOKE
332 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
333 {"crtkill", local, REV | OMIT, ECHOKE, 0},
334 #endif
336 {"evenp", combination, REV | OMIT, 0, 0},
337 {"parity", combination, REV | OMIT, 0, 0},
338 {"oddp", combination, REV | OMIT, 0, 0},
339 {"nl", combination, REV | OMIT, 0, 0},
340 {"ek", combination, OMIT, 0, 0},
341 {"sane", combination, OMIT, 0, 0},
342 {"cooked", combination, REV | OMIT, 0, 0},
343 {"raw", combination, REV | OMIT, 0, 0},
344 {"pass8", combination, REV | OMIT, 0, 0},
345 {"litout", combination, REV | OMIT, 0, 0},
346 {"cbreak", combination, REV | OMIT, 0, 0},
347 #ifdef IXANY
348 {"decctlq", combination, REV | OMIT, 0, 0},
349 #endif
350 #if defined TABDLY || defined OXTABS
351 {"tabs", combination, REV | OMIT, 0, 0},
352 #endif
353 #if defined XCASE && defined IUCLC && defined OLCUC
354 {"lcase", combination, REV | OMIT, 0, 0},
355 {"LCASE", combination, REV | OMIT, 0, 0},
356 #endif
357 {"crt", combination, OMIT, 0, 0},
358 {"dec", combination, OMIT, 0, 0},
360 {NULL, control, 0, 0, 0}
363 /* Control character settings. */
364 struct control_info
366 const char *name; /* Name given on command line. */
367 cc_t saneval; /* Value to set for `stty sane'. */
368 size_t offset; /* Offset in c_cc. */
371 /* Control characters. */
373 static struct control_info control_info[] =
375 {"intr", CINTR, VINTR},
376 {"quit", CQUIT, VQUIT},
377 {"erase", CERASE, VERASE},
378 {"kill", CKILL, VKILL},
379 {"eof", CEOF, VEOF},
380 {"eol", CEOL, VEOL},
381 #ifdef VEOL2
382 {"eol2", CEOL2, VEOL2},
383 #endif
384 #ifdef VSWTCH
385 {"swtch", CSWTCH, VSWTCH},
386 #endif
387 {"start", CSTART, VSTART},
388 {"stop", CSTOP, VSTOP},
389 {"susp", CSUSP, VSUSP},
390 #ifdef VDSUSP
391 {"dsusp", CDSUSP, VDSUSP},
392 #endif
393 #ifdef VREPRINT
394 {"rprnt", CRPRNT, VREPRINT},
395 #else
396 # ifdef CREPRINT /* HPUX 10.20 needs this */
397 {"rprnt", CRPRNT, CREPRINT},
398 # endif
399 #endif
400 #ifdef VWERASE
401 {"werase", CWERASE, VWERASE},
402 #endif
403 #ifdef VLNEXT
404 {"lnext", CLNEXT, VLNEXT},
405 #endif
406 #ifdef VFLUSHO
407 {"flush", CFLUSHO, VFLUSHO},
408 #endif
409 #ifdef VSTATUS
410 {"status", CSTATUS, VSTATUS},
411 #endif
413 /* These must be last because of the display routines. */
414 {"min", 1, VMIN},
415 {"time", 0, VTIME},
416 {NULL, 0, 0}
419 static char const *visible (cc_t ch);
420 static unsigned long int baud_to_value (speed_t speed);
421 static bool recover_mode (char const *arg, struct termios *mode);
422 static int screen_columns (void);
423 static bool set_mode (struct mode_info *info, bool reversed,
424 struct termios *mode);
425 static unsigned long int integer_arg (const char *s, unsigned long int max);
426 static speed_t string_to_baud (const char *arg);
427 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
428 static void display_all (struct termios *mode, char const *device_name);
429 static void display_changed (struct termios *mode);
430 static void display_recoverable (struct termios *mode);
431 static void display_settings (enum output_type output_type,
432 struct termios *mode,
433 const char *device_name);
434 static void display_speed (struct termios *mode, bool fancy);
435 static void display_window_size (bool fancy, char const *device_name);
436 static void sane_mode (struct termios *mode);
437 static void set_control_char (struct control_info *info,
438 const char *arg,
439 struct termios *mode);
440 static void set_speed (enum speed_setting type, const char *arg,
441 struct termios *mode);
442 static void set_window_size (int rows, int cols, char const *device_name);
444 /* The width of the screen, for output wrapping. */
445 static int max_col;
447 /* Current position, to know when to wrap. */
448 static int current_col;
450 static struct option longopts[] =
452 {"all", no_argument, NULL, 'a'},
453 {"save", no_argument, NULL, 'g'},
454 {"file", required_argument, NULL, 'F'},
455 {GETOPT_HELP_OPTION_DECL},
456 {GETOPT_VERSION_OPTION_DECL},
457 {NULL, 0, NULL, 0}
460 /* The name this program was run with. */
461 char *program_name;
463 static void wrapf (const char *message, ...)
464 __attribute__ ((__format__ (__printf__, 1, 2)));
466 /* Print format string MESSAGE and optional args.
467 Wrap to next line first if it won't fit.
468 Print a space first unless MESSAGE will start a new line. */
470 static void
471 wrapf (const char *message,...)
473 va_list args;
474 char *buf;
475 int buflen;
477 va_start (args, message);
478 buflen = vasprintf (&buf, message, args);
479 va_end (args);
481 if (buflen < 0)
482 xalloc_die ();
484 if (0 < current_col)
486 if (max_col - current_col < buflen)
488 putchar ('\n');
489 current_col = 0;
491 else
493 putchar (' ');
494 current_col++;
498 fputs (buf, stdout);
499 free (buf);
500 current_col += buflen;
503 void
504 usage (int status)
506 if (status != EXIT_SUCCESS)
507 fprintf (stderr, _("Try `%s --help' for more information.\n"),
508 program_name);
509 else
511 printf (_("\
512 Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\
513 or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\
514 or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\
516 program_name, program_name, program_name);
517 fputs (_("\
518 Print or change terminal characteristics.\n\
520 -a, --all print all current settings in human-readable form\n\
521 -g, --save print all current settings in a stty-readable form\n\
522 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
523 "), stdout);
524 fputs (HELP_OPTION_DESCRIPTION, stdout);
525 fputs (VERSION_OPTION_DESCRIPTION, stdout);
526 fputs (_("\
528 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
529 settings. The underlying system defines which settings are available.\n\
530 "), stdout);
531 fputs (_("\
533 Special characters:\n\
534 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
535 eof CHAR CHAR will send an end of file (terminate the input)\n\
536 eol CHAR CHAR will end the line\n\
537 "), stdout);
538 fputs (_("\
539 * eol2 CHAR alternate CHAR for ending the line\n\
540 erase CHAR CHAR will erase the last character typed\n\
541 intr CHAR CHAR will send an interrupt signal\n\
542 kill CHAR CHAR will erase the current line\n\
543 "), stdout);
544 fputs (_("\
545 * lnext CHAR CHAR will enter the next character quoted\n\
546 quit CHAR CHAR will send a quit signal\n\
547 * rprnt CHAR CHAR will redraw the current line\n\
548 start CHAR CHAR will restart the output after stopping it\n\
549 "), stdout);
550 fputs (_("\
551 stop CHAR CHAR will stop the output\n\
552 susp CHAR CHAR will send a terminal stop signal\n\
553 * swtch CHAR CHAR will switch to a different shell layer\n\
554 * werase CHAR CHAR will erase the last word typed\n\
555 "), stdout);
556 fputs (_("\
558 Special settings:\n\
559 N set the input and output speeds to N bauds\n\
560 * cols N tell the kernel that the terminal has N columns\n\
561 * columns N same as cols N\n\
562 "), stdout);
563 fputs (_("\
564 ispeed N set the input speed to N\n\
565 * line N use line discipline N\n\
566 min N with -icanon, set N characters minimum for a completed read\n\
567 ospeed N set the output speed to N\n\
568 "), stdout);
569 fputs (_("\
570 * rows N tell the kernel that the terminal has N rows\n\
571 * size print the number of rows and columns according to the kernel\n\
572 speed print the terminal speed\n\
573 time N with -icanon, set read timeout of N tenths of a second\n\
574 "), stdout);
575 fputs (_("\
577 Control settings:\n\
578 [-]clocal disable modem control signals\n\
579 [-]cread allow input to be received\n\
580 * [-]crtscts enable RTS/CTS handshaking\n\
581 csN set character size to N bits, N in [5..8]\n\
582 "), stdout);
583 fputs (_("\
584 [-]cstopb use two stop bits per character (one with `-')\n\
585 [-]hup send a hangup signal when the last process closes the tty\n\
586 [-]hupcl same as [-]hup\n\
587 [-]parenb generate parity bit in output and expect parity bit in input\n\
588 [-]parodd set odd parity (even with `-')\n\
589 "), stdout);
590 fputs (_("\
592 Input settings:\n\
593 [-]brkint breaks cause an interrupt signal\n\
594 [-]icrnl translate carriage return to newline\n\
595 [-]ignbrk ignore break characters\n\
596 [-]igncr ignore carriage return\n\
597 "), stdout);
598 fputs (_("\
599 [-]ignpar ignore characters with parity errors\n\
600 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
601 [-]inlcr translate newline to carriage return\n\
602 [-]inpck enable input parity checking\n\
603 [-]istrip clear high (8th) bit of input characters\n\
604 "), stdout);
605 fputs (_("\
606 * [-]iutf8 assume input characters are UTF-8 encoded\n\
607 "), stdout);
608 fputs (_("\
609 * [-]iuclc translate uppercase characters to lowercase\n\
610 * [-]ixany let any character restart output, not only start character\n\
611 [-]ixoff enable sending of start/stop characters\n\
612 [-]ixon enable XON/XOFF flow control\n\
613 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
614 [-]tandem same as [-]ixoff\n\
615 "), stdout);
616 fputs (_("\
618 Output settings:\n\
619 * bsN backspace delay style, N in [0..1]\n\
620 * crN carriage return delay style, N in [0..3]\n\
621 * ffN form feed delay style, N in [0..1]\n\
622 * nlN newline delay style, N in [0..1]\n\
623 "), stdout);
624 fputs (_("\
625 * [-]ocrnl translate carriage return to newline\n\
626 * [-]ofdel use delete characters for fill instead of null characters\n\
627 * [-]ofill use fill (padding) characters instead of timing for delays\n\
628 * [-]olcuc translate lowercase characters to uppercase\n\
629 * [-]onlcr translate newline to carriage return-newline\n\
630 * [-]onlret newline performs a carriage return\n\
631 "), stdout);
632 fputs (_("\
633 * [-]onocr do not print carriage returns in the first column\n\
634 [-]opost postprocess output\n\
635 * tabN horizontal tab delay style, N in [0..3]\n\
636 * tabs same as tab0\n\
637 * -tabs same as tab3\n\
638 * vtN vertical tab delay style, N in [0..1]\n\
639 "), stdout);
640 fputs (_("\
642 Local settings:\n\
643 [-]crterase echo erase characters as backspace-space-backspace\n\
644 * crtkill kill all line by obeying the echoprt and echoe settings\n\
645 * -crtkill kill all line by obeying the echoctl and echok settings\n\
646 "), stdout);
647 fputs (_("\
648 * [-]ctlecho echo control characters in hat notation (`^c')\n\
649 [-]echo echo input characters\n\
650 * [-]echoctl same as [-]ctlecho\n\
651 [-]echoe same as [-]crterase\n\
652 [-]echok echo a newline after a kill character\n\
653 "), stdout);
654 fputs (_("\
655 * [-]echoke same as [-]crtkill\n\
656 [-]echonl echo newline even if not echoing other characters\n\
657 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
658 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
659 [-]iexten enable non-POSIX special characters\n\
660 "), stdout);
661 fputs (_("\
662 [-]isig enable interrupt, quit, and suspend special characters\n\
663 [-]noflsh disable flushing after interrupt and quit special characters\n\
664 * [-]prterase same as [-]echoprt\n\
665 * [-]tostop stop background jobs that try to write to the terminal\n\
666 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
667 "), stdout);
668 fputs (_("\
670 Combination settings:\n\
671 * [-]LCASE same as [-]lcase\n\
672 cbreak same as -icanon\n\
673 -cbreak same as icanon\n\
674 "), stdout);
675 fputs (_("\
676 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
677 icanon, eof and eol characters to their default values\n\
678 -cooked same as raw\n\
679 crt same as echoe echoctl echoke\n\
680 "), stdout);
681 fputs (_("\
682 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
683 kill ^u\n\
684 * [-]decctlq same as [-]ixany\n\
685 ek erase and kill characters to their default values\n\
686 evenp same as parenb -parodd cs7\n\
687 "), stdout);
688 fputs (_("\
689 -evenp same as -parenb cs8\n\
690 * [-]lcase same as xcase iuclc olcuc\n\
691 litout same as -parenb -istrip -opost cs8\n\
692 -litout same as parenb istrip opost cs7\n\
693 nl same as -icrnl -onlcr\n\
694 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
695 "), stdout);
696 fputs (_("\
697 oddp same as parenb parodd cs7\n\
698 -oddp same as -parenb cs8\n\
699 [-]parity same as [-]evenp\n\
700 pass8 same as -parenb -istrip cs8\n\
701 -pass8 same as parenb istrip cs7\n\
702 "), stdout);
703 fputs (_("\
704 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
705 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
706 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
707 -raw same as cooked\n\
708 "), stdout);
709 fputs (_("\
710 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
711 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
712 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
713 isig icanon iexten echo echoe echok -echonl -noflsh\n\
714 -xcase -tostop -echoprt echoctl echoke, all special\n\
715 characters to their default values.\n\
716 "), stdout);
717 fputs (_("\
719 Handle the tty line connected to standard input. Without arguments,\n\
720 prints baud rate, line discipline, and deviations from stty sane. In\n\
721 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
722 127; special values ^- or undef used to disable special characters.\n\
723 "), stdout);
724 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
726 exit (status);
730 main (int argc, char **argv)
732 /* Initialize to all zeroes so there is no risk memcmp will report a
733 spurious difference in an uninitialized portion of the structure. */
734 struct termios mode = { 0, };
736 enum output_type output_type;
737 int optc;
738 int argi = 0;
739 int opti = 1;
740 bool require_set_attr;
741 bool speed_was_set;
742 bool verbose_output;
743 bool recoverable_output;
744 int k;
745 bool noargs = true;
746 char *file_name = NULL;
747 const char *device_name;
749 initialize_main (&argc, &argv);
750 program_name = argv[0];
751 setlocale (LC_ALL, "");
752 bindtextdomain (PACKAGE, LOCALEDIR);
753 textdomain (PACKAGE);
755 atexit (close_stdout);
757 output_type = changed;
758 verbose_output = false;
759 recoverable_output = false;
761 /* Don't print error messages for unrecognized options. */
762 opterr = 0;
764 /* If any new options are ever added to stty, the short options MUST
765 NOT allow any ambiguity with the stty settings. For example, the
766 stty setting "-gagFork" would not be feasible, since it will be
767 parsed as "-g -a -g -F ork". If you change anything about how
768 stty parses options, be sure it still works with combinations of
769 short and long options, --, POSIXLY_CORRECT, etc. */
771 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
772 longopts, NULL))
773 != -1)
775 switch (optc)
777 case 'a':
778 verbose_output = true;
779 output_type = all;
780 break;
782 case 'g':
783 recoverable_output = true;
784 output_type = recoverable;
785 break;
787 case 'F':
788 if (file_name)
789 error (EXIT_FAILURE, 0, _("only one device may be specified"));
790 file_name = optarg;
791 break;
793 case_GETOPT_HELP_CHAR;
795 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
797 default:
798 noargs = false;
800 /* Skip the argument containing this unrecognized option;
801 the 2nd pass will analyze it. */
802 argi += opti;
804 /* Restart getopt_long from the first unskipped argument. */
805 opti = 1;
806 optind = 0;
808 break;
811 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
812 while (opti < optind)
813 argv[argi + opti++] = NULL;
816 /* Specifying both -a and -g gets an error. */
817 if (verbose_output & recoverable_output)
818 error (EXIT_FAILURE, 0,
819 _("the options for verbose and stty-readable output styles are\n"
820 "mutually exclusive"));
822 /* Specifying any other arguments with -a or -g gets an error. */
823 if (!noargs & (verbose_output | recoverable_output))
824 error (EXIT_FAILURE, 0,
825 _("when specifying an output style, modes may not be set"));
827 /* FIXME: it'd be better not to open the file until we've verified
828 that all arguments are valid. Otherwise, we could end up doing
829 only some of the requested operations and then failing, probably
830 leaving things in an undesirable state. */
832 if (file_name)
834 int fdflags;
835 device_name = file_name;
836 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
837 error (EXIT_FAILURE, errno, "%s", device_name);
838 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
839 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
840 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
841 device_name);
843 else
844 device_name = _("standard input");
846 if (tcgetattr (STDIN_FILENO, &mode))
847 error (EXIT_FAILURE, errno, "%s", device_name);
849 if (verbose_output | recoverable_output | noargs)
851 max_col = screen_columns ();
852 current_col = 0;
853 display_settings (output_type, &mode, device_name);
854 exit (EXIT_SUCCESS);
857 speed_was_set = false;
858 require_set_attr = false;
859 for (k = 1; k < argc; k++)
861 char const *arg = argv[k];
862 bool match_found = false;
863 bool reversed = false;
864 int i;
866 if (! arg)
867 continue;
869 if (arg[0] == '-')
871 ++arg;
872 reversed = true;
874 for (i = 0; mode_info[i].name != NULL; ++i)
876 if (STREQ (arg, mode_info[i].name))
878 match_found = set_mode (&mode_info[i], reversed, &mode);
879 require_set_attr = true;
880 break;
883 if (!match_found & reversed)
885 error (0, 0, _("invalid argument %s"), quote (arg - 1));
886 usage (EXIT_FAILURE);
888 if (!match_found)
890 for (i = 0; control_info[i].name != NULL; ++i)
892 if (STREQ (arg, control_info[i].name))
894 if (k == argc - 1)
896 error (0, 0, _("missing argument to %s"), quote (arg));
897 usage (EXIT_FAILURE);
899 match_found = true;
900 ++k;
901 set_control_char (&control_info[i], argv[k], &mode);
902 require_set_attr = true;
903 break;
907 if (!match_found)
909 if (STREQ (arg, "ispeed"))
911 if (k == argc - 1)
913 error (0, 0, _("missing argument to %s"), quote (arg));
914 usage (EXIT_FAILURE);
916 ++k;
917 set_speed (input_speed, argv[k], &mode);
918 speed_was_set = true;
919 require_set_attr = true;
921 else if (STREQ (arg, "ospeed"))
923 if (k == argc - 1)
925 error (0, 0, _("missing argument to %s"), quote (arg));
926 usage (EXIT_FAILURE);
928 ++k;
929 set_speed (output_speed, argv[k], &mode);
930 speed_was_set = true;
931 require_set_attr = true;
933 #ifdef TIOCGWINSZ
934 else if (STREQ (arg, "rows"))
936 if (k == argc - 1)
938 error (0, 0, _("missing argument to %s"), quote (arg));
939 usage (EXIT_FAILURE);
941 ++k;
942 set_window_size (integer_arg (argv[k], INT_MAX), -1,
943 device_name);
945 else if (STREQ (arg, "cols")
946 || STREQ (arg, "columns"))
948 if (k == argc - 1)
950 error (0, 0, _("missing argument to %s"), quote (arg));
951 usage (EXIT_FAILURE);
953 ++k;
954 set_window_size (-1, integer_arg (argv[k], INT_MAX),
955 device_name);
957 else if (STREQ (arg, "size"))
959 max_col = screen_columns ();
960 current_col = 0;
961 display_window_size (false, device_name);
963 #endif
964 #ifdef HAVE_C_LINE
965 else if (STREQ (arg, "line"))
967 unsigned long int value;
968 if (k == argc - 1)
970 error (0, 0, _("missing argument to %s"), quote (arg));
971 usage (EXIT_FAILURE);
973 ++k;
974 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
975 if (mode.c_line != value)
976 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
977 require_set_attr = true;
979 #endif
980 else if (STREQ (arg, "speed"))
982 max_col = screen_columns ();
983 display_speed (&mode, false);
985 else if (string_to_baud (arg) != (speed_t) -1)
987 set_speed (both_speeds, arg, &mode);
988 speed_was_set = true;
989 require_set_attr = true;
991 else
993 if (! recover_mode (arg, &mode))
995 error (0, 0, _("invalid argument %s"), quote (arg));
996 usage (EXIT_FAILURE);
998 require_set_attr = true;
1003 if (require_set_attr)
1005 /* Initialize to all zeroes so there is no risk memcmp will report a
1006 spurious difference in an uninitialized portion of the structure. */
1007 struct termios new_mode = { 0, };
1009 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1010 error (EXIT_FAILURE, errno, "%s", device_name);
1012 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1013 it performs *any* of the requested operations. This means it
1014 can report `success' when it has actually failed to perform
1015 some proper subset of the requested operations. To detect
1016 this partial failure, get the current terminal attributes and
1017 compare them to the requested ones. */
1019 if (tcgetattr (STDIN_FILENO, &new_mode))
1020 error (EXIT_FAILURE, errno, "%s", device_name);
1022 /* Normally, one shouldn't use memcmp to compare structures that
1023 may have `holes' containing uninitialized data, but we have been
1024 careful to initialize the storage of these two variables to all
1025 zeroes. One might think it more efficient simply to compare the
1026 modified fields, but that would require enumerating those fields --
1027 and not all systems have the same fields in this structure. */
1029 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1031 #ifdef CIBAUD
1032 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1033 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1034 sometimes (m1 != m2). The only difference is in the four bits
1035 of the c_cflag field corresponding to the baud rate. To save
1036 Sun users a little confusion, don't report an error if this
1037 happens. But suppress the error only if we haven't tried to
1038 set the baud rate explicitly -- otherwise we'd never give an
1039 error for a true failure to set the baud rate. */
1041 new_mode.c_cflag &= (~CIBAUD);
1042 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1043 #endif
1045 error (EXIT_FAILURE, 0,
1046 _("%s: unable to perform all requested operations"),
1047 device_name);
1048 #ifdef TESTING
1050 size_t i;
1051 printf (_("new_mode: mode\n"));
1052 for (i = 0; i < sizeof (new_mode); i++)
1053 printf ("0x%02x: 0x%02x\n",
1054 *(((unsigned char *) &new_mode) + i),
1055 *(((unsigned char *) &mode) + i));
1057 #endif
1062 exit (EXIT_SUCCESS);
1065 /* Return false if not applied because not reversible; otherwise
1066 return true. */
1068 static bool
1069 set_mode (struct mode_info *info, bool reversed, struct termios *mode)
1071 tcflag_t *bitsp;
1073 if (reversed && (info->flags & REV) == 0)
1074 return false;
1076 bitsp = mode_type_flag (info->type, mode);
1078 if (bitsp == NULL)
1080 /* Combination mode. */
1081 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1083 if (reversed)
1084 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1085 else
1086 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1088 else if (STREQ (info->name, "oddp"))
1090 if (reversed)
1091 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1092 else
1093 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1095 else if (STREQ (info->name, "nl"))
1097 if (reversed)
1099 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1100 mode->c_oflag = (mode->c_oflag
1101 #ifdef ONLCR
1102 | ONLCR
1103 #endif
1105 #ifdef OCRNL
1106 & ~OCRNL
1107 #endif
1108 #ifdef ONLRET
1109 & ~ONLRET
1110 #endif
1113 else
1115 mode->c_iflag = mode->c_iflag & ~ICRNL;
1116 #ifdef ONLCR
1117 mode->c_oflag = mode->c_oflag & ~ONLCR;
1118 #endif
1121 else if (STREQ (info->name, "ek"))
1123 mode->c_cc[VERASE] = CERASE;
1124 mode->c_cc[VKILL] = CKILL;
1126 else if (STREQ (info->name, "sane"))
1127 sane_mode (mode);
1128 else if (STREQ (info->name, "cbreak"))
1130 if (reversed)
1131 mode->c_lflag |= ICANON;
1132 else
1133 mode->c_lflag &= ~ICANON;
1135 else if (STREQ (info->name, "pass8"))
1137 if (reversed)
1139 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1140 mode->c_iflag |= ISTRIP;
1142 else
1144 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1145 mode->c_iflag &= ~ISTRIP;
1148 else if (STREQ (info->name, "litout"))
1150 if (reversed)
1152 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1153 mode->c_iflag |= ISTRIP;
1154 mode->c_oflag |= OPOST;
1156 else
1158 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1159 mode->c_iflag &= ~ISTRIP;
1160 mode->c_oflag &= ~OPOST;
1163 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1165 if ((info->name[0] == 'r' && reversed)
1166 || (info->name[0] == 'c' && !reversed))
1168 /* Cooked mode. */
1169 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1170 mode->c_oflag |= OPOST;
1171 mode->c_lflag |= ISIG | ICANON;
1172 #if VMIN == VEOF
1173 mode->c_cc[VEOF] = CEOF;
1174 #endif
1175 #if VTIME == VEOL
1176 mode->c_cc[VEOL] = CEOL;
1177 #endif
1179 else
1181 /* Raw mode. */
1182 mode->c_iflag = 0;
1183 mode->c_oflag &= ~OPOST;
1184 mode->c_lflag &= ~(ISIG | ICANON
1185 #ifdef XCASE
1186 | XCASE
1187 #endif
1189 mode->c_cc[VMIN] = 1;
1190 mode->c_cc[VTIME] = 0;
1193 #ifdef IXANY
1194 else if (STREQ (info->name, "decctlq"))
1196 if (reversed)
1197 mode->c_iflag |= IXANY;
1198 else
1199 mode->c_iflag &= ~IXANY;
1201 #endif
1202 #ifdef TABDLY
1203 else if (STREQ (info->name, "tabs"))
1205 if (reversed)
1206 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1207 else
1208 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1210 #else
1211 # ifdef OXTABS
1212 else if (STREQ (info->name, "tabs"))
1214 if (reversed)
1215 mode->c_oflag = mode->c_oflag | OXTABS;
1216 else
1217 mode->c_oflag = mode->c_oflag & ~OXTABS;
1219 # endif
1220 #endif
1221 #if defined XCASE && defined IUCLC && defined OLCUC
1222 else if (STREQ (info->name, "lcase")
1223 || STREQ (info->name, "LCASE"))
1225 if (reversed)
1227 mode->c_lflag &= ~XCASE;
1228 mode->c_iflag &= ~IUCLC;
1229 mode->c_oflag &= ~OLCUC;
1231 else
1233 mode->c_lflag |= XCASE;
1234 mode->c_iflag |= IUCLC;
1235 mode->c_oflag |= OLCUC;
1238 #endif
1239 else if (STREQ (info->name, "crt"))
1240 mode->c_lflag |= ECHOE
1241 #ifdef ECHOCTL
1242 | ECHOCTL
1243 #endif
1244 #ifdef ECHOKE
1245 | ECHOKE
1246 #endif
1248 else if (STREQ (info->name, "dec"))
1250 mode->c_cc[VINTR] = 3; /* ^C */
1251 mode->c_cc[VERASE] = 127; /* DEL */
1252 mode->c_cc[VKILL] = 21; /* ^U */
1253 mode->c_lflag |= ECHOE
1254 #ifdef ECHOCTL
1255 | ECHOCTL
1256 #endif
1257 #ifdef ECHOKE
1258 | ECHOKE
1259 #endif
1261 #ifdef IXANY
1262 mode->c_iflag &= ~IXANY;
1263 #endif
1266 else if (reversed)
1267 *bitsp = *bitsp & ~info->mask & ~info->bits;
1268 else
1269 *bitsp = (*bitsp & ~info->mask) | info->bits;
1271 return true;
1274 static void
1275 set_control_char (struct control_info *info, const char *arg,
1276 struct termios *mode)
1278 unsigned long int value;
1280 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1281 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1282 else if (arg[0] == '\0' || arg[1] == '\0')
1283 value = to_uchar (arg[0]);
1284 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1285 value = _POSIX_VDISABLE;
1286 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1288 if (arg[1] == '?')
1289 value = 127;
1290 else
1291 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1293 else
1294 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1295 mode->c_cc[info->offset] = value;
1298 static void
1299 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1301 speed_t baud;
1303 baud = string_to_baud (arg);
1304 if (type == input_speed || type == both_speeds)
1305 cfsetispeed (mode, baud);
1306 if (type == output_speed || type == both_speeds)
1307 cfsetospeed (mode, baud);
1310 #ifdef TIOCGWINSZ
1312 static int
1313 get_win_size (int fd, struct winsize *win)
1315 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1316 return err;
1319 static void
1320 set_window_size (int rows, int cols, char const *device_name)
1322 struct winsize win;
1324 if (get_win_size (STDIN_FILENO, &win))
1326 if (errno != EINVAL)
1327 error (EXIT_FAILURE, errno, "%s", device_name);
1328 memset (&win, 0, sizeof (win));
1331 if (rows >= 0)
1332 win.ws_row = rows;
1333 if (cols >= 0)
1334 win.ws_col = cols;
1336 # ifdef TIOCSSIZE
1337 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1338 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1339 This comment from sys/ttold.h describes Sun's twisted logic - a better
1340 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1341 At any rate, the problem is gone in Solaris 2.x.
1343 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1344 but they can be disambiguated by checking whether a "struct ttysize"
1345 structure's "ts_lines" field is greater than 64K or not. If so,
1346 it's almost certainly a "struct winsize" instead.
1348 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1349 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1350 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1351 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1352 "stty cols 0 rows 0" would do the right thing. On a little-endian
1353 machine like the sun386i, the problem is the same, but for ws_col == 0.
1355 The workaround is to do the ioctl once with row and col = 1 to set the
1356 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1358 if (win.ws_row == 0 || win.ws_col == 0)
1360 struct ttysize ttysz;
1362 ttysz.ts_lines = win.ws_row;
1363 ttysz.ts_cols = win.ws_col;
1365 win.ws_row = 1;
1366 win.ws_col = 1;
1368 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1369 error (EXIT_FAILURE, errno, "%s", device_name);
1371 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1372 error (EXIT_FAILURE, errno, "%s", device_name);
1373 return;
1375 # endif
1377 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1378 error (EXIT_FAILURE, errno, "%s", device_name);
1381 static void
1382 display_window_size (bool fancy, char const *device_name)
1384 struct winsize win;
1386 if (get_win_size (STDIN_FILENO, &win))
1388 if (errno != EINVAL)
1389 error (EXIT_FAILURE, errno, "%s", device_name);
1390 if (!fancy)
1391 error (EXIT_FAILURE, 0,
1392 _("%s: no size information for this device"), device_name);
1394 else
1396 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1397 win.ws_row, win.ws_col);
1398 if (!fancy)
1399 current_col = 0;
1402 #endif
1404 static int
1405 screen_columns (void)
1407 #ifdef TIOCGWINSZ
1408 struct winsize win;
1410 /* With Solaris 2.[123], this ioctl fails and errno is set to
1411 EINVAL for telnet (but not rlogin) sessions.
1412 On ISC 3.0, it fails for the console and the serial port
1413 (but it works for ptys).
1414 It can also fail on any system when stdout isn't a tty.
1415 In case of any failure, just use the default. */
1416 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1417 return win.ws_col;
1418 #endif
1420 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1421 char *col_string = getenv ("COLUMNS");
1422 long int n_columns;
1423 if (!(col_string != NULL
1424 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1425 && 0 < n_columns
1426 && n_columns <= INT_MAX))
1427 n_columns = 80;
1428 return n_columns;
1432 static tcflag_t *
1433 mode_type_flag (enum mode_type type, struct termios *mode)
1435 switch (type)
1437 case control:
1438 return &mode->c_cflag;
1440 case input:
1441 return &mode->c_iflag;
1443 case output:
1444 return &mode->c_oflag;
1446 case local:
1447 return &mode->c_lflag;
1449 case combination:
1450 return NULL;
1452 default:
1453 abort ();
1457 static void
1458 display_settings (enum output_type output_type, struct termios *mode,
1459 char const *device_name)
1461 switch (output_type)
1463 case changed:
1464 display_changed (mode);
1465 break;
1467 case all:
1468 display_all (mode, device_name);
1469 break;
1471 case recoverable:
1472 display_recoverable (mode);
1473 break;
1477 static void
1478 display_changed (struct termios *mode)
1480 int i;
1481 bool empty_line;
1482 tcflag_t *bitsp;
1483 unsigned long mask;
1484 enum mode_type prev_type = control;
1486 display_speed (mode, true);
1487 #ifdef HAVE_C_LINE
1488 wrapf ("line = %d;", mode->c_line);
1489 #endif
1490 putchar ('\n');
1491 current_col = 0;
1493 empty_line = true;
1494 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1496 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1497 continue;
1498 /* If swtch is the same as susp, don't print both. */
1499 #if VSWTCH == VSUSP
1500 if (STREQ (control_info[i].name, "swtch"))
1501 continue;
1502 #endif
1503 /* If eof uses the same slot as min, only print whichever applies. */
1504 #if VEOF == VMIN
1505 if ((mode->c_lflag & ICANON) == 0
1506 && (STREQ (control_info[i].name, "eof")
1507 || STREQ (control_info[i].name, "eol")))
1508 continue;
1509 #endif
1511 empty_line = false;
1512 wrapf ("%s = %s;", control_info[i].name,
1513 visible (mode->c_cc[control_info[i].offset]));
1515 if ((mode->c_lflag & ICANON) == 0)
1517 wrapf ("min = %lu; time = %lu;\n",
1518 (unsigned long int) mode->c_cc[VMIN],
1519 (unsigned long int) mode->c_cc[VTIME]);
1521 else if (!empty_line)
1522 putchar ('\n');
1523 current_col = 0;
1525 empty_line = true;
1526 for (i = 0; mode_info[i].name != NULL; ++i)
1528 if (mode_info[i].flags & OMIT)
1529 continue;
1530 if (mode_info[i].type != prev_type)
1532 if (!empty_line)
1534 putchar ('\n');
1535 current_col = 0;
1536 empty_line = true;
1538 prev_type = mode_info[i].type;
1541 bitsp = mode_type_flag (mode_info[i].type, mode);
1542 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1543 if ((*bitsp & mask) == mode_info[i].bits)
1545 if (mode_info[i].flags & SANE_UNSET)
1547 wrapf ("%s", mode_info[i].name);
1548 empty_line = false;
1551 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1553 wrapf ("-%s", mode_info[i].name);
1554 empty_line = false;
1557 if (!empty_line)
1558 putchar ('\n');
1559 current_col = 0;
1562 static void
1563 display_all (struct termios *mode, char const *device_name)
1565 int i;
1566 tcflag_t *bitsp;
1567 unsigned long mask;
1568 enum mode_type prev_type = control;
1570 display_speed (mode, true);
1571 #ifdef TIOCGWINSZ
1572 display_window_size (true, device_name);
1573 #endif
1574 #ifdef HAVE_C_LINE
1575 wrapf ("line = %d;", mode->c_line);
1576 #endif
1577 putchar ('\n');
1578 current_col = 0;
1580 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1582 /* If swtch is the same as susp, don't print both. */
1583 #if VSWTCH == VSUSP
1584 if (STREQ (control_info[i].name, "swtch"))
1585 continue;
1586 #endif
1587 /* If eof uses the same slot as min, only print whichever applies. */
1588 #if VEOF == VMIN
1589 if ((mode->c_lflag & ICANON) == 0
1590 && (STREQ (control_info[i].name, "eof")
1591 || STREQ (control_info[i].name, "eol")))
1592 continue;
1593 #endif
1594 wrapf ("%s = %s;", control_info[i].name,
1595 visible (mode->c_cc[control_info[i].offset]));
1597 #if VEOF == VMIN
1598 if ((mode->c_lflag & ICANON) == 0)
1599 #endif
1600 wrapf ("min = %lu; time = %lu;",
1601 (unsigned long int) mode->c_cc[VMIN],
1602 (unsigned long int) mode->c_cc[VTIME]);
1603 if (current_col != 0)
1604 putchar ('\n');
1605 current_col = 0;
1607 for (i = 0; mode_info[i].name != NULL; ++i)
1609 if (mode_info[i].flags & OMIT)
1610 continue;
1611 if (mode_info[i].type != prev_type)
1613 putchar ('\n');
1614 current_col = 0;
1615 prev_type = mode_info[i].type;
1618 bitsp = mode_type_flag (mode_info[i].type, mode);
1619 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1620 if ((*bitsp & mask) == mode_info[i].bits)
1621 wrapf ("%s", mode_info[i].name);
1622 else if (mode_info[i].flags & REV)
1623 wrapf ("-%s", mode_info[i].name);
1625 putchar ('\n');
1626 current_col = 0;
1629 static void
1630 display_speed (struct termios *mode, bool fancy)
1632 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1633 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1634 baud_to_value (cfgetospeed (mode)));
1635 else
1636 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1637 baud_to_value (cfgetispeed (mode)),
1638 baud_to_value (cfgetospeed (mode)));
1639 if (!fancy)
1640 current_col = 0;
1643 static void
1644 display_recoverable (struct termios *mode)
1646 size_t i;
1648 printf ("%lx:%lx:%lx:%lx",
1649 (unsigned long int) mode->c_iflag,
1650 (unsigned long int) mode->c_oflag,
1651 (unsigned long int) mode->c_cflag,
1652 (unsigned long int) mode->c_lflag);
1653 for (i = 0; i < NCCS; ++i)
1654 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1655 putchar ('\n');
1658 static bool
1659 recover_mode (char const *arg, struct termios *mode)
1661 size_t i;
1662 int n;
1663 unsigned long int chr;
1664 unsigned long int iflag, oflag, cflag, lflag;
1666 /* Scan into temporaries since it is too much trouble to figure out
1667 the right format for `tcflag_t'. */
1668 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1669 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1670 return false;
1671 mode->c_iflag = iflag;
1672 mode->c_oflag = oflag;
1673 mode->c_cflag = cflag;
1674 mode->c_lflag = lflag;
1675 if (mode->c_iflag != iflag
1676 || mode->c_oflag != oflag
1677 || mode->c_cflag != cflag
1678 || mode->c_lflag != lflag)
1679 return false;
1680 arg += n;
1681 for (i = 0; i < NCCS; ++i)
1683 if (sscanf (arg, ":%lx%n", &chr, &n) != 1)
1684 return false;
1685 mode->c_cc[i] = chr;
1686 if (mode->c_cc[i] != chr)
1687 return false;
1688 arg += n;
1691 /* Fail if there are too many fields. */
1692 if (*arg != '\0')
1693 return false;
1695 return true;
1698 struct speed_map
1700 const char *string; /* ASCII representation. */
1701 speed_t speed; /* Internal form. */
1702 unsigned long int value; /* Numeric value. */
1705 static struct speed_map speeds[] =
1707 {"0", B0, 0},
1708 {"50", B50, 50},
1709 {"75", B75, 75},
1710 {"110", B110, 110},
1711 {"134", B134, 134},
1712 {"134.5", B134, 134},
1713 {"150", B150, 150},
1714 {"200", B200, 200},
1715 {"300", B300, 300},
1716 {"600", B600, 600},
1717 {"1200", B1200, 1200},
1718 {"1800", B1800, 1800},
1719 {"2400", B2400, 2400},
1720 {"4800", B4800, 4800},
1721 {"9600", B9600, 9600},
1722 {"19200", B19200, 19200},
1723 {"38400", B38400, 38400},
1724 {"exta", B19200, 19200},
1725 {"extb", B38400, 38400},
1726 #ifdef B57600
1727 {"57600", B57600, 57600},
1728 #endif
1729 #ifdef B115200
1730 {"115200", B115200, 115200},
1731 #endif
1732 #ifdef B230400
1733 {"230400", B230400, 230400},
1734 #endif
1735 #ifdef B460800
1736 {"460800", B460800, 460800},
1737 #endif
1738 #ifdef B500000
1739 {"500000", B500000, 500000},
1740 #endif
1741 #ifdef B576000
1742 {"576000", B576000, 576000},
1743 #endif
1744 #ifdef B921600
1745 {"921600", B921600, 921600},
1746 #endif
1747 #ifdef B1000000
1748 {"1000000", B1000000, 1000000},
1749 #endif
1750 #ifdef B1152000
1751 {"1152000", B1152000, 1152000},
1752 #endif
1753 #ifdef B1500000
1754 {"1500000", B1500000, 1500000},
1755 #endif
1756 #ifdef B2000000
1757 {"2000000", B2000000, 2000000},
1758 #endif
1759 #ifdef B2500000
1760 {"2500000", B2500000, 2500000},
1761 #endif
1762 #ifdef B3000000
1763 {"3000000", B3000000, 3000000},
1764 #endif
1765 #ifdef B3500000
1766 {"3500000", B3500000, 3500000},
1767 #endif
1768 #ifdef B4000000
1769 {"4000000", B4000000, 4000000},
1770 #endif
1771 {NULL, 0, 0}
1774 static speed_t
1775 string_to_baud (const char *arg)
1777 int i;
1779 for (i = 0; speeds[i].string != NULL; ++i)
1780 if (STREQ (arg, speeds[i].string))
1781 return speeds[i].speed;
1782 return (speed_t) -1;
1785 static unsigned long int
1786 baud_to_value (speed_t speed)
1788 int i;
1790 for (i = 0; speeds[i].string != NULL; ++i)
1791 if (speed == speeds[i].speed)
1792 return speeds[i].value;
1793 return 0;
1796 static void
1797 sane_mode (struct termios *mode)
1799 int i;
1800 tcflag_t *bitsp;
1802 for (i = 0; control_info[i].name; ++i)
1804 #if VMIN == VEOF
1805 if (STREQ (control_info[i].name, "min"))
1806 break;
1807 #endif
1808 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1811 for (i = 0; mode_info[i].name != NULL; ++i)
1813 if (mode_info[i].flags & SANE_SET)
1815 bitsp = mode_type_flag (mode_info[i].type, mode);
1816 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1818 else if (mode_info[i].flags & SANE_UNSET)
1820 bitsp = mode_type_flag (mode_info[i].type, mode);
1821 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1826 /* Return a string that is the printable representation of character CH. */
1827 /* Adapted from `cat' by Torbjorn Granlund. */
1829 static const char *
1830 visible (cc_t ch)
1832 static char buf[10];
1833 char *bpout = buf;
1835 if (ch == _POSIX_VDISABLE)
1836 return "<undef>";
1838 if (ch >= 32)
1840 if (ch < 127)
1841 *bpout++ = ch;
1842 else if (ch == 127)
1844 *bpout++ = '^';
1845 *bpout++ = '?';
1847 else
1849 *bpout++ = 'M',
1850 *bpout++ = '-';
1851 if (ch >= 128 + 32)
1853 if (ch < 128 + 127)
1854 *bpout++ = ch - 128;
1855 else
1857 *bpout++ = '^';
1858 *bpout++ = '?';
1861 else
1863 *bpout++ = '^';
1864 *bpout++ = ch - 128 + 64;
1868 else
1870 *bpout++ = '^';
1871 *bpout++ = ch + 64;
1873 *bpout = '\0';
1874 return (const char *) buf;
1877 /* Parse string S as an integer, using decimal radix by default,
1878 but allowing octal and hex numbers as in C. Reject values
1879 larger than MAXVAL. */
1881 static unsigned long int
1882 integer_arg (const char *s, unsigned long int maxval)
1884 unsigned long int value;
1885 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK
1886 || maxval < value)
1888 error (0, 0, _("invalid integer argument %s"), quote (s));
1889 usage (EXIT_FAILURE);
1891 return value;