maint: cleanup up various uses of __attribute__
[coreutils.git] / src / stty.c
blobe518839d58e08bf1e762563a0304a9c106afd53b
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2013 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>
55 #include <assert.h>
57 #include "system.h"
58 #include "error.h"
59 #include "fd-reopen.h"
60 #include "quote.h"
61 #include "xstrtol.h"
63 /* The official name of this program (e.g., no 'g' prefix). */
64 #define PROGRAM_NAME "stty"
66 #define AUTHORS proper_name ("David MacKenzie")
68 #ifndef _POSIX_VDISABLE
69 # define _POSIX_VDISABLE 0
70 #endif
72 #define Control(c) ((c) & 0x1f)
73 /* Canonical values for control characters. */
74 #ifndef CINTR
75 # define CINTR Control ('c')
76 #endif
77 #ifndef CQUIT
78 # define CQUIT 28
79 #endif
80 #ifndef CERASE
81 # define CERASE 127
82 #endif
83 #ifndef CKILL
84 # define CKILL Control ('u')
85 #endif
86 #ifndef CEOF
87 # define CEOF Control ('d')
88 #endif
89 #ifndef CEOL
90 # define CEOL _POSIX_VDISABLE
91 #endif
92 #ifndef CSTART
93 # define CSTART Control ('q')
94 #endif
95 #ifndef CSTOP
96 # define CSTOP Control ('s')
97 #endif
98 #ifndef CSUSP
99 # define CSUSP Control ('z')
100 #endif
101 #if defined VEOL2 && !defined CEOL2
102 # define CEOL2 _POSIX_VDISABLE
103 #endif
104 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
105 character is initialized by CSWTCH, if present. */
106 #if defined VSWTC && !defined VSWTCH
107 # define VSWTCH VSWTC
108 #endif
109 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
110 #if defined VSUSP && !defined VSWTCH
111 # define VSWTCH VSUSP
112 # if defined CSUSP && !defined CSWTCH
113 # define CSWTCH CSUSP
114 # endif
115 #endif
116 #if defined VSWTCH && !defined CSWTCH
117 # define CSWTCH _POSIX_VDISABLE
118 #endif
120 /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
121 So the default is to disable 'swtch.' */
122 #if defined __sparc__ && defined __svr4__
123 # undef CSWTCH
124 # define CSWTCH _POSIX_VDISABLE
125 #endif
127 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
128 # define VWERASE VWERSE
129 #endif
130 #if defined VDSUSP && !defined CDSUSP
131 # define CDSUSP Control ('y')
132 #endif
133 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
134 # define VREPRINT VRPRNT
135 #endif
136 #if defined VREPRINT && !defined CRPRNT
137 # define CRPRNT Control ('r')
138 #endif
139 #if defined CREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
141 #endif
142 #if defined VWERASE && !defined CWERASE
143 # define CWERASE Control ('w')
144 #endif
145 #if defined VLNEXT && !defined CLNEXT
146 # define CLNEXT Control ('v')
147 #endif
148 #if defined VDISCARD && !defined VFLUSHO
149 # define VFLUSHO VDISCARD
150 #endif
151 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
152 # define VFLUSHO VFLUSH
153 #endif
154 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
155 # define ECHOCTL CTLECH
156 #endif
157 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
158 # define ECHOCTL TCTLECH
159 #endif
160 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
161 # define ECHOKE CRTKIL
162 #endif
163 #if defined VFLUSHO && !defined CFLUSHO
164 # define CFLUSHO Control ('o')
165 #endif
166 #if defined VSTATUS && !defined CSTATUS
167 # define CSTATUS Control ('t')
168 #endif
170 /* Which speeds to set. */
171 enum speed_setting
173 input_speed, output_speed, both_speeds
176 /* What to output and how. */
177 enum output_type
179 changed, all, recoverable /* Default, -a, -g. */
182 /* Which member(s) of 'struct termios' a mode uses. */
183 enum mode_type
185 control, input, output, local, combination
188 /* Flags for 'struct mode_info'. */
189 #define SANE_SET 1 /* Set in 'sane' mode. */
190 #define SANE_UNSET 2 /* Unset in 'sane' mode. */
191 #define REV 4 /* Can be turned off by prepending '-'. */
192 #define OMIT 8 /* Don't display value. */
194 /* Each mode. */
195 struct mode_info
197 const char *name; /* Name given on command line. */
198 enum mode_type type; /* Which structure element to change. */
199 char flags; /* Setting and display options. */
200 unsigned long bits; /* Bits to set for this mode. */
201 unsigned long mask; /* Other bits to turn off for this mode. */
204 static struct mode_info const mode_info[] =
206 {"parenb", control, REV, PARENB, 0},
207 {"parodd", control, REV, PARODD, 0},
208 {"cs5", control, 0, CS5, CSIZE},
209 {"cs6", control, 0, CS6, CSIZE},
210 {"cs7", control, 0, CS7, CSIZE},
211 {"cs8", control, 0, CS8, CSIZE},
212 {"hupcl", control, REV, HUPCL, 0},
213 {"hup", control, REV | OMIT, HUPCL, 0},
214 {"cstopb", control, REV, CSTOPB, 0},
215 {"cread", control, SANE_SET | REV, CREAD, 0},
216 {"clocal", control, REV, CLOCAL, 0},
217 #ifdef CRTSCTS
218 {"crtscts", control, REV, CRTSCTS, 0},
219 #endif
220 #ifdef CDTRDSR
221 {"cdtrdsr", control, REV, CDTRDSR, 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 emit_try_help ();
511 else
513 printf (_("\
514 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
515 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
516 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
518 program_name, program_name, program_name);
519 fputs (_("\
520 Print or change terminal characteristics.\n\
521 "), stdout);
523 emit_mandatory_arg_note ();
525 fputs (_("\
526 -a, --all print all current settings in human-readable form\n\
527 -g, --save print all current settings in a stty-readable form\n\
528 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
529 "), stdout);
530 fputs (HELP_OPTION_DESCRIPTION, stdout);
531 fputs (VERSION_OPTION_DESCRIPTION, stdout);
532 fputs (_("\
534 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
535 settings. The underlying system defines which settings are available.\n\
536 "), stdout);
537 fputs (_("\
539 Special characters:\n\
540 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
541 eof CHAR CHAR will send an end of file (terminate the input)\n\
542 eol CHAR CHAR will end the line\n\
543 "), stdout);
544 fputs (_("\
545 * eol2 CHAR alternate CHAR for ending the line\n\
546 erase CHAR CHAR will erase the last character typed\n\
547 intr CHAR CHAR will send an interrupt signal\n\
548 kill CHAR CHAR will erase the current line\n\
549 "), stdout);
550 fputs (_("\
551 * lnext CHAR CHAR will enter the next character quoted\n\
552 quit CHAR CHAR will send a quit signal\n\
553 * rprnt CHAR CHAR will redraw the current line\n\
554 start CHAR CHAR will restart the output after stopping it\n\
555 "), stdout);
556 fputs (_("\
557 stop CHAR CHAR will stop the output\n\
558 susp CHAR CHAR will send a terminal stop signal\n\
559 * swtch CHAR CHAR will switch to a different shell layer\n\
560 * werase CHAR CHAR will erase the last word typed\n\
561 "), stdout);
562 fputs (_("\
564 Special settings:\n\
565 N set the input and output speeds to N bauds\n\
566 * cols N tell the kernel that the terminal has N columns\n\
567 * columns N same as cols N\n\
568 "), stdout);
569 fputs (_("\
570 ispeed N set the input speed to N\n\
571 * line N use line discipline N\n\
572 min N with -icanon, set N characters minimum for a completed read\n\
573 ospeed N set the output speed to N\n\
574 "), stdout);
575 fputs (_("\
576 * rows N tell the kernel that the terminal has N rows\n\
577 * size print the number of rows and columns according to the kernel\n\
578 speed print the terminal speed\n\
579 time N with -icanon, set read timeout of N tenths of a second\n\
580 "), stdout);
581 fputs (_("\
583 Control settings:\n\
584 [-]clocal disable modem control signals\n\
585 [-]cread allow input to be received\n\
586 * [-]crtscts enable RTS/CTS handshaking\n\
587 * [-]cdtrdsr enable DTR/DSR handshaking\n\
588 csN set character size to N bits, N in [5..8]\n\
589 "), stdout);
590 fputs (_("\
591 [-]cstopb use two stop bits per character (one with '-')\n\
592 [-]hup send a hangup signal when the last process closes the tty\n\
593 [-]hupcl same as [-]hup\n\
594 [-]parenb generate parity bit in output and expect parity bit in input\n\
595 [-]parodd set odd parity (or even parity with '-')\n\
596 "), stdout);
597 fputs (_("\
599 Input settings:\n\
600 [-]brkint breaks cause an interrupt signal\n\
601 [-]icrnl translate carriage return to newline\n\
602 [-]ignbrk ignore break characters\n\
603 [-]igncr ignore carriage return\n\
604 "), stdout);
605 fputs (_("\
606 [-]ignpar ignore characters with parity errors\n\
607 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
608 [-]inlcr translate newline to carriage return\n\
609 [-]inpck enable input parity checking\n\
610 [-]istrip clear high (8th) bit of input characters\n\
611 "), stdout);
612 fputs (_("\
613 * [-]iutf8 assume input characters are UTF-8 encoded\n\
614 "), stdout);
615 fputs (_("\
616 * [-]iuclc translate uppercase characters to lowercase\n\
617 * [-]ixany let any character restart output, not only start character\n\
618 [-]ixoff enable sending of start/stop characters\n\
619 [-]ixon enable XON/XOFF flow control\n\
620 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
621 [-]tandem same as [-]ixoff\n\
622 "), stdout);
623 fputs (_("\
625 Output settings:\n\
626 * bsN backspace delay style, N in [0..1]\n\
627 * crN carriage return delay style, N in [0..3]\n\
628 * ffN form feed delay style, N in [0..1]\n\
629 * nlN newline delay style, N in [0..1]\n\
630 "), stdout);
631 fputs (_("\
632 * [-]ocrnl translate carriage return to newline\n\
633 * [-]ofdel use delete characters for fill instead of null characters\n\
634 * [-]ofill use fill (padding) characters instead of timing for delays\n\
635 * [-]olcuc translate lowercase characters to uppercase\n\
636 * [-]onlcr translate newline to carriage return-newline\n\
637 * [-]onlret newline performs a carriage return\n\
638 "), stdout);
639 fputs (_("\
640 * [-]onocr do not print carriage returns in the first column\n\
641 [-]opost postprocess output\n\
642 * tabN horizontal tab delay style, N in [0..3]\n\
643 * tabs same as tab0\n\
644 * -tabs same as tab3\n\
645 * vtN vertical tab delay style, N in [0..1]\n\
646 "), stdout);
647 fputs (_("\
649 Local settings:\n\
650 [-]crterase echo erase characters as backspace-space-backspace\n\
651 * crtkill kill all line by obeying the echoprt and echoe settings\n\
652 * -crtkill kill all line by obeying the echoctl and echok settings\n\
653 "), stdout);
654 fputs (_("\
655 * [-]ctlecho echo control characters in hat notation ('^c')\n\
656 [-]echo echo input characters\n\
657 * [-]echoctl same as [-]ctlecho\n\
658 [-]echoe same as [-]crterase\n\
659 [-]echok echo a newline after a kill character\n\
660 "), stdout);
661 fputs (_("\
662 * [-]echoke same as [-]crtkill\n\
663 [-]echonl echo newline even if not echoing other characters\n\
664 * [-]echoprt echo erased characters backward, between '\\' and '/'\n\
665 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
666 [-]iexten enable non-POSIX special characters\n\
667 "), stdout);
668 fputs (_("\
669 [-]isig enable interrupt, quit, and suspend special characters\n\
670 [-]noflsh disable flushing after interrupt and quit special characters\n\
671 * [-]prterase same as [-]echoprt\n\
672 * [-]tostop stop background jobs that try to write to the terminal\n\
673 * [-]xcase with icanon, escape with '\\' for uppercase characters\n\
674 "), stdout);
675 fputs (_("\
677 Combination settings:\n\
678 * [-]LCASE same as [-]lcase\n\
679 cbreak same as -icanon\n\
680 -cbreak same as icanon\n\
681 "), stdout);
682 fputs (_("\
683 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
684 icanon, eof and eol characters to their default values\n\
685 -cooked same as raw\n\
686 crt same as echoe echoctl echoke\n\
687 "), stdout);
688 fputs (_("\
689 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
690 kill ^u\n\
691 * [-]decctlq same as [-]ixany\n\
692 ek erase and kill characters to their default values\n\
693 evenp same as parenb -parodd cs7\n\
694 "), stdout);
695 fputs (_("\
696 -evenp same as -parenb cs8\n\
697 * [-]lcase same as xcase iuclc olcuc\n\
698 litout same as -parenb -istrip -opost cs8\n\
699 -litout same as parenb istrip opost cs7\n\
700 nl same as -icrnl -onlcr\n\
701 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
702 "), stdout);
703 fputs (_("\
704 oddp same as parenb parodd cs7\n\
705 -oddp same as -parenb cs8\n\
706 [-]parity same as [-]evenp\n\
707 pass8 same as -parenb -istrip cs8\n\
708 -pass8 same as parenb istrip cs7\n\
709 "), stdout);
710 fputs (_("\
711 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
712 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
713 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
714 -raw same as cooked\n\
715 "), stdout);
716 fputs (_("\
717 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
718 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
719 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
720 isig icanon iexten echo echoe echok -echonl -noflsh\n\
721 -xcase -tostop -echoprt echoctl echoke, all special\n\
722 characters to their default values\n\
723 "), stdout);
724 fputs (_("\
726 Handle the tty line connected to standard input. Without arguments,\n\
727 prints baud rate, line discipline, and deviations from stty sane. In\n\
728 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
729 127; special values ^- or undef used to disable special characters.\n\
730 "), stdout);
731 emit_ancillary_info ();
733 exit (status);
737 main (int argc, char **argv)
739 /* Initialize to all zeroes so there is no risk memcmp will report a
740 spurious difference in an uninitialized portion of the structure. */
741 static struct termios mode;
743 enum output_type output_type;
744 int optc;
745 int argi = 0;
746 int opti = 1;
747 bool require_set_attr;
748 bool speed_was_set _GL_UNUSED;
749 bool verbose_output;
750 bool recoverable_output;
751 int k;
752 bool noargs = true;
753 char *file_name = NULL;
754 const char *device_name;
756 initialize_main (&argc, &argv);
757 set_program_name (argv[0]);
758 setlocale (LC_ALL, "");
759 bindtextdomain (PACKAGE, LOCALEDIR);
760 textdomain (PACKAGE);
762 atexit (close_stdout);
764 output_type = changed;
765 verbose_output = false;
766 recoverable_output = false;
768 /* Don't print error messages for unrecognized options. */
769 opterr = 0;
771 /* If any new options are ever added to stty, the short options MUST
772 NOT allow any ambiguity with the stty settings. For example, the
773 stty setting "-gagFork" would not be feasible, since it will be
774 parsed as "-g -a -g -F ork". If you change anything about how
775 stty parses options, be sure it still works with combinations of
776 short and long options, --, POSIXLY_CORRECT, etc. */
778 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
779 longopts, NULL))
780 != -1)
782 switch (optc)
784 case 'a':
785 verbose_output = true;
786 output_type = all;
787 break;
789 case 'g':
790 recoverable_output = true;
791 output_type = recoverable;
792 break;
794 case 'F':
795 if (file_name)
796 error (EXIT_FAILURE, 0, _("only one device may be specified"));
797 file_name = optarg;
798 break;
800 case_GETOPT_HELP_CHAR;
802 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
804 default:
805 noargs = false;
807 /* Skip the argument containing this unrecognized option;
808 the 2nd pass will analyze it. */
809 argi += opti;
811 /* Restart getopt_long from the first unskipped argument. */
812 opti = 1;
813 optind = 0;
815 break;
818 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
819 while (opti < optind)
820 argv[argi + opti++] = NULL;
823 /* Specifying both -a and -g gets an error. */
824 if (verbose_output && recoverable_output)
825 error (EXIT_FAILURE, 0,
826 _("the options for verbose and stty-readable output styles are\n"
827 "mutually exclusive"));
829 /* Specifying any other arguments with -a or -g gets an error. */
830 if (!noargs && (verbose_output || recoverable_output))
831 error (EXIT_FAILURE, 0,
832 _("when specifying an output style, modes may not be set"));
834 /* FIXME: it'd be better not to open the file until we've verified
835 that all arguments are valid. Otherwise, we could end up doing
836 only some of the requested operations and then failing, probably
837 leaving things in an undesirable state. */
839 if (file_name)
841 int fdflags;
842 device_name = file_name;
843 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
844 error (EXIT_FAILURE, errno, "%s", device_name);
845 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
846 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
847 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
848 device_name);
850 else
851 device_name = _("standard input");
853 if (tcgetattr (STDIN_FILENO, &mode))
854 error (EXIT_FAILURE, errno, "%s", device_name);
856 if (verbose_output || recoverable_output || noargs)
858 max_col = screen_columns ();
859 current_col = 0;
860 display_settings (output_type, &mode, device_name);
861 exit (EXIT_SUCCESS);
864 speed_was_set = false;
865 require_set_attr = false;
866 for (k = 1; k < argc; k++)
868 char const *arg = argv[k];
869 bool match_found = false;
870 bool reversed = false;
871 int i;
873 if (! arg)
874 continue;
876 if (arg[0] == '-')
878 ++arg;
879 reversed = true;
881 for (i = 0; mode_info[i].name != NULL; ++i)
883 if (STREQ (arg, mode_info[i].name))
885 match_found = set_mode (&mode_info[i], reversed, &mode);
886 require_set_attr = true;
887 break;
890 if (!match_found && reversed)
892 error (0, 0, _("invalid argument %s"), quote (arg - 1));
893 usage (EXIT_FAILURE);
895 if (!match_found)
897 for (i = 0; control_info[i].name != NULL; ++i)
899 if (STREQ (arg, control_info[i].name))
901 if (k == argc - 1)
903 error (0, 0, _("missing argument to %s"), quote (arg));
904 usage (EXIT_FAILURE);
906 match_found = true;
907 ++k;
908 set_control_char (&control_info[i], argv[k], &mode);
909 require_set_attr = true;
910 break;
914 if (!match_found)
916 if (STREQ (arg, "ispeed"))
918 if (k == argc - 1)
920 error (0, 0, _("missing argument to %s"), quote (arg));
921 usage (EXIT_FAILURE);
923 ++k;
924 set_speed (input_speed, argv[k], &mode);
925 speed_was_set = true;
926 require_set_attr = true;
928 else if (STREQ (arg, "ospeed"))
930 if (k == argc - 1)
932 error (0, 0, _("missing argument to %s"), quote (arg));
933 usage (EXIT_FAILURE);
935 ++k;
936 set_speed (output_speed, argv[k], &mode);
937 speed_was_set = true;
938 require_set_attr = true;
940 #ifdef TIOCGWINSZ
941 else if (STREQ (arg, "rows"))
943 if (k == argc - 1)
945 error (0, 0, _("missing argument to %s"), quote (arg));
946 usage (EXIT_FAILURE);
948 ++k;
949 set_window_size (integer_arg (argv[k], INT_MAX), -1,
950 device_name);
952 else if (STREQ (arg, "cols")
953 || STREQ (arg, "columns"))
955 if (k == argc - 1)
957 error (0, 0, _("missing argument to %s"), quote (arg));
958 usage (EXIT_FAILURE);
960 ++k;
961 set_window_size (-1, integer_arg (argv[k], INT_MAX),
962 device_name);
964 else if (STREQ (arg, "size"))
966 max_col = screen_columns ();
967 current_col = 0;
968 display_window_size (false, device_name);
970 #endif
971 #ifdef HAVE_C_LINE
972 else if (STREQ (arg, "line"))
974 unsigned long int value;
975 if (k == argc - 1)
977 error (0, 0, _("missing argument to %s"), quote (arg));
978 usage (EXIT_FAILURE);
980 ++k;
981 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
982 if (mode.c_line != value)
983 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
984 require_set_attr = true;
986 #endif
987 else if (STREQ (arg, "speed"))
989 max_col = screen_columns ();
990 display_speed (&mode, false);
992 else if (string_to_baud (arg) != (speed_t) -1)
994 set_speed (both_speeds, arg, &mode);
995 speed_was_set = true;
996 require_set_attr = true;
998 else
1000 if (! recover_mode (arg, &mode))
1002 error (0, 0, _("invalid argument %s"), quote (arg));
1003 usage (EXIT_FAILURE);
1005 require_set_attr = true;
1010 if (require_set_attr)
1012 /* Initialize to all zeroes so there is no risk memcmp will report a
1013 spurious difference in an uninitialized portion of the structure. */
1014 static struct termios new_mode;
1016 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1017 error (EXIT_FAILURE, errno, "%s", device_name);
1019 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1020 it performs *any* of the requested operations. This means it
1021 can report 'success' when it has actually failed to perform
1022 some proper subset of the requested operations. To detect
1023 this partial failure, get the current terminal attributes and
1024 compare them to the requested ones. */
1026 if (tcgetattr (STDIN_FILENO, &new_mode))
1027 error (EXIT_FAILURE, errno, "%s", device_name);
1029 /* Normally, one shouldn't use memcmp to compare structures that
1030 may have 'holes' containing uninitialized data, but we have been
1031 careful to initialize the storage of these two variables to all
1032 zeroes. One might think it more efficient simply to compare the
1033 modified fields, but that would require enumerating those fields --
1034 and not all systems have the same fields in this structure. */
1036 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1038 #ifdef CIBAUD
1039 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1040 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1041 sometimes (m1 != m2). The only difference is in the four bits
1042 of the c_cflag field corresponding to the baud rate. To save
1043 Sun users a little confusion, don't report an error if this
1044 happens. But suppress the error only if we haven't tried to
1045 set the baud rate explicitly -- otherwise we'd never give an
1046 error for a true failure to set the baud rate. */
1048 new_mode.c_cflag &= (~CIBAUD);
1049 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1050 #endif
1052 error (EXIT_FAILURE, 0,
1053 _("%s: unable to perform all requested operations"),
1054 device_name);
1055 #ifdef TESTING
1057 size_t i;
1058 printf ("new_mode: mode\n");
1059 for (i = 0; i < sizeof (new_mode); i++)
1060 printf ("0x%02x: 0x%02x\n",
1061 *(((unsigned char *) &new_mode) + i),
1062 *(((unsigned char *) &mode) + i));
1064 #endif
1069 exit (EXIT_SUCCESS);
1072 /* Return false if not applied because not reversible; otherwise
1073 return true. */
1075 static bool
1076 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1078 tcflag_t *bitsp;
1080 if (reversed && (info->flags & REV) == 0)
1081 return false;
1083 bitsp = mode_type_flag (info->type, mode);
1085 if (bitsp == NULL)
1087 /* Combination mode. */
1088 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1090 if (reversed)
1091 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1092 else
1093 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1095 else if (STREQ (info->name, "oddp"))
1097 if (reversed)
1098 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1099 else
1100 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1102 else if (STREQ (info->name, "nl"))
1104 if (reversed)
1106 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1107 mode->c_oflag = (mode->c_oflag
1108 #ifdef ONLCR
1109 | ONLCR
1110 #endif
1112 #ifdef OCRNL
1113 & ~OCRNL
1114 #endif
1115 #ifdef ONLRET
1116 & ~ONLRET
1117 #endif
1120 else
1122 mode->c_iflag = mode->c_iflag & ~ICRNL;
1123 #ifdef ONLCR
1124 mode->c_oflag = mode->c_oflag & ~ONLCR;
1125 #endif
1128 else if (STREQ (info->name, "ek"))
1130 mode->c_cc[VERASE] = CERASE;
1131 mode->c_cc[VKILL] = CKILL;
1133 else if (STREQ (info->name, "sane"))
1134 sane_mode (mode);
1135 else if (STREQ (info->name, "cbreak"))
1137 if (reversed)
1138 mode->c_lflag |= ICANON;
1139 else
1140 mode->c_lflag &= ~ICANON;
1142 else if (STREQ (info->name, "pass8"))
1144 if (reversed)
1146 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1147 mode->c_iflag |= ISTRIP;
1149 else
1151 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1152 mode->c_iflag &= ~ISTRIP;
1155 else if (STREQ (info->name, "litout"))
1157 if (reversed)
1159 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1160 mode->c_iflag |= ISTRIP;
1161 mode->c_oflag |= OPOST;
1163 else
1165 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1166 mode->c_iflag &= ~ISTRIP;
1167 mode->c_oflag &= ~OPOST;
1170 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1172 if ((info->name[0] == 'r' && reversed)
1173 || (info->name[0] == 'c' && !reversed))
1175 /* Cooked mode. */
1176 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1177 mode->c_oflag |= OPOST;
1178 mode->c_lflag |= ISIG | ICANON;
1179 #if VMIN == VEOF
1180 mode->c_cc[VEOF] = CEOF;
1181 #endif
1182 #if VTIME == VEOL
1183 mode->c_cc[VEOL] = CEOL;
1184 #endif
1186 else
1188 /* Raw mode. */
1189 mode->c_iflag = 0;
1190 mode->c_oflag &= ~OPOST;
1191 mode->c_lflag &= ~(ISIG | ICANON
1192 #ifdef XCASE
1193 | XCASE
1194 #endif
1196 mode->c_cc[VMIN] = 1;
1197 mode->c_cc[VTIME] = 0;
1200 #ifdef IXANY
1201 else if (STREQ (info->name, "decctlq"))
1203 if (reversed)
1204 mode->c_iflag |= IXANY;
1205 else
1206 mode->c_iflag &= ~IXANY;
1208 #endif
1209 #ifdef TABDLY
1210 else if (STREQ (info->name, "tabs"))
1212 if (reversed)
1213 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1214 else
1215 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1217 #else
1218 # ifdef OXTABS
1219 else if (STREQ (info->name, "tabs"))
1221 if (reversed)
1222 mode->c_oflag = mode->c_oflag | OXTABS;
1223 else
1224 mode->c_oflag = mode->c_oflag & ~OXTABS;
1226 # endif
1227 #endif
1228 #if defined XCASE && defined IUCLC && defined OLCUC
1229 else if (STREQ (info->name, "lcase")
1230 || STREQ (info->name, "LCASE"))
1232 if (reversed)
1234 mode->c_lflag &= ~XCASE;
1235 mode->c_iflag &= ~IUCLC;
1236 mode->c_oflag &= ~OLCUC;
1238 else
1240 mode->c_lflag |= XCASE;
1241 mode->c_iflag |= IUCLC;
1242 mode->c_oflag |= OLCUC;
1245 #endif
1246 else if (STREQ (info->name, "crt"))
1247 mode->c_lflag |= ECHOE
1248 #ifdef ECHOCTL
1249 | ECHOCTL
1250 #endif
1251 #ifdef ECHOKE
1252 | ECHOKE
1253 #endif
1255 else if (STREQ (info->name, "dec"))
1257 mode->c_cc[VINTR] = 3; /* ^C */
1258 mode->c_cc[VERASE] = 127; /* DEL */
1259 mode->c_cc[VKILL] = 21; /* ^U */
1260 mode->c_lflag |= ECHOE
1261 #ifdef ECHOCTL
1262 | ECHOCTL
1263 #endif
1264 #ifdef ECHOKE
1265 | ECHOKE
1266 #endif
1268 #ifdef IXANY
1269 mode->c_iflag &= ~IXANY;
1270 #endif
1273 else if (reversed)
1274 *bitsp = *bitsp & ~info->mask & ~info->bits;
1275 else
1276 *bitsp = (*bitsp & ~info->mask) | info->bits;
1278 return true;
1281 static void
1282 set_control_char (struct control_info const *info, const char *arg,
1283 struct termios *mode)
1285 unsigned long int value;
1287 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1288 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1289 else if (arg[0] == '\0' || arg[1] == '\0')
1290 value = to_uchar (arg[0]);
1291 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1292 value = _POSIX_VDISABLE;
1293 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1295 if (arg[1] == '?')
1296 value = 127;
1297 else
1298 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1300 else
1301 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1302 mode->c_cc[info->offset] = value;
1305 static void
1306 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1308 speed_t baud;
1310 baud = string_to_baud (arg);
1311 if (type == input_speed || type == both_speeds)
1312 cfsetispeed (mode, baud);
1313 if (type == output_speed || type == both_speeds)
1314 cfsetospeed (mode, baud);
1317 #ifdef TIOCGWINSZ
1319 static int
1320 get_win_size (int fd, struct winsize *win)
1322 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1323 return err;
1326 static void
1327 set_window_size (int rows, int cols, char const *device_name)
1329 struct winsize win;
1331 if (get_win_size (STDIN_FILENO, &win))
1333 if (errno != EINVAL)
1334 error (EXIT_FAILURE, errno, "%s", device_name);
1335 memset (&win, 0, sizeof (win));
1338 if (rows >= 0)
1339 win.ws_row = rows;
1340 if (cols >= 0)
1341 win.ws_col = cols;
1343 # ifdef TIOCSSIZE
1344 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1345 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1346 This comment from sys/ttold.h describes Sun's twisted logic - a better
1347 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1348 At any rate, the problem is gone in Solaris 2.x.
1350 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1351 but they can be disambiguated by checking whether a "struct ttysize"
1352 structure's "ts_lines" field is greater than 64K or not. If so,
1353 it's almost certainly a "struct winsize" instead.
1355 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1356 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16)
1357 + ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1358 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1359 "stty cols 0 rows 0" would do the right thing. On a little-endian
1360 machine like the sun386i, the problem is the same, but for ws_col == 0.
1362 The workaround is to do the ioctl once with row and col = 1 to set the
1363 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1365 if (win.ws_row == 0 || win.ws_col == 0)
1367 struct ttysize ttysz;
1369 ttysz.ts_lines = win.ws_row;
1370 ttysz.ts_cols = win.ws_col;
1372 win.ws_row = 1;
1373 win.ws_col = 1;
1375 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1376 error (EXIT_FAILURE, errno, "%s", device_name);
1378 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1379 error (EXIT_FAILURE, errno, "%s", device_name);
1380 return;
1382 # endif
1384 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1385 error (EXIT_FAILURE, errno, "%s", device_name);
1388 static void
1389 display_window_size (bool fancy, char const *device_name)
1391 struct winsize win;
1393 if (get_win_size (STDIN_FILENO, &win))
1395 if (errno != EINVAL)
1396 error (EXIT_FAILURE, errno, "%s", device_name);
1397 if (!fancy)
1398 error (EXIT_FAILURE, 0,
1399 _("%s: no size information for this device"), device_name);
1401 else
1403 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1404 win.ws_row, win.ws_col);
1405 if (!fancy)
1406 current_col = 0;
1409 #endif
1411 static int
1412 screen_columns (void)
1414 #ifdef TIOCGWINSZ
1415 struct winsize win;
1417 /* With Solaris 2.[123], this ioctl fails and errno is set to
1418 EINVAL for telnet (but not rlogin) sessions.
1419 On ISC 3.0, it fails for the console and the serial port
1420 (but it works for ptys).
1421 It can also fail on any system when stdout isn't a tty.
1422 In case of any failure, just use the default. */
1423 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1424 return win.ws_col;
1425 #endif
1427 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1428 char *col_string = getenv ("COLUMNS");
1429 long int n_columns;
1430 if (!(col_string != NULL
1431 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1432 && 0 < n_columns
1433 && n_columns <= INT_MAX))
1434 n_columns = 80;
1435 return n_columns;
1439 static tcflag_t * _GL_ATTRIBUTE_PURE
1440 mode_type_flag (enum mode_type type, struct termios *mode)
1442 switch (type)
1444 case control:
1445 return &mode->c_cflag;
1447 case input:
1448 return &mode->c_iflag;
1450 case output:
1451 return &mode->c_oflag;
1453 case local:
1454 return &mode->c_lflag;
1456 case combination:
1457 return NULL;
1459 default:
1460 abort ();
1464 static void
1465 display_settings (enum output_type output_type, struct termios *mode,
1466 char const *device_name)
1468 switch (output_type)
1470 case changed:
1471 display_changed (mode);
1472 break;
1474 case all:
1475 display_all (mode, device_name);
1476 break;
1478 case recoverable:
1479 display_recoverable (mode);
1480 break;
1484 static void
1485 display_changed (struct termios *mode)
1487 int i;
1488 bool empty_line;
1489 tcflag_t *bitsp;
1490 unsigned long mask;
1491 enum mode_type prev_type = control;
1493 display_speed (mode, true);
1494 #ifdef HAVE_C_LINE
1495 wrapf ("line = %d;", mode->c_line);
1496 #endif
1497 putchar ('\n');
1498 current_col = 0;
1500 empty_line = true;
1501 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1503 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1504 continue;
1505 /* If swtch is the same as susp, don't print both. */
1506 #if VSWTCH == VSUSP
1507 if (STREQ (control_info[i].name, "swtch"))
1508 continue;
1509 #endif
1510 /* If eof uses the same slot as min, only print whichever applies. */
1511 #if VEOF == VMIN
1512 if ((mode->c_lflag & ICANON) == 0
1513 && (STREQ (control_info[i].name, "eof")
1514 || STREQ (control_info[i].name, "eol")))
1515 continue;
1516 #endif
1518 empty_line = false;
1519 wrapf ("%s = %s;", control_info[i].name,
1520 visible (mode->c_cc[control_info[i].offset]));
1522 if ((mode->c_lflag & ICANON) == 0)
1524 wrapf ("min = %lu; time = %lu;\n",
1525 (unsigned long int) mode->c_cc[VMIN],
1526 (unsigned long int) mode->c_cc[VTIME]);
1528 else if (!empty_line)
1529 putchar ('\n');
1530 current_col = 0;
1532 empty_line = true;
1533 for (i = 0; mode_info[i].name != NULL; ++i)
1535 if (mode_info[i].flags & OMIT)
1536 continue;
1537 if (mode_info[i].type != prev_type)
1539 if (!empty_line)
1541 putchar ('\n');
1542 current_col = 0;
1543 empty_line = true;
1545 prev_type = mode_info[i].type;
1548 bitsp = mode_type_flag (mode_info[i].type, mode);
1549 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1551 /* bitsp would be NULL only for "combination" modes, yet those
1552 are filtered out above via the OMIT flag. Tell static analysis
1553 tools that it's ok to dereference bitsp here. */
1554 assert (bitsp);
1556 if ((*bitsp & mask) == mode_info[i].bits)
1558 if (mode_info[i].flags & SANE_UNSET)
1560 wrapf ("%s", mode_info[i].name);
1561 empty_line = false;
1564 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1566 wrapf ("-%s", mode_info[i].name);
1567 empty_line = false;
1570 if (!empty_line)
1571 putchar ('\n');
1572 current_col = 0;
1575 static void
1576 display_all (struct termios *mode, char const *device_name)
1578 int i;
1579 tcflag_t *bitsp;
1580 unsigned long mask;
1581 enum mode_type prev_type = control;
1583 display_speed (mode, true);
1584 #ifdef TIOCGWINSZ
1585 display_window_size (true, device_name);
1586 #endif
1587 #ifdef HAVE_C_LINE
1588 wrapf ("line = %d;", mode->c_line);
1589 #endif
1590 putchar ('\n');
1591 current_col = 0;
1593 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1595 /* If swtch is the same as susp, don't print both. */
1596 #if VSWTCH == VSUSP
1597 if (STREQ (control_info[i].name, "swtch"))
1598 continue;
1599 #endif
1600 /* If eof uses the same slot as min, only print whichever applies. */
1601 #if VEOF == VMIN
1602 if ((mode->c_lflag & ICANON) == 0
1603 && (STREQ (control_info[i].name, "eof")
1604 || STREQ (control_info[i].name, "eol")))
1605 continue;
1606 #endif
1607 wrapf ("%s = %s;", control_info[i].name,
1608 visible (mode->c_cc[control_info[i].offset]));
1610 #if VEOF == VMIN
1611 if ((mode->c_lflag & ICANON) == 0)
1612 #endif
1613 wrapf ("min = %lu; time = %lu;",
1614 (unsigned long int) mode->c_cc[VMIN],
1615 (unsigned long int) mode->c_cc[VTIME]);
1616 if (current_col != 0)
1617 putchar ('\n');
1618 current_col = 0;
1620 for (i = 0; mode_info[i].name != NULL; ++i)
1622 if (mode_info[i].flags & OMIT)
1623 continue;
1624 if (mode_info[i].type != prev_type)
1626 putchar ('\n');
1627 current_col = 0;
1628 prev_type = mode_info[i].type;
1631 bitsp = mode_type_flag (mode_info[i].type, mode);
1632 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1633 assert (bitsp); /* See the identical assertion and comment above. */
1634 if ((*bitsp & mask) == mode_info[i].bits)
1635 wrapf ("%s", mode_info[i].name);
1636 else if (mode_info[i].flags & REV)
1637 wrapf ("-%s", mode_info[i].name);
1639 putchar ('\n');
1640 current_col = 0;
1643 static void
1644 display_speed (struct termios *mode, bool fancy)
1646 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1647 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1648 baud_to_value (cfgetospeed (mode)));
1649 else
1650 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1651 baud_to_value (cfgetispeed (mode)),
1652 baud_to_value (cfgetospeed (mode)));
1653 if (!fancy)
1654 current_col = 0;
1657 static void
1658 display_recoverable (struct termios *mode)
1660 size_t i;
1662 printf ("%lx:%lx:%lx:%lx",
1663 (unsigned long int) mode->c_iflag,
1664 (unsigned long int) mode->c_oflag,
1665 (unsigned long int) mode->c_cflag,
1666 (unsigned long int) mode->c_lflag);
1667 for (i = 0; i < NCCS; ++i)
1668 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1669 putchar ('\n');
1672 /* NOTE: identical to below, modulo use of tcflag_t */
1673 static int
1674 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1675 char delim)
1677 unsigned long ul;
1678 errno = 0;
1679 ul = strtoul (s, p, base);
1680 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1681 return -1;
1682 *result = ul;
1683 return 0;
1686 /* NOTE: identical to above, modulo use of cc_t */
1687 static int
1688 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1690 unsigned long ul;
1691 errno = 0;
1692 ul = strtoul (s, p, base);
1693 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1694 return -1;
1695 *result = ul;
1696 return 0;
1699 /* Parse the output of display_recoverable.
1700 Return false if any part of it is invalid. */
1701 static bool
1702 recover_mode (char const *arg, struct termios *mode)
1704 tcflag_t flag[4];
1705 char const *s = arg;
1706 size_t i;
1707 for (i = 0; i < 4; i++)
1709 char *p;
1710 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1711 return false;
1712 s = p + 1;
1714 mode->c_iflag = flag[0];
1715 mode->c_oflag = flag[1];
1716 mode->c_cflag = flag[2];
1717 mode->c_lflag = flag[3];
1719 for (i = 0; i < NCCS; ++i)
1721 char *p;
1722 char delim = i < NCCS - 1 ? ':' : '\0';
1723 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1724 return false;
1725 s = p + 1;
1728 return true;
1731 struct speed_map
1733 const char *string; /* ASCII representation. */
1734 speed_t speed; /* Internal form. */
1735 unsigned long int value; /* Numeric value. */
1738 static struct speed_map const speeds[] =
1740 {"0", B0, 0},
1741 {"50", B50, 50},
1742 {"75", B75, 75},
1743 {"110", B110, 110},
1744 {"134", B134, 134},
1745 {"134.5", B134, 134},
1746 {"150", B150, 150},
1747 {"200", B200, 200},
1748 {"300", B300, 300},
1749 {"600", B600, 600},
1750 {"1200", B1200, 1200},
1751 {"1800", B1800, 1800},
1752 {"2400", B2400, 2400},
1753 {"4800", B4800, 4800},
1754 {"9600", B9600, 9600},
1755 {"19200", B19200, 19200},
1756 {"38400", B38400, 38400},
1757 {"exta", B19200, 19200},
1758 {"extb", B38400, 38400},
1759 #ifdef B57600
1760 {"57600", B57600, 57600},
1761 #endif
1762 #ifdef B115200
1763 {"115200", B115200, 115200},
1764 #endif
1765 #ifdef B230400
1766 {"230400", B230400, 230400},
1767 #endif
1768 #ifdef B460800
1769 {"460800", B460800, 460800},
1770 #endif
1771 #ifdef B500000
1772 {"500000", B500000, 500000},
1773 #endif
1774 #ifdef B576000
1775 {"576000", B576000, 576000},
1776 #endif
1777 #ifdef B921600
1778 {"921600", B921600, 921600},
1779 #endif
1780 #ifdef B1000000
1781 {"1000000", B1000000, 1000000},
1782 #endif
1783 #ifdef B1152000
1784 {"1152000", B1152000, 1152000},
1785 #endif
1786 #ifdef B1500000
1787 {"1500000", B1500000, 1500000},
1788 #endif
1789 #ifdef B2000000
1790 {"2000000", B2000000, 2000000},
1791 #endif
1792 #ifdef B2500000
1793 {"2500000", B2500000, 2500000},
1794 #endif
1795 #ifdef B3000000
1796 {"3000000", B3000000, 3000000},
1797 #endif
1798 #ifdef B3500000
1799 {"3500000", B3500000, 3500000},
1800 #endif
1801 #ifdef B4000000
1802 {"4000000", B4000000, 4000000},
1803 #endif
1804 {NULL, 0, 0}
1807 static speed_t _GL_ATTRIBUTE_PURE
1808 string_to_baud (const char *arg)
1810 int i;
1812 for (i = 0; speeds[i].string != NULL; ++i)
1813 if (STREQ (arg, speeds[i].string))
1814 return speeds[i].speed;
1815 return (speed_t) -1;
1818 static unsigned long int _GL_ATTRIBUTE_PURE
1819 baud_to_value (speed_t speed)
1821 int i;
1823 for (i = 0; speeds[i].string != NULL; ++i)
1824 if (speed == speeds[i].speed)
1825 return speeds[i].value;
1826 return 0;
1829 static void
1830 sane_mode (struct termios *mode)
1832 int i;
1833 tcflag_t *bitsp;
1835 for (i = 0; control_info[i].name; ++i)
1837 #if VMIN == VEOF
1838 if (STREQ (control_info[i].name, "min"))
1839 break;
1840 #endif
1841 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1844 for (i = 0; mode_info[i].name != NULL; ++i)
1846 if (mode_info[i].flags & SANE_SET)
1848 bitsp = mode_type_flag (mode_info[i].type, mode);
1849 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1851 else if (mode_info[i].flags & SANE_UNSET)
1853 bitsp = mode_type_flag (mode_info[i].type, mode);
1854 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1859 /* Return a string that is the printable representation of character CH. */
1860 /* Adapted from 'cat' by Torbjorn Granlund. */
1862 static const char *
1863 visible (cc_t ch)
1865 static char buf[10];
1866 char *bpout = buf;
1868 if (ch == _POSIX_VDISABLE)
1869 return "<undef>";
1871 if (ch >= 32)
1873 if (ch < 127)
1874 *bpout++ = ch;
1875 else if (ch == 127)
1877 *bpout++ = '^';
1878 *bpout++ = '?';
1880 else
1882 *bpout++ = 'M';
1883 *bpout++ = '-';
1884 if (ch >= 128 + 32)
1886 if (ch < 128 + 127)
1887 *bpout++ = ch - 128;
1888 else
1890 *bpout++ = '^';
1891 *bpout++ = '?';
1894 else
1896 *bpout++ = '^';
1897 *bpout++ = ch - 128 + 64;
1901 else
1903 *bpout++ = '^';
1904 *bpout++ = ch + 64;
1906 *bpout = '\0';
1907 return (const char *) buf;
1910 /* Parse string S as an integer, using decimal radix by default,
1911 but allowing octal and hex numbers as in C. Reject values
1912 larger than MAXVAL. */
1914 static unsigned long int
1915 integer_arg (const char *s, unsigned long int maxval)
1917 unsigned long int value;
1918 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1920 error (0, 0, _("invalid integer argument %s"), quote (s));
1921 usage (EXIT_FAILURE);
1923 return value;