tests: add printenv coverage
[coreutils.git] / src / stty.c
blob2545048600284b4054b23c23b0e8067e3f0e180a
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005, 2007-2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
19 Options:
20 -a, --all Write all current settings to stdout in human-readable form.
21 -g, --save Write all current settings to stdout in stty-readable form.
22 -F, --file Open and use the specified device instead of stdin
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on the specified device, or stdin if none was specified.
28 David MacKenzie <djm@gnu.ai.mit.edu> */
30 #include <config.h>
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
34 #endif
36 #include <stdio.h>
37 #include <sys/types.h>
39 #if HAVE_TERMIOS_H
40 # include <termios.h>
41 #endif
42 #if HAVE_STROPTS_H
43 # include <stropts.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 # include <sys/ioctl.h>
47 #endif
49 #ifdef WINSIZE_IN_PTEM
50 # include <sys/stream.h>
51 # include <sys/ptem.h>
52 #endif
53 #ifdef GWINSZ_IN_SYS_PTY
54 # include <sys/tty.h>
55 # include <sys/pty.h>
56 #endif
57 #include <getopt.h>
58 #include <stdarg.h>
60 #include "system.h"
61 #include "error.h"
62 #include "fd-reopen.h"
63 #include "quote.h"
64 #include "xstrtol.h"
66 /* The official name of this program (e.g., no `g' prefix). */
67 #define PROGRAM_NAME "stty"
69 #define AUTHORS proper_name ("David MacKenzie")
71 #ifndef _POSIX_VDISABLE
72 # define _POSIX_VDISABLE 0
73 #endif
75 #define Control(c) ((c) & 0x1f)
76 /* Canonical values for control characters. */
77 #ifndef CINTR
78 # define CINTR Control ('c')
79 #endif
80 #ifndef CQUIT
81 # define CQUIT 28
82 #endif
83 #ifndef CERASE
84 # define CERASE 127
85 #endif
86 #ifndef CKILL
87 # define CKILL Control ('u')
88 #endif
89 #ifndef CEOF
90 # define CEOF Control ('d')
91 #endif
92 #ifndef CEOL
93 # define CEOL _POSIX_VDISABLE
94 #endif
95 #ifndef CSTART
96 # define CSTART Control ('q')
97 #endif
98 #ifndef CSTOP
99 # define CSTOP Control ('s')
100 #endif
101 #ifndef CSUSP
102 # define CSUSP Control ('z')
103 #endif
104 #if defined VEOL2 && !defined CEOL2
105 # define CEOL2 _POSIX_VDISABLE
106 #endif
107 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
108 character is initialized by CSWTCH, if present. */
109 #if defined VSWTC && !defined VSWTCH
110 # define VSWTCH VSWTC
111 #endif
112 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
113 #if defined VSUSP && !defined VSWTCH
114 # define VSWTCH VSUSP
115 # if defined CSUSP && !defined CSWTCH
116 # define CSWTCH CSUSP
117 # endif
118 #endif
119 #if defined VSWTCH && !defined CSWTCH
120 # define CSWTCH _POSIX_VDISABLE
121 #endif
123 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
124 So the default is to disable `swtch.' */
125 #if defined __sparc__ && defined __svr4__
126 # undef CSWTCH
127 # define CSWTCH _POSIX_VDISABLE
128 #endif
130 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
131 # define VWERASE VWERSE
132 #endif
133 #if defined VDSUSP && !defined CDSUSP
134 # define CDSUSP Control ('y')
135 #endif
136 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
137 # define VREPRINT VRPRNT
138 #endif
139 #if defined VREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
141 #endif
142 #if defined CREPRINT && !defined CRPRNT
143 # define CRPRNT Control ('r')
144 #endif
145 #if defined VWERASE && !defined CWERASE
146 # define CWERASE Control ('w')
147 #endif
148 #if defined VLNEXT && !defined CLNEXT
149 # define CLNEXT Control ('v')
150 #endif
151 #if defined VDISCARD && !defined VFLUSHO
152 # define VFLUSHO VDISCARD
153 #endif
154 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
155 # define VFLUSHO VFLUSH
156 #endif
157 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
158 # define ECHOCTL CTLECH
159 #endif
160 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
161 # define ECHOCTL TCTLECH
162 #endif
163 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
164 # define ECHOKE CRTKIL
165 #endif
166 #if defined VFLUSHO && !defined CFLUSHO
167 # define CFLUSHO Control ('o')
168 #endif
169 #if defined VSTATUS && !defined CSTATUS
170 # define CSTATUS Control ('t')
171 #endif
173 /* Which speeds to set. */
174 enum speed_setting
176 input_speed, output_speed, both_speeds
179 /* What to output and how. */
180 enum output_type
182 changed, all, recoverable /* Default, -a, -g. */
185 /* Which member(s) of `struct termios' a mode uses. */
186 enum mode_type
188 control, input, output, local, combination
191 /* Flags for `struct mode_info'. */
192 #define SANE_SET 1 /* Set in `sane' mode. */
193 #define SANE_UNSET 2 /* Unset in `sane' mode. */
194 #define REV 4 /* Can be turned off by prepending `-'. */
195 #define OMIT 8 /* Don't display value. */
197 /* Each mode. */
198 struct mode_info
200 const char *name; /* Name given on command line. */
201 enum mode_type type; /* Which structure element to change. */
202 char flags; /* Setting and display options. */
203 unsigned long bits; /* Bits to set for this mode. */
204 unsigned long mask; /* Other bits to turn off for this mode. */
207 static struct mode_info const mode_info[] =
209 {"parenb", control, REV, PARENB, 0},
210 {"parodd", control, REV, PARODD, 0},
211 {"cs5", control, 0, CS5, CSIZE},
212 {"cs6", control, 0, CS6, CSIZE},
213 {"cs7", control, 0, CS7, CSIZE},
214 {"cs8", control, 0, CS8, CSIZE},
215 {"hupcl", control, REV, HUPCL, 0},
216 {"hup", control, REV | OMIT, HUPCL, 0},
217 {"cstopb", control, REV, CSTOPB, 0},
218 {"cread", control, SANE_SET | REV, CREAD, 0},
219 {"clocal", control, REV, CLOCAL, 0},
220 #ifdef CRTSCTS
221 {"crtscts", control, REV, CRTSCTS, 0},
222 #endif
224 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
225 {"brkint", input, SANE_SET | REV, BRKINT, 0},
226 {"ignpar", input, REV, IGNPAR, 0},
227 {"parmrk", input, REV, PARMRK, 0},
228 {"inpck", input, REV, INPCK, 0},
229 {"istrip", input, REV, ISTRIP, 0},
230 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
231 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
232 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
233 {"ixon", input, REV, IXON, 0},
234 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
235 {"tandem", input, REV | OMIT, IXOFF, 0},
236 #ifdef IUCLC
237 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
238 #endif
239 #ifdef IXANY
240 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
241 #endif
242 #ifdef IMAXBEL
243 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
244 #endif
245 #ifdef IUTF8
246 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
247 #endif
249 {"opost", output, SANE_SET | REV, OPOST, 0},
250 #ifdef OLCUC
251 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
252 #endif
253 #ifdef OCRNL
254 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
255 #endif
256 #ifdef ONLCR
257 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
258 #endif
259 #ifdef ONOCR
260 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
261 #endif
262 #ifdef ONLRET
263 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
264 #endif
265 #ifdef OFILL
266 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
267 #endif
268 #ifdef OFDEL
269 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
270 #endif
271 #ifdef NLDLY
272 {"nl1", output, SANE_UNSET, NL1, NLDLY},
273 {"nl0", output, SANE_SET, NL0, NLDLY},
274 #endif
275 #ifdef CRDLY
276 {"cr3", output, SANE_UNSET, CR3, CRDLY},
277 {"cr2", output, SANE_UNSET, CR2, CRDLY},
278 {"cr1", output, SANE_UNSET, CR1, CRDLY},
279 {"cr0", output, SANE_SET, CR0, CRDLY},
280 #endif
281 #ifdef TABDLY
282 # ifdef TAB3
283 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
284 # endif
285 # ifdef TAB2
286 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
287 # endif
288 # ifdef TAB1
289 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
290 # endif
291 # ifdef TAB0
292 {"tab0", output, SANE_SET, TAB0, TABDLY},
293 # endif
294 #else
295 # ifdef OXTABS
296 {"tab3", output, SANE_UNSET, OXTABS, 0},
297 # endif
298 #endif
299 #ifdef BSDLY
300 {"bs1", output, SANE_UNSET, BS1, BSDLY},
301 {"bs0", output, SANE_SET, BS0, BSDLY},
302 #endif
303 #ifdef VTDLY
304 {"vt1", output, SANE_UNSET, VT1, VTDLY},
305 {"vt0", output, SANE_SET, VT0, VTDLY},
306 #endif
307 #ifdef FFDLY
308 {"ff1", output, SANE_UNSET, FF1, FFDLY},
309 {"ff0", output, SANE_SET, FF0, FFDLY},
310 #endif
312 {"isig", local, SANE_SET | REV, ISIG, 0},
313 {"icanon", local, SANE_SET | REV, ICANON, 0},
314 #ifdef IEXTEN
315 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
316 #endif
317 {"echo", local, SANE_SET | REV, ECHO, 0},
318 {"echoe", local, SANE_SET | REV, ECHOE, 0},
319 {"crterase", local, REV | OMIT, ECHOE, 0},
320 {"echok", local, SANE_SET | REV, ECHOK, 0},
321 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
322 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
323 #ifdef XCASE
324 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
325 #endif
326 #ifdef TOSTOP
327 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
328 #endif
329 #ifdef ECHOPRT
330 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
331 {"prterase", local, REV | OMIT, ECHOPRT, 0},
332 #endif
333 #ifdef ECHOCTL
334 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
335 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
336 #endif
337 #ifdef ECHOKE
338 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
339 {"crtkill", local, REV | OMIT, ECHOKE, 0},
340 #endif
342 {"evenp", combination, REV | OMIT, 0, 0},
343 {"parity", combination, REV | OMIT, 0, 0},
344 {"oddp", combination, REV | OMIT, 0, 0},
345 {"nl", combination, REV | OMIT, 0, 0},
346 {"ek", combination, OMIT, 0, 0},
347 {"sane", combination, OMIT, 0, 0},
348 {"cooked", combination, REV | OMIT, 0, 0},
349 {"raw", combination, REV | OMIT, 0, 0},
350 {"pass8", combination, REV | OMIT, 0, 0},
351 {"litout", combination, REV | OMIT, 0, 0},
352 {"cbreak", combination, REV | OMIT, 0, 0},
353 #ifdef IXANY
354 {"decctlq", combination, REV | OMIT, 0, 0},
355 #endif
356 #if defined TABDLY || defined OXTABS
357 {"tabs", combination, REV | OMIT, 0, 0},
358 #endif
359 #if defined XCASE && defined IUCLC && defined OLCUC
360 {"lcase", combination, REV | OMIT, 0, 0},
361 {"LCASE", combination, REV | OMIT, 0, 0},
362 #endif
363 {"crt", combination, OMIT, 0, 0},
364 {"dec", combination, OMIT, 0, 0},
366 {NULL, control, 0, 0, 0}
369 /* Control character settings. */
370 struct control_info
372 const char *name; /* Name given on command line. */
373 cc_t saneval; /* Value to set for `stty sane'. */
374 size_t offset; /* Offset in c_cc. */
377 /* Control characters. */
379 static struct control_info const control_info[] =
381 {"intr", CINTR, VINTR},
382 {"quit", CQUIT, VQUIT},
383 {"erase", CERASE, VERASE},
384 {"kill", CKILL, VKILL},
385 {"eof", CEOF, VEOF},
386 {"eol", CEOL, VEOL},
387 #ifdef VEOL2
388 {"eol2", CEOL2, VEOL2},
389 #endif
390 #ifdef VSWTCH
391 {"swtch", CSWTCH, VSWTCH},
392 #endif
393 {"start", CSTART, VSTART},
394 {"stop", CSTOP, VSTOP},
395 {"susp", CSUSP, VSUSP},
396 #ifdef VDSUSP
397 {"dsusp", CDSUSP, VDSUSP},
398 #endif
399 #ifdef VREPRINT
400 {"rprnt", CRPRNT, VREPRINT},
401 #else
402 # ifdef CREPRINT /* HPUX 10.20 needs this */
403 {"rprnt", CRPRNT, CREPRINT},
404 # endif
405 #endif
406 #ifdef VWERASE
407 {"werase", CWERASE, VWERASE},
408 #endif
409 #ifdef VLNEXT
410 {"lnext", CLNEXT, VLNEXT},
411 #endif
412 #ifdef VFLUSHO
413 {"flush", CFLUSHO, VFLUSHO},
414 #endif
415 #ifdef VSTATUS
416 {"status", CSTATUS, VSTATUS},
417 #endif
419 /* These must be last because of the display routines. */
420 {"min", 1, VMIN},
421 {"time", 0, VTIME},
422 {NULL, 0, 0}
425 static char const *visible (cc_t ch);
426 static unsigned long int baud_to_value (speed_t speed);
427 static bool recover_mode (char const *arg, struct termios *mode);
428 static int screen_columns (void);
429 static bool set_mode (struct mode_info const *info, bool reversed,
430 struct termios *mode);
431 static unsigned long int integer_arg (const char *s, unsigned long int max);
432 static speed_t string_to_baud (const char *arg);
433 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
434 static void display_all (struct termios *mode, char const *device_name);
435 static void display_changed (struct termios *mode);
436 static void display_recoverable (struct termios *mode);
437 static void display_settings (enum output_type output_type,
438 struct termios *mode,
439 const char *device_name);
440 static void display_speed (struct termios *mode, bool fancy);
441 static void display_window_size (bool fancy, char const *device_name);
442 static void sane_mode (struct termios *mode);
443 static void set_control_char (struct control_info const *info,
444 const char *arg,
445 struct termios *mode);
446 static void set_speed (enum speed_setting type, const char *arg,
447 struct termios *mode);
448 static void set_window_size (int rows, int cols, char const *device_name);
450 /* The width of the screen, for output wrapping. */
451 static int max_col;
453 /* Current position, to know when to wrap. */
454 static int current_col;
456 static struct option const longopts[] =
458 {"all", no_argument, NULL, 'a'},
459 {"save", no_argument, NULL, 'g'},
460 {"file", required_argument, NULL, 'F'},
461 {GETOPT_HELP_OPTION_DECL},
462 {GETOPT_VERSION_OPTION_DECL},
463 {NULL, 0, NULL, 0}
466 static void wrapf (const char *message, ...)
467 __attribute__ ((__format__ (__printf__, 1, 2)));
469 /* Print format string MESSAGE and optional args.
470 Wrap to next line first if it won't fit.
471 Print a space first unless MESSAGE will start a new line. */
473 static void
474 wrapf (const char *message,...)
476 va_list args;
477 char *buf;
478 int buflen;
480 va_start (args, message);
481 buflen = vasprintf (&buf, message, args);
482 va_end (args);
484 if (buflen < 0)
485 xalloc_die ();
487 if (0 < current_col)
489 if (max_col - current_col < buflen)
491 putchar ('\n');
492 current_col = 0;
494 else
496 putchar (' ');
497 current_col++;
501 fputs (buf, stdout);
502 free (buf);
503 current_col += buflen;
506 void
507 usage (int status)
509 if (status != EXIT_SUCCESS)
510 fprintf (stderr, _("Try `%s --help' for more information.\n"),
511 program_name);
512 else
514 printf (_("\
515 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
516 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
517 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
519 program_name, program_name, program_name);
520 fputs (_("\
521 Print or change terminal characteristics.\n\
523 -a, --all print all current settings in human-readable form\n\
524 -g, --save print all current settings in a stty-readable form\n\
525 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
526 "), stdout);
527 fputs (HELP_OPTION_DESCRIPTION, stdout);
528 fputs (VERSION_OPTION_DESCRIPTION, stdout);
529 fputs (_("\
531 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
532 settings. The underlying system defines which settings are available.\n\
533 "), stdout);
534 fputs (_("\
536 Special characters:\n\
537 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
538 eof CHAR CHAR will send an end of file (terminate the input)\n\
539 eol CHAR CHAR will end the line\n\
540 "), stdout);
541 fputs (_("\
542 * eol2 CHAR alternate CHAR for ending the line\n\
543 erase CHAR CHAR will erase the last character typed\n\
544 intr CHAR CHAR will send an interrupt signal\n\
545 kill CHAR CHAR will erase the current line\n\
546 "), stdout);
547 fputs (_("\
548 * lnext CHAR CHAR will enter the next character quoted\n\
549 quit CHAR CHAR will send a quit signal\n\
550 * rprnt CHAR CHAR will redraw the current line\n\
551 start CHAR CHAR will restart the output after stopping it\n\
552 "), stdout);
553 fputs (_("\
554 stop CHAR CHAR will stop the output\n\
555 susp CHAR CHAR will send a terminal stop signal\n\
556 * swtch CHAR CHAR will switch to a different shell layer\n\
557 * werase CHAR CHAR will erase the last word typed\n\
558 "), stdout);
559 fputs (_("\
561 Special settings:\n\
562 N set the input and output speeds to N bauds\n\
563 * cols N tell the kernel that the terminal has N columns\n\
564 * columns N same as cols N\n\
565 "), stdout);
566 fputs (_("\
567 ispeed N set the input speed to N\n\
568 * line N use line discipline N\n\
569 min N with -icanon, set N characters minimum for a completed read\n\
570 ospeed N set the output speed to N\n\
571 "), stdout);
572 fputs (_("\
573 * rows N tell the kernel that the terminal has N rows\n\
574 * size print the number of rows and columns according to the kernel\n\
575 speed print the terminal speed\n\
576 time N with -icanon, set read timeout of N tenths of a second\n\
577 "), stdout);
578 fputs (_("\
580 Control settings:\n\
581 [-]clocal disable modem control signals\n\
582 [-]cread allow input to be received\n\
583 * [-]crtscts enable RTS/CTS handshaking\n\
584 csN set character size to N bits, N in [5..8]\n\
585 "), stdout);
586 fputs (_("\
587 [-]cstopb use two stop bits per character (one with `-')\n\
588 [-]hup send a hangup signal when the last process closes the tty\n\
589 [-]hupcl same as [-]hup\n\
590 [-]parenb generate parity bit in output and expect parity bit in input\n\
591 [-]parodd set odd parity (even with `-')\n\
592 "), stdout);
593 fputs (_("\
595 Input settings:\n\
596 [-]brkint breaks cause an interrupt signal\n\
597 [-]icrnl translate carriage return to newline\n\
598 [-]ignbrk ignore break characters\n\
599 [-]igncr ignore carriage return\n\
600 "), stdout);
601 fputs (_("\
602 [-]ignpar ignore characters with parity errors\n\
603 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
604 [-]inlcr translate newline to carriage return\n\
605 [-]inpck enable input parity checking\n\
606 [-]istrip clear high (8th) bit of input characters\n\
607 "), stdout);
608 fputs (_("\
609 * [-]iutf8 assume input characters are UTF-8 encoded\n\
610 "), stdout);
611 fputs (_("\
612 * [-]iuclc translate uppercase characters to lowercase\n\
613 * [-]ixany let any character restart output, not only start character\n\
614 [-]ixoff enable sending of start/stop characters\n\
615 [-]ixon enable XON/XOFF flow control\n\
616 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
617 [-]tandem same as [-]ixoff\n\
618 "), stdout);
619 fputs (_("\
621 Output settings:\n\
622 * bsN backspace delay style, N in [0..1]\n\
623 * crN carriage return delay style, N in [0..3]\n\
624 * ffN form feed delay style, N in [0..1]\n\
625 * nlN newline delay style, N in [0..1]\n\
626 "), stdout);
627 fputs (_("\
628 * [-]ocrnl translate carriage return to newline\n\
629 * [-]ofdel use delete characters for fill instead of null characters\n\
630 * [-]ofill use fill (padding) characters instead of timing for delays\n\
631 * [-]olcuc translate lowercase characters to uppercase\n\
632 * [-]onlcr translate newline to carriage return-newline\n\
633 * [-]onlret newline performs a carriage return\n\
634 "), stdout);
635 fputs (_("\
636 * [-]onocr do not print carriage returns in the first column\n\
637 [-]opost postprocess output\n\
638 * tabN horizontal tab delay style, N in [0..3]\n\
639 * tabs same as tab0\n\
640 * -tabs same as tab3\n\
641 * vtN vertical tab delay style, N in [0..1]\n\
642 "), stdout);
643 fputs (_("\
645 Local settings:\n\
646 [-]crterase echo erase characters as backspace-space-backspace\n\
647 * crtkill kill all line by obeying the echoprt and echoe settings\n\
648 * -crtkill kill all line by obeying the echoctl and echok settings\n\
649 "), stdout);
650 fputs (_("\
651 * [-]ctlecho echo control characters in hat notation (`^c')\n\
652 [-]echo echo input characters\n\
653 * [-]echoctl same as [-]ctlecho\n\
654 [-]echoe same as [-]crterase\n\
655 [-]echok echo a newline after a kill character\n\
656 "), stdout);
657 fputs (_("\
658 * [-]echoke same as [-]crtkill\n\
659 [-]echonl echo newline even if not echoing other characters\n\
660 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
661 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
662 [-]iexten enable non-POSIX special characters\n\
663 "), stdout);
664 fputs (_("\
665 [-]isig enable interrupt, quit, and suspend special characters\n\
666 [-]noflsh disable flushing after interrupt and quit special characters\n\
667 * [-]prterase same as [-]echoprt\n\
668 * [-]tostop stop background jobs that try to write to the terminal\n\
669 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
670 "), stdout);
671 fputs (_("\
673 Combination settings:\n\
674 * [-]LCASE same as [-]lcase\n\
675 cbreak same as -icanon\n\
676 -cbreak same as icanon\n\
677 "), stdout);
678 fputs (_("\
679 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
680 icanon, eof and eol characters to their default values\n\
681 -cooked same as raw\n\
682 crt same as echoe echoctl echoke\n\
683 "), stdout);
684 fputs (_("\
685 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
686 kill ^u\n\
687 * [-]decctlq same as [-]ixany\n\
688 ek erase and kill characters to their default values\n\
689 evenp same as parenb -parodd cs7\n\
690 "), stdout);
691 fputs (_("\
692 -evenp same as -parenb cs8\n\
693 * [-]lcase same as xcase iuclc olcuc\n\
694 litout same as -parenb -istrip -opost cs8\n\
695 -litout same as parenb istrip opost cs7\n\
696 nl same as -icrnl -onlcr\n\
697 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
698 "), stdout);
699 fputs (_("\
700 oddp same as parenb parodd cs7\n\
701 -oddp same as -parenb cs8\n\
702 [-]parity same as [-]evenp\n\
703 pass8 same as -parenb -istrip cs8\n\
704 -pass8 same as parenb istrip cs7\n\
705 "), stdout);
706 fputs (_("\
707 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
708 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
709 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
710 -raw same as cooked\n\
711 "), stdout);
712 fputs (_("\
713 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
714 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
715 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
716 isig icanon iexten echo echoe echok -echonl -noflsh\n\
717 -xcase -tostop -echoprt echoctl echoke, all special\n\
718 characters to their default values\n\
719 "), stdout);
720 fputs (_("\
722 Handle the tty line connected to standard input. Without arguments,\n\
723 prints baud rate, line discipline, and deviations from stty sane. In\n\
724 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
725 127; special values ^- or undef used to disable special characters.\n\
726 "), stdout);
727 emit_ancillary_info ();
729 exit (status);
733 main (int argc, char **argv)
735 /* Initialize to all zeroes so there is no risk memcmp will report a
736 spurious difference in an uninitialized portion of the structure. */
737 DECLARE_ZEROED_AGGREGATE (struct termios, mode);
739 enum output_type output_type;
740 int optc;
741 int argi = 0;
742 int opti = 1;
743 bool require_set_attr;
744 bool speed_was_set;
745 bool verbose_output;
746 bool recoverable_output;
747 int k;
748 bool noargs = true;
749 char *file_name = NULL;
750 const char *device_name;
752 initialize_main (&argc, &argv);
753 set_program_name (argv[0]);
754 setlocale (LC_ALL, "");
755 bindtextdomain (PACKAGE, LOCALEDIR);
756 textdomain (PACKAGE);
758 atexit (close_stdout);
760 output_type = changed;
761 verbose_output = false;
762 recoverable_output = false;
764 /* Don't print error messages for unrecognized options. */
765 opterr = 0;
767 /* If any new options are ever added to stty, the short options MUST
768 NOT allow any ambiguity with the stty settings. For example, the
769 stty setting "-gagFork" would not be feasible, since it will be
770 parsed as "-g -a -g -F ork". If you change anything about how
771 stty parses options, be sure it still works with combinations of
772 short and long options, --, POSIXLY_CORRECT, etc. */
774 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
775 longopts, NULL))
776 != -1)
778 switch (optc)
780 case 'a':
781 verbose_output = true;
782 output_type = all;
783 break;
785 case 'g':
786 recoverable_output = true;
787 output_type = recoverable;
788 break;
790 case 'F':
791 if (file_name)
792 error (EXIT_FAILURE, 0, _("only one device may be specified"));
793 file_name = optarg;
794 break;
796 case_GETOPT_HELP_CHAR;
798 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
800 default:
801 noargs = false;
803 /* Skip the argument containing this unrecognized option;
804 the 2nd pass will analyze it. */
805 argi += opti;
807 /* Restart getopt_long from the first unskipped argument. */
808 opti = 1;
809 optind = 0;
811 break;
814 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
815 while (opti < optind)
816 argv[argi + opti++] = NULL;
819 /* Specifying both -a and -g gets an error. */
820 if (verbose_output && recoverable_output)
821 error (EXIT_FAILURE, 0,
822 _("the options for verbose and stty-readable output styles are\n"
823 "mutually exclusive"));
825 /* Specifying any other arguments with -a or -g gets an error. */
826 if (!noargs && (verbose_output || recoverable_output))
827 error (EXIT_FAILURE, 0,
828 _("when specifying an output style, modes may not be set"));
830 /* FIXME: it'd be better not to open the file until we've verified
831 that all arguments are valid. Otherwise, we could end up doing
832 only some of the requested operations and then failing, probably
833 leaving things in an undesirable state. */
835 if (file_name)
837 int fdflags;
838 device_name = file_name;
839 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
840 error (EXIT_FAILURE, errno, "%s", device_name);
841 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
842 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
843 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
844 device_name);
846 else
847 device_name = _("standard input");
849 if (tcgetattr (STDIN_FILENO, &mode))
850 error (EXIT_FAILURE, errno, "%s", device_name);
852 if (verbose_output || recoverable_output || noargs)
854 max_col = screen_columns ();
855 current_col = 0;
856 display_settings (output_type, &mode, device_name);
857 exit (EXIT_SUCCESS);
860 speed_was_set = false;
861 require_set_attr = false;
862 for (k = 1; k < argc; k++)
864 char const *arg = argv[k];
865 bool match_found = false;
866 bool reversed = false;
867 int i;
869 if (! arg)
870 continue;
872 if (arg[0] == '-')
874 ++arg;
875 reversed = true;
877 for (i = 0; mode_info[i].name != NULL; ++i)
879 if (STREQ (arg, mode_info[i].name))
881 match_found = set_mode (&mode_info[i], reversed, &mode);
882 require_set_attr = true;
883 break;
886 if (!match_found && reversed)
888 error (0, 0, _("invalid argument %s"), quote (arg - 1));
889 usage (EXIT_FAILURE);
891 if (!match_found)
893 for (i = 0; control_info[i].name != NULL; ++i)
895 if (STREQ (arg, control_info[i].name))
897 if (k == argc - 1)
899 error (0, 0, _("missing argument to %s"), quote (arg));
900 usage (EXIT_FAILURE);
902 match_found = true;
903 ++k;
904 set_control_char (&control_info[i], argv[k], &mode);
905 require_set_attr = true;
906 break;
910 if (!match_found)
912 if (STREQ (arg, "ispeed"))
914 if (k == argc - 1)
916 error (0, 0, _("missing argument to %s"), quote (arg));
917 usage (EXIT_FAILURE);
919 ++k;
920 set_speed (input_speed, argv[k], &mode);
921 speed_was_set = true;
922 require_set_attr = true;
924 else if (STREQ (arg, "ospeed"))
926 if (k == argc - 1)
928 error (0, 0, _("missing argument to %s"), quote (arg));
929 usage (EXIT_FAILURE);
931 ++k;
932 set_speed (output_speed, argv[k], &mode);
933 speed_was_set = true;
934 require_set_attr = true;
936 #ifdef TIOCGWINSZ
937 else if (STREQ (arg, "rows"))
939 if (k == argc - 1)
941 error (0, 0, _("missing argument to %s"), quote (arg));
942 usage (EXIT_FAILURE);
944 ++k;
945 set_window_size (integer_arg (argv[k], INT_MAX), -1,
946 device_name);
948 else if (STREQ (arg, "cols")
949 || STREQ (arg, "columns"))
951 if (k == argc - 1)
953 error (0, 0, _("missing argument to %s"), quote (arg));
954 usage (EXIT_FAILURE);
956 ++k;
957 set_window_size (-1, integer_arg (argv[k], INT_MAX),
958 device_name);
960 else if (STREQ (arg, "size"))
962 max_col = screen_columns ();
963 current_col = 0;
964 display_window_size (false, device_name);
966 #endif
967 #ifdef HAVE_C_LINE
968 else if (STREQ (arg, "line"))
970 unsigned long int value;
971 if (k == argc - 1)
973 error (0, 0, _("missing argument to %s"), quote (arg));
974 usage (EXIT_FAILURE);
976 ++k;
977 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
978 if (mode.c_line != value)
979 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
980 require_set_attr = true;
982 #endif
983 else if (STREQ (arg, "speed"))
985 max_col = screen_columns ();
986 display_speed (&mode, false);
988 else if (string_to_baud (arg) != (speed_t) -1)
990 set_speed (both_speeds, arg, &mode);
991 speed_was_set = true;
992 require_set_attr = true;
994 else
996 if (! recover_mode (arg, &mode))
998 error (0, 0, _("invalid argument %s"), quote (arg));
999 usage (EXIT_FAILURE);
1001 require_set_attr = true;
1006 if (require_set_attr)
1008 /* Initialize to all zeroes so there is no risk memcmp will report a
1009 spurious difference in an uninitialized portion of the structure. */
1010 DECLARE_ZEROED_AGGREGATE (struct termios, new_mode);
1012 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1013 error (EXIT_FAILURE, errno, "%s", device_name);
1015 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1016 it performs *any* of the requested operations. This means it
1017 can report `success' when it has actually failed to perform
1018 some proper subset of the requested operations. To detect
1019 this partial failure, get the current terminal attributes and
1020 compare them to the requested ones. */
1022 if (tcgetattr (STDIN_FILENO, &new_mode))
1023 error (EXIT_FAILURE, errno, "%s", device_name);
1025 /* Normally, one shouldn't use memcmp to compare structures that
1026 may have `holes' containing uninitialized data, but we have been
1027 careful to initialize the storage of these two variables to all
1028 zeroes. One might think it more efficient simply to compare the
1029 modified fields, but that would require enumerating those fields --
1030 and not all systems have the same fields in this structure. */
1032 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1034 #ifdef CIBAUD
1035 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1036 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1037 sometimes (m1 != m2). The only difference is in the four bits
1038 of the c_cflag field corresponding to the baud rate. To save
1039 Sun users a little confusion, don't report an error if this
1040 happens. But suppress the error only if we haven't tried to
1041 set the baud rate explicitly -- otherwise we'd never give an
1042 error for a true failure to set the baud rate. */
1044 new_mode.c_cflag &= (~CIBAUD);
1045 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1046 #endif
1048 error (EXIT_FAILURE, 0,
1049 _("%s: unable to perform all requested operations"),
1050 device_name);
1051 #ifdef TESTING
1053 size_t i;
1054 printf ("new_mode: mode\n");
1055 for (i = 0; i < sizeof (new_mode); i++)
1056 printf ("0x%02x: 0x%02x\n",
1057 *(((unsigned char *) &new_mode) + i),
1058 *(((unsigned char *) &mode) + i));
1060 #endif
1065 exit (EXIT_SUCCESS);
1068 /* Return false if not applied because not reversible; otherwise
1069 return true. */
1071 static bool
1072 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1074 tcflag_t *bitsp;
1076 if (reversed && (info->flags & REV) == 0)
1077 return false;
1079 bitsp = mode_type_flag (info->type, mode);
1081 if (bitsp == NULL)
1083 /* Combination mode. */
1084 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1086 if (reversed)
1087 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1088 else
1089 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1091 else if (STREQ (info->name, "oddp"))
1093 if (reversed)
1094 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1095 else
1096 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1098 else if (STREQ (info->name, "nl"))
1100 if (reversed)
1102 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1103 mode->c_oflag = (mode->c_oflag
1104 #ifdef ONLCR
1105 | ONLCR
1106 #endif
1108 #ifdef OCRNL
1109 & ~OCRNL
1110 #endif
1111 #ifdef ONLRET
1112 & ~ONLRET
1113 #endif
1116 else
1118 mode->c_iflag = mode->c_iflag & ~ICRNL;
1119 #ifdef ONLCR
1120 mode->c_oflag = mode->c_oflag & ~ONLCR;
1121 #endif
1124 else if (STREQ (info->name, "ek"))
1126 mode->c_cc[VERASE] = CERASE;
1127 mode->c_cc[VKILL] = CKILL;
1129 else if (STREQ (info->name, "sane"))
1130 sane_mode (mode);
1131 else if (STREQ (info->name, "cbreak"))
1133 if (reversed)
1134 mode->c_lflag |= ICANON;
1135 else
1136 mode->c_lflag &= ~ICANON;
1138 else if (STREQ (info->name, "pass8"))
1140 if (reversed)
1142 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1143 mode->c_iflag |= ISTRIP;
1145 else
1147 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1148 mode->c_iflag &= ~ISTRIP;
1151 else if (STREQ (info->name, "litout"))
1153 if (reversed)
1155 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1156 mode->c_iflag |= ISTRIP;
1157 mode->c_oflag |= OPOST;
1159 else
1161 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1162 mode->c_iflag &= ~ISTRIP;
1163 mode->c_oflag &= ~OPOST;
1166 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1168 if ((info->name[0] == 'r' && reversed)
1169 || (info->name[0] == 'c' && !reversed))
1171 /* Cooked mode. */
1172 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1173 mode->c_oflag |= OPOST;
1174 mode->c_lflag |= ISIG | ICANON;
1175 #if VMIN == VEOF
1176 mode->c_cc[VEOF] = CEOF;
1177 #endif
1178 #if VTIME == VEOL
1179 mode->c_cc[VEOL] = CEOL;
1180 #endif
1182 else
1184 /* Raw mode. */
1185 mode->c_iflag = 0;
1186 mode->c_oflag &= ~OPOST;
1187 mode->c_lflag &= ~(ISIG | ICANON
1188 #ifdef XCASE
1189 | XCASE
1190 #endif
1192 mode->c_cc[VMIN] = 1;
1193 mode->c_cc[VTIME] = 0;
1196 #ifdef IXANY
1197 else if (STREQ (info->name, "decctlq"))
1199 if (reversed)
1200 mode->c_iflag |= IXANY;
1201 else
1202 mode->c_iflag &= ~IXANY;
1204 #endif
1205 #ifdef TABDLY
1206 else if (STREQ (info->name, "tabs"))
1208 if (reversed)
1209 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1210 else
1211 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1213 #else
1214 # ifdef OXTABS
1215 else if (STREQ (info->name, "tabs"))
1217 if (reversed)
1218 mode->c_oflag = mode->c_oflag | OXTABS;
1219 else
1220 mode->c_oflag = mode->c_oflag & ~OXTABS;
1222 # endif
1223 #endif
1224 #if defined XCASE && defined IUCLC && defined OLCUC
1225 else if (STREQ (info->name, "lcase")
1226 || STREQ (info->name, "LCASE"))
1228 if (reversed)
1230 mode->c_lflag &= ~XCASE;
1231 mode->c_iflag &= ~IUCLC;
1232 mode->c_oflag &= ~OLCUC;
1234 else
1236 mode->c_lflag |= XCASE;
1237 mode->c_iflag |= IUCLC;
1238 mode->c_oflag |= OLCUC;
1241 #endif
1242 else if (STREQ (info->name, "crt"))
1243 mode->c_lflag |= ECHOE
1244 #ifdef ECHOCTL
1245 | ECHOCTL
1246 #endif
1247 #ifdef ECHOKE
1248 | ECHOKE
1249 #endif
1251 else if (STREQ (info->name, "dec"))
1253 mode->c_cc[VINTR] = 3; /* ^C */
1254 mode->c_cc[VERASE] = 127; /* DEL */
1255 mode->c_cc[VKILL] = 21; /* ^U */
1256 mode->c_lflag |= ECHOE
1257 #ifdef ECHOCTL
1258 | ECHOCTL
1259 #endif
1260 #ifdef ECHOKE
1261 | ECHOKE
1262 #endif
1264 #ifdef IXANY
1265 mode->c_iflag &= ~IXANY;
1266 #endif
1269 else if (reversed)
1270 *bitsp = *bitsp & ~info->mask & ~info->bits;
1271 else
1272 *bitsp = (*bitsp & ~info->mask) | info->bits;
1274 return true;
1277 static void
1278 set_control_char (struct control_info const *info, const char *arg,
1279 struct termios *mode)
1281 unsigned long int value;
1283 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1284 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1285 else if (arg[0] == '\0' || arg[1] == '\0')
1286 value = to_uchar (arg[0]);
1287 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1288 value = _POSIX_VDISABLE;
1289 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1291 if (arg[1] == '?')
1292 value = 127;
1293 else
1294 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1296 else
1297 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1298 mode->c_cc[info->offset] = value;
1301 static void
1302 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1304 speed_t baud;
1306 baud = string_to_baud (arg);
1307 if (type == input_speed || type == both_speeds)
1308 cfsetispeed (mode, baud);
1309 if (type == output_speed || type == both_speeds)
1310 cfsetospeed (mode, baud);
1313 #ifdef TIOCGWINSZ
1315 static int
1316 get_win_size (int fd, struct winsize *win)
1318 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1319 return err;
1322 static void
1323 set_window_size (int rows, int cols, char const *device_name)
1325 struct winsize win;
1327 if (get_win_size (STDIN_FILENO, &win))
1329 if (errno != EINVAL)
1330 error (EXIT_FAILURE, errno, "%s", device_name);
1331 memset (&win, 0, sizeof (win));
1334 if (rows >= 0)
1335 win.ws_row = rows;
1336 if (cols >= 0)
1337 win.ws_col = cols;
1339 # ifdef TIOCSSIZE
1340 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1341 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1342 This comment from sys/ttold.h describes Sun's twisted logic - a better
1343 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1344 At any rate, the problem is gone in Solaris 2.x.
1346 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1347 but they can be disambiguated by checking whether a "struct ttysize"
1348 structure's "ts_lines" field is greater than 64K or not. If so,
1349 it's almost certainly a "struct winsize" instead.
1351 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1352 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1353 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1354 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1355 "stty cols 0 rows 0" would do the right thing. On a little-endian
1356 machine like the sun386i, the problem is the same, but for ws_col == 0.
1358 The workaround is to do the ioctl once with row and col = 1 to set the
1359 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1361 if (win.ws_row == 0 || win.ws_col == 0)
1363 struct ttysize ttysz;
1365 ttysz.ts_lines = win.ws_row;
1366 ttysz.ts_cols = win.ws_col;
1368 win.ws_row = 1;
1369 win.ws_col = 1;
1371 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1372 error (EXIT_FAILURE, errno, "%s", device_name);
1374 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1375 error (EXIT_FAILURE, errno, "%s", device_name);
1376 return;
1378 # endif
1380 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1381 error (EXIT_FAILURE, errno, "%s", device_name);
1384 static void
1385 display_window_size (bool fancy, char const *device_name)
1387 struct winsize win;
1389 if (get_win_size (STDIN_FILENO, &win))
1391 if (errno != EINVAL)
1392 error (EXIT_FAILURE, errno, "%s", device_name);
1393 if (!fancy)
1394 error (EXIT_FAILURE, 0,
1395 _("%s: no size information for this device"), device_name);
1397 else
1399 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1400 win.ws_row, win.ws_col);
1401 if (!fancy)
1402 current_col = 0;
1405 #endif
1407 static int
1408 screen_columns (void)
1410 #ifdef TIOCGWINSZ
1411 struct winsize win;
1413 /* With Solaris 2.[123], this ioctl fails and errno is set to
1414 EINVAL for telnet (but not rlogin) sessions.
1415 On ISC 3.0, it fails for the console and the serial port
1416 (but it works for ptys).
1417 It can also fail on any system when stdout isn't a tty.
1418 In case of any failure, just use the default. */
1419 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1420 return win.ws_col;
1421 #endif
1423 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1424 char *col_string = getenv ("COLUMNS");
1425 long int n_columns;
1426 if (!(col_string != NULL
1427 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1428 && 0 < n_columns
1429 && n_columns <= INT_MAX))
1430 n_columns = 80;
1431 return n_columns;
1435 static tcflag_t *
1436 mode_type_flag (enum mode_type type, struct termios *mode)
1438 switch (type)
1440 case control:
1441 return &mode->c_cflag;
1443 case input:
1444 return &mode->c_iflag;
1446 case output:
1447 return &mode->c_oflag;
1449 case local:
1450 return &mode->c_lflag;
1452 case combination:
1453 return NULL;
1455 default:
1456 abort ();
1460 static void
1461 display_settings (enum output_type output_type, struct termios *mode,
1462 char const *device_name)
1464 switch (output_type)
1466 case changed:
1467 display_changed (mode);
1468 break;
1470 case all:
1471 display_all (mode, device_name);
1472 break;
1474 case recoverable:
1475 display_recoverable (mode);
1476 break;
1480 static void
1481 display_changed (struct termios *mode)
1483 int i;
1484 bool empty_line;
1485 tcflag_t *bitsp;
1486 unsigned long mask;
1487 enum mode_type prev_type = control;
1489 display_speed (mode, true);
1490 #ifdef HAVE_C_LINE
1491 wrapf ("line = %d;", mode->c_line);
1492 #endif
1493 putchar ('\n');
1494 current_col = 0;
1496 empty_line = true;
1497 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1499 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1500 continue;
1501 /* If swtch is the same as susp, don't print both. */
1502 #if VSWTCH == VSUSP
1503 if (STREQ (control_info[i].name, "swtch"))
1504 continue;
1505 #endif
1506 /* If eof uses the same slot as min, only print whichever applies. */
1507 #if VEOF == VMIN
1508 if ((mode->c_lflag & ICANON) == 0
1509 && (STREQ (control_info[i].name, "eof")
1510 || STREQ (control_info[i].name, "eol")))
1511 continue;
1512 #endif
1514 empty_line = false;
1515 wrapf ("%s = %s;", control_info[i].name,
1516 visible (mode->c_cc[control_info[i].offset]));
1518 if ((mode->c_lflag & ICANON) == 0)
1520 wrapf ("min = %lu; time = %lu;\n",
1521 (unsigned long int) mode->c_cc[VMIN],
1522 (unsigned long int) mode->c_cc[VTIME]);
1524 else if (!empty_line)
1525 putchar ('\n');
1526 current_col = 0;
1528 empty_line = true;
1529 for (i = 0; mode_info[i].name != NULL; ++i)
1531 if (mode_info[i].flags & OMIT)
1532 continue;
1533 if (mode_info[i].type != prev_type)
1535 if (!empty_line)
1537 putchar ('\n');
1538 current_col = 0;
1539 empty_line = true;
1541 prev_type = mode_info[i].type;
1544 bitsp = mode_type_flag (mode_info[i].type, mode);
1545 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1546 if ((*bitsp & mask) == mode_info[i].bits)
1548 if (mode_info[i].flags & SANE_UNSET)
1550 wrapf ("%s", mode_info[i].name);
1551 empty_line = false;
1554 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1556 wrapf ("-%s", mode_info[i].name);
1557 empty_line = false;
1560 if (!empty_line)
1561 putchar ('\n');
1562 current_col = 0;
1565 static void
1566 display_all (struct termios *mode, char const *device_name)
1568 int i;
1569 tcflag_t *bitsp;
1570 unsigned long mask;
1571 enum mode_type prev_type = control;
1573 display_speed (mode, true);
1574 #ifdef TIOCGWINSZ
1575 display_window_size (true, device_name);
1576 #endif
1577 #ifdef HAVE_C_LINE
1578 wrapf ("line = %d;", mode->c_line);
1579 #endif
1580 putchar ('\n');
1581 current_col = 0;
1583 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1585 /* If swtch is the same as susp, don't print both. */
1586 #if VSWTCH == VSUSP
1587 if (STREQ (control_info[i].name, "swtch"))
1588 continue;
1589 #endif
1590 /* If eof uses the same slot as min, only print whichever applies. */
1591 #if VEOF == VMIN
1592 if ((mode->c_lflag & ICANON) == 0
1593 && (STREQ (control_info[i].name, "eof")
1594 || STREQ (control_info[i].name, "eol")))
1595 continue;
1596 #endif
1597 wrapf ("%s = %s;", control_info[i].name,
1598 visible (mode->c_cc[control_info[i].offset]));
1600 #if VEOF == VMIN
1601 if ((mode->c_lflag & ICANON) == 0)
1602 #endif
1603 wrapf ("min = %lu; time = %lu;",
1604 (unsigned long int) mode->c_cc[VMIN],
1605 (unsigned long int) mode->c_cc[VTIME]);
1606 if (current_col != 0)
1607 putchar ('\n');
1608 current_col = 0;
1610 for (i = 0; mode_info[i].name != NULL; ++i)
1612 if (mode_info[i].flags & OMIT)
1613 continue;
1614 if (mode_info[i].type != prev_type)
1616 putchar ('\n');
1617 current_col = 0;
1618 prev_type = mode_info[i].type;
1621 bitsp = mode_type_flag (mode_info[i].type, mode);
1622 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1623 if ((*bitsp & mask) == mode_info[i].bits)
1624 wrapf ("%s", mode_info[i].name);
1625 else if (mode_info[i].flags & REV)
1626 wrapf ("-%s", mode_info[i].name);
1628 putchar ('\n');
1629 current_col = 0;
1632 static void
1633 display_speed (struct termios *mode, bool fancy)
1635 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1636 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1637 baud_to_value (cfgetospeed (mode)));
1638 else
1639 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1640 baud_to_value (cfgetispeed (mode)),
1641 baud_to_value (cfgetospeed (mode)));
1642 if (!fancy)
1643 current_col = 0;
1646 static void
1647 display_recoverable (struct termios *mode)
1649 size_t i;
1651 printf ("%lx:%lx:%lx:%lx",
1652 (unsigned long int) mode->c_iflag,
1653 (unsigned long int) mode->c_oflag,
1654 (unsigned long int) mode->c_cflag,
1655 (unsigned long int) mode->c_lflag);
1656 for (i = 0; i < NCCS; ++i)
1657 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1658 putchar ('\n');
1661 /* NOTE: identical to below, modulo use of tcflag_t */
1662 static int
1663 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1664 char delim)
1666 unsigned long ul;
1667 errno = 0;
1668 ul = strtoul (s, p, base);
1669 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1670 return -1;
1671 *result = ul;
1672 return 0;
1675 /* NOTE: identical to above, modulo use of cc_t */
1676 static int
1677 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1679 unsigned long ul;
1680 errno = 0;
1681 ul = strtoul (s, p, base);
1682 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1683 return -1;
1684 *result = ul;
1685 return 0;
1688 /* Parse the output of display_recoverable.
1689 Return false if any part of it is invalid. */
1690 static bool
1691 recover_mode (char const *arg, struct termios *mode)
1693 tcflag_t flag[4];
1694 char const *s = arg;
1695 size_t i;
1696 for (i = 0; i < 4; i++)
1698 char *p;
1699 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1700 return false;
1701 s = p + 1;
1703 mode->c_iflag = flag[0];
1704 mode->c_oflag = flag[1];
1705 mode->c_cflag = flag[2];
1706 mode->c_lflag = flag[3];
1708 for (i = 0; i < NCCS; ++i)
1710 char *p;
1711 char delim = i < NCCS - 1 ? ':' : '\0';
1712 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1713 return false;
1714 s = p + 1;
1717 return true;
1720 struct speed_map
1722 const char *string; /* ASCII representation. */
1723 speed_t speed; /* Internal form. */
1724 unsigned long int value; /* Numeric value. */
1727 static struct speed_map const speeds[] =
1729 {"0", B0, 0},
1730 {"50", B50, 50},
1731 {"75", B75, 75},
1732 {"110", B110, 110},
1733 {"134", B134, 134},
1734 {"134.5", B134, 134},
1735 {"150", B150, 150},
1736 {"200", B200, 200},
1737 {"300", B300, 300},
1738 {"600", B600, 600},
1739 {"1200", B1200, 1200},
1740 {"1800", B1800, 1800},
1741 {"2400", B2400, 2400},
1742 {"4800", B4800, 4800},
1743 {"9600", B9600, 9600},
1744 {"19200", B19200, 19200},
1745 {"38400", B38400, 38400},
1746 {"exta", B19200, 19200},
1747 {"extb", B38400, 38400},
1748 #ifdef B57600
1749 {"57600", B57600, 57600},
1750 #endif
1751 #ifdef B115200
1752 {"115200", B115200, 115200},
1753 #endif
1754 #ifdef B230400
1755 {"230400", B230400, 230400},
1756 #endif
1757 #ifdef B460800
1758 {"460800", B460800, 460800},
1759 #endif
1760 #ifdef B500000
1761 {"500000", B500000, 500000},
1762 #endif
1763 #ifdef B576000
1764 {"576000", B576000, 576000},
1765 #endif
1766 #ifdef B921600
1767 {"921600", B921600, 921600},
1768 #endif
1769 #ifdef B1000000
1770 {"1000000", B1000000, 1000000},
1771 #endif
1772 #ifdef B1152000
1773 {"1152000", B1152000, 1152000},
1774 #endif
1775 #ifdef B1500000
1776 {"1500000", B1500000, 1500000},
1777 #endif
1778 #ifdef B2000000
1779 {"2000000", B2000000, 2000000},
1780 #endif
1781 #ifdef B2500000
1782 {"2500000", B2500000, 2500000},
1783 #endif
1784 #ifdef B3000000
1785 {"3000000", B3000000, 3000000},
1786 #endif
1787 #ifdef B3500000
1788 {"3500000", B3500000, 3500000},
1789 #endif
1790 #ifdef B4000000
1791 {"4000000", B4000000, 4000000},
1792 #endif
1793 {NULL, 0, 0}
1796 static speed_t
1797 string_to_baud (const char *arg)
1799 int i;
1801 for (i = 0; speeds[i].string != NULL; ++i)
1802 if (STREQ (arg, speeds[i].string))
1803 return speeds[i].speed;
1804 return (speed_t) -1;
1807 static unsigned long int
1808 baud_to_value (speed_t speed)
1810 int i;
1812 for (i = 0; speeds[i].string != NULL; ++i)
1813 if (speed == speeds[i].speed)
1814 return speeds[i].value;
1815 return 0;
1818 static void
1819 sane_mode (struct termios *mode)
1821 int i;
1822 tcflag_t *bitsp;
1824 for (i = 0; control_info[i].name; ++i)
1826 #if VMIN == VEOF
1827 if (STREQ (control_info[i].name, "min"))
1828 break;
1829 #endif
1830 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1833 for (i = 0; mode_info[i].name != NULL; ++i)
1835 if (mode_info[i].flags & SANE_SET)
1837 bitsp = mode_type_flag (mode_info[i].type, mode);
1838 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1840 else if (mode_info[i].flags & SANE_UNSET)
1842 bitsp = mode_type_flag (mode_info[i].type, mode);
1843 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1848 /* Return a string that is the printable representation of character CH. */
1849 /* Adapted from `cat' by Torbjorn Granlund. */
1851 static const char *
1852 visible (cc_t ch)
1854 static char buf[10];
1855 char *bpout = buf;
1857 if (ch == _POSIX_VDISABLE)
1858 return "<undef>";
1860 if (ch >= 32)
1862 if (ch < 127)
1863 *bpout++ = ch;
1864 else if (ch == 127)
1866 *bpout++ = '^';
1867 *bpout++ = '?';
1869 else
1871 *bpout++ = 'M';
1872 *bpout++ = '-';
1873 if (ch >= 128 + 32)
1875 if (ch < 128 + 127)
1876 *bpout++ = ch - 128;
1877 else
1879 *bpout++ = '^';
1880 *bpout++ = '?';
1883 else
1885 *bpout++ = '^';
1886 *bpout++ = ch - 128 + 64;
1890 else
1892 *bpout++ = '^';
1893 *bpout++ = ch + 64;
1895 *bpout = '\0';
1896 return (const char *) buf;
1899 /* Parse string S as an integer, using decimal radix by default,
1900 but allowing octal and hex numbers as in C. Reject values
1901 larger than MAXVAL. */
1903 static unsigned long int
1904 integer_arg (const char *s, unsigned long int maxval)
1906 unsigned long int value;
1907 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1909 error (0, 0, _("invalid integer argument %s"), quote (s));
1910 usage (EXIT_FAILURE);
1912 return value;