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