* src/dd.c (flags): noatime and nofollow now depend on
[coreutils/bo.git] / src / stty.c
blob9e1ba0a7c05de2dce23971bf84b8956e34a05468
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 struct termios mode;
733 enum output_type output_type;
734 int optc;
735 int argi = 0;
736 int opti = 1;
737 bool require_set_attr;
738 bool speed_was_set;
739 bool verbose_output;
740 bool recoverable_output;
741 int k;
742 bool noargs = true;
743 char *file_name = NULL;
744 const char *device_name;
746 initialize_main (&argc, &argv);
747 program_name = argv[0];
748 setlocale (LC_ALL, "");
749 bindtextdomain (PACKAGE, LOCALEDIR);
750 textdomain (PACKAGE);
752 atexit (close_stdout);
754 output_type = changed;
755 verbose_output = false;
756 recoverable_output = false;
758 /* Don't print error messages for unrecognized options. */
759 opterr = 0;
761 /* If any new options are ever added to stty, the short options MUST
762 NOT allow any ambiguity with the stty settings. For example, the
763 stty setting "-gagFork" would not be feasible, since it will be
764 parsed as "-g -a -g -F ork". If you change anything about how
765 stty parses options, be sure it still works with combinations of
766 short and long options, --, POSIXLY_CORRECT, etc. */
768 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
769 longopts, NULL))
770 != -1)
772 switch (optc)
774 case 'a':
775 verbose_output = true;
776 output_type = all;
777 break;
779 case 'g':
780 recoverable_output = true;
781 output_type = recoverable;
782 break;
784 case 'F':
785 if (file_name)
786 error (EXIT_FAILURE, 0, _("only one device may be specified"));
787 file_name = optarg;
788 break;
790 case_GETOPT_HELP_CHAR;
792 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
794 default:
795 noargs = false;
797 /* Skip the argument containing this unrecognized option;
798 the 2nd pass will analyze it. */
799 argi += opti;
801 /* Restart getopt_long from the first unskipped argument. */
802 opti = 1;
803 optind = 0;
805 break;
808 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
809 while (opti < optind)
810 argv[argi + opti++] = NULL;
813 /* Specifying both -a and -g gets an error. */
814 if (verbose_output & recoverable_output)
815 error (EXIT_FAILURE, 0,
816 _("the options for verbose and stty-readable output styles are\n"
817 "mutually exclusive"));
819 /* Specifying any other arguments with -a or -g gets an error. */
820 if (!noargs & (verbose_output | recoverable_output))
821 error (EXIT_FAILURE, 0,
822 _("when specifying an output style, modes may not be set"));
824 /* FIXME: it'd be better not to open the file until we've verified
825 that all arguments are valid. Otherwise, we could end up doing
826 only some of the requested operations and then failing, probably
827 leaving things in an undesirable state. */
829 if (file_name)
831 int fdflags;
832 device_name = file_name;
833 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
834 error (EXIT_FAILURE, errno, "%s", device_name);
835 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
836 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
837 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
838 device_name);
840 else
841 device_name = _("standard input");
843 /* Initialize to all zeroes so there is no risk memcmp will report a
844 spurious difference in an uninitialized portion of the structure. */
845 memset (&mode, 0, sizeof (mode));
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 struct termios new_mode;
1007 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1008 error (EXIT_FAILURE, errno, "%s", device_name);
1010 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1011 it performs *any* of the requested operations. This means it
1012 can report `success' when it has actually failed to perform
1013 some proper subset of the requested operations. To detect
1014 this partial failure, get the current terminal attributes and
1015 compare them to the requested ones. */
1017 /* Initialize to all zeroes so there is no risk memcmp will report a
1018 spurious difference in an uninitialized portion of the structure. */
1019 memset (&new_mode, 0, sizeof (new_mode));
1020 if (tcgetattr (STDIN_FILENO, &new_mode))
1021 error (EXIT_FAILURE, errno, "%s", device_name);
1023 /* Normally, one shouldn't use memcmp to compare structures that
1024 may have `holes' containing uninitialized data, but we have been
1025 careful to initialize the storage of these two variables to all
1026 zeroes. One might think it more efficient simply to compare the
1027 modified fields, but that would require enumerating those fields --
1028 and not all systems have the same fields in this structure. */
1030 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1032 #ifdef CIBAUD
1033 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1034 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1035 sometimes (m1 != m2). The only difference is in the four bits
1036 of the c_cflag field corresponding to the baud rate. To save
1037 Sun users a little confusion, don't report an error if this
1038 happens. But suppress the error only if we haven't tried to
1039 set the baud rate explicitly -- otherwise we'd never give an
1040 error for a true failure to set the baud rate. */
1042 new_mode.c_cflag &= (~CIBAUD);
1043 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1044 #endif
1046 error (EXIT_FAILURE, 0,
1047 _("%s: unable to perform all requested operations"),
1048 device_name);
1049 #ifdef TESTING
1051 size_t i;
1052 printf (_("new_mode: mode\n"));
1053 for (i = 0; i < sizeof (new_mode); i++)
1054 printf ("0x%02x: 0x%02x\n",
1055 *(((unsigned char *) &new_mode) + i),
1056 *(((unsigned char *) &mode) + i));
1058 #endif
1063 exit (EXIT_SUCCESS);
1066 /* Return false if not applied because not reversible; otherwise
1067 return true. */
1069 static bool
1070 set_mode (struct mode_info *info, bool reversed, struct termios *mode)
1072 tcflag_t *bitsp;
1074 if (reversed && (info->flags & REV) == 0)
1075 return false;
1077 bitsp = mode_type_flag (info->type, mode);
1079 if (bitsp == NULL)
1081 /* Combination mode. */
1082 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1084 if (reversed)
1085 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1086 else
1087 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1089 else if (STREQ (info->name, "oddp"))
1091 if (reversed)
1092 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1093 else
1094 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1096 else if (STREQ (info->name, "nl"))
1098 if (reversed)
1100 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1101 mode->c_oflag = (mode->c_oflag
1102 #ifdef ONLCR
1103 | ONLCR
1104 #endif
1106 #ifdef OCRNL
1107 & ~OCRNL
1108 #endif
1109 #ifdef ONLRET
1110 & ~ONLRET
1111 #endif
1114 else
1116 mode->c_iflag = mode->c_iflag & ~ICRNL;
1117 #ifdef ONLCR
1118 mode->c_oflag = mode->c_oflag & ~ONLCR;
1119 #endif
1122 else if (STREQ (info->name, "ek"))
1124 mode->c_cc[VERASE] = CERASE;
1125 mode->c_cc[VKILL] = CKILL;
1127 else if (STREQ (info->name, "sane"))
1128 sane_mode (mode);
1129 else if (STREQ (info->name, "cbreak"))
1131 if (reversed)
1132 mode->c_lflag |= ICANON;
1133 else
1134 mode->c_lflag &= ~ICANON;
1136 else if (STREQ (info->name, "pass8"))
1138 if (reversed)
1140 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1141 mode->c_iflag |= ISTRIP;
1143 else
1145 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1146 mode->c_iflag &= ~ISTRIP;
1149 else if (STREQ (info->name, "litout"))
1151 if (reversed)
1153 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1154 mode->c_iflag |= ISTRIP;
1155 mode->c_oflag |= OPOST;
1157 else
1159 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1160 mode->c_iflag &= ~ISTRIP;
1161 mode->c_oflag &= ~OPOST;
1164 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1166 if ((info->name[0] == 'r' && reversed)
1167 || (info->name[0] == 'c' && !reversed))
1169 /* Cooked mode. */
1170 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1171 mode->c_oflag |= OPOST;
1172 mode->c_lflag |= ISIG | ICANON;
1173 #if VMIN == VEOF
1174 mode->c_cc[VEOF] = CEOF;
1175 #endif
1176 #if VTIME == VEOL
1177 mode->c_cc[VEOL] = CEOL;
1178 #endif
1180 else
1182 /* Raw mode. */
1183 mode->c_iflag = 0;
1184 mode->c_oflag &= ~OPOST;
1185 mode->c_lflag &= ~(ISIG | ICANON
1186 #ifdef XCASE
1187 | XCASE
1188 #endif
1190 mode->c_cc[VMIN] = 1;
1191 mode->c_cc[VTIME] = 0;
1194 #ifdef IXANY
1195 else if (STREQ (info->name, "decctlq"))
1197 if (reversed)
1198 mode->c_iflag |= IXANY;
1199 else
1200 mode->c_iflag &= ~IXANY;
1202 #endif
1203 #ifdef TABDLY
1204 else if (STREQ (info->name, "tabs"))
1206 if (reversed)
1207 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1208 else
1209 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1211 #else
1212 # ifdef OXTABS
1213 else if (STREQ (info->name, "tabs"))
1215 if (reversed)
1216 mode->c_oflag = mode->c_oflag | OXTABS;
1217 else
1218 mode->c_oflag = mode->c_oflag & ~OXTABS;
1220 # endif
1221 #endif
1222 #if defined XCASE && defined IUCLC && defined OLCUC
1223 else if (STREQ (info->name, "lcase")
1224 || STREQ (info->name, "LCASE"))
1226 if (reversed)
1228 mode->c_lflag &= ~XCASE;
1229 mode->c_iflag &= ~IUCLC;
1230 mode->c_oflag &= ~OLCUC;
1232 else
1234 mode->c_lflag |= XCASE;
1235 mode->c_iflag |= IUCLC;
1236 mode->c_oflag |= OLCUC;
1239 #endif
1240 else if (STREQ (info->name, "crt"))
1241 mode->c_lflag |= ECHOE
1242 #ifdef ECHOCTL
1243 | ECHOCTL
1244 #endif
1245 #ifdef ECHOKE
1246 | ECHOKE
1247 #endif
1249 else if (STREQ (info->name, "dec"))
1251 mode->c_cc[VINTR] = 3; /* ^C */
1252 mode->c_cc[VERASE] = 127; /* DEL */
1253 mode->c_cc[VKILL] = 21; /* ^U */
1254 mode->c_lflag |= ECHOE
1255 #ifdef ECHOCTL
1256 | ECHOCTL
1257 #endif
1258 #ifdef ECHOKE
1259 | ECHOKE
1260 #endif
1262 #ifdef IXANY
1263 mode->c_iflag &= ~IXANY;
1264 #endif
1267 else if (reversed)
1268 *bitsp = *bitsp & ~info->mask & ~info->bits;
1269 else
1270 *bitsp = (*bitsp & ~info->mask) | info->bits;
1272 return true;
1275 static void
1276 set_control_char (struct control_info *info, const char *arg,
1277 struct termios *mode)
1279 unsigned long int value;
1281 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1282 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1283 else if (arg[0] == '\0' || arg[1] == '\0')
1284 value = to_uchar (arg[0]);
1285 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1286 value = _POSIX_VDISABLE;
1287 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1289 if (arg[1] == '?')
1290 value = 127;
1291 else
1292 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1294 else
1295 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1296 mode->c_cc[info->offset] = value;
1299 static void
1300 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1302 speed_t baud;
1304 baud = string_to_baud (arg);
1305 if (type == input_speed || type == both_speeds)
1306 cfsetispeed (mode, baud);
1307 if (type == output_speed || type == both_speeds)
1308 cfsetospeed (mode, baud);
1311 #ifdef TIOCGWINSZ
1313 static int
1314 get_win_size (int fd, struct winsize *win)
1316 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1317 return err;
1320 static void
1321 set_window_size (int rows, int cols, char const *device_name)
1323 struct winsize win;
1325 if (get_win_size (STDIN_FILENO, &win))
1327 if (errno != EINVAL)
1328 error (EXIT_FAILURE, errno, "%s", device_name);
1329 memset (&win, 0, sizeof (win));
1332 if (rows >= 0)
1333 win.ws_row = rows;
1334 if (cols >= 0)
1335 win.ws_col = cols;
1337 # ifdef TIOCSSIZE
1338 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1339 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1340 This comment from sys/ttold.h describes Sun's twisted logic - a better
1341 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1342 At any rate, the problem is gone in Solaris 2.x.
1344 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1345 but they can be disambiguated by checking whether a "struct ttysize"
1346 structure's "ts_lines" field is greater than 64K or not. If so,
1347 it's almost certainly a "struct winsize" instead.
1349 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1350 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1351 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1352 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1353 "stty cols 0 rows 0" would do the right thing. On a little-endian
1354 machine like the sun386i, the problem is the same, but for ws_col == 0.
1356 The workaround is to do the ioctl once with row and col = 1 to set the
1357 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1359 if (win.ws_row == 0 || win.ws_col == 0)
1361 struct ttysize ttysz;
1363 ttysz.ts_lines = win.ws_row;
1364 ttysz.ts_cols = win.ws_col;
1366 win.ws_row = 1;
1367 win.ws_col = 1;
1369 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1370 error (EXIT_FAILURE, errno, "%s", device_name);
1372 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1373 error (EXIT_FAILURE, errno, "%s", device_name);
1374 return;
1376 # endif
1378 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1379 error (EXIT_FAILURE, errno, "%s", device_name);
1382 static void
1383 display_window_size (bool fancy, char const *device_name)
1385 struct winsize win;
1387 if (get_win_size (STDIN_FILENO, &win))
1389 if (errno != EINVAL)
1390 error (EXIT_FAILURE, errno, "%s", device_name);
1391 if (!fancy)
1392 error (EXIT_FAILURE, 0,
1393 _("%s: no size information for this device"), device_name);
1395 else
1397 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1398 win.ws_row, win.ws_col);
1399 if (!fancy)
1400 current_col = 0;
1403 #endif
1405 static int
1406 screen_columns (void)
1408 #ifdef TIOCGWINSZ
1409 struct winsize win;
1411 /* With Solaris 2.[123], this ioctl fails and errno is set to
1412 EINVAL for telnet (but not rlogin) sessions.
1413 On ISC 3.0, it fails for the console and the serial port
1414 (but it works for ptys).
1415 It can also fail on any system when stdout isn't a tty.
1416 In case of any failure, just use the default. */
1417 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1418 return win.ws_col;
1419 #endif
1421 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1422 char *col_string = getenv ("COLUMNS");
1423 long int n_columns;
1424 if (!(col_string != NULL
1425 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1426 && 0 < n_columns
1427 && n_columns <= INT_MAX))
1428 n_columns = 80;
1429 return n_columns;
1433 static tcflag_t *
1434 mode_type_flag (enum mode_type type, struct termios *mode)
1436 switch (type)
1438 case control:
1439 return &mode->c_cflag;
1441 case input:
1442 return &mode->c_iflag;
1444 case output:
1445 return &mode->c_oflag;
1447 case local:
1448 return &mode->c_lflag;
1450 case combination:
1451 return NULL;
1453 default:
1454 abort ();
1458 static void
1459 display_settings (enum output_type output_type, struct termios *mode,
1460 char const *device_name)
1462 switch (output_type)
1464 case changed:
1465 display_changed (mode);
1466 break;
1468 case all:
1469 display_all (mode, device_name);
1470 break;
1472 case recoverable:
1473 display_recoverable (mode);
1474 break;
1478 static void
1479 display_changed (struct termios *mode)
1481 int i;
1482 bool empty_line;
1483 tcflag_t *bitsp;
1484 unsigned long mask;
1485 enum mode_type prev_type = control;
1487 display_speed (mode, true);
1488 #ifdef HAVE_C_LINE
1489 wrapf ("line = %d;", mode->c_line);
1490 #endif
1491 putchar ('\n');
1492 current_col = 0;
1494 empty_line = true;
1495 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1497 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1498 continue;
1499 /* If swtch is the same as susp, don't print both. */
1500 #if VSWTCH == VSUSP
1501 if (STREQ (control_info[i].name, "swtch"))
1502 continue;
1503 #endif
1504 /* If eof uses the same slot as min, only print whichever applies. */
1505 #if VEOF == VMIN
1506 if ((mode->c_lflag & ICANON) == 0
1507 && (STREQ (control_info[i].name, "eof")
1508 || STREQ (control_info[i].name, "eol")))
1509 continue;
1510 #endif
1512 empty_line = false;
1513 wrapf ("%s = %s;", control_info[i].name,
1514 visible (mode->c_cc[control_info[i].offset]));
1516 if ((mode->c_lflag & ICANON) == 0)
1518 wrapf ("min = %lu; time = %lu;\n",
1519 (unsigned long int) mode->c_cc[VMIN],
1520 (unsigned long int) mode->c_cc[VTIME]);
1522 else if (!empty_line)
1523 putchar ('\n');
1524 current_col = 0;
1526 empty_line = true;
1527 for (i = 0; mode_info[i].name != NULL; ++i)
1529 if (mode_info[i].flags & OMIT)
1530 continue;
1531 if (mode_info[i].type != prev_type)
1533 if (!empty_line)
1535 putchar ('\n');
1536 current_col = 0;
1537 empty_line = true;
1539 prev_type = mode_info[i].type;
1542 bitsp = mode_type_flag (mode_info[i].type, mode);
1543 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1544 if ((*bitsp & mask) == mode_info[i].bits)
1546 if (mode_info[i].flags & SANE_UNSET)
1548 wrapf ("%s", mode_info[i].name);
1549 empty_line = false;
1552 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1554 wrapf ("-%s", mode_info[i].name);
1555 empty_line = false;
1558 if (!empty_line)
1559 putchar ('\n');
1560 current_col = 0;
1563 static void
1564 display_all (struct termios *mode, char const *device_name)
1566 int i;
1567 tcflag_t *bitsp;
1568 unsigned long mask;
1569 enum mode_type prev_type = control;
1571 display_speed (mode, true);
1572 #ifdef TIOCGWINSZ
1573 display_window_size (true, device_name);
1574 #endif
1575 #ifdef HAVE_C_LINE
1576 wrapf ("line = %d;", mode->c_line);
1577 #endif
1578 putchar ('\n');
1579 current_col = 0;
1581 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1583 /* If swtch is the same as susp, don't print both. */
1584 #if VSWTCH == VSUSP
1585 if (STREQ (control_info[i].name, "swtch"))
1586 continue;
1587 #endif
1588 /* If eof uses the same slot as min, only print whichever applies. */
1589 #if VEOF == VMIN
1590 if ((mode->c_lflag & ICANON) == 0
1591 && (STREQ (control_info[i].name, "eof")
1592 || STREQ (control_info[i].name, "eol")))
1593 continue;
1594 #endif
1595 wrapf ("%s = %s;", control_info[i].name,
1596 visible (mode->c_cc[control_info[i].offset]));
1598 #if VEOF == VMIN
1599 if ((mode->c_lflag & ICANON) == 0)
1600 #endif
1601 wrapf ("min = %lu; time = %lu;",
1602 (unsigned long int) mode->c_cc[VMIN],
1603 (unsigned long int) mode->c_cc[VTIME]);
1604 if (current_col != 0)
1605 putchar ('\n');
1606 current_col = 0;
1608 for (i = 0; mode_info[i].name != NULL; ++i)
1610 if (mode_info[i].flags & OMIT)
1611 continue;
1612 if (mode_info[i].type != prev_type)
1614 putchar ('\n');
1615 current_col = 0;
1616 prev_type = mode_info[i].type;
1619 bitsp = mode_type_flag (mode_info[i].type, mode);
1620 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1621 if ((*bitsp & mask) == mode_info[i].bits)
1622 wrapf ("%s", mode_info[i].name);
1623 else if (mode_info[i].flags & REV)
1624 wrapf ("-%s", mode_info[i].name);
1626 putchar ('\n');
1627 current_col = 0;
1630 static void
1631 display_speed (struct termios *mode, bool fancy)
1633 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1634 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1635 baud_to_value (cfgetospeed (mode)));
1636 else
1637 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1638 baud_to_value (cfgetispeed (mode)),
1639 baud_to_value (cfgetospeed (mode)));
1640 if (!fancy)
1641 current_col = 0;
1644 static void
1645 display_recoverable (struct termios *mode)
1647 size_t i;
1649 printf ("%lx:%lx:%lx:%lx",
1650 (unsigned long int) mode->c_iflag,
1651 (unsigned long int) mode->c_oflag,
1652 (unsigned long int) mode->c_cflag,
1653 (unsigned long int) mode->c_lflag);
1654 for (i = 0; i < NCCS; ++i)
1655 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1656 putchar ('\n');
1659 static bool
1660 recover_mode (char const *arg, struct termios *mode)
1662 size_t i;
1663 int n;
1664 unsigned long int chr;
1665 unsigned long int iflag, oflag, cflag, lflag;
1667 /* Scan into temporaries since it is too much trouble to figure out
1668 the right format for `tcflag_t'. */
1669 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1670 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1671 return false;
1672 mode->c_iflag = iflag;
1673 mode->c_oflag = oflag;
1674 mode->c_cflag = cflag;
1675 mode->c_lflag = lflag;
1676 if (mode->c_iflag != iflag
1677 || mode->c_oflag != oflag
1678 || mode->c_cflag != cflag
1679 || mode->c_lflag != lflag)
1680 return false;
1681 arg += n;
1682 for (i = 0; i < NCCS; ++i)
1684 if (sscanf (arg, ":%lx%n", &chr, &n) != 1)
1685 return false;
1686 mode->c_cc[i] = chr;
1687 if (mode->c_cc[i] != chr)
1688 return false;
1689 arg += n;
1692 /* Fail if there are too many fields. */
1693 if (*arg != '\0')
1694 return false;
1696 return true;
1699 struct speed_map
1701 const char *string; /* ASCII representation. */
1702 speed_t speed; /* Internal form. */
1703 unsigned long int value; /* Numeric value. */
1706 static struct speed_map speeds[] =
1708 {"0", B0, 0},
1709 {"50", B50, 50},
1710 {"75", B75, 75},
1711 {"110", B110, 110},
1712 {"134", B134, 134},
1713 {"134.5", B134, 134},
1714 {"150", B150, 150},
1715 {"200", B200, 200},
1716 {"300", B300, 300},
1717 {"600", B600, 600},
1718 {"1200", B1200, 1200},
1719 {"1800", B1800, 1800},
1720 {"2400", B2400, 2400},
1721 {"4800", B4800, 4800},
1722 {"9600", B9600, 9600},
1723 {"19200", B19200, 19200},
1724 {"38400", B38400, 38400},
1725 {"exta", B19200, 19200},
1726 {"extb", B38400, 38400},
1727 #ifdef B57600
1728 {"57600", B57600, 57600},
1729 #endif
1730 #ifdef B115200
1731 {"115200", B115200, 115200},
1732 #endif
1733 #ifdef B230400
1734 {"230400", B230400, 230400},
1735 #endif
1736 #ifdef B460800
1737 {"460800", B460800, 460800},
1738 #endif
1739 #ifdef B500000
1740 {"500000", B500000, 500000},
1741 #endif
1742 #ifdef B576000
1743 {"576000", B576000, 576000},
1744 #endif
1745 #ifdef B921600
1746 {"921600", B921600, 921600},
1747 #endif
1748 #ifdef B1000000
1749 {"1000000", B1000000, 1000000},
1750 #endif
1751 #ifdef B1152000
1752 {"1152000", B1152000, 1152000},
1753 #endif
1754 #ifdef B1500000
1755 {"1500000", B1500000, 1500000},
1756 #endif
1757 #ifdef B2000000
1758 {"2000000", B2000000, 2000000},
1759 #endif
1760 #ifdef B2500000
1761 {"2500000", B2500000, 2500000},
1762 #endif
1763 #ifdef B3000000
1764 {"3000000", B3000000, 3000000},
1765 #endif
1766 #ifdef B3500000
1767 {"3500000", B3500000, 3500000},
1768 #endif
1769 #ifdef B4000000
1770 {"4000000", B4000000, 4000000},
1771 #endif
1772 {NULL, 0, 0}
1775 static speed_t
1776 string_to_baud (const char *arg)
1778 int i;
1780 for (i = 0; speeds[i].string != NULL; ++i)
1781 if (STREQ (arg, speeds[i].string))
1782 return speeds[i].speed;
1783 return (speed_t) -1;
1786 static unsigned long int
1787 baud_to_value (speed_t speed)
1789 int i;
1791 for (i = 0; speeds[i].string != NULL; ++i)
1792 if (speed == speeds[i].speed)
1793 return speeds[i].value;
1794 return 0;
1797 static void
1798 sane_mode (struct termios *mode)
1800 int i;
1801 tcflag_t *bitsp;
1803 for (i = 0; control_info[i].name; ++i)
1805 #if VMIN == VEOF
1806 if (STREQ (control_info[i].name, "min"))
1807 break;
1808 #endif
1809 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1812 for (i = 0; mode_info[i].name != NULL; ++i)
1814 if (mode_info[i].flags & SANE_SET)
1816 bitsp = mode_type_flag (mode_info[i].type, mode);
1817 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1819 else if (mode_info[i].flags & SANE_UNSET)
1821 bitsp = mode_type_flag (mode_info[i].type, mode);
1822 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1827 /* Return a string that is the printable representation of character CH. */
1828 /* Adapted from `cat' by Torbjorn Granlund. */
1830 static const char *
1831 visible (cc_t ch)
1833 static char buf[10];
1834 char *bpout = buf;
1836 if (ch == _POSIX_VDISABLE)
1837 return "<undef>";
1839 if (ch >= 32)
1841 if (ch < 127)
1842 *bpout++ = ch;
1843 else if (ch == 127)
1845 *bpout++ = '^';
1846 *bpout++ = '?';
1848 else
1850 *bpout++ = 'M',
1851 *bpout++ = '-';
1852 if (ch >= 128 + 32)
1854 if (ch < 128 + 127)
1855 *bpout++ = ch - 128;
1856 else
1858 *bpout++ = '^';
1859 *bpout++ = '?';
1862 else
1864 *bpout++ = '^';
1865 *bpout++ = ch - 128 + 64;
1869 else
1871 *bpout++ = '^';
1872 *bpout++ = ch + 64;
1874 *bpout = '\0';
1875 return (const char *) buf;
1878 /* Parse string S as an integer, using decimal radix by default,
1879 but allowing octal and hex numbers as in C. Reject values
1880 larger than MAXVAL. */
1882 static unsigned long int
1883 integer_arg (const char *s, unsigned long int maxval)
1885 unsigned long int value;
1886 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK
1887 || maxval < value)
1889 error (0, 0, _("invalid integer argument %s"), quote (s));
1890 usage (EXIT_FAILURE);
1892 return value;