maint: use new emit_try_help in place of equivalent fprintf
[coreutils/ericb.git] / src / stty.c
blobfa48dbbeff04c8db7ebd5885fd85b5da7369355f
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005, 2007-2012 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
19 Options:
20 -a, --all Write all current settings to stdout in human-readable form.
21 -g, --save Write all current settings to stdout in stty-readable form.
22 -F, --file Open and use the specified device instead of stdin
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on the specified device, or stdin if none was specified.
28 David MacKenzie <djm@gnu.ai.mit.edu> */
30 #include <config.h>
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
34 #endif
36 #include <stdio.h>
37 #include <sys/types.h>
39 #include <termios.h>
40 #if HAVE_STROPTS_H
41 # include <stropts.h>
42 #endif
43 #include <sys/ioctl.h>
45 #ifdef WINSIZE_IN_PTEM
46 # include <sys/stream.h>
47 # include <sys/ptem.h>
48 #endif
49 #ifdef GWINSZ_IN_SYS_PTY
50 # include <sys/tty.h>
51 # include <sys/pty.h>
52 #endif
53 #include <getopt.h>
54 #include <stdarg.h>
56 #include "system.h"
57 #include "error.h"
58 #include "fd-reopen.h"
59 #include "quote.h"
60 #include "xstrtol.h"
62 /* The official name of this program (e.g., no `g' prefix). */
63 #define PROGRAM_NAME "stty"
65 #define AUTHORS proper_name ("David MacKenzie")
67 #ifndef _POSIX_VDISABLE
68 # define _POSIX_VDISABLE 0
69 #endif
71 #define Control(c) ((c) & 0x1f)
72 /* Canonical values for control characters. */
73 #ifndef CINTR
74 # define CINTR Control ('c')
75 #endif
76 #ifndef CQUIT
77 # define CQUIT 28
78 #endif
79 #ifndef CERASE
80 # define CERASE 127
81 #endif
82 #ifndef CKILL
83 # define CKILL Control ('u')
84 #endif
85 #ifndef CEOF
86 # define CEOF Control ('d')
87 #endif
88 #ifndef CEOL
89 # define CEOL _POSIX_VDISABLE
90 #endif
91 #ifndef CSTART
92 # define CSTART Control ('q')
93 #endif
94 #ifndef CSTOP
95 # define CSTOP Control ('s')
96 #endif
97 #ifndef CSUSP
98 # define CSUSP Control ('z')
99 #endif
100 #if defined VEOL2 && !defined CEOL2
101 # define CEOL2 _POSIX_VDISABLE
102 #endif
103 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
104 character is initialized by CSWTCH, if present. */
105 #if defined VSWTC && !defined VSWTCH
106 # define VSWTCH VSWTC
107 #endif
108 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
109 #if defined VSUSP && !defined VSWTCH
110 # define VSWTCH VSUSP
111 # if defined CSUSP && !defined CSWTCH
112 # define CSWTCH CSUSP
113 # endif
114 #endif
115 #if defined VSWTCH && !defined CSWTCH
116 # define CSWTCH _POSIX_VDISABLE
117 #endif
119 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
120 So the default is to disable `swtch.' */
121 #if defined __sparc__ && defined __svr4__
122 # undef CSWTCH
123 # define CSWTCH _POSIX_VDISABLE
124 #endif
126 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
127 # define VWERASE VWERSE
128 #endif
129 #if defined VDSUSP && !defined CDSUSP
130 # define CDSUSP Control ('y')
131 #endif
132 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
133 # define VREPRINT VRPRNT
134 #endif
135 #if defined VREPRINT && !defined CRPRNT
136 # define CRPRNT Control ('r')
137 #endif
138 #if defined CREPRINT && !defined CRPRNT
139 # define CRPRNT Control ('r')
140 #endif
141 #if defined VWERASE && !defined CWERASE
142 # define CWERASE Control ('w')
143 #endif
144 #if defined VLNEXT && !defined CLNEXT
145 # define CLNEXT Control ('v')
146 #endif
147 #if defined VDISCARD && !defined VFLUSHO
148 # define VFLUSHO VDISCARD
149 #endif
150 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
151 # define VFLUSHO VFLUSH
152 #endif
153 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
154 # define ECHOCTL CTLECH
155 #endif
156 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
157 # define ECHOCTL TCTLECH
158 #endif
159 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
160 # define ECHOKE CRTKIL
161 #endif
162 #if defined VFLUSHO && !defined CFLUSHO
163 # define CFLUSHO Control ('o')
164 #endif
165 #if defined VSTATUS && !defined CSTATUS
166 # define CSTATUS Control ('t')
167 #endif
169 /* Which speeds to set. */
170 enum speed_setting
172 input_speed, output_speed, both_speeds
175 /* What to output and how. */
176 enum output_type
178 changed, all, recoverable /* Default, -a, -g. */
181 /* Which member(s) of `struct termios' a mode uses. */
182 enum mode_type
184 control, input, output, local, combination
187 /* Flags for `struct mode_info'. */
188 #define SANE_SET 1 /* Set in `sane' mode. */
189 #define SANE_UNSET 2 /* Unset in `sane' mode. */
190 #define REV 4 /* Can be turned off by prepending `-'. */
191 #define OMIT 8 /* Don't display value. */
193 /* Each mode. */
194 struct mode_info
196 const char *name; /* Name given on command line. */
197 enum mode_type type; /* Which structure element to change. */
198 char flags; /* Setting and display options. */
199 unsigned long bits; /* Bits to set for this mode. */
200 unsigned long mask; /* Other bits to turn off for this mode. */
203 static struct mode_info const mode_info[] =
205 {"parenb", control, REV, PARENB, 0},
206 {"parodd", control, REV, PARODD, 0},
207 {"cs5", control, 0, CS5, CSIZE},
208 {"cs6", control, 0, CS6, CSIZE},
209 {"cs7", control, 0, CS7, CSIZE},
210 {"cs8", control, 0, CS8, CSIZE},
211 {"hupcl", control, REV, HUPCL, 0},
212 {"hup", control, REV | OMIT, HUPCL, 0},
213 {"cstopb", control, REV, CSTOPB, 0},
214 {"cread", control, SANE_SET | REV, CREAD, 0},
215 {"clocal", control, REV, CLOCAL, 0},
216 #ifdef CRTSCTS
217 {"crtscts", control, REV, CRTSCTS, 0},
218 #endif
220 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
221 {"brkint", input, SANE_SET | REV, BRKINT, 0},
222 {"ignpar", input, REV, IGNPAR, 0},
223 {"parmrk", input, REV, PARMRK, 0},
224 {"inpck", input, REV, INPCK, 0},
225 {"istrip", input, REV, ISTRIP, 0},
226 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
227 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
228 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
229 {"ixon", input, REV, IXON, 0},
230 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
231 {"tandem", input, REV | OMIT, IXOFF, 0},
232 #ifdef IUCLC
233 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
234 #endif
235 #ifdef IXANY
236 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
237 #endif
238 #ifdef IMAXBEL
239 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
240 #endif
241 #ifdef IUTF8
242 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
243 #endif
245 {"opost", output, SANE_SET | REV, OPOST, 0},
246 #ifdef OLCUC
247 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
248 #endif
249 #ifdef OCRNL
250 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
251 #endif
252 #ifdef ONLCR
253 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
254 #endif
255 #ifdef ONOCR
256 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
257 #endif
258 #ifdef ONLRET
259 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
260 #endif
261 #ifdef OFILL
262 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
263 #endif
264 #ifdef OFDEL
265 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
266 #endif
267 #ifdef NLDLY
268 {"nl1", output, SANE_UNSET, NL1, NLDLY},
269 {"nl0", output, SANE_SET, NL0, NLDLY},
270 #endif
271 #ifdef CRDLY
272 {"cr3", output, SANE_UNSET, CR3, CRDLY},
273 {"cr2", output, SANE_UNSET, CR2, CRDLY},
274 {"cr1", output, SANE_UNSET, CR1, CRDLY},
275 {"cr0", output, SANE_SET, CR0, CRDLY},
276 #endif
277 #ifdef TABDLY
278 # ifdef TAB3
279 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
280 # endif
281 # ifdef TAB2
282 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
283 # endif
284 # ifdef TAB1
285 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
286 # endif
287 # ifdef TAB0
288 {"tab0", output, SANE_SET, TAB0, TABDLY},
289 # endif
290 #else
291 # ifdef OXTABS
292 {"tab3", output, SANE_UNSET, OXTABS, 0},
293 # endif
294 #endif
295 #ifdef BSDLY
296 {"bs1", output, SANE_UNSET, BS1, BSDLY},
297 {"bs0", output, SANE_SET, BS0, BSDLY},
298 #endif
299 #ifdef VTDLY
300 {"vt1", output, SANE_UNSET, VT1, VTDLY},
301 {"vt0", output, SANE_SET, VT0, VTDLY},
302 #endif
303 #ifdef FFDLY
304 {"ff1", output, SANE_UNSET, FF1, FFDLY},
305 {"ff0", output, SANE_SET, FF0, FFDLY},
306 #endif
308 {"isig", local, SANE_SET | REV, ISIG, 0},
309 {"icanon", local, SANE_SET | REV, ICANON, 0},
310 #ifdef IEXTEN
311 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
312 #endif
313 {"echo", local, SANE_SET | REV, ECHO, 0},
314 {"echoe", local, SANE_SET | REV, ECHOE, 0},
315 {"crterase", local, REV | OMIT, ECHOE, 0},
316 {"echok", local, SANE_SET | REV, ECHOK, 0},
317 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
318 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
319 #ifdef XCASE
320 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
321 #endif
322 #ifdef TOSTOP
323 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
324 #endif
325 #ifdef ECHOPRT
326 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
327 {"prterase", local, REV | OMIT, ECHOPRT, 0},
328 #endif
329 #ifdef ECHOCTL
330 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
331 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
332 #endif
333 #ifdef ECHOKE
334 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
335 {"crtkill", local, REV | OMIT, ECHOKE, 0},
336 #endif
338 {"evenp", combination, REV | OMIT, 0, 0},
339 {"parity", combination, REV | OMIT, 0, 0},
340 {"oddp", combination, REV | OMIT, 0, 0},
341 {"nl", combination, REV | OMIT, 0, 0},
342 {"ek", combination, OMIT, 0, 0},
343 {"sane", combination, OMIT, 0, 0},
344 {"cooked", combination, REV | OMIT, 0, 0},
345 {"raw", combination, REV | OMIT, 0, 0},
346 {"pass8", combination, REV | OMIT, 0, 0},
347 {"litout", combination, REV | OMIT, 0, 0},
348 {"cbreak", combination, REV | OMIT, 0, 0},
349 #ifdef IXANY
350 {"decctlq", combination, REV | OMIT, 0, 0},
351 #endif
352 #if defined TABDLY || defined OXTABS
353 {"tabs", combination, REV | OMIT, 0, 0},
354 #endif
355 #if defined XCASE && defined IUCLC && defined OLCUC
356 {"lcase", combination, REV | OMIT, 0, 0},
357 {"LCASE", combination, REV | OMIT, 0, 0},
358 #endif
359 {"crt", combination, OMIT, 0, 0},
360 {"dec", combination, OMIT, 0, 0},
362 {NULL, control, 0, 0, 0}
365 /* Control character settings. */
366 struct control_info
368 const char *name; /* Name given on command line. */
369 cc_t saneval; /* Value to set for `stty sane'. */
370 size_t offset; /* Offset in c_cc. */
373 /* Control characters. */
375 static struct control_info const control_info[] =
377 {"intr", CINTR, VINTR},
378 {"quit", CQUIT, VQUIT},
379 {"erase", CERASE, VERASE},
380 {"kill", CKILL, VKILL},
381 {"eof", CEOF, VEOF},
382 {"eol", CEOL, VEOL},
383 #ifdef VEOL2
384 {"eol2", CEOL2, VEOL2},
385 #endif
386 #ifdef VSWTCH
387 {"swtch", CSWTCH, VSWTCH},
388 #endif
389 {"start", CSTART, VSTART},
390 {"stop", CSTOP, VSTOP},
391 {"susp", CSUSP, VSUSP},
392 #ifdef VDSUSP
393 {"dsusp", CDSUSP, VDSUSP},
394 #endif
395 #ifdef VREPRINT
396 {"rprnt", CRPRNT, VREPRINT},
397 #else
398 # ifdef CREPRINT /* HPUX 10.20 needs this */
399 {"rprnt", CRPRNT, CREPRINT},
400 # endif
401 #endif
402 #ifdef VWERASE
403 {"werase", CWERASE, VWERASE},
404 #endif
405 #ifdef VLNEXT
406 {"lnext", CLNEXT, VLNEXT},
407 #endif
408 #ifdef VFLUSHO
409 {"flush", CFLUSHO, VFLUSHO},
410 #endif
411 #ifdef VSTATUS
412 {"status", CSTATUS, VSTATUS},
413 #endif
415 /* These must be last because of the display routines. */
416 {"min", 1, VMIN},
417 {"time", 0, VTIME},
418 {NULL, 0, 0}
421 static char const *visible (cc_t ch);
422 static unsigned long int baud_to_value (speed_t speed);
423 static bool recover_mode (char const *arg, struct termios *mode);
424 static int screen_columns (void);
425 static bool set_mode (struct mode_info const *info, bool reversed,
426 struct termios *mode);
427 static unsigned long int integer_arg (const char *s, unsigned long int max);
428 static speed_t string_to_baud (const char *arg);
429 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
430 static void display_all (struct termios *mode, char const *device_name);
431 static void display_changed (struct termios *mode);
432 static void display_recoverable (struct termios *mode);
433 static void display_settings (enum output_type output_type,
434 struct termios *mode,
435 const char *device_name);
436 static void display_speed (struct termios *mode, bool fancy);
437 static void display_window_size (bool fancy, char const *device_name);
438 static void sane_mode (struct termios *mode);
439 static void set_control_char (struct control_info const *info,
440 const char *arg,
441 struct termios *mode);
442 static void set_speed (enum speed_setting type, const char *arg,
443 struct termios *mode);
444 static void set_window_size (int rows, int cols, char const *device_name);
446 /* The width of the screen, for output wrapping. */
447 static int max_col;
449 /* Current position, to know when to wrap. */
450 static int current_col;
452 static struct option const longopts[] =
454 {"all", no_argument, NULL, 'a'},
455 {"save", no_argument, NULL, 'g'},
456 {"file", required_argument, NULL, 'F'},
457 {GETOPT_HELP_OPTION_DECL},
458 {GETOPT_VERSION_OPTION_DECL},
459 {NULL, 0, NULL, 0}
462 static void wrapf (const char *message, ...)
463 __attribute__ ((__format__ (__printf__, 1, 2)));
465 /* Print format string MESSAGE and optional args.
466 Wrap to next line first if it won't fit.
467 Print a space first unless MESSAGE will start a new line. */
469 static void
470 wrapf (const char *message,...)
472 va_list args;
473 char *buf;
474 int buflen;
476 va_start (args, message);
477 buflen = vasprintf (&buf, message, args);
478 va_end (args);
480 if (buflen < 0)
481 xalloc_die ();
483 if (0 < current_col)
485 if (max_col - current_col < buflen)
487 putchar ('\n');
488 current_col = 0;
490 else
492 putchar (' ');
493 current_col++;
497 fputs (buf, stdout);
498 free (buf);
499 current_col += buflen;
502 void
503 usage (int status)
505 if (status != EXIT_SUCCESS)
506 emit_try_help ();
507 else
509 printf (_("\
510 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
511 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
512 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
514 program_name, program_name, program_name);
515 fputs (_("\
516 Print or change terminal characteristics.\n\
518 -a, --all print all current settings in human-readable form\n\
519 -g, --save print all current settings in a stty-readable form\n\
520 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
521 "), stdout);
522 fputs (HELP_OPTION_DESCRIPTION, stdout);
523 fputs (VERSION_OPTION_DESCRIPTION, stdout);
524 fputs (_("\
526 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
527 settings. The underlying system defines which settings are available.\n\
528 "), stdout);
529 fputs (_("\
531 Special characters:\n\
532 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
533 eof CHAR CHAR will send an end of file (terminate the input)\n\
534 eol CHAR CHAR will end the line\n\
535 "), stdout);
536 fputs (_("\
537 * eol2 CHAR alternate CHAR for ending the line\n\
538 erase CHAR CHAR will erase the last character typed\n\
539 intr CHAR CHAR will send an interrupt signal\n\
540 kill CHAR CHAR will erase the current line\n\
541 "), stdout);
542 fputs (_("\
543 * lnext CHAR CHAR will enter the next character quoted\n\
544 quit CHAR CHAR will send a quit signal\n\
545 * rprnt CHAR CHAR will redraw the current line\n\
546 start CHAR CHAR will restart the output after stopping it\n\
547 "), stdout);
548 fputs (_("\
549 stop CHAR CHAR will stop the output\n\
550 susp CHAR CHAR will send a terminal stop signal\n\
551 * swtch CHAR CHAR will switch to a different shell layer\n\
552 * werase CHAR CHAR will erase the last word typed\n\
553 "), stdout);
554 fputs (_("\
556 Special settings:\n\
557 N set the input and output speeds to N bauds\n\
558 * cols N tell the kernel that the terminal has N columns\n\
559 * columns N same as cols N\n\
560 "), stdout);
561 fputs (_("\
562 ispeed N set the input speed to N\n\
563 * line N use line discipline N\n\
564 min N with -icanon, set N characters minimum for a completed read\n\
565 ospeed N set the output speed to N\n\
566 "), stdout);
567 fputs (_("\
568 * rows N tell the kernel that the terminal has N rows\n\
569 * size print the number of rows and columns according to the kernel\n\
570 speed print the terminal speed\n\
571 time N with -icanon, set read timeout of N tenths of a second\n\
572 "), stdout);
573 fputs (_("\
575 Control settings:\n\
576 [-]clocal disable modem control signals\n\
577 [-]cread allow input to be received\n\
578 * [-]crtscts enable RTS/CTS handshaking\n\
579 csN set character size to N bits, N in [5..8]\n\
580 "), stdout);
581 fputs (_("\
582 [-]cstopb use two stop bits per character (one with `-')\n\
583 [-]hup send a hangup signal when the last process closes the tty\n\
584 [-]hupcl same as [-]hup\n\
585 [-]parenb generate parity bit in output and expect parity bit in input\n\
586 [-]parodd set odd parity (even with `-')\n\
587 "), stdout);
588 fputs (_("\
590 Input settings:\n\
591 [-]brkint breaks cause an interrupt signal\n\
592 [-]icrnl translate carriage return to newline\n\
593 [-]ignbrk ignore break characters\n\
594 [-]igncr ignore carriage return\n\
595 "), stdout);
596 fputs (_("\
597 [-]ignpar ignore characters with parity errors\n\
598 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
599 [-]inlcr translate newline to carriage return\n\
600 [-]inpck enable input parity checking\n\
601 [-]istrip clear high (8th) bit of input characters\n\
602 "), stdout);
603 fputs (_("\
604 * [-]iutf8 assume input characters are UTF-8 encoded\n\
605 "), stdout);
606 fputs (_("\
607 * [-]iuclc translate uppercase characters to lowercase\n\
608 * [-]ixany let any character restart output, not only start character\n\
609 [-]ixoff enable sending of start/stop characters\n\
610 [-]ixon enable XON/XOFF flow control\n\
611 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
612 [-]tandem same as [-]ixoff\n\
613 "), stdout);
614 fputs (_("\
616 Output settings:\n\
617 * bsN backspace delay style, N in [0..1]\n\
618 * crN carriage return delay style, N in [0..3]\n\
619 * ffN form feed delay style, N in [0..1]\n\
620 * nlN newline delay style, N in [0..1]\n\
621 "), stdout);
622 fputs (_("\
623 * [-]ocrnl translate carriage return to newline\n\
624 * [-]ofdel use delete characters for fill instead of null characters\n\
625 * [-]ofill use fill (padding) characters instead of timing for delays\n\
626 * [-]olcuc translate lowercase characters to uppercase\n\
627 * [-]onlcr translate newline to carriage return-newline\n\
628 * [-]onlret newline performs a carriage return\n\
629 "), stdout);
630 fputs (_("\
631 * [-]onocr do not print carriage returns in the first column\n\
632 [-]opost postprocess output\n\
633 * tabN horizontal tab delay style, N in [0..3]\n\
634 * tabs same as tab0\n\
635 * -tabs same as tab3\n\
636 * vtN vertical tab delay style, N in [0..1]\n\
637 "), stdout);
638 fputs (_("\
640 Local settings:\n\
641 [-]crterase echo erase characters as backspace-space-backspace\n\
642 * crtkill kill all line by obeying the echoprt and echoe settings\n\
643 * -crtkill kill all line by obeying the echoctl and echok settings\n\
644 "), stdout);
645 fputs (_("\
646 * [-]ctlecho echo control characters in hat notation (`^c')\n\
647 [-]echo echo input characters\n\
648 * [-]echoctl same as [-]ctlecho\n\
649 [-]echoe same as [-]crterase\n\
650 [-]echok echo a newline after a kill character\n\
651 "), stdout);
652 fputs (_("\
653 * [-]echoke same as [-]crtkill\n\
654 [-]echonl echo newline even if not echoing other characters\n\
655 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
656 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
657 [-]iexten enable non-POSIX special characters\n\
658 "), stdout);
659 fputs (_("\
660 [-]isig enable interrupt, quit, and suspend special characters\n\
661 [-]noflsh disable flushing after interrupt and quit special characters\n\
662 * [-]prterase same as [-]echoprt\n\
663 * [-]tostop stop background jobs that try to write to the terminal\n\
664 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
665 "), stdout);
666 fputs (_("\
668 Combination settings:\n\
669 * [-]LCASE same as [-]lcase\n\
670 cbreak same as -icanon\n\
671 -cbreak same as icanon\n\
672 "), stdout);
673 fputs (_("\
674 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
675 icanon, eof and eol characters to their default values\n\
676 -cooked same as raw\n\
677 crt same as echoe echoctl echoke\n\
678 "), stdout);
679 fputs (_("\
680 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
681 kill ^u\n\
682 * [-]decctlq same as [-]ixany\n\
683 ek erase and kill characters to their default values\n\
684 evenp same as parenb -parodd cs7\n\
685 "), stdout);
686 fputs (_("\
687 -evenp same as -parenb cs8\n\
688 * [-]lcase same as xcase iuclc olcuc\n\
689 litout same as -parenb -istrip -opost cs8\n\
690 -litout same as parenb istrip opost cs7\n\
691 nl same as -icrnl -onlcr\n\
692 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
693 "), stdout);
694 fputs (_("\
695 oddp same as parenb parodd cs7\n\
696 -oddp same as -parenb cs8\n\
697 [-]parity same as [-]evenp\n\
698 pass8 same as -parenb -istrip cs8\n\
699 -pass8 same as parenb istrip cs7\n\
700 "), stdout);
701 fputs (_("\
702 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
703 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
704 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
705 -raw same as cooked\n\
706 "), stdout);
707 fputs (_("\
708 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
709 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
710 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
711 isig icanon iexten echo echoe echok -echonl -noflsh\n\
712 -xcase -tostop -echoprt echoctl echoke, all special\n\
713 characters to their default values\n\
714 "), stdout);
715 fputs (_("\
717 Handle the tty line connected to standard input. Without arguments,\n\
718 prints baud rate, line discipline, and deviations from stty sane. In\n\
719 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
720 127; special values ^- or undef used to disable special characters.\n\
721 "), stdout);
722 emit_ancillary_info ();
724 exit (status);
728 main (int argc, char **argv)
730 /* Initialize to all zeroes so there is no risk memcmp will report a
731 spurious difference in an uninitialized portion of the structure. */
732 struct termios mode = { 0, };
734 enum output_type output_type;
735 int optc;
736 int argi = 0;
737 int opti = 1;
738 bool require_set_attr;
739 bool speed_was_set;
740 bool verbose_output;
741 bool recoverable_output;
742 int k;
743 bool noargs = true;
744 char *file_name = NULL;
745 const char *device_name;
747 initialize_main (&argc, &argv);
748 set_program_name (argv[0]);
749 setlocale (LC_ALL, "");
750 bindtextdomain (PACKAGE, LOCALEDIR);
751 textdomain (PACKAGE);
753 atexit (close_stdout);
755 output_type = changed;
756 verbose_output = false;
757 recoverable_output = false;
759 /* Don't print error messages for unrecognized options. */
760 opterr = 0;
762 /* If any new options are ever added to stty, the short options MUST
763 NOT allow any ambiguity with the stty settings. For example, the
764 stty setting "-gagFork" would not be feasible, since it will be
765 parsed as "-g -a -g -F ork". If you change anything about how
766 stty parses options, be sure it still works with combinations of
767 short and long options, --, POSIXLY_CORRECT, etc. */
769 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
770 longopts, NULL))
771 != -1)
773 switch (optc)
775 case 'a':
776 verbose_output = true;
777 output_type = all;
778 break;
780 case 'g':
781 recoverable_output = true;
782 output_type = recoverable;
783 break;
785 case 'F':
786 if (file_name)
787 error (EXIT_FAILURE, 0, _("only one device may be specified"));
788 file_name = optarg;
789 break;
791 case_GETOPT_HELP_CHAR;
793 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
795 default:
796 noargs = false;
798 /* Skip the argument containing this unrecognized option;
799 the 2nd pass will analyze it. */
800 argi += opti;
802 /* Restart getopt_long from the first unskipped argument. */
803 opti = 1;
804 optind = 0;
806 break;
809 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
810 while (opti < optind)
811 argv[argi + opti++] = NULL;
814 /* Specifying both -a and -g gets an error. */
815 if (verbose_output && recoverable_output)
816 error (EXIT_FAILURE, 0,
817 _("the options for verbose and stty-readable output styles are\n"
818 "mutually exclusive"));
820 /* Specifying any other arguments with -a or -g gets an error. */
821 if (!noargs && (verbose_output || recoverable_output))
822 error (EXIT_FAILURE, 0,
823 _("when specifying an output style, modes may not be set"));
825 /* FIXME: it'd be better not to open the file until we've verified
826 that all arguments are valid. Otherwise, we could end up doing
827 only some of the requested operations and then failing, probably
828 leaving things in an undesirable state. */
830 if (file_name)
832 int fdflags;
833 device_name = file_name;
834 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
835 error (EXIT_FAILURE, errno, "%s", device_name);
836 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
837 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
838 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
839 device_name);
841 else
842 device_name = _("standard input");
844 if (tcgetattr (STDIN_FILENO, &mode))
845 error (EXIT_FAILURE, errno, "%s", device_name);
847 if (verbose_output || recoverable_output || noargs)
849 max_col = screen_columns ();
850 current_col = 0;
851 display_settings (output_type, &mode, device_name);
852 exit (EXIT_SUCCESS);
855 speed_was_set = false;
856 require_set_attr = false;
857 for (k = 1; k < argc; k++)
859 char const *arg = argv[k];
860 bool match_found = false;
861 bool reversed = false;
862 int i;
864 if (! arg)
865 continue;
867 if (arg[0] == '-')
869 ++arg;
870 reversed = true;
872 for (i = 0; mode_info[i].name != NULL; ++i)
874 if (STREQ (arg, mode_info[i].name))
876 match_found = set_mode (&mode_info[i], reversed, &mode);
877 require_set_attr = true;
878 break;
881 if (!match_found && reversed)
883 error (0, 0, _("invalid argument %s"), quote (arg - 1));
884 usage (EXIT_FAILURE);
886 if (!match_found)
888 for (i = 0; control_info[i].name != NULL; ++i)
890 if (STREQ (arg, control_info[i].name))
892 if (k == argc - 1)
894 error (0, 0, _("missing argument to %s"), quote (arg));
895 usage (EXIT_FAILURE);
897 match_found = true;
898 ++k;
899 set_control_char (&control_info[i], argv[k], &mode);
900 require_set_attr = true;
901 break;
905 if (!match_found)
907 if (STREQ (arg, "ispeed"))
909 if (k == argc - 1)
911 error (0, 0, _("missing argument to %s"), quote (arg));
912 usage (EXIT_FAILURE);
914 ++k;
915 set_speed (input_speed, argv[k], &mode);
916 speed_was_set = true;
917 require_set_attr = true;
919 else if (STREQ (arg, "ospeed"))
921 if (k == argc - 1)
923 error (0, 0, _("missing argument to %s"), quote (arg));
924 usage (EXIT_FAILURE);
926 ++k;
927 set_speed (output_speed, argv[k], &mode);
928 speed_was_set = true;
929 require_set_attr = true;
931 #ifdef TIOCGWINSZ
932 else if (STREQ (arg, "rows"))
934 if (k == argc - 1)
936 error (0, 0, _("missing argument to %s"), quote (arg));
937 usage (EXIT_FAILURE);
939 ++k;
940 set_window_size (integer_arg (argv[k], INT_MAX), -1,
941 device_name);
943 else if (STREQ (arg, "cols")
944 || STREQ (arg, "columns"))
946 if (k == argc - 1)
948 error (0, 0, _("missing argument to %s"), quote (arg));
949 usage (EXIT_FAILURE);
951 ++k;
952 set_window_size (-1, integer_arg (argv[k], INT_MAX),
953 device_name);
955 else if (STREQ (arg, "size"))
957 max_col = screen_columns ();
958 current_col = 0;
959 display_window_size (false, device_name);
961 #endif
962 #ifdef HAVE_C_LINE
963 else if (STREQ (arg, "line"))
965 unsigned long int value;
966 if (k == argc - 1)
968 error (0, 0, _("missing argument to %s"), quote (arg));
969 usage (EXIT_FAILURE);
971 ++k;
972 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
973 if (mode.c_line != value)
974 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
975 require_set_attr = true;
977 #endif
978 else if (STREQ (arg, "speed"))
980 max_col = screen_columns ();
981 display_speed (&mode, false);
983 else if (string_to_baud (arg) != (speed_t) -1)
985 set_speed (both_speeds, arg, &mode);
986 speed_was_set = true;
987 require_set_attr = true;
989 else
991 if (! recover_mode (arg, &mode))
993 error (0, 0, _("invalid argument %s"), quote (arg));
994 usage (EXIT_FAILURE);
996 require_set_attr = true;
1001 if (require_set_attr)
1003 /* Initialize to all zeroes so there is no risk memcmp will report a
1004 spurious difference in an uninitialized portion of the structure. */
1005 struct termios new_mode = { 0, };
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 if (tcgetattr (STDIN_FILENO, &new_mode))
1018 error (EXIT_FAILURE, errno, "%s", device_name);
1020 /* Normally, one shouldn't use memcmp to compare structures that
1021 may have `holes' containing uninitialized data, but we have been
1022 careful to initialize the storage of these two variables to all
1023 zeroes. One might think it more efficient simply to compare the
1024 modified fields, but that would require enumerating those fields --
1025 and not all systems have the same fields in this structure. */
1027 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1029 #ifdef CIBAUD
1030 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1031 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1032 sometimes (m1 != m2). The only difference is in the four bits
1033 of the c_cflag field corresponding to the baud rate. To save
1034 Sun users a little confusion, don't report an error if this
1035 happens. But suppress the error only if we haven't tried to
1036 set the baud rate explicitly -- otherwise we'd never give an
1037 error for a true failure to set the baud rate. */
1039 new_mode.c_cflag &= (~CIBAUD);
1040 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1041 #endif
1043 error (EXIT_FAILURE, 0,
1044 _("%s: unable to perform all requested operations"),
1045 device_name);
1046 #ifdef TESTING
1048 size_t i;
1049 printf ("new_mode: mode\n");
1050 for (i = 0; i < sizeof (new_mode); i++)
1051 printf ("0x%02x: 0x%02x\n",
1052 *(((unsigned char *) &new_mode) + i),
1053 *(((unsigned char *) &mode) + i));
1055 #endif
1060 exit (EXIT_SUCCESS);
1063 /* Return false if not applied because not reversible; otherwise
1064 return true. */
1066 static bool
1067 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1069 tcflag_t *bitsp;
1071 if (reversed && (info->flags & REV) == 0)
1072 return false;
1074 bitsp = mode_type_flag (info->type, mode);
1076 if (bitsp == NULL)
1078 /* Combination mode. */
1079 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1081 if (reversed)
1082 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1083 else
1084 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1086 else if (STREQ (info->name, "oddp"))
1088 if (reversed)
1089 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1090 else
1091 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1093 else if (STREQ (info->name, "nl"))
1095 if (reversed)
1097 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1098 mode->c_oflag = (mode->c_oflag
1099 #ifdef ONLCR
1100 | ONLCR
1101 #endif
1103 #ifdef OCRNL
1104 & ~OCRNL
1105 #endif
1106 #ifdef ONLRET
1107 & ~ONLRET
1108 #endif
1111 else
1113 mode->c_iflag = mode->c_iflag & ~ICRNL;
1114 #ifdef ONLCR
1115 mode->c_oflag = mode->c_oflag & ~ONLCR;
1116 #endif
1119 else if (STREQ (info->name, "ek"))
1121 mode->c_cc[VERASE] = CERASE;
1122 mode->c_cc[VKILL] = CKILL;
1124 else if (STREQ (info->name, "sane"))
1125 sane_mode (mode);
1126 else if (STREQ (info->name, "cbreak"))
1128 if (reversed)
1129 mode->c_lflag |= ICANON;
1130 else
1131 mode->c_lflag &= ~ICANON;
1133 else if (STREQ (info->name, "pass8"))
1135 if (reversed)
1137 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1138 mode->c_iflag |= ISTRIP;
1140 else
1142 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1143 mode->c_iflag &= ~ISTRIP;
1146 else if (STREQ (info->name, "litout"))
1148 if (reversed)
1150 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1151 mode->c_iflag |= ISTRIP;
1152 mode->c_oflag |= OPOST;
1154 else
1156 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1157 mode->c_iflag &= ~ISTRIP;
1158 mode->c_oflag &= ~OPOST;
1161 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1163 if ((info->name[0] == 'r' && reversed)
1164 || (info->name[0] == 'c' && !reversed))
1166 /* Cooked mode. */
1167 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1168 mode->c_oflag |= OPOST;
1169 mode->c_lflag |= ISIG | ICANON;
1170 #if VMIN == VEOF
1171 mode->c_cc[VEOF] = CEOF;
1172 #endif
1173 #if VTIME == VEOL
1174 mode->c_cc[VEOL] = CEOL;
1175 #endif
1177 else
1179 /* Raw mode. */
1180 mode->c_iflag = 0;
1181 mode->c_oflag &= ~OPOST;
1182 mode->c_lflag &= ~(ISIG | ICANON
1183 #ifdef XCASE
1184 | XCASE
1185 #endif
1187 mode->c_cc[VMIN] = 1;
1188 mode->c_cc[VTIME] = 0;
1191 #ifdef IXANY
1192 else if (STREQ (info->name, "decctlq"))
1194 if (reversed)
1195 mode->c_iflag |= IXANY;
1196 else
1197 mode->c_iflag &= ~IXANY;
1199 #endif
1200 #ifdef TABDLY
1201 else if (STREQ (info->name, "tabs"))
1203 if (reversed)
1204 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1205 else
1206 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1208 #else
1209 # ifdef OXTABS
1210 else if (STREQ (info->name, "tabs"))
1212 if (reversed)
1213 mode->c_oflag = mode->c_oflag | OXTABS;
1214 else
1215 mode->c_oflag = mode->c_oflag & ~OXTABS;
1217 # endif
1218 #endif
1219 #if defined XCASE && defined IUCLC && defined OLCUC
1220 else if (STREQ (info->name, "lcase")
1221 || STREQ (info->name, "LCASE"))
1223 if (reversed)
1225 mode->c_lflag &= ~XCASE;
1226 mode->c_iflag &= ~IUCLC;
1227 mode->c_oflag &= ~OLCUC;
1229 else
1231 mode->c_lflag |= XCASE;
1232 mode->c_iflag |= IUCLC;
1233 mode->c_oflag |= OLCUC;
1236 #endif
1237 else if (STREQ (info->name, "crt"))
1238 mode->c_lflag |= ECHOE
1239 #ifdef ECHOCTL
1240 | ECHOCTL
1241 #endif
1242 #ifdef ECHOKE
1243 | ECHOKE
1244 #endif
1246 else if (STREQ (info->name, "dec"))
1248 mode->c_cc[VINTR] = 3; /* ^C */
1249 mode->c_cc[VERASE] = 127; /* DEL */
1250 mode->c_cc[VKILL] = 21; /* ^U */
1251 mode->c_lflag |= ECHOE
1252 #ifdef ECHOCTL
1253 | ECHOCTL
1254 #endif
1255 #ifdef ECHOKE
1256 | ECHOKE
1257 #endif
1259 #ifdef IXANY
1260 mode->c_iflag &= ~IXANY;
1261 #endif
1264 else if (reversed)
1265 *bitsp = *bitsp & ~info->mask & ~info->bits;
1266 else
1267 *bitsp = (*bitsp & ~info->mask) | info->bits;
1269 return true;
1272 static void
1273 set_control_char (struct control_info const *info, const char *arg,
1274 struct termios *mode)
1276 unsigned long int value;
1278 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1279 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1280 else if (arg[0] == '\0' || arg[1] == '\0')
1281 value = to_uchar (arg[0]);
1282 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1283 value = _POSIX_VDISABLE;
1284 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1286 if (arg[1] == '?')
1287 value = 127;
1288 else
1289 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1291 else
1292 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1293 mode->c_cc[info->offset] = value;
1296 static void
1297 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1299 speed_t baud;
1301 baud = string_to_baud (arg);
1302 if (type == input_speed || type == both_speeds)
1303 cfsetispeed (mode, baud);
1304 if (type == output_speed || type == both_speeds)
1305 cfsetospeed (mode, baud);
1308 #ifdef TIOCGWINSZ
1310 static int
1311 get_win_size (int fd, struct winsize *win)
1313 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1314 return err;
1317 static void
1318 set_window_size (int rows, int cols, char const *device_name)
1320 struct winsize win;
1322 if (get_win_size (STDIN_FILENO, &win))
1324 if (errno != EINVAL)
1325 error (EXIT_FAILURE, errno, "%s", device_name);
1326 memset (&win, 0, sizeof (win));
1329 if (rows >= 0)
1330 win.ws_row = rows;
1331 if (cols >= 0)
1332 win.ws_col = cols;
1334 # ifdef TIOCSSIZE
1335 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1336 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1337 This comment from sys/ttold.h describes Sun's twisted logic - a better
1338 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1339 At any rate, the problem is gone in Solaris 2.x.
1341 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1342 but they can be disambiguated by checking whether a "struct ttysize"
1343 structure's "ts_lines" field is greater than 64K or not. If so,
1344 it's almost certainly a "struct winsize" instead.
1346 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1347 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1348 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1349 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1350 "stty cols 0 rows 0" would do the right thing. On a little-endian
1351 machine like the sun386i, the problem is the same, but for ws_col == 0.
1353 The workaround is to do the ioctl once with row and col = 1 to set the
1354 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1356 if (win.ws_row == 0 || win.ws_col == 0)
1358 struct ttysize ttysz;
1360 ttysz.ts_lines = win.ws_row;
1361 ttysz.ts_cols = win.ws_col;
1363 win.ws_row = 1;
1364 win.ws_col = 1;
1366 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1367 error (EXIT_FAILURE, errno, "%s", device_name);
1369 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1370 error (EXIT_FAILURE, errno, "%s", device_name);
1371 return;
1373 # endif
1375 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1376 error (EXIT_FAILURE, errno, "%s", device_name);
1379 static void
1380 display_window_size (bool fancy, char const *device_name)
1382 struct winsize win;
1384 if (get_win_size (STDIN_FILENO, &win))
1386 if (errno != EINVAL)
1387 error (EXIT_FAILURE, errno, "%s", device_name);
1388 if (!fancy)
1389 error (EXIT_FAILURE, 0,
1390 _("%s: no size information for this device"), device_name);
1392 else
1394 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1395 win.ws_row, win.ws_col);
1396 if (!fancy)
1397 current_col = 0;
1400 #endif
1402 static int
1403 screen_columns (void)
1405 #ifdef TIOCGWINSZ
1406 struct winsize win;
1408 /* With Solaris 2.[123], this ioctl fails and errno is set to
1409 EINVAL for telnet (but not rlogin) sessions.
1410 On ISC 3.0, it fails for the console and the serial port
1411 (but it works for ptys).
1412 It can also fail on any system when stdout isn't a tty.
1413 In case of any failure, just use the default. */
1414 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1415 return win.ws_col;
1416 #endif
1418 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1419 char *col_string = getenv ("COLUMNS");
1420 long int n_columns;
1421 if (!(col_string != NULL
1422 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1423 && 0 < n_columns
1424 && n_columns <= INT_MAX))
1425 n_columns = 80;
1426 return n_columns;
1430 static tcflag_t * _GL_ATTRIBUTE_PURE
1431 mode_type_flag (enum mode_type type, struct termios *mode)
1433 switch (type)
1435 case control:
1436 return &mode->c_cflag;
1438 case input:
1439 return &mode->c_iflag;
1441 case output:
1442 return &mode->c_oflag;
1444 case local:
1445 return &mode->c_lflag;
1447 case combination:
1448 return NULL;
1450 default:
1451 abort ();
1455 static void
1456 display_settings (enum output_type output_type, struct termios *mode,
1457 char const *device_name)
1459 switch (output_type)
1461 case changed:
1462 display_changed (mode);
1463 break;
1465 case all:
1466 display_all (mode, device_name);
1467 break;
1469 case recoverable:
1470 display_recoverable (mode);
1471 break;
1475 static void
1476 display_changed (struct termios *mode)
1478 int i;
1479 bool empty_line;
1480 tcflag_t *bitsp;
1481 unsigned long mask;
1482 enum mode_type prev_type = control;
1484 display_speed (mode, true);
1485 #ifdef HAVE_C_LINE
1486 wrapf ("line = %d;", mode->c_line);
1487 #endif
1488 putchar ('\n');
1489 current_col = 0;
1491 empty_line = true;
1492 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1494 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1495 continue;
1496 /* If swtch is the same as susp, don't print both. */
1497 #if VSWTCH == VSUSP
1498 if (STREQ (control_info[i].name, "swtch"))
1499 continue;
1500 #endif
1501 /* If eof uses the same slot as min, only print whichever applies. */
1502 #if VEOF == VMIN
1503 if ((mode->c_lflag & ICANON) == 0
1504 && (STREQ (control_info[i].name, "eof")
1505 || STREQ (control_info[i].name, "eol")))
1506 continue;
1507 #endif
1509 empty_line = false;
1510 wrapf ("%s = %s;", control_info[i].name,
1511 visible (mode->c_cc[control_info[i].offset]));
1513 if ((mode->c_lflag & ICANON) == 0)
1515 wrapf ("min = %lu; time = %lu;\n",
1516 (unsigned long int) mode->c_cc[VMIN],
1517 (unsigned long int) mode->c_cc[VTIME]);
1519 else if (!empty_line)
1520 putchar ('\n');
1521 current_col = 0;
1523 empty_line = true;
1524 for (i = 0; mode_info[i].name != NULL; ++i)
1526 if (mode_info[i].flags & OMIT)
1527 continue;
1528 if (mode_info[i].type != prev_type)
1530 if (!empty_line)
1532 putchar ('\n');
1533 current_col = 0;
1534 empty_line = true;
1536 prev_type = mode_info[i].type;
1539 bitsp = mode_type_flag (mode_info[i].type, mode);
1540 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1541 if ((*bitsp & mask) == mode_info[i].bits)
1543 if (mode_info[i].flags & SANE_UNSET)
1545 wrapf ("%s", mode_info[i].name);
1546 empty_line = false;
1549 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1551 wrapf ("-%s", mode_info[i].name);
1552 empty_line = false;
1555 if (!empty_line)
1556 putchar ('\n');
1557 current_col = 0;
1560 static void
1561 display_all (struct termios *mode, char const *device_name)
1563 int i;
1564 tcflag_t *bitsp;
1565 unsigned long mask;
1566 enum mode_type prev_type = control;
1568 display_speed (mode, true);
1569 #ifdef TIOCGWINSZ
1570 display_window_size (true, device_name);
1571 #endif
1572 #ifdef HAVE_C_LINE
1573 wrapf ("line = %d;", mode->c_line);
1574 #endif
1575 putchar ('\n');
1576 current_col = 0;
1578 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1580 /* If swtch is the same as susp, don't print both. */
1581 #if VSWTCH == VSUSP
1582 if (STREQ (control_info[i].name, "swtch"))
1583 continue;
1584 #endif
1585 /* If eof uses the same slot as min, only print whichever applies. */
1586 #if VEOF == VMIN
1587 if ((mode->c_lflag & ICANON) == 0
1588 && (STREQ (control_info[i].name, "eof")
1589 || STREQ (control_info[i].name, "eol")))
1590 continue;
1591 #endif
1592 wrapf ("%s = %s;", control_info[i].name,
1593 visible (mode->c_cc[control_info[i].offset]));
1595 #if VEOF == VMIN
1596 if ((mode->c_lflag & ICANON) == 0)
1597 #endif
1598 wrapf ("min = %lu; time = %lu;",
1599 (unsigned long int) mode->c_cc[VMIN],
1600 (unsigned long int) mode->c_cc[VTIME]);
1601 if (current_col != 0)
1602 putchar ('\n');
1603 current_col = 0;
1605 for (i = 0; mode_info[i].name != NULL; ++i)
1607 if (mode_info[i].flags & OMIT)
1608 continue;
1609 if (mode_info[i].type != prev_type)
1611 putchar ('\n');
1612 current_col = 0;
1613 prev_type = mode_info[i].type;
1616 bitsp = mode_type_flag (mode_info[i].type, mode);
1617 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1618 if ((*bitsp & mask) == mode_info[i].bits)
1619 wrapf ("%s", mode_info[i].name);
1620 else if (mode_info[i].flags & REV)
1621 wrapf ("-%s", mode_info[i].name);
1623 putchar ('\n');
1624 current_col = 0;
1627 static void
1628 display_speed (struct termios *mode, bool fancy)
1630 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1631 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1632 baud_to_value (cfgetospeed (mode)));
1633 else
1634 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1635 baud_to_value (cfgetispeed (mode)),
1636 baud_to_value (cfgetospeed (mode)));
1637 if (!fancy)
1638 current_col = 0;
1641 static void
1642 display_recoverable (struct termios *mode)
1644 size_t i;
1646 printf ("%lx:%lx:%lx:%lx",
1647 (unsigned long int) mode->c_iflag,
1648 (unsigned long int) mode->c_oflag,
1649 (unsigned long int) mode->c_cflag,
1650 (unsigned long int) mode->c_lflag);
1651 for (i = 0; i < NCCS; ++i)
1652 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1653 putchar ('\n');
1656 /* NOTE: identical to below, modulo use of tcflag_t */
1657 static int
1658 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1659 char delim)
1661 unsigned long ul;
1662 errno = 0;
1663 ul = strtoul (s, p, base);
1664 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1665 return -1;
1666 *result = ul;
1667 return 0;
1670 /* NOTE: identical to above, modulo use of cc_t */
1671 static int
1672 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1674 unsigned long ul;
1675 errno = 0;
1676 ul = strtoul (s, p, base);
1677 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1678 return -1;
1679 *result = ul;
1680 return 0;
1683 /* Parse the output of display_recoverable.
1684 Return false if any part of it is invalid. */
1685 static bool
1686 recover_mode (char const *arg, struct termios *mode)
1688 tcflag_t flag[4];
1689 char const *s = arg;
1690 size_t i;
1691 for (i = 0; i < 4; i++)
1693 char *p;
1694 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1695 return false;
1696 s = p + 1;
1698 mode->c_iflag = flag[0];
1699 mode->c_oflag = flag[1];
1700 mode->c_cflag = flag[2];
1701 mode->c_lflag = flag[3];
1703 for (i = 0; i < NCCS; ++i)
1705 char *p;
1706 char delim = i < NCCS - 1 ? ':' : '\0';
1707 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1708 return false;
1709 s = p + 1;
1712 return true;
1715 struct speed_map
1717 const char *string; /* ASCII representation. */
1718 speed_t speed; /* Internal form. */
1719 unsigned long int value; /* Numeric value. */
1722 static struct speed_map const speeds[] =
1724 {"0", B0, 0},
1725 {"50", B50, 50},
1726 {"75", B75, 75},
1727 {"110", B110, 110},
1728 {"134", B134, 134},
1729 {"134.5", B134, 134},
1730 {"150", B150, 150},
1731 {"200", B200, 200},
1732 {"300", B300, 300},
1733 {"600", B600, 600},
1734 {"1200", B1200, 1200},
1735 {"1800", B1800, 1800},
1736 {"2400", B2400, 2400},
1737 {"4800", B4800, 4800},
1738 {"9600", B9600, 9600},
1739 {"19200", B19200, 19200},
1740 {"38400", B38400, 38400},
1741 {"exta", B19200, 19200},
1742 {"extb", B38400, 38400},
1743 #ifdef B57600
1744 {"57600", B57600, 57600},
1745 #endif
1746 #ifdef B115200
1747 {"115200", B115200, 115200},
1748 #endif
1749 #ifdef B230400
1750 {"230400", B230400, 230400},
1751 #endif
1752 #ifdef B460800
1753 {"460800", B460800, 460800},
1754 #endif
1755 #ifdef B500000
1756 {"500000", B500000, 500000},
1757 #endif
1758 #ifdef B576000
1759 {"576000", B576000, 576000},
1760 #endif
1761 #ifdef B921600
1762 {"921600", B921600, 921600},
1763 #endif
1764 #ifdef B1000000
1765 {"1000000", B1000000, 1000000},
1766 #endif
1767 #ifdef B1152000
1768 {"1152000", B1152000, 1152000},
1769 #endif
1770 #ifdef B1500000
1771 {"1500000", B1500000, 1500000},
1772 #endif
1773 #ifdef B2000000
1774 {"2000000", B2000000, 2000000},
1775 #endif
1776 #ifdef B2500000
1777 {"2500000", B2500000, 2500000},
1778 #endif
1779 #ifdef B3000000
1780 {"3000000", B3000000, 3000000},
1781 #endif
1782 #ifdef B3500000
1783 {"3500000", B3500000, 3500000},
1784 #endif
1785 #ifdef B4000000
1786 {"4000000", B4000000, 4000000},
1787 #endif
1788 {NULL, 0, 0}
1791 static speed_t _GL_ATTRIBUTE_PURE
1792 string_to_baud (const char *arg)
1794 int i;
1796 for (i = 0; speeds[i].string != NULL; ++i)
1797 if (STREQ (arg, speeds[i].string))
1798 return speeds[i].speed;
1799 return (speed_t) -1;
1802 static unsigned long int _GL_ATTRIBUTE_PURE
1803 baud_to_value (speed_t speed)
1805 int i;
1807 for (i = 0; speeds[i].string != NULL; ++i)
1808 if (speed == speeds[i].speed)
1809 return speeds[i].value;
1810 return 0;
1813 static void
1814 sane_mode (struct termios *mode)
1816 int i;
1817 tcflag_t *bitsp;
1819 for (i = 0; control_info[i].name; ++i)
1821 #if VMIN == VEOF
1822 if (STREQ (control_info[i].name, "min"))
1823 break;
1824 #endif
1825 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1828 for (i = 0; mode_info[i].name != NULL; ++i)
1830 if (mode_info[i].flags & SANE_SET)
1832 bitsp = mode_type_flag (mode_info[i].type, mode);
1833 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1835 else if (mode_info[i].flags & SANE_UNSET)
1837 bitsp = mode_type_flag (mode_info[i].type, mode);
1838 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1843 /* Return a string that is the printable representation of character CH. */
1844 /* Adapted from `cat' by Torbjorn Granlund. */
1846 static const char *
1847 visible (cc_t ch)
1849 static char buf[10];
1850 char *bpout = buf;
1852 if (ch == _POSIX_VDISABLE)
1853 return "<undef>";
1855 if (ch >= 32)
1857 if (ch < 127)
1858 *bpout++ = ch;
1859 else if (ch == 127)
1861 *bpout++ = '^';
1862 *bpout++ = '?';
1864 else
1866 *bpout++ = 'M';
1867 *bpout++ = '-';
1868 if (ch >= 128 + 32)
1870 if (ch < 128 + 127)
1871 *bpout++ = ch - 128;
1872 else
1874 *bpout++ = '^';
1875 *bpout++ = '?';
1878 else
1880 *bpout++ = '^';
1881 *bpout++ = ch - 128 + 64;
1885 else
1887 *bpout++ = '^';
1888 *bpout++ = ch + 64;
1890 *bpout = '\0';
1891 return (const char *) buf;
1894 /* Parse string S as an integer, using decimal radix by default,
1895 but allowing octal and hex numbers as in C. Reject values
1896 larger than MAXVAL. */
1898 static unsigned long int
1899 integer_arg (const char *s, unsigned long int maxval)
1901 unsigned long int value;
1902 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1904 error (0, 0, _("invalid integer argument %s"), quote (s));
1905 usage (EXIT_FAILURE);
1907 return value;