maint: avoid new syntax-check failure
[coreutils/ericb.git] / src / stty.c
blob5f5211b5e59e0b1b8089766bf36c40c3cbda7c79
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005, 2007-2011 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 fprintf (stderr, _("Try `%s --help' for more information.\n"),
507 program_name);
508 else
510 printf (_("\
511 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
512 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
513 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
515 program_name, program_name, program_name);
516 fputs (_("\
517 Print or change terminal characteristics.\n\
519 -a, --all print all current settings in human-readable form\n\
520 -g, --save print all current settings in a stty-readable form\n\
521 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
522 "), stdout);
523 fputs (HELP_OPTION_DESCRIPTION, stdout);
524 fputs (VERSION_OPTION_DESCRIPTION, stdout);
525 fputs (_("\
527 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
528 settings. The underlying system defines which settings are available.\n\
529 "), stdout);
530 fputs (_("\
532 Special characters:\n\
533 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
534 eof CHAR CHAR will send an end of file (terminate the input)\n\
535 eol CHAR CHAR will end the line\n\
536 "), stdout);
537 fputs (_("\
538 * eol2 CHAR alternate CHAR for ending the line\n\
539 erase CHAR CHAR will erase the last character typed\n\
540 intr CHAR CHAR will send an interrupt signal\n\
541 kill CHAR CHAR will erase the current line\n\
542 "), stdout);
543 fputs (_("\
544 * lnext CHAR CHAR will enter the next character quoted\n\
545 quit CHAR CHAR will send a quit signal\n\
546 * rprnt CHAR CHAR will redraw the current line\n\
547 start CHAR CHAR will restart the output after stopping it\n\
548 "), stdout);
549 fputs (_("\
550 stop CHAR CHAR will stop the output\n\
551 susp CHAR CHAR will send a terminal stop signal\n\
552 * swtch CHAR CHAR will switch to a different shell layer\n\
553 * werase CHAR CHAR will erase the last word typed\n\
554 "), stdout);
555 fputs (_("\
557 Special settings:\n\
558 N set the input and output speeds to N bauds\n\
559 * cols N tell the kernel that the terminal has N columns\n\
560 * columns N same as cols N\n\
561 "), stdout);
562 fputs (_("\
563 ispeed N set the input speed to N\n\
564 * line N use line discipline N\n\
565 min N with -icanon, set N characters minimum for a completed read\n\
566 ospeed N set the output speed to N\n\
567 "), stdout);
568 fputs (_("\
569 * rows N tell the kernel that the terminal has N rows\n\
570 * size print the number of rows and columns according to the kernel\n\
571 speed print the terminal speed\n\
572 time N with -icanon, set read timeout of N tenths of a second\n\
573 "), stdout);
574 fputs (_("\
576 Control settings:\n\
577 [-]clocal disable modem control signals\n\
578 [-]cread allow input to be received\n\
579 * [-]crtscts enable RTS/CTS handshaking\n\
580 csN set character size to N bits, N in [5..8]\n\
581 "), stdout);
582 fputs (_("\
583 [-]cstopb use two stop bits per character (one with `-')\n\
584 [-]hup send a hangup signal when the last process closes the tty\n\
585 [-]hupcl same as [-]hup\n\
586 [-]parenb generate parity bit in output and expect parity bit in input\n\
587 [-]parodd set odd parity (even with `-')\n\
588 "), stdout);
589 fputs (_("\
591 Input settings:\n\
592 [-]brkint breaks cause an interrupt signal\n\
593 [-]icrnl translate carriage return to newline\n\
594 [-]ignbrk ignore break characters\n\
595 [-]igncr ignore carriage return\n\
596 "), stdout);
597 fputs (_("\
598 [-]ignpar ignore characters with parity errors\n\
599 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
600 [-]inlcr translate newline to carriage return\n\
601 [-]inpck enable input parity checking\n\
602 [-]istrip clear high (8th) bit of input characters\n\
603 "), stdout);
604 fputs (_("\
605 * [-]iutf8 assume input characters are UTF-8 encoded\n\
606 "), stdout);
607 fputs (_("\
608 * [-]iuclc translate uppercase characters to lowercase\n\
609 * [-]ixany let any character restart output, not only start character\n\
610 [-]ixoff enable sending of start/stop characters\n\
611 [-]ixon enable XON/XOFF flow control\n\
612 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
613 [-]tandem same as [-]ixoff\n\
614 "), stdout);
615 fputs (_("\
617 Output settings:\n\
618 * bsN backspace delay style, N in [0..1]\n\
619 * crN carriage return delay style, N in [0..3]\n\
620 * ffN form feed delay style, N in [0..1]\n\
621 * nlN newline delay style, N in [0..1]\n\
622 "), stdout);
623 fputs (_("\
624 * [-]ocrnl translate carriage return to newline\n\
625 * [-]ofdel use delete characters for fill instead of null characters\n\
626 * [-]ofill use fill (padding) characters instead of timing for delays\n\
627 * [-]olcuc translate lowercase characters to uppercase\n\
628 * [-]onlcr translate newline to carriage return-newline\n\
629 * [-]onlret newline performs a carriage return\n\
630 "), stdout);
631 fputs (_("\
632 * [-]onocr do not print carriage returns in the first column\n\
633 [-]opost postprocess output\n\
634 * tabN horizontal tab delay style, N in [0..3]\n\
635 * tabs same as tab0\n\
636 * -tabs same as tab3\n\
637 * vtN vertical tab delay style, N in [0..1]\n\
638 "), stdout);
639 fputs (_("\
641 Local settings:\n\
642 [-]crterase echo erase characters as backspace-space-backspace\n\
643 * crtkill kill all line by obeying the echoprt and echoe settings\n\
644 * -crtkill kill all line by obeying the echoctl and echok settings\n\
645 "), stdout);
646 fputs (_("\
647 * [-]ctlecho echo control characters in hat notation (`^c')\n\
648 [-]echo echo input characters\n\
649 * [-]echoctl same as [-]ctlecho\n\
650 [-]echoe same as [-]crterase\n\
651 [-]echok echo a newline after a kill character\n\
652 "), stdout);
653 fputs (_("\
654 * [-]echoke same as [-]crtkill\n\
655 [-]echonl echo newline even if not echoing other characters\n\
656 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
657 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
658 [-]iexten enable non-POSIX special characters\n\
659 "), stdout);
660 fputs (_("\
661 [-]isig enable interrupt, quit, and suspend special characters\n\
662 [-]noflsh disable flushing after interrupt and quit special characters\n\
663 * [-]prterase same as [-]echoprt\n\
664 * [-]tostop stop background jobs that try to write to the terminal\n\
665 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
666 "), stdout);
667 fputs (_("\
669 Combination settings:\n\
670 * [-]LCASE same as [-]lcase\n\
671 cbreak same as -icanon\n\
672 -cbreak same as icanon\n\
673 "), stdout);
674 fputs (_("\
675 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
676 icanon, eof and eol characters to their default values\n\
677 -cooked same as raw\n\
678 crt same as echoe echoctl echoke\n\
679 "), stdout);
680 fputs (_("\
681 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
682 kill ^u\n\
683 * [-]decctlq same as [-]ixany\n\
684 ek erase and kill characters to their default values\n\
685 evenp same as parenb -parodd cs7\n\
686 "), stdout);
687 fputs (_("\
688 -evenp same as -parenb cs8\n\
689 * [-]lcase same as xcase iuclc olcuc\n\
690 litout same as -parenb -istrip -opost cs8\n\
691 -litout same as parenb istrip opost cs7\n\
692 nl same as -icrnl -onlcr\n\
693 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
694 "), stdout);
695 fputs (_("\
696 oddp same as parenb parodd cs7\n\
697 -oddp same as -parenb cs8\n\
698 [-]parity same as [-]evenp\n\
699 pass8 same as -parenb -istrip cs8\n\
700 -pass8 same as parenb istrip cs7\n\
701 "), stdout);
702 fputs (_("\
703 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
704 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
705 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
706 -raw same as cooked\n\
707 "), stdout);
708 fputs (_("\
709 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
710 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
711 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
712 isig icanon iexten echo echoe echok -echonl -noflsh\n\
713 -xcase -tostop -echoprt echoctl echoke, all special\n\
714 characters to their default values\n\
715 "), stdout);
716 fputs (_("\
718 Handle the tty line connected to standard input. Without arguments,\n\
719 prints baud rate, line discipline, and deviations from stty sane. In\n\
720 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
721 127; special values ^- or undef used to disable special characters.\n\
722 "), stdout);
723 emit_ancillary_info ();
725 exit (status);
729 main (int argc, char **argv)
731 /* Initialize to all zeroes so there is no risk memcmp will report a
732 spurious difference in an uninitialized portion of the structure. */
733 struct termios mode = { 0, };
735 enum output_type output_type;
736 int optc;
737 int argi = 0;
738 int opti = 1;
739 bool require_set_attr;
740 bool speed_was_set;
741 bool verbose_output;
742 bool recoverable_output;
743 int k;
744 bool noargs = true;
745 char *file_name = NULL;
746 const char *device_name;
748 initialize_main (&argc, &argv);
749 set_program_name (argv[0]);
750 setlocale (LC_ALL, "");
751 bindtextdomain (PACKAGE, LOCALEDIR);
752 textdomain (PACKAGE);
754 atexit (close_stdout);
756 output_type = changed;
757 verbose_output = false;
758 recoverable_output = false;
760 /* Don't print error messages for unrecognized options. */
761 opterr = 0;
763 /* If any new options are ever added to stty, the short options MUST
764 NOT allow any ambiguity with the stty settings. For example, the
765 stty setting "-gagFork" would not be feasible, since it will be
766 parsed as "-g -a -g -F ork". If you change anything about how
767 stty parses options, be sure it still works with combinations of
768 short and long options, --, POSIXLY_CORRECT, etc. */
770 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
771 longopts, NULL))
772 != -1)
774 switch (optc)
776 case 'a':
777 verbose_output = true;
778 output_type = all;
779 break;
781 case 'g':
782 recoverable_output = true;
783 output_type = recoverable;
784 break;
786 case 'F':
787 if (file_name)
788 error (EXIT_FAILURE, 0, _("only one device may be specified"));
789 file_name = optarg;
790 break;
792 case_GETOPT_HELP_CHAR;
794 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
796 default:
797 noargs = false;
799 /* Skip the argument containing this unrecognized option;
800 the 2nd pass will analyze it. */
801 argi += opti;
803 /* Restart getopt_long from the first unskipped argument. */
804 opti = 1;
805 optind = 0;
807 break;
810 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
811 while (opti < optind)
812 argv[argi + opti++] = NULL;
815 /* Specifying both -a and -g gets an error. */
816 if (verbose_output && recoverable_output)
817 error (EXIT_FAILURE, 0,
818 _("the options for verbose and stty-readable output styles are\n"
819 "mutually exclusive"));
821 /* Specifying any other arguments with -a or -g gets an error. */
822 if (!noargs && (verbose_output || recoverable_output))
823 error (EXIT_FAILURE, 0,
824 _("when specifying an output style, modes may not be set"));
826 /* FIXME: it'd be better not to open the file until we've verified
827 that all arguments are valid. Otherwise, we could end up doing
828 only some of the requested operations and then failing, probably
829 leaving things in an undesirable state. */
831 if (file_name)
833 int fdflags;
834 device_name = file_name;
835 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
836 error (EXIT_FAILURE, errno, "%s", device_name);
837 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
838 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
839 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
840 device_name);
842 else
843 device_name = _("standard input");
845 if (tcgetattr (STDIN_FILENO, &mode))
846 error (EXIT_FAILURE, errno, "%s", device_name);
848 if (verbose_output || recoverable_output || noargs)
850 max_col = screen_columns ();
851 current_col = 0;
852 display_settings (output_type, &mode, device_name);
853 exit (EXIT_SUCCESS);
856 speed_was_set = false;
857 require_set_attr = false;
858 for (k = 1; k < argc; k++)
860 char const *arg = argv[k];
861 bool match_found = false;
862 bool reversed = false;
863 int i;
865 if (! arg)
866 continue;
868 if (arg[0] == '-')
870 ++arg;
871 reversed = true;
873 for (i = 0; mode_info[i].name != NULL; ++i)
875 if (STREQ (arg, mode_info[i].name))
877 match_found = set_mode (&mode_info[i], reversed, &mode);
878 require_set_attr = true;
879 break;
882 if (!match_found && reversed)
884 error (0, 0, _("invalid argument %s"), quote (arg - 1));
885 usage (EXIT_FAILURE);
887 if (!match_found)
889 for (i = 0; control_info[i].name != NULL; ++i)
891 if (STREQ (arg, control_info[i].name))
893 if (k == argc - 1)
895 error (0, 0, _("missing argument to %s"), quote (arg));
896 usage (EXIT_FAILURE);
898 match_found = true;
899 ++k;
900 set_control_char (&control_info[i], argv[k], &mode);
901 require_set_attr = true;
902 break;
906 if (!match_found)
908 if (STREQ (arg, "ispeed"))
910 if (k == argc - 1)
912 error (0, 0, _("missing argument to %s"), quote (arg));
913 usage (EXIT_FAILURE);
915 ++k;
916 set_speed (input_speed, argv[k], &mode);
917 speed_was_set = true;
918 require_set_attr = true;
920 else if (STREQ (arg, "ospeed"))
922 if (k == argc - 1)
924 error (0, 0, _("missing argument to %s"), quote (arg));
925 usage (EXIT_FAILURE);
927 ++k;
928 set_speed (output_speed, argv[k], &mode);
929 speed_was_set = true;
930 require_set_attr = true;
932 #ifdef TIOCGWINSZ
933 else if (STREQ (arg, "rows"))
935 if (k == argc - 1)
937 error (0, 0, _("missing argument to %s"), quote (arg));
938 usage (EXIT_FAILURE);
940 ++k;
941 set_window_size (integer_arg (argv[k], INT_MAX), -1,
942 device_name);
944 else if (STREQ (arg, "cols")
945 || STREQ (arg, "columns"))
947 if (k == argc - 1)
949 error (0, 0, _("missing argument to %s"), quote (arg));
950 usage (EXIT_FAILURE);
952 ++k;
953 set_window_size (-1, integer_arg (argv[k], INT_MAX),
954 device_name);
956 else if (STREQ (arg, "size"))
958 max_col = screen_columns ();
959 current_col = 0;
960 display_window_size (false, device_name);
962 #endif
963 #ifdef HAVE_C_LINE
964 else if (STREQ (arg, "line"))
966 unsigned long int value;
967 if (k == argc - 1)
969 error (0, 0, _("missing argument to %s"), quote (arg));
970 usage (EXIT_FAILURE);
972 ++k;
973 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
974 if (mode.c_line != value)
975 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
976 require_set_attr = true;
978 #endif
979 else if (STREQ (arg, "speed"))
981 max_col = screen_columns ();
982 display_speed (&mode, false);
984 else if (string_to_baud (arg) != (speed_t) -1)
986 set_speed (both_speeds, arg, &mode);
987 speed_was_set = true;
988 require_set_attr = true;
990 else
992 if (! recover_mode (arg, &mode))
994 error (0, 0, _("invalid argument %s"), quote (arg));
995 usage (EXIT_FAILURE);
997 require_set_attr = true;
1002 if (require_set_attr)
1004 /* Initialize to all zeroes so there is no risk memcmp will report a
1005 spurious difference in an uninitialized portion of the structure. */
1006 struct termios new_mode = { 0, };
1008 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1009 error (EXIT_FAILURE, errno, "%s", device_name);
1011 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1012 it performs *any* of the requested operations. This means it
1013 can report `success' when it has actually failed to perform
1014 some proper subset of the requested operations. To detect
1015 this partial failure, get the current terminal attributes and
1016 compare them to the requested ones. */
1018 if (tcgetattr (STDIN_FILENO, &new_mode))
1019 error (EXIT_FAILURE, errno, "%s", device_name);
1021 /* Normally, one shouldn't use memcmp to compare structures that
1022 may have `holes' containing uninitialized data, but we have been
1023 careful to initialize the storage of these two variables to all
1024 zeroes. One might think it more efficient simply to compare the
1025 modified fields, but that would require enumerating those fields --
1026 and not all systems have the same fields in this structure. */
1028 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1030 #ifdef CIBAUD
1031 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1032 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1033 sometimes (m1 != m2). The only difference is in the four bits
1034 of the c_cflag field corresponding to the baud rate. To save
1035 Sun users a little confusion, don't report an error if this
1036 happens. But suppress the error only if we haven't tried to
1037 set the baud rate explicitly -- otherwise we'd never give an
1038 error for a true failure to set the baud rate. */
1040 new_mode.c_cflag &= (~CIBAUD);
1041 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1042 #endif
1044 error (EXIT_FAILURE, 0,
1045 _("%s: unable to perform all requested operations"),
1046 device_name);
1047 #ifdef TESTING
1049 size_t i;
1050 printf ("new_mode: mode\n");
1051 for (i = 0; i < sizeof (new_mode); i++)
1052 printf ("0x%02x: 0x%02x\n",
1053 *(((unsigned char *) &new_mode) + i),
1054 *(((unsigned char *) &mode) + i));
1056 #endif
1061 exit (EXIT_SUCCESS);
1064 /* Return false if not applied because not reversible; otherwise
1065 return true. */
1067 static bool
1068 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1070 tcflag_t *bitsp;
1072 if (reversed && (info->flags & REV) == 0)
1073 return false;
1075 bitsp = mode_type_flag (info->type, mode);
1077 if (bitsp == NULL)
1079 /* Combination mode. */
1080 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1082 if (reversed)
1083 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1084 else
1085 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1087 else if (STREQ (info->name, "oddp"))
1089 if (reversed)
1090 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1091 else
1092 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1094 else if (STREQ (info->name, "nl"))
1096 if (reversed)
1098 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1099 mode->c_oflag = (mode->c_oflag
1100 #ifdef ONLCR
1101 | ONLCR
1102 #endif
1104 #ifdef OCRNL
1105 & ~OCRNL
1106 #endif
1107 #ifdef ONLRET
1108 & ~ONLRET
1109 #endif
1112 else
1114 mode->c_iflag = mode->c_iflag & ~ICRNL;
1115 #ifdef ONLCR
1116 mode->c_oflag = mode->c_oflag & ~ONLCR;
1117 #endif
1120 else if (STREQ (info->name, "ek"))
1122 mode->c_cc[VERASE] = CERASE;
1123 mode->c_cc[VKILL] = CKILL;
1125 else if (STREQ (info->name, "sane"))
1126 sane_mode (mode);
1127 else if (STREQ (info->name, "cbreak"))
1129 if (reversed)
1130 mode->c_lflag |= ICANON;
1131 else
1132 mode->c_lflag &= ~ICANON;
1134 else if (STREQ (info->name, "pass8"))
1136 if (reversed)
1138 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1139 mode->c_iflag |= ISTRIP;
1141 else
1143 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1144 mode->c_iflag &= ~ISTRIP;
1147 else if (STREQ (info->name, "litout"))
1149 if (reversed)
1151 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1152 mode->c_iflag |= ISTRIP;
1153 mode->c_oflag |= OPOST;
1155 else
1157 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1158 mode->c_iflag &= ~ISTRIP;
1159 mode->c_oflag &= ~OPOST;
1162 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1164 if ((info->name[0] == 'r' && reversed)
1165 || (info->name[0] == 'c' && !reversed))
1167 /* Cooked mode. */
1168 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1169 mode->c_oflag |= OPOST;
1170 mode->c_lflag |= ISIG | ICANON;
1171 #if VMIN == VEOF
1172 mode->c_cc[VEOF] = CEOF;
1173 #endif
1174 #if VTIME == VEOL
1175 mode->c_cc[VEOL] = CEOL;
1176 #endif
1178 else
1180 /* Raw mode. */
1181 mode->c_iflag = 0;
1182 mode->c_oflag &= ~OPOST;
1183 mode->c_lflag &= ~(ISIG | ICANON
1184 #ifdef XCASE
1185 | XCASE
1186 #endif
1188 mode->c_cc[VMIN] = 1;
1189 mode->c_cc[VTIME] = 0;
1192 #ifdef IXANY
1193 else if (STREQ (info->name, "decctlq"))
1195 if (reversed)
1196 mode->c_iflag |= IXANY;
1197 else
1198 mode->c_iflag &= ~IXANY;
1200 #endif
1201 #ifdef TABDLY
1202 else if (STREQ (info->name, "tabs"))
1204 if (reversed)
1205 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1206 else
1207 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1209 #else
1210 # ifdef OXTABS
1211 else if (STREQ (info->name, "tabs"))
1213 if (reversed)
1214 mode->c_oflag = mode->c_oflag | OXTABS;
1215 else
1216 mode->c_oflag = mode->c_oflag & ~OXTABS;
1218 # endif
1219 #endif
1220 #if defined XCASE && defined IUCLC && defined OLCUC
1221 else if (STREQ (info->name, "lcase")
1222 || STREQ (info->name, "LCASE"))
1224 if (reversed)
1226 mode->c_lflag &= ~XCASE;
1227 mode->c_iflag &= ~IUCLC;
1228 mode->c_oflag &= ~OLCUC;
1230 else
1232 mode->c_lflag |= XCASE;
1233 mode->c_iflag |= IUCLC;
1234 mode->c_oflag |= OLCUC;
1237 #endif
1238 else if (STREQ (info->name, "crt"))
1239 mode->c_lflag |= ECHOE
1240 #ifdef ECHOCTL
1241 | ECHOCTL
1242 #endif
1243 #ifdef ECHOKE
1244 | ECHOKE
1245 #endif
1247 else if (STREQ (info->name, "dec"))
1249 mode->c_cc[VINTR] = 3; /* ^C */
1250 mode->c_cc[VERASE] = 127; /* DEL */
1251 mode->c_cc[VKILL] = 21; /* ^U */
1252 mode->c_lflag |= ECHOE
1253 #ifdef ECHOCTL
1254 | ECHOCTL
1255 #endif
1256 #ifdef ECHOKE
1257 | ECHOKE
1258 #endif
1260 #ifdef IXANY
1261 mode->c_iflag &= ~IXANY;
1262 #endif
1265 else if (reversed)
1266 *bitsp = *bitsp & ~info->mask & ~info->bits;
1267 else
1268 *bitsp = (*bitsp & ~info->mask) | info->bits;
1270 return true;
1273 static void
1274 set_control_char (struct control_info const *info, const char *arg,
1275 struct termios *mode)
1277 unsigned long int value;
1279 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1280 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1281 else if (arg[0] == '\0' || arg[1] == '\0')
1282 value = to_uchar (arg[0]);
1283 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1284 value = _POSIX_VDISABLE;
1285 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1287 if (arg[1] == '?')
1288 value = 127;
1289 else
1290 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1292 else
1293 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1294 mode->c_cc[info->offset] = value;
1297 static void
1298 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1300 speed_t baud;
1302 baud = string_to_baud (arg);
1303 if (type == input_speed || type == both_speeds)
1304 cfsetispeed (mode, baud);
1305 if (type == output_speed || type == both_speeds)
1306 cfsetospeed (mode, baud);
1309 #ifdef TIOCGWINSZ
1311 static int
1312 get_win_size (int fd, struct winsize *win)
1314 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1315 return err;
1318 static void
1319 set_window_size (int rows, int cols, char const *device_name)
1321 struct winsize win;
1323 if (get_win_size (STDIN_FILENO, &win))
1325 if (errno != EINVAL)
1326 error (EXIT_FAILURE, errno, "%s", device_name);
1327 memset (&win, 0, sizeof (win));
1330 if (rows >= 0)
1331 win.ws_row = rows;
1332 if (cols >= 0)
1333 win.ws_col = cols;
1335 # ifdef TIOCSSIZE
1336 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1337 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1338 This comment from sys/ttold.h describes Sun's twisted logic - a better
1339 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1340 At any rate, the problem is gone in Solaris 2.x.
1342 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1343 but they can be disambiguated by checking whether a "struct ttysize"
1344 structure's "ts_lines" field is greater than 64K or not. If so,
1345 it's almost certainly a "struct winsize" instead.
1347 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1348 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1349 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1350 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1351 "stty cols 0 rows 0" would do the right thing. On a little-endian
1352 machine like the sun386i, the problem is the same, but for ws_col == 0.
1354 The workaround is to do the ioctl once with row and col = 1 to set the
1355 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1357 if (win.ws_row == 0 || win.ws_col == 0)
1359 struct ttysize ttysz;
1361 ttysz.ts_lines = win.ws_row;
1362 ttysz.ts_cols = win.ws_col;
1364 win.ws_row = 1;
1365 win.ws_col = 1;
1367 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1368 error (EXIT_FAILURE, errno, "%s", device_name);
1370 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1371 error (EXIT_FAILURE, errno, "%s", device_name);
1372 return;
1374 # endif
1376 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1377 error (EXIT_FAILURE, errno, "%s", device_name);
1380 static void
1381 display_window_size (bool fancy, char const *device_name)
1383 struct winsize win;
1385 if (get_win_size (STDIN_FILENO, &win))
1387 if (errno != EINVAL)
1388 error (EXIT_FAILURE, errno, "%s", device_name);
1389 if (!fancy)
1390 error (EXIT_FAILURE, 0,
1391 _("%s: no size information for this device"), device_name);
1393 else
1395 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1396 win.ws_row, win.ws_col);
1397 if (!fancy)
1398 current_col = 0;
1401 #endif
1403 static int
1404 screen_columns (void)
1406 #ifdef TIOCGWINSZ
1407 struct winsize win;
1409 /* With Solaris 2.[123], this ioctl fails and errno is set to
1410 EINVAL for telnet (but not rlogin) sessions.
1411 On ISC 3.0, it fails for the console and the serial port
1412 (but it works for ptys).
1413 It can also fail on any system when stdout isn't a tty.
1414 In case of any failure, just use the default. */
1415 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1416 return win.ws_col;
1417 #endif
1419 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1420 char *col_string = getenv ("COLUMNS");
1421 long int n_columns;
1422 if (!(col_string != NULL
1423 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1424 && 0 < n_columns
1425 && n_columns <= INT_MAX))
1426 n_columns = 80;
1427 return n_columns;
1431 static tcflag_t * _GL_ATTRIBUTE_PURE
1432 mode_type_flag (enum mode_type type, struct termios *mode)
1434 switch (type)
1436 case control:
1437 return &mode->c_cflag;
1439 case input:
1440 return &mode->c_iflag;
1442 case output:
1443 return &mode->c_oflag;
1445 case local:
1446 return &mode->c_lflag;
1448 case combination:
1449 return NULL;
1451 default:
1452 abort ();
1456 static void
1457 display_settings (enum output_type output_type, struct termios *mode,
1458 char const *device_name)
1460 switch (output_type)
1462 case changed:
1463 display_changed (mode);
1464 break;
1466 case all:
1467 display_all (mode, device_name);
1468 break;
1470 case recoverable:
1471 display_recoverable (mode);
1472 break;
1476 static void
1477 display_changed (struct termios *mode)
1479 int i;
1480 bool empty_line;
1481 tcflag_t *bitsp;
1482 unsigned long mask;
1483 enum mode_type prev_type = control;
1485 display_speed (mode, true);
1486 #ifdef HAVE_C_LINE
1487 wrapf ("line = %d;", mode->c_line);
1488 #endif
1489 putchar ('\n');
1490 current_col = 0;
1492 empty_line = true;
1493 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1495 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1496 continue;
1497 /* If swtch is the same as susp, don't print both. */
1498 #if VSWTCH == VSUSP
1499 if (STREQ (control_info[i].name, "swtch"))
1500 continue;
1501 #endif
1502 /* If eof uses the same slot as min, only print whichever applies. */
1503 #if VEOF == VMIN
1504 if ((mode->c_lflag & ICANON) == 0
1505 && (STREQ (control_info[i].name, "eof")
1506 || STREQ (control_info[i].name, "eol")))
1507 continue;
1508 #endif
1510 empty_line = false;
1511 wrapf ("%s = %s;", control_info[i].name,
1512 visible (mode->c_cc[control_info[i].offset]));
1514 if ((mode->c_lflag & ICANON) == 0)
1516 wrapf ("min = %lu; time = %lu;\n",
1517 (unsigned long int) mode->c_cc[VMIN],
1518 (unsigned long int) mode->c_cc[VTIME]);
1520 else if (!empty_line)
1521 putchar ('\n');
1522 current_col = 0;
1524 empty_line = true;
1525 for (i = 0; mode_info[i].name != NULL; ++i)
1527 if (mode_info[i].flags & OMIT)
1528 continue;
1529 if (mode_info[i].type != prev_type)
1531 if (!empty_line)
1533 putchar ('\n');
1534 current_col = 0;
1535 empty_line = true;
1537 prev_type = mode_info[i].type;
1540 bitsp = mode_type_flag (mode_info[i].type, mode);
1541 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1542 if ((*bitsp & mask) == mode_info[i].bits)
1544 if (mode_info[i].flags & SANE_UNSET)
1546 wrapf ("%s", mode_info[i].name);
1547 empty_line = false;
1550 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1552 wrapf ("-%s", mode_info[i].name);
1553 empty_line = false;
1556 if (!empty_line)
1557 putchar ('\n');
1558 current_col = 0;
1561 static void
1562 display_all (struct termios *mode, char const *device_name)
1564 int i;
1565 tcflag_t *bitsp;
1566 unsigned long mask;
1567 enum mode_type prev_type = control;
1569 display_speed (mode, true);
1570 #ifdef TIOCGWINSZ
1571 display_window_size (true, device_name);
1572 #endif
1573 #ifdef HAVE_C_LINE
1574 wrapf ("line = %d;", mode->c_line);
1575 #endif
1576 putchar ('\n');
1577 current_col = 0;
1579 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1581 /* If swtch is the same as susp, don't print both. */
1582 #if VSWTCH == VSUSP
1583 if (STREQ (control_info[i].name, "swtch"))
1584 continue;
1585 #endif
1586 /* If eof uses the same slot as min, only print whichever applies. */
1587 #if VEOF == VMIN
1588 if ((mode->c_lflag & ICANON) == 0
1589 && (STREQ (control_info[i].name, "eof")
1590 || STREQ (control_info[i].name, "eol")))
1591 continue;
1592 #endif
1593 wrapf ("%s = %s;", control_info[i].name,
1594 visible (mode->c_cc[control_info[i].offset]));
1596 #if VEOF == VMIN
1597 if ((mode->c_lflag & ICANON) == 0)
1598 #endif
1599 wrapf ("min = %lu; time = %lu;",
1600 (unsigned long int) mode->c_cc[VMIN],
1601 (unsigned long int) mode->c_cc[VTIME]);
1602 if (current_col != 0)
1603 putchar ('\n');
1604 current_col = 0;
1606 for (i = 0; mode_info[i].name != NULL; ++i)
1608 if (mode_info[i].flags & OMIT)
1609 continue;
1610 if (mode_info[i].type != prev_type)
1612 putchar ('\n');
1613 current_col = 0;
1614 prev_type = mode_info[i].type;
1617 bitsp = mode_type_flag (mode_info[i].type, mode);
1618 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1619 if ((*bitsp & mask) == mode_info[i].bits)
1620 wrapf ("%s", mode_info[i].name);
1621 else if (mode_info[i].flags & REV)
1622 wrapf ("-%s", mode_info[i].name);
1624 putchar ('\n');
1625 current_col = 0;
1628 static void
1629 display_speed (struct termios *mode, bool fancy)
1631 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1632 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1633 baud_to_value (cfgetospeed (mode)));
1634 else
1635 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1636 baud_to_value (cfgetispeed (mode)),
1637 baud_to_value (cfgetospeed (mode)));
1638 if (!fancy)
1639 current_col = 0;
1642 static void
1643 display_recoverable (struct termios *mode)
1645 size_t i;
1647 printf ("%lx:%lx:%lx:%lx",
1648 (unsigned long int) mode->c_iflag,
1649 (unsigned long int) mode->c_oflag,
1650 (unsigned long int) mode->c_cflag,
1651 (unsigned long int) mode->c_lflag);
1652 for (i = 0; i < NCCS; ++i)
1653 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1654 putchar ('\n');
1657 /* NOTE: identical to below, modulo use of tcflag_t */
1658 static int
1659 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1660 char delim)
1662 unsigned long ul;
1663 errno = 0;
1664 ul = strtoul (s, p, base);
1665 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1666 return -1;
1667 *result = ul;
1668 return 0;
1671 /* NOTE: identical to above, modulo use of cc_t */
1672 static int
1673 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1675 unsigned long ul;
1676 errno = 0;
1677 ul = strtoul (s, p, base);
1678 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1679 return -1;
1680 *result = ul;
1681 return 0;
1684 /* Parse the output of display_recoverable.
1685 Return false if any part of it is invalid. */
1686 static bool
1687 recover_mode (char const *arg, struct termios *mode)
1689 tcflag_t flag[4];
1690 char const *s = arg;
1691 size_t i;
1692 for (i = 0; i < 4; i++)
1694 char *p;
1695 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1696 return false;
1697 s = p + 1;
1699 mode->c_iflag = flag[0];
1700 mode->c_oflag = flag[1];
1701 mode->c_cflag = flag[2];
1702 mode->c_lflag = flag[3];
1704 for (i = 0; i < NCCS; ++i)
1706 char *p;
1707 char delim = i < NCCS - 1 ? ':' : '\0';
1708 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1709 return false;
1710 s = p + 1;
1713 return true;
1716 struct speed_map
1718 const char *string; /* ASCII representation. */
1719 speed_t speed; /* Internal form. */
1720 unsigned long int value; /* Numeric value. */
1723 static struct speed_map const speeds[] =
1725 {"0", B0, 0},
1726 {"50", B50, 50},
1727 {"75", B75, 75},
1728 {"110", B110, 110},
1729 {"134", B134, 134},
1730 {"134.5", B134, 134},
1731 {"150", B150, 150},
1732 {"200", B200, 200},
1733 {"300", B300, 300},
1734 {"600", B600, 600},
1735 {"1200", B1200, 1200},
1736 {"1800", B1800, 1800},
1737 {"2400", B2400, 2400},
1738 {"4800", B4800, 4800},
1739 {"9600", B9600, 9600},
1740 {"19200", B19200, 19200},
1741 {"38400", B38400, 38400},
1742 {"exta", B19200, 19200},
1743 {"extb", B38400, 38400},
1744 #ifdef B57600
1745 {"57600", B57600, 57600},
1746 #endif
1747 #ifdef B115200
1748 {"115200", B115200, 115200},
1749 #endif
1750 #ifdef B230400
1751 {"230400", B230400, 230400},
1752 #endif
1753 #ifdef B460800
1754 {"460800", B460800, 460800},
1755 #endif
1756 #ifdef B500000
1757 {"500000", B500000, 500000},
1758 #endif
1759 #ifdef B576000
1760 {"576000", B576000, 576000},
1761 #endif
1762 #ifdef B921600
1763 {"921600", B921600, 921600},
1764 #endif
1765 #ifdef B1000000
1766 {"1000000", B1000000, 1000000},
1767 #endif
1768 #ifdef B1152000
1769 {"1152000", B1152000, 1152000},
1770 #endif
1771 #ifdef B1500000
1772 {"1500000", B1500000, 1500000},
1773 #endif
1774 #ifdef B2000000
1775 {"2000000", B2000000, 2000000},
1776 #endif
1777 #ifdef B2500000
1778 {"2500000", B2500000, 2500000},
1779 #endif
1780 #ifdef B3000000
1781 {"3000000", B3000000, 3000000},
1782 #endif
1783 #ifdef B3500000
1784 {"3500000", B3500000, 3500000},
1785 #endif
1786 #ifdef B4000000
1787 {"4000000", B4000000, 4000000},
1788 #endif
1789 {NULL, 0, 0}
1792 static speed_t _GL_ATTRIBUTE_PURE
1793 string_to_baud (const char *arg)
1795 int i;
1797 for (i = 0; speeds[i].string != NULL; ++i)
1798 if (STREQ (arg, speeds[i].string))
1799 return speeds[i].speed;
1800 return (speed_t) -1;
1803 static unsigned long int _GL_ATTRIBUTE_PURE
1804 baud_to_value (speed_t speed)
1806 int i;
1808 for (i = 0; speeds[i].string != NULL; ++i)
1809 if (speed == speeds[i].speed)
1810 return speeds[i].value;
1811 return 0;
1814 static void
1815 sane_mode (struct termios *mode)
1817 int i;
1818 tcflag_t *bitsp;
1820 for (i = 0; control_info[i].name; ++i)
1822 #if VMIN == VEOF
1823 if (STREQ (control_info[i].name, "min"))
1824 break;
1825 #endif
1826 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1829 for (i = 0; mode_info[i].name != NULL; ++i)
1831 if (mode_info[i].flags & SANE_SET)
1833 bitsp = mode_type_flag (mode_info[i].type, mode);
1834 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1836 else if (mode_info[i].flags & SANE_UNSET)
1838 bitsp = mode_type_flag (mode_info[i].type, mode);
1839 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1844 /* Return a string that is the printable representation of character CH. */
1845 /* Adapted from `cat' by Torbjorn Granlund. */
1847 static const char *
1848 visible (cc_t ch)
1850 static char buf[10];
1851 char *bpout = buf;
1853 if (ch == _POSIX_VDISABLE)
1854 return "<undef>";
1856 if (ch >= 32)
1858 if (ch < 127)
1859 *bpout++ = ch;
1860 else if (ch == 127)
1862 *bpout++ = '^';
1863 *bpout++ = '?';
1865 else
1867 *bpout++ = 'M';
1868 *bpout++ = '-';
1869 if (ch >= 128 + 32)
1871 if (ch < 128 + 127)
1872 *bpout++ = ch - 128;
1873 else
1875 *bpout++ = '^';
1876 *bpout++ = '?';
1879 else
1881 *bpout++ = '^';
1882 *bpout++ = ch - 128 + 64;
1886 else
1888 *bpout++ = '^';
1889 *bpout++ = ch + 64;
1891 *bpout = '\0';
1892 return (const char *) buf;
1895 /* Parse string S as an integer, using decimal radix by default,
1896 but allowing octal and hex numbers as in C. Reject values
1897 larger than MAXVAL. */
1899 static unsigned long int
1900 integer_arg (const char *s, unsigned long int maxval)
1902 unsigned long int value;
1903 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1905 error (0, 0, _("invalid integer argument %s"), quote (s));
1906 usage (EXIT_FAILURE);
1908 return value;