maint: fix typos found by misspellings
[platform/upstream/coreutils.git] / src / stty.c
1 /* stty -- change and print terminal line settings
2    Copyright (C) 1990-2012 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>.  */
16
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
18
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
23
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.
27
28    David MacKenzie <djm@gnu.ai.mit.edu> */
29
30 #include <config.h>
31
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
34 #endif
35
36 #include <stdio.h>
37 #include <sys/types.h>
38
39 #include <termios.h>
40 #if HAVE_STROPTS_H
41 # include <stropts.h>
42 #endif
43 #include <sys/ioctl.h>
44
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>
56
57 #include "system.h"
58 #include "error.h"
59 #include "fd-reopen.h"
60 #include "quote.h"
61 #include "xstrtol.h"
62
63 /* The official name of this program (e.g., no 'g' prefix).  */
64 #define PROGRAM_NAME "stty"
65
66 #define AUTHORS proper_name ("David MacKenzie")
67
68 #ifndef _POSIX_VDISABLE
69 # define _POSIX_VDISABLE 0
70 #endif
71
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
119
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
126
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
169
170 /* Which speeds to set.  */
171 enum speed_setting
172   {
173     input_speed, output_speed, both_speeds
174   };
175
176 /* What to output and how.  */
177 enum output_type
178   {
179     changed, all, recoverable   /* Default, -a, -g.  */
180   };
181
182 /* Which member(s) of 'struct termios' a mode uses.  */
183 enum mode_type
184   {
185     control, input, output, local, combination
186   };
187
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. */
193
194 /* Each mode.  */
195 struct mode_info
196   {
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.  */
202   };
203
204 static struct mode_info const mode_info[] =
205 {
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
221   {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
222   {"brkint", input, SANE_SET | REV, BRKINT, 0},
223   {"ignpar", input, REV, IGNPAR, 0},
224   {"parmrk", input, REV, PARMRK, 0},
225   {"inpck", input, REV, INPCK, 0},
226   {"istrip", input, REV, ISTRIP, 0},
227   {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
228   {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
229   {"icrnl", input, SANE_SET | REV, ICRNL, 0},
230   {"ixon", input, REV, IXON, 0},
231   {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
232   {"tandem", input, REV | OMIT, IXOFF, 0},
233 #ifdef IUCLC
234   {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
235 #endif
236 #ifdef IXANY
237   {"ixany", input, SANE_UNSET | REV, IXANY, 0},
238 #endif
239 #ifdef IMAXBEL
240   {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
241 #endif
242 #ifdef IUTF8
243   {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
244 #endif
245
246   {"opost", output, SANE_SET | REV, OPOST, 0},
247 #ifdef OLCUC
248   {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
249 #endif
250 #ifdef OCRNL
251   {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
252 #endif
253 #ifdef ONLCR
254   {"onlcr", output, SANE_SET | REV, ONLCR, 0},
255 #endif
256 #ifdef ONOCR
257   {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
258 #endif
259 #ifdef ONLRET
260   {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
261 #endif
262 #ifdef OFILL
263   {"ofill", output, SANE_UNSET | REV, OFILL, 0},
264 #endif
265 #ifdef OFDEL
266   {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
267 #endif
268 #ifdef NLDLY
269   {"nl1", output, SANE_UNSET, NL1, NLDLY},
270   {"nl0", output, SANE_SET, NL0, NLDLY},
271 #endif
272 #ifdef CRDLY
273   {"cr3", output, SANE_UNSET, CR3, CRDLY},
274   {"cr2", output, SANE_UNSET, CR2, CRDLY},
275   {"cr1", output, SANE_UNSET, CR1, CRDLY},
276   {"cr0", output, SANE_SET, CR0, CRDLY},
277 #endif
278 #ifdef TABDLY
279 # ifdef TAB3
280   {"tab3", output, SANE_UNSET, TAB3, TABDLY},
281 # endif
282 # ifdef TAB2
283   {"tab2", output, SANE_UNSET, TAB2, TABDLY},
284 # endif
285 # ifdef TAB1
286   {"tab1", output, SANE_UNSET, TAB1, TABDLY},
287 # endif
288 # ifdef TAB0
289   {"tab0", output, SANE_SET, TAB0, TABDLY},
290 # endif
291 #else
292 # ifdef OXTABS
293   {"tab3", output, SANE_UNSET, OXTABS, 0},
294 # endif
295 #endif
296 #ifdef BSDLY
297   {"bs1", output, SANE_UNSET, BS1, BSDLY},
298   {"bs0", output, SANE_SET, BS0, BSDLY},
299 #endif
300 #ifdef VTDLY
301   {"vt1", output, SANE_UNSET, VT1, VTDLY},
302   {"vt0", output, SANE_SET, VT0, VTDLY},
303 #endif
304 #ifdef FFDLY
305   {"ff1", output, SANE_UNSET, FF1, FFDLY},
306   {"ff0", output, SANE_SET, FF0, FFDLY},
307 #endif
308
309   {"isig", local, SANE_SET | REV, ISIG, 0},
310   {"icanon", local, SANE_SET | REV, ICANON, 0},
311 #ifdef IEXTEN
312   {"iexten", local, SANE_SET | REV, IEXTEN, 0},
313 #endif
314   {"echo", local, SANE_SET | REV, ECHO, 0},
315   {"echoe", local, SANE_SET | REV, ECHOE, 0},
316   {"crterase", local, REV | OMIT, ECHOE, 0},
317   {"echok", local, SANE_SET | REV, ECHOK, 0},
318   {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
319   {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
320 #ifdef XCASE
321   {"xcase", local, SANE_UNSET | REV, XCASE, 0},
322 #endif
323 #ifdef TOSTOP
324   {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
325 #endif
326 #ifdef ECHOPRT
327   {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
328   {"prterase", local, REV | OMIT, ECHOPRT, 0},
329 #endif
330 #ifdef ECHOCTL
331   {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
332   {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
333 #endif
334 #ifdef ECHOKE
335   {"echoke", local, SANE_SET | REV, ECHOKE, 0},
336   {"crtkill", local, REV | OMIT, ECHOKE, 0},
337 #endif
338
339   {"evenp", combination, REV | OMIT, 0, 0},
340   {"parity", combination, REV | OMIT, 0, 0},
341   {"oddp", combination, REV | OMIT, 0, 0},
342   {"nl", combination, REV | OMIT, 0, 0},
343   {"ek", combination, OMIT, 0, 0},
344   {"sane", combination, OMIT, 0, 0},
345   {"cooked", combination, REV | OMIT, 0, 0},
346   {"raw", combination, REV | OMIT, 0, 0},
347   {"pass8", combination, REV | OMIT, 0, 0},
348   {"litout", combination, REV | OMIT, 0, 0},
349   {"cbreak", combination, REV | OMIT, 0, 0},
350 #ifdef IXANY
351   {"decctlq", combination, REV | OMIT, 0, 0},
352 #endif
353 #if defined TABDLY || defined OXTABS
354   {"tabs", combination, REV | OMIT, 0, 0},
355 #endif
356 #if defined XCASE && defined IUCLC && defined OLCUC
357   {"lcase", combination, REV | OMIT, 0, 0},
358   {"LCASE", combination, REV | OMIT, 0, 0},
359 #endif
360   {"crt", combination, OMIT, 0, 0},
361   {"dec", combination, OMIT, 0, 0},
362
363   {NULL, control, 0, 0, 0}
364 };
365
366 /* Control character settings.  */
367 struct control_info
368   {
369     const char *name;           /* Name given on command line.  */
370     cc_t saneval;               /* Value to set for 'stty sane'.  */
371     size_t offset;              /* Offset in c_cc.  */
372   };
373
374 /* Control characters. */
375
376 static struct control_info const control_info[] =
377 {
378   {"intr", CINTR, VINTR},
379   {"quit", CQUIT, VQUIT},
380   {"erase", CERASE, VERASE},
381   {"kill", CKILL, VKILL},
382   {"eof", CEOF, VEOF},
383   {"eol", CEOL, VEOL},
384 #ifdef VEOL2
385   {"eol2", CEOL2, VEOL2},
386 #endif
387 #ifdef VSWTCH
388   {"swtch", CSWTCH, VSWTCH},
389 #endif
390   {"start", CSTART, VSTART},
391   {"stop", CSTOP, VSTOP},
392   {"susp", CSUSP, VSUSP},
393 #ifdef VDSUSP
394   {"dsusp", CDSUSP, VDSUSP},
395 #endif
396 #ifdef VREPRINT
397   {"rprnt", CRPRNT, VREPRINT},
398 #else
399 # ifdef CREPRINT /* HPUX 10.20 needs this */
400   {"rprnt", CRPRNT, CREPRINT},
401 # endif
402 #endif
403 #ifdef VWERASE
404   {"werase", CWERASE, VWERASE},
405 #endif
406 #ifdef VLNEXT
407   {"lnext", CLNEXT, VLNEXT},
408 #endif
409 #ifdef VFLUSHO
410   {"flush", CFLUSHO, VFLUSHO},
411 #endif
412 #ifdef VSTATUS
413   {"status", CSTATUS, VSTATUS},
414 #endif
415
416   /* These must be last because of the display routines. */
417   {"min", 1, VMIN},
418   {"time", 0, VTIME},
419   {NULL, 0, 0}
420 };
421
422 static char const *visible (cc_t ch);
423 static unsigned long int baud_to_value (speed_t speed);
424 static bool recover_mode (char const *arg, struct termios *mode);
425 static int screen_columns (void);
426 static bool set_mode (struct mode_info const *info, bool reversed,
427                       struct termios *mode);
428 static unsigned long int integer_arg (const char *s, unsigned long int max);
429 static speed_t string_to_baud (const char *arg);
430 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
431 static void display_all (struct termios *mode, char const *device_name);
432 static void display_changed (struct termios *mode);
433 static void display_recoverable (struct termios *mode);
434 static void display_settings (enum output_type output_type,
435                               struct termios *mode,
436                               const char *device_name);
437 static void display_speed (struct termios *mode, bool fancy);
438 static void display_window_size (bool fancy, char const *device_name);
439 static void sane_mode (struct termios *mode);
440 static void set_control_char (struct control_info const *info,
441                               const char *arg,
442                               struct termios *mode);
443 static void set_speed (enum speed_setting type, const char *arg,
444                        struct termios *mode);
445 static void set_window_size (int rows, int cols, char const *device_name);
446
447 /* The width of the screen, for output wrapping. */
448 static int max_col;
449
450 /* Current position, to know when to wrap. */
451 static int current_col;
452
453 static struct option const longopts[] =
454 {
455   {"all", no_argument, NULL, 'a'},
456   {"save", no_argument, NULL, 'g'},
457   {"file", required_argument, NULL, 'F'},
458   {GETOPT_HELP_OPTION_DECL},
459   {GETOPT_VERSION_OPTION_DECL},
460   {NULL, 0, NULL, 0}
461 };
462
463 static void wrapf (const char *message, ...)
464      __attribute__ ((__format__ (__printf__, 1, 2)));
465
466 /* Print format string MESSAGE and optional args.
467    Wrap to next line first if it won't fit.
468    Print a space first unless MESSAGE will start a new line. */
469
470 static void
471 wrapf (const char *message,...)
472 {
473   va_list args;
474   char *buf;
475   int buflen;
476
477   va_start (args, message);
478   buflen = vasprintf (&buf, message, args);
479   va_end (args);
480
481   if (buflen < 0)
482     xalloc_die ();
483
484   if (0 < current_col)
485     {
486       if (max_col - current_col < buflen)
487         {
488           putchar ('\n');
489           current_col = 0;
490         }
491       else
492         {
493           putchar (' ');
494           current_col++;
495         }
496     }
497
498   fputs (buf, stdout);
499   free (buf);
500   current_col += buflen;
501 }
502
503 void
504 usage (int status)
505 {
506   if (status != EXIT_SUCCESS)
507     emit_try_help ();
508   else
509     {
510       printf (_("\
511 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
512   or:  %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
513   or:  %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
514 "),
515               program_name, program_name, program_name);
516       fputs (_("\
517 Print or change terminal characteristics.\n\
518 \n\
519   -a, --all          print all current settings in human-readable form\n\
520   -g, --save         print all current settings in a stty-readable form\n\
521   -F, --file=DEVICE  open and use the specified DEVICE instead of stdin\n\
522 "), stdout);
523       fputs (HELP_OPTION_DESCRIPTION, stdout);
524       fputs (VERSION_OPTION_DESCRIPTION, stdout);
525       fputs (_("\
526 \n\
527 Optional - before SETTING indicates negation.  An * marks non-POSIX\n\
528 settings.  The underlying system defines which settings are available.\n\
529 "), stdout);
530       fputs (_("\
531 \n\
532 Special characters:\n\
533  * dsusp CHAR    CHAR will send a terminal stop signal once input flushed\n\
534    eof CHAR      CHAR will send an end of file (terminate the input)\n\
535    eol CHAR      CHAR will end the line\n\
536 "), stdout);
537       fputs (_("\
538  * eol2 CHAR     alternate CHAR for ending the line\n\
539    erase CHAR    CHAR will erase the last character typed\n\
540    intr CHAR     CHAR will send an interrupt signal\n\
541    kill CHAR     CHAR will erase the current line\n\
542 "), stdout);
543       fputs (_("\
544  * lnext CHAR    CHAR will enter the next character quoted\n\
545    quit CHAR     CHAR will send a quit signal\n\
546  * rprnt CHAR    CHAR will redraw the current line\n\
547    start CHAR    CHAR will restart the output after stopping it\n\
548 "), stdout);
549       fputs (_("\
550    stop CHAR     CHAR will stop the output\n\
551    susp CHAR     CHAR will send a terminal stop signal\n\
552  * swtch CHAR    CHAR will switch to a different shell layer\n\
553  * werase CHAR   CHAR will erase the last word typed\n\
554 "), stdout);
555       fputs (_("\
556 \n\
557 Special settings:\n\
558    N             set the input and output speeds to N bauds\n\
559  * cols N        tell the kernel that the terminal has N columns\n\
560  * columns N     same as cols N\n\
561 "), stdout);
562       fputs (_("\
563    ispeed N      set the input speed to N\n\
564  * line N        use line discipline N\n\
565    min N         with -icanon, set N characters minimum for a completed read\n\
566    ospeed N      set the output speed to N\n\
567 "), stdout);
568       fputs (_("\
569  * rows N        tell the kernel that the terminal has N rows\n\
570  * size          print the number of rows and columns according to the kernel\n\
571    speed         print the terminal speed\n\
572    time N        with -icanon, set read timeout of N tenths of a second\n\
573 "), stdout);
574       fputs (_("\
575 \n\
576 Control settings:\n\
577    [-]clocal     disable modem control signals\n\
578    [-]cread      allow input to be received\n\
579  * [-]crtscts    enable RTS/CTS handshaking\n\
580    csN           set character size to N bits, N in [5..8]\n\
581 "), stdout);
582       fputs (_("\
583    [-]cstopb     use two stop bits per character (one with '-')\n\
584    [-]hup        send a hangup signal when the last process closes the tty\n\
585    [-]hupcl      same as [-]hup\n\
586    [-]parenb     generate parity bit in output and expect parity bit in input\n\
587    [-]parodd     set odd parity (or even parity with '-')\n\
588 "), stdout);
589       fputs (_("\
590 \n\
591 Input settings:\n\
592    [-]brkint     breaks cause an interrupt signal\n\
593    [-]icrnl      translate carriage return to newline\n\
594    [-]ignbrk     ignore break characters\n\
595    [-]igncr      ignore carriage return\n\
596 "), stdout);
597       fputs (_("\
598    [-]ignpar     ignore characters with parity errors\n\
599  * [-]imaxbel    beep and do not flush a full input buffer on a character\n\
600    [-]inlcr      translate newline to carriage return\n\
601    [-]inpck      enable input parity checking\n\
602    [-]istrip     clear high (8th) bit of input characters\n\
603 "), stdout);
604       fputs (_("\
605  * [-]iutf8      assume input characters are UTF-8 encoded\n\
606 "), stdout);
607       fputs (_("\
608  * [-]iuclc      translate uppercase characters to lowercase\n\
609  * [-]ixany      let any character restart output, not only start character\n\
610    [-]ixoff      enable sending of start/stop characters\n\
611    [-]ixon       enable XON/XOFF flow control\n\
612    [-]parmrk     mark parity errors (with a 255-0-character sequence)\n\
613    [-]tandem     same as [-]ixoff\n\
614 "), stdout);
615       fputs (_("\
616 \n\
617 Output settings:\n\
618  * bsN           backspace delay style, N in [0..1]\n\
619  * crN           carriage return delay style, N in [0..3]\n\
620  * ffN           form feed delay style, N in [0..1]\n\
621  * nlN           newline delay style, N in [0..1]\n\
622 "), stdout);
623       fputs (_("\
624  * [-]ocrnl      translate carriage return to newline\n\
625  * [-]ofdel      use delete characters for fill instead of null characters\n\
626  * [-]ofill      use fill (padding) characters instead of timing for delays\n\
627  * [-]olcuc      translate lowercase characters to uppercase\n\
628  * [-]onlcr      translate newline to carriage return-newline\n\
629  * [-]onlret     newline performs a carriage return\n\
630 "), stdout);
631       fputs (_("\
632  * [-]onocr      do not print carriage returns in the first column\n\
633    [-]opost      postprocess output\n\
634  * tabN          horizontal tab delay style, N in [0..3]\n\
635  * tabs          same as tab0\n\
636  * -tabs         same as tab3\n\
637  * vtN           vertical tab delay style, N in [0..1]\n\
638 "), stdout);
639       fputs (_("\
640 \n\
641 Local settings:\n\
642    [-]crterase   echo erase characters as backspace-space-backspace\n\
643  * crtkill       kill all line by obeying the echoprt and echoe settings\n\
644  * -crtkill      kill all line by obeying the echoctl and echok settings\n\
645 "), stdout);
646       fputs (_("\
647  * [-]ctlecho    echo control characters in hat notation ('^c')\n\
648    [-]echo       echo input characters\n\
649  * [-]echoctl    same as [-]ctlecho\n\
650    [-]echoe      same as [-]crterase\n\
651    [-]echok      echo a newline after a kill character\n\
652 "), stdout);
653       fputs (_("\
654  * [-]echoke     same as [-]crtkill\n\
655    [-]echonl     echo newline even if not echoing other characters\n\
656  * [-]echoprt    echo erased characters backward, between '\\' and '/'\n\
657    [-]icanon     enable erase, kill, werase, and rprnt special characters\n\
658    [-]iexten     enable non-POSIX special characters\n\
659 "), stdout);
660       fputs (_("\
661    [-]isig       enable interrupt, quit, and suspend special characters\n\
662    [-]noflsh     disable flushing after interrupt and quit special characters\n\
663  * [-]prterase   same as [-]echoprt\n\
664  * [-]tostop     stop background jobs that try to write to the terminal\n\
665  * [-]xcase      with icanon, escape with '\\' for uppercase characters\n\
666 "), stdout);
667       fputs (_("\
668 \n\
669 Combination settings:\n\
670  * [-]LCASE      same as [-]lcase\n\
671    cbreak        same as -icanon\n\
672    -cbreak       same as icanon\n\
673 "), stdout);
674       fputs (_("\
675    cooked        same as brkint ignpar istrip icrnl ixon opost isig\n\
676                  icanon, eof and eol characters to their default values\n\
677    -cooked       same as raw\n\
678    crt           same as echoe echoctl echoke\n\
679 "), stdout);
680       fputs (_("\
681    dec           same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
682                  kill ^u\n\
683  * [-]decctlq    same as [-]ixany\n\
684    ek            erase and kill characters to their default values\n\
685    evenp         same as parenb -parodd cs7\n\
686 "), stdout);
687       fputs (_("\
688    -evenp        same as -parenb cs8\n\
689  * [-]lcase      same as xcase iuclc olcuc\n\
690    litout        same as -parenb -istrip -opost cs8\n\
691    -litout       same as parenb istrip opost cs7\n\
692    nl            same as -icrnl -onlcr\n\
693    -nl           same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
694 "), stdout);
695       fputs (_("\
696    oddp          same as parenb parodd cs7\n\
697    -oddp         same as -parenb cs8\n\
698    [-]parity     same as [-]evenp\n\
699    pass8         same as -parenb -istrip cs8\n\
700    -pass8        same as parenb istrip cs7\n\
701 "), stdout);
702       fputs (_("\
703    raw           same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
704                  -inlcr -igncr -icrnl  -ixon  -ixoff  -iuclc  -ixany\n\
705                  -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
706    -raw          same as cooked\n\
707 "), stdout);
708       fputs (_("\
709    sane          same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
710                  -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
711                  -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
712                  isig icanon iexten echo echoe echok -echonl -noflsh\n\
713                  -xcase -tostop -echoprt echoctl echoke, all special\n\
714                  characters to their default values\n\
715 "), stdout);
716       fputs (_("\
717 \n\
718 Handle the tty line connected to standard input.  Without arguments,\n\
719 prints baud rate, line discipline, and deviations from stty sane.  In\n\
720 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
721 127; special values ^- or undef used to disable special characters.\n\
722 "), stdout);
723       emit_ancillary_info ();
724     }
725   exit (status);
726 }
727
728 int
729 main (int argc, char **argv)
730 {
731   /* Initialize to all zeroes so there is no risk memcmp will report a
732      spurious difference in an uninitialized portion of the structure.  */
733   static struct termios mode;
734
735   enum output_type output_type;
736   int optc;
737   int argi = 0;
738   int opti = 1;
739   bool require_set_attr;
740   bool speed_was_set ATTRIBUTE_UNUSED;
741   bool verbose_output;
742   bool recoverable_output;
743   int k;
744   bool noargs = true;
745   char *file_name = NULL;
746   const char *device_name;
747
748   initialize_main (&argc, &argv);
749   set_program_name (argv[0]);
750   setlocale (LC_ALL, "");
751   bindtextdomain (PACKAGE, LOCALEDIR);
752   textdomain (PACKAGE);
753
754   atexit (close_stdout);
755
756   output_type = changed;
757   verbose_output = false;
758   recoverable_output = false;
759
760   /* Don't print error messages for unrecognized options.  */
761   opterr = 0;
762
763   /* If any new options are ever added to stty, the short options MUST
764      NOT allow any ambiguity with the stty settings.  For example, the
765      stty setting "-gagFork" would not be feasible, since it will be
766      parsed as "-g -a -g -F ork".  If you change anything about how
767      stty parses options, be sure it still works with combinations of
768      short and long options, --, POSIXLY_CORRECT, etc.  */
769
770   while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
771                               longopts, NULL))
772          != -1)
773     {
774       switch (optc)
775         {
776         case 'a':
777           verbose_output = true;
778           output_type = all;
779           break;
780
781         case 'g':
782           recoverable_output = true;
783           output_type = recoverable;
784           break;
785
786         case 'F':
787           if (file_name)
788             error (EXIT_FAILURE, 0, _("only one device may be specified"));
789           file_name = optarg;
790           break;
791
792         case_GETOPT_HELP_CHAR;
793
794         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
795
796         default:
797           noargs = false;
798
799           /* Skip the argument containing this unrecognized option;
800              the 2nd pass will analyze it.  */
801           argi += opti;
802
803           /* Restart getopt_long from the first unskipped argument.  */
804           opti = 1;
805           optind = 0;
806
807           break;
808         }
809
810       /* Clear fully-parsed arguments, so they don't confuse the 2nd pass.  */
811       while (opti < optind)
812         argv[argi + opti++] = NULL;
813     }
814
815   /* Specifying both -a and -g gets an error.  */
816   if (verbose_output && recoverable_output)
817     error (EXIT_FAILURE, 0,
818            _("the options for verbose and stty-readable output styles are\n"
819              "mutually exclusive"));
820
821   /* Specifying any other arguments with -a or -g gets an error.  */
822   if (!noargs && (verbose_output || recoverable_output))
823     error (EXIT_FAILURE, 0,
824            _("when specifying an output style, modes may not be set"));
825
826   /* FIXME: it'd be better not to open the file until we've verified
827      that all arguments are valid.  Otherwise, we could end up doing
828      only some of the requested operations and then failing, probably
829      leaving things in an undesirable state.  */
830
831   if (file_name)
832     {
833       int fdflags;
834       device_name = file_name;
835       if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
836         error (EXIT_FAILURE, errno, "%s", device_name);
837       if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
838           || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
839         error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
840                device_name);
841     }
842   else
843     device_name = _("standard input");
844
845   if (tcgetattr (STDIN_FILENO, &mode))
846     error (EXIT_FAILURE, errno, "%s", device_name);
847
848   if (verbose_output || recoverable_output || noargs)
849     {
850       max_col = screen_columns ();
851       current_col = 0;
852       display_settings (output_type, &mode, device_name);
853       exit (EXIT_SUCCESS);
854     }
855
856   speed_was_set = false;
857   require_set_attr = false;
858   for (k = 1; k < argc; k++)
859     {
860       char const *arg = argv[k];
861       bool match_found = false;
862       bool reversed = false;
863       int i;
864
865       if (! arg)
866         continue;
867
868       if (arg[0] == '-')
869         {
870           ++arg;
871           reversed = true;
872         }
873       for (i = 0; mode_info[i].name != NULL; ++i)
874         {
875           if (STREQ (arg, mode_info[i].name))
876             {
877               match_found = set_mode (&mode_info[i], reversed, &mode);
878               require_set_attr = true;
879               break;
880             }
881         }
882       if (!match_found && reversed)
883         {
884           error (0, 0, _("invalid argument %s"), quote (arg - 1));
885           usage (EXIT_FAILURE);
886         }
887       if (!match_found)
888         {
889           for (i = 0; control_info[i].name != NULL; ++i)
890             {
891               if (STREQ (arg, control_info[i].name))
892                 {
893                   if (k == argc - 1)
894                     {
895                       error (0, 0, _("missing argument to %s"), quote (arg));
896                       usage (EXIT_FAILURE);
897                     }
898                   match_found = true;
899                   ++k;
900                   set_control_char (&control_info[i], argv[k], &mode);
901                   require_set_attr = true;
902                   break;
903                 }
904             }
905         }
906       if (!match_found)
907         {
908           if (STREQ (arg, "ispeed"))
909             {
910               if (k == argc - 1)
911                 {
912                   error (0, 0, _("missing argument to %s"), quote (arg));
913                   usage (EXIT_FAILURE);
914                 }
915               ++k;
916               set_speed (input_speed, argv[k], &mode);
917               speed_was_set = true;
918               require_set_attr = true;
919             }
920           else if (STREQ (arg, "ospeed"))
921             {
922               if (k == argc - 1)
923                 {
924                   error (0, 0, _("missing argument to %s"), quote (arg));
925                   usage (EXIT_FAILURE);
926                 }
927               ++k;
928               set_speed (output_speed, argv[k], &mode);
929               speed_was_set = true;
930               require_set_attr = true;
931             }
932 #ifdef TIOCGWINSZ
933           else if (STREQ (arg, "rows"))
934             {
935               if (k == argc - 1)
936                 {
937                   error (0, 0, _("missing argument to %s"), quote (arg));
938                   usage (EXIT_FAILURE);
939                 }
940               ++k;
941               set_window_size (integer_arg (argv[k], INT_MAX), -1,
942                                device_name);
943             }
944           else if (STREQ (arg, "cols")
945                    || STREQ (arg, "columns"))
946             {
947               if (k == argc - 1)
948                 {
949                   error (0, 0, _("missing argument to %s"), quote (arg));
950                   usage (EXIT_FAILURE);
951                 }
952               ++k;
953               set_window_size (-1, integer_arg (argv[k], INT_MAX),
954                                device_name);
955             }
956           else if (STREQ (arg, "size"))
957             {
958               max_col = screen_columns ();
959               current_col = 0;
960               display_window_size (false, device_name);
961             }
962 #endif
963 #ifdef HAVE_C_LINE
964           else if (STREQ (arg, "line"))
965             {
966               unsigned long int value;
967               if (k == argc - 1)
968                 {
969                   error (0, 0, _("missing argument to %s"), quote (arg));
970                   usage (EXIT_FAILURE);
971                 }
972               ++k;
973               mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
974               if (mode.c_line != value)
975                 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
976               require_set_attr = true;
977             }
978 #endif
979           else if (STREQ (arg, "speed"))
980             {
981               max_col = screen_columns ();
982               display_speed (&mode, false);
983             }
984           else if (string_to_baud (arg) != (speed_t) -1)
985             {
986               set_speed (both_speeds, arg, &mode);
987               speed_was_set = true;
988               require_set_attr = true;
989             }
990           else
991             {
992               if (! recover_mode (arg, &mode))
993                 {
994                   error (0, 0, _("invalid argument %s"), quote (arg));
995                   usage (EXIT_FAILURE);
996                 }
997               require_set_attr = true;
998             }
999         }
1000     }
1001
1002   if (require_set_attr)
1003     {
1004       /* Initialize to all zeroes so there is no risk memcmp will report a
1005          spurious difference in an uninitialized portion of the structure.  */
1006       static struct termios new_mode;
1007
1008       if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1009         error (EXIT_FAILURE, errno, "%s", device_name);
1010
1011       /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1012          it performs *any* of the requested operations.  This means it
1013          can report 'success' when it has actually failed to perform
1014          some proper subset of the requested operations.  To detect
1015          this partial failure, get the current terminal attributes and
1016          compare them to the requested ones.  */
1017
1018       if (tcgetattr (STDIN_FILENO, &new_mode))
1019         error (EXIT_FAILURE, errno, "%s", device_name);
1020
1021       /* Normally, one shouldn't use memcmp to compare structures that
1022          may have 'holes' containing uninitialized data, but we have been
1023          careful to initialize the storage of these two variables to all
1024          zeroes.  One might think it more efficient simply to compare the
1025          modified fields, but that would require enumerating those fields --
1026          and not all systems have the same fields in this structure.  */
1027
1028       if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1029         {
1030 #ifdef CIBAUD
1031           /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1032              tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1033              sometimes (m1 != m2).  The only difference is in the four bits
1034              of the c_cflag field corresponding to the baud rate.  To save
1035              Sun users a little confusion, don't report an error if this
1036              happens.  But suppress the error only if we haven't tried to
1037              set the baud rate explicitly -- otherwise we'd never give an
1038              error for a true failure to set the baud rate.  */
1039
1040           new_mode.c_cflag &= (~CIBAUD);
1041           if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1042 #endif
1043             {
1044               error (EXIT_FAILURE, 0,
1045                      _("%s: unable to perform all requested operations"),
1046                      device_name);
1047 #ifdef TESTING
1048               {
1049                 size_t i;
1050                 printf ("new_mode: mode\n");
1051                 for (i = 0; i < sizeof (new_mode); i++)
1052                   printf ("0x%02x: 0x%02x\n",
1053                           *(((unsigned char *) &new_mode) + i),
1054                           *(((unsigned char *) &mode) + i));
1055               }
1056 #endif
1057             }
1058         }
1059     }
1060
1061   exit (EXIT_SUCCESS);
1062 }
1063
1064 /* Return false if not applied because not reversible; otherwise
1065    return true.  */
1066
1067 static bool
1068 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1069 {
1070   tcflag_t *bitsp;
1071
1072   if (reversed && (info->flags & REV) == 0)
1073     return false;
1074
1075   bitsp = mode_type_flag (info->type, mode);
1076
1077   if (bitsp == NULL)
1078     {
1079       /* Combination mode. */
1080       if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1081         {
1082           if (reversed)
1083             mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1084           else
1085             mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1086         }
1087       else if (STREQ (info->name, "oddp"))
1088         {
1089           if (reversed)
1090             mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1091           else
1092             mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1093         }
1094       else if (STREQ (info->name, "nl"))
1095         {
1096           if (reversed)
1097             {
1098               mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1099               mode->c_oflag = (mode->c_oflag
1100 #ifdef ONLCR
1101                                | ONLCR
1102 #endif
1103                 )
1104 #ifdef OCRNL
1105                 & ~OCRNL
1106 #endif
1107 #ifdef ONLRET
1108                 & ~ONLRET
1109 #endif
1110                 ;
1111             }
1112           else
1113             {
1114               mode->c_iflag = mode->c_iflag & ~ICRNL;
1115 #ifdef ONLCR
1116               mode->c_oflag = mode->c_oflag & ~ONLCR;
1117 #endif
1118             }
1119         }
1120       else if (STREQ (info->name, "ek"))
1121         {
1122           mode->c_cc[VERASE] = CERASE;
1123           mode->c_cc[VKILL] = CKILL;
1124         }
1125       else if (STREQ (info->name, "sane"))
1126         sane_mode (mode);
1127       else if (STREQ (info->name, "cbreak"))
1128         {
1129           if (reversed)
1130             mode->c_lflag |= ICANON;
1131           else
1132             mode->c_lflag &= ~ICANON;
1133         }
1134       else if (STREQ (info->name, "pass8"))
1135         {
1136           if (reversed)
1137             {
1138               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1139               mode->c_iflag |= ISTRIP;
1140             }
1141           else
1142             {
1143               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1144               mode->c_iflag &= ~ISTRIP;
1145             }
1146         }
1147       else if (STREQ (info->name, "litout"))
1148         {
1149           if (reversed)
1150             {
1151               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1152               mode->c_iflag |= ISTRIP;
1153               mode->c_oflag |= OPOST;
1154             }
1155           else
1156             {
1157               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1158               mode->c_iflag &= ~ISTRIP;
1159               mode->c_oflag &= ~OPOST;
1160             }
1161         }
1162       else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1163         {
1164           if ((info->name[0] == 'r' && reversed)
1165               || (info->name[0] == 'c' && !reversed))
1166             {
1167               /* Cooked mode. */
1168               mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1169               mode->c_oflag |= OPOST;
1170               mode->c_lflag |= ISIG | ICANON;
1171 #if VMIN == VEOF
1172               mode->c_cc[VEOF] = CEOF;
1173 #endif
1174 #if VTIME == VEOL
1175               mode->c_cc[VEOL] = CEOL;
1176 #endif
1177             }
1178           else
1179             {
1180               /* Raw mode. */
1181               mode->c_iflag = 0;
1182               mode->c_oflag &= ~OPOST;
1183               mode->c_lflag &= ~(ISIG | ICANON
1184 #ifdef XCASE
1185                                  | XCASE
1186 #endif
1187                 );
1188               mode->c_cc[VMIN] = 1;
1189               mode->c_cc[VTIME] = 0;
1190             }
1191         }
1192 #ifdef IXANY
1193       else if (STREQ (info->name, "decctlq"))
1194         {
1195           if (reversed)
1196             mode->c_iflag |= IXANY;
1197           else
1198             mode->c_iflag &= ~IXANY;
1199         }
1200 #endif
1201 #ifdef TABDLY
1202       else if (STREQ (info->name, "tabs"))
1203         {
1204           if (reversed)
1205             mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1206           else
1207             mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1208         }
1209 #else
1210 # ifdef OXTABS
1211       else if (STREQ (info->name, "tabs"))
1212         {
1213           if (reversed)
1214             mode->c_oflag = mode->c_oflag | OXTABS;
1215           else
1216             mode->c_oflag = mode->c_oflag & ~OXTABS;
1217         }
1218 # endif
1219 #endif
1220 #if defined XCASE && defined IUCLC && defined OLCUC
1221       else if (STREQ (info->name, "lcase")
1222                || STREQ (info->name, "LCASE"))
1223         {
1224           if (reversed)
1225             {
1226               mode->c_lflag &= ~XCASE;
1227               mode->c_iflag &= ~IUCLC;
1228               mode->c_oflag &= ~OLCUC;
1229             }
1230           else
1231             {
1232               mode->c_lflag |= XCASE;
1233               mode->c_iflag |= IUCLC;
1234               mode->c_oflag |= OLCUC;
1235             }
1236         }
1237 #endif
1238       else if (STREQ (info->name, "crt"))
1239         mode->c_lflag |= ECHOE
1240 #ifdef ECHOCTL
1241           | ECHOCTL
1242 #endif
1243 #ifdef ECHOKE
1244           | ECHOKE
1245 #endif
1246           ;
1247       else if (STREQ (info->name, "dec"))
1248         {
1249           mode->c_cc[VINTR] = 3;        /* ^C */
1250           mode->c_cc[VERASE] = 127;     /* DEL */
1251           mode->c_cc[VKILL] = 21;       /* ^U */
1252           mode->c_lflag |= ECHOE
1253 #ifdef ECHOCTL
1254             | ECHOCTL
1255 #endif
1256 #ifdef ECHOKE
1257             | ECHOKE
1258 #endif
1259             ;
1260 #ifdef IXANY
1261           mode->c_iflag &= ~IXANY;
1262 #endif
1263         }
1264     }
1265   else if (reversed)
1266     *bitsp = *bitsp & ~info->mask & ~info->bits;
1267   else
1268     *bitsp = (*bitsp & ~info->mask) | info->bits;
1269
1270   return true;
1271 }
1272
1273 static void
1274 set_control_char (struct control_info const *info, const char *arg,
1275                   struct termios *mode)
1276 {
1277   unsigned long int value;
1278
1279   if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1280     value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1281   else if (arg[0] == '\0' || arg[1] == '\0')
1282     value = to_uchar (arg[0]);
1283   else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1284     value = _POSIX_VDISABLE;
1285   else if (arg[0] == '^' && arg[1] != '\0')     /* Ignore any trailing junk. */
1286     {
1287       if (arg[1] == '?')
1288         value = 127;
1289       else
1290         value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1291     }
1292   else
1293     value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1294   mode->c_cc[info->offset] = value;
1295 }
1296
1297 static void
1298 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1299 {
1300   speed_t baud;
1301
1302   baud = string_to_baud (arg);
1303   if (type == input_speed || type == both_speeds)
1304     cfsetispeed (mode, baud);
1305   if (type == output_speed || type == both_speeds)
1306     cfsetospeed (mode, baud);
1307 }
1308
1309 #ifdef TIOCGWINSZ
1310
1311 static int
1312 get_win_size (int fd, struct winsize *win)
1313 {
1314   int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1315   return err;
1316 }
1317
1318 static void
1319 set_window_size (int rows, int cols, char const *device_name)
1320 {
1321   struct winsize win;
1322
1323   if (get_win_size (STDIN_FILENO, &win))
1324     {
1325       if (errno != EINVAL)
1326         error (EXIT_FAILURE, errno, "%s", device_name);
1327       memset (&win, 0, sizeof (win));
1328     }
1329
1330   if (rows >= 0)
1331     win.ws_row = rows;
1332   if (cols >= 0)
1333     win.ws_col = cols;
1334
1335 # ifdef TIOCSSIZE
1336   /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1337      The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1338      This comment from sys/ttold.h describes Sun's twisted logic - a better
1339      test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1340      At any rate, the problem is gone in Solaris 2.x.
1341
1342      Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1343      but they can be disambiguated by checking whether a "struct ttysize"
1344      structure's "ts_lines" field is greater than 64K or not.  If so,
1345      it's almost certainly a "struct winsize" instead.
1346
1347      At any rate, the bug manifests itself when ws_row == 0; the symptom is
1348      that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16)
1349      + ws_ypixel.  Since GNU stty sets rows and columns separately, this bug
1350      caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1351      "stty cols 0 rows 0" would do the right thing.  On a little-endian
1352      machine like the sun386i, the problem is the same, but for ws_col == 0.
1353
1354      The workaround is to do the ioctl once with row and col = 1 to set the
1355      pixel info, and then do it again using a TIOCSSIZE to set rows/cols.  */
1356
1357   if (win.ws_row == 0 || win.ws_col == 0)
1358     {
1359       struct ttysize ttysz;
1360
1361       ttysz.ts_lines = win.ws_row;
1362       ttysz.ts_cols = win.ws_col;
1363
1364       win.ws_row = 1;
1365       win.ws_col = 1;
1366
1367       if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1368         error (EXIT_FAILURE, errno, "%s", device_name);
1369
1370       if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1371         error (EXIT_FAILURE, errno, "%s", device_name);
1372       return;
1373     }
1374 # endif
1375
1376   if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1377     error (EXIT_FAILURE, errno, "%s", device_name);
1378 }
1379
1380 static void
1381 display_window_size (bool fancy, char const *device_name)
1382 {
1383   struct winsize win;
1384
1385   if (get_win_size (STDIN_FILENO, &win))
1386     {
1387       if (errno != EINVAL)
1388         error (EXIT_FAILURE, errno, "%s", device_name);
1389       if (!fancy)
1390         error (EXIT_FAILURE, 0,
1391                _("%s: no size information for this device"), device_name);
1392     }
1393   else
1394     {
1395       wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1396              win.ws_row, win.ws_col);
1397       if (!fancy)
1398         current_col = 0;
1399     }
1400 }
1401 #endif
1402
1403 static int
1404 screen_columns (void)
1405 {
1406 #ifdef TIOCGWINSZ
1407   struct winsize win;
1408
1409   /* With Solaris 2.[123], this ioctl fails and errno is set to
1410      EINVAL for telnet (but not rlogin) sessions.
1411      On ISC 3.0, it fails for the console and the serial port
1412      (but it works for ptys).
1413      It can also fail on any system when stdout isn't a tty.
1414      In case of any failure, just use the default.  */
1415   if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1416     return win.ws_col;
1417 #endif
1418   {
1419     /* Use $COLUMNS if it's in [1..INT_MAX].  */
1420     char *col_string = getenv ("COLUMNS");
1421     long int n_columns;
1422     if (!(col_string != NULL
1423           && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1424           && 0 < n_columns
1425           && n_columns <= INT_MAX))
1426       n_columns = 80;
1427     return n_columns;
1428   }
1429 }
1430
1431 static tcflag_t * _GL_ATTRIBUTE_PURE
1432 mode_type_flag (enum mode_type type, struct termios *mode)
1433 {
1434   switch (type)
1435     {
1436     case control:
1437       return &mode->c_cflag;
1438
1439     case input:
1440       return &mode->c_iflag;
1441
1442     case output:
1443       return &mode->c_oflag;
1444
1445     case local:
1446       return &mode->c_lflag;
1447
1448     case combination:
1449       return NULL;
1450
1451     default:
1452       abort ();
1453     }
1454 }
1455
1456 static void
1457 display_settings (enum output_type output_type, struct termios *mode,
1458                   char const *device_name)
1459 {
1460   switch (output_type)
1461     {
1462     case changed:
1463       display_changed (mode);
1464       break;
1465
1466     case all:
1467       display_all (mode, device_name);
1468       break;
1469
1470     case recoverable:
1471       display_recoverable (mode);
1472       break;
1473     }
1474 }
1475
1476 static void
1477 display_changed (struct termios *mode)
1478 {
1479   int i;
1480   bool empty_line;
1481   tcflag_t *bitsp;
1482   unsigned long mask;
1483   enum mode_type prev_type = control;
1484
1485   display_speed (mode, true);
1486 #ifdef HAVE_C_LINE
1487   wrapf ("line = %d;", mode->c_line);
1488 #endif
1489   putchar ('\n');
1490   current_col = 0;
1491
1492   empty_line = true;
1493   for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1494     {
1495       if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1496         continue;
1497       /* If swtch is the same as susp, don't print both.  */
1498 #if VSWTCH == VSUSP
1499       if (STREQ (control_info[i].name, "swtch"))
1500         continue;
1501 #endif
1502       /* If eof uses the same slot as min, only print whichever applies.  */
1503 #if VEOF == VMIN
1504       if ((mode->c_lflag & ICANON) == 0
1505           && (STREQ (control_info[i].name, "eof")
1506               || STREQ (control_info[i].name, "eol")))
1507         continue;
1508 #endif
1509
1510       empty_line = false;
1511       wrapf ("%s = %s;", control_info[i].name,
1512              visible (mode->c_cc[control_info[i].offset]));
1513     }
1514   if ((mode->c_lflag & ICANON) == 0)
1515     {
1516       wrapf ("min = %lu; time = %lu;\n",
1517              (unsigned long int) mode->c_cc[VMIN],
1518              (unsigned long int) mode->c_cc[VTIME]);
1519     }
1520   else if (!empty_line)
1521     putchar ('\n');
1522   current_col = 0;
1523
1524   empty_line = true;
1525   for (i = 0; mode_info[i].name != NULL; ++i)
1526     {
1527       if (mode_info[i].flags & OMIT)
1528         continue;
1529       if (mode_info[i].type != prev_type)
1530         {
1531           if (!empty_line)
1532             {
1533               putchar ('\n');
1534               current_col = 0;
1535               empty_line = true;
1536             }
1537           prev_type = mode_info[i].type;
1538         }
1539
1540       bitsp = mode_type_flag (mode_info[i].type, mode);
1541       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1542
1543       /* bitsp would be NULL only for "combination" modes, yet those
1544          are filtered out above via the OMIT flag.  Tell static analysis
1545          tools that it's ok to dereference bitsp here.  */
1546       assert (bitsp);
1547
1548       if ((*bitsp & mask) == mode_info[i].bits)
1549         {
1550           if (mode_info[i].flags & SANE_UNSET)
1551             {
1552               wrapf ("%s", mode_info[i].name);
1553               empty_line = false;
1554             }
1555         }
1556       else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1557         {
1558           wrapf ("-%s", mode_info[i].name);
1559           empty_line = false;
1560         }
1561     }
1562   if (!empty_line)
1563     putchar ('\n');
1564   current_col = 0;
1565 }
1566
1567 static void
1568 display_all (struct termios *mode, char const *device_name)
1569 {
1570   int i;
1571   tcflag_t *bitsp;
1572   unsigned long mask;
1573   enum mode_type prev_type = control;
1574
1575   display_speed (mode, true);
1576 #ifdef TIOCGWINSZ
1577   display_window_size (true, device_name);
1578 #endif
1579 #ifdef HAVE_C_LINE
1580   wrapf ("line = %d;", mode->c_line);
1581 #endif
1582   putchar ('\n');
1583   current_col = 0;
1584
1585   for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1586     {
1587       /* If swtch is the same as susp, don't print both.  */
1588 #if VSWTCH == VSUSP
1589       if (STREQ (control_info[i].name, "swtch"))
1590         continue;
1591 #endif
1592       /* If eof uses the same slot as min, only print whichever applies.  */
1593 #if VEOF == VMIN
1594       if ((mode->c_lflag & ICANON) == 0
1595           && (STREQ (control_info[i].name, "eof")
1596               || STREQ (control_info[i].name, "eol")))
1597         continue;
1598 #endif
1599       wrapf ("%s = %s;", control_info[i].name,
1600              visible (mode->c_cc[control_info[i].offset]));
1601     }
1602 #if VEOF == VMIN
1603   if ((mode->c_lflag & ICANON) == 0)
1604 #endif
1605     wrapf ("min = %lu; time = %lu;",
1606            (unsigned long int) mode->c_cc[VMIN],
1607            (unsigned long int) mode->c_cc[VTIME]);
1608   if (current_col != 0)
1609     putchar ('\n');
1610   current_col = 0;
1611
1612   for (i = 0; mode_info[i].name != NULL; ++i)
1613     {
1614       if (mode_info[i].flags & OMIT)
1615         continue;
1616       if (mode_info[i].type != prev_type)
1617         {
1618           putchar ('\n');
1619           current_col = 0;
1620           prev_type = mode_info[i].type;
1621         }
1622
1623       bitsp = mode_type_flag (mode_info[i].type, mode);
1624       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1625       assert (bitsp); /* See the identical assertion and comment above.  */
1626       if ((*bitsp & mask) == mode_info[i].bits)
1627         wrapf ("%s", mode_info[i].name);
1628       else if (mode_info[i].flags & REV)
1629         wrapf ("-%s", mode_info[i].name);
1630     }
1631   putchar ('\n');
1632   current_col = 0;
1633 }
1634
1635 static void
1636 display_speed (struct termios *mode, bool fancy)
1637 {
1638   if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1639     wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1640            baud_to_value (cfgetospeed (mode)));
1641   else
1642     wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1643            baud_to_value (cfgetispeed (mode)),
1644            baud_to_value (cfgetospeed (mode)));
1645   if (!fancy)
1646     current_col = 0;
1647 }
1648
1649 static void
1650 display_recoverable (struct termios *mode)
1651 {
1652   size_t i;
1653
1654   printf ("%lx:%lx:%lx:%lx",
1655           (unsigned long int) mode->c_iflag,
1656           (unsigned long int) mode->c_oflag,
1657           (unsigned long int) mode->c_cflag,
1658           (unsigned long int) mode->c_lflag);
1659   for (i = 0; i < NCCS; ++i)
1660     printf (":%lx", (unsigned long int) mode->c_cc[i]);
1661   putchar ('\n');
1662 }
1663
1664 /* NOTE: identical to below, modulo use of tcflag_t */
1665 static int
1666 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1667                   char delim)
1668 {
1669   unsigned long ul;
1670   errno = 0;
1671   ul = strtoul (s, p, base);
1672   if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1673     return -1;
1674   *result = ul;
1675   return 0;
1676 }
1677
1678 /* NOTE: identical to above, modulo use of cc_t */
1679 static int
1680 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1681 {
1682   unsigned long ul;
1683   errno = 0;
1684   ul = strtoul (s, p, base);
1685   if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1686     return -1;
1687   *result = ul;
1688   return 0;
1689 }
1690
1691 /* Parse the output of display_recoverable.
1692    Return false if any part of it is invalid.  */
1693 static bool
1694 recover_mode (char const *arg, struct termios *mode)
1695 {
1696   tcflag_t flag[4];
1697   char const *s = arg;
1698   size_t i;
1699   for (i = 0; i < 4; i++)
1700     {
1701       char *p;
1702       if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1703         return false;
1704       s = p + 1;
1705     }
1706   mode->c_iflag = flag[0];
1707   mode->c_oflag = flag[1];
1708   mode->c_cflag = flag[2];
1709   mode->c_lflag = flag[3];
1710
1711   for (i = 0; i < NCCS; ++i)
1712     {
1713       char *p;
1714       char delim = i < NCCS - 1 ? ':' : '\0';
1715       if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1716         return false;
1717       s = p + 1;
1718     }
1719
1720   return true;
1721 }
1722
1723 struct speed_map
1724 {
1725   const char *string;           /* ASCII representation. */
1726   speed_t speed;                /* Internal form. */
1727   unsigned long int value;      /* Numeric value. */
1728 };
1729
1730 static struct speed_map const speeds[] =
1731 {
1732   {"0", B0, 0},
1733   {"50", B50, 50},
1734   {"75", B75, 75},
1735   {"110", B110, 110},
1736   {"134", B134, 134},
1737   {"134.5", B134, 134},
1738   {"150", B150, 150},
1739   {"200", B200, 200},
1740   {"300", B300, 300},
1741   {"600", B600, 600},
1742   {"1200", B1200, 1200},
1743   {"1800", B1800, 1800},
1744   {"2400", B2400, 2400},
1745   {"4800", B4800, 4800},
1746   {"9600", B9600, 9600},
1747   {"19200", B19200, 19200},
1748   {"38400", B38400, 38400},
1749   {"exta", B19200, 19200},
1750   {"extb", B38400, 38400},
1751 #ifdef B57600
1752   {"57600", B57600, 57600},
1753 #endif
1754 #ifdef B115200
1755   {"115200", B115200, 115200},
1756 #endif
1757 #ifdef B230400
1758   {"230400", B230400, 230400},
1759 #endif
1760 #ifdef B460800
1761   {"460800", B460800, 460800},
1762 #endif
1763 #ifdef B500000
1764   {"500000", B500000, 500000},
1765 #endif
1766 #ifdef B576000
1767   {"576000", B576000, 576000},
1768 #endif
1769 #ifdef B921600
1770   {"921600", B921600, 921600},
1771 #endif
1772 #ifdef B1000000
1773   {"1000000", B1000000, 1000000},
1774 #endif
1775 #ifdef B1152000
1776   {"1152000", B1152000, 1152000},
1777 #endif
1778 #ifdef B1500000
1779   {"1500000", B1500000, 1500000},
1780 #endif
1781 #ifdef B2000000
1782   {"2000000", B2000000, 2000000},
1783 #endif
1784 #ifdef B2500000
1785   {"2500000", B2500000, 2500000},
1786 #endif
1787 #ifdef B3000000
1788   {"3000000", B3000000, 3000000},
1789 #endif
1790 #ifdef B3500000
1791   {"3500000", B3500000, 3500000},
1792 #endif
1793 #ifdef B4000000
1794   {"4000000", B4000000, 4000000},
1795 #endif
1796   {NULL, 0, 0}
1797 };
1798
1799 static speed_t _GL_ATTRIBUTE_PURE
1800 string_to_baud (const char *arg)
1801 {
1802   int i;
1803
1804   for (i = 0; speeds[i].string != NULL; ++i)
1805     if (STREQ (arg, speeds[i].string))
1806       return speeds[i].speed;
1807   return (speed_t) -1;
1808 }
1809
1810 static unsigned long int _GL_ATTRIBUTE_PURE
1811 baud_to_value (speed_t speed)
1812 {
1813   int i;
1814
1815   for (i = 0; speeds[i].string != NULL; ++i)
1816     if (speed == speeds[i].speed)
1817       return speeds[i].value;
1818   return 0;
1819 }
1820
1821 static void
1822 sane_mode (struct termios *mode)
1823 {
1824   int i;
1825   tcflag_t *bitsp;
1826
1827   for (i = 0; control_info[i].name; ++i)
1828     {
1829 #if VMIN == VEOF
1830       if (STREQ (control_info[i].name, "min"))
1831         break;
1832 #endif
1833       mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1834     }
1835
1836   for (i = 0; mode_info[i].name != NULL; ++i)
1837     {
1838       if (mode_info[i].flags & SANE_SET)
1839         {
1840           bitsp = mode_type_flag (mode_info[i].type, mode);
1841           *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1842         }
1843       else if (mode_info[i].flags & SANE_UNSET)
1844         {
1845           bitsp = mode_type_flag (mode_info[i].type, mode);
1846           *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1847         }
1848     }
1849 }
1850
1851 /* Return a string that is the printable representation of character CH.  */
1852 /* Adapted from 'cat' by Torbjorn Granlund.  */
1853
1854 static const char *
1855 visible (cc_t ch)
1856 {
1857   static char buf[10];
1858   char *bpout = buf;
1859
1860   if (ch == _POSIX_VDISABLE)
1861     return "<undef>";
1862
1863   if (ch >= 32)
1864     {
1865       if (ch < 127)
1866         *bpout++ = ch;
1867       else if (ch == 127)
1868         {
1869           *bpout++ = '^';
1870           *bpout++ = '?';
1871         }
1872       else
1873         {
1874           *bpout++ = 'M';
1875           *bpout++ = '-';
1876           if (ch >= 128 + 32)
1877             {
1878               if (ch < 128 + 127)
1879                 *bpout++ = ch - 128;
1880               else
1881                 {
1882                   *bpout++ = '^';
1883                   *bpout++ = '?';
1884                 }
1885             }
1886           else
1887             {
1888               *bpout++ = '^';
1889               *bpout++ = ch - 128 + 64;
1890             }
1891         }
1892     }
1893   else
1894     {
1895       *bpout++ = '^';
1896       *bpout++ = ch + 64;
1897     }
1898   *bpout = '\0';
1899   return (const char *) buf;
1900 }
1901
1902 /* Parse string S as an integer, using decimal radix by default,
1903    but allowing octal and hex numbers as in C.  Reject values
1904    larger than MAXVAL.  */
1905
1906 static unsigned long int
1907 integer_arg (const char *s, unsigned long int maxval)
1908 {
1909   unsigned long int value;
1910   if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1911     {
1912       error (0, 0, _("invalid integer argument %s"), quote (s));
1913       usage (EXIT_FAILURE);
1914     }
1915   return value;
1916 }