stty: diagnose an invalid hex value in 35-colon commmand-line argument
[platform/upstream/coreutils.git] / src / stty.c
1 /* stty -- change and print terminal line settings
2    Copyright (C) 1990-2005, 2007 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 2, or (at your option)
7    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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
19
20    Options:
21    -a, --all    Write all current settings to stdout in human-readable form.
22    -g, --save   Write all current settings to stdout in stty-readable form.
23    -F, --file   Open and use the specified device instead of stdin
24
25    If no args are given, write to stdout the baud rate and settings that
26    have been changed from their defaults.  Mode reading and changes
27    are done on the specified device, or stdin if none was specified.
28
29    David MacKenzie <djm@gnu.ai.mit.edu> */
30
31 #include <config.h>
32
33 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
34 # define _XOPEN_SOURCE
35 #endif
36
37 #include <stdio.h>
38 #include <sys/types.h>
39
40 #if HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
43 #if HAVE_STROPTS_H
44 # include <stropts.h>
45 #endif
46 #ifdef HAVE_SYS_IOCTL_H
47 # include <sys/ioctl.h>
48 #endif
49
50 #ifdef WINSIZE_IN_PTEM
51 # include <sys/stream.h>
52 # include <sys/ptem.h>
53 #endif
54 #ifdef GWINSZ_IN_SYS_PTY
55 # include <sys/tty.h>
56 # include <sys/pty.h>
57 #endif
58 #include <getopt.h>
59 #include <stdarg.h>
60
61 #include "system.h"
62 #include "error.h"
63 #include "fd-reopen.h"
64 #include "quote.h"
65 #include "xstrtol.h"
66
67 /* The official name of this program (e.g., no `g' prefix).  */
68 #define PROGRAM_NAME "stty"
69
70 #define AUTHORS "David MacKenzie"
71
72 #ifndef _POSIX_VDISABLE
73 # define _POSIX_VDISABLE 0
74 #endif
75
76 #define Control(c) ((c) & 0x1f)
77 /* Canonical values for control characters. */
78 #ifndef CINTR
79 # define CINTR Control ('c')
80 #endif
81 #ifndef CQUIT
82 # define CQUIT 28
83 #endif
84 #ifndef CERASE
85 # define CERASE 127
86 #endif
87 #ifndef CKILL
88 # define CKILL Control ('u')
89 #endif
90 #ifndef CEOF
91 # define CEOF Control ('d')
92 #endif
93 #ifndef CEOL
94 # define CEOL _POSIX_VDISABLE
95 #endif
96 #ifndef CSTART
97 # define CSTART Control ('q')
98 #endif
99 #ifndef CSTOP
100 # define CSTOP Control ('s')
101 #endif
102 #ifndef CSUSP
103 # define CSUSP Control ('z')
104 #endif
105 #if defined VEOL2 && !defined CEOL2
106 # define CEOL2 _POSIX_VDISABLE
107 #endif
108 /* Some platforms have VSWTC, others VSWTCH.  In both cases, this control
109    character is initialized by CSWTCH, if present.  */
110 #if defined VSWTC && !defined VSWTCH
111 # define VSWTCH VSWTC
112 #endif
113 /* ISC renamed swtch to susp for termios, but we'll accept either name.  */
114 #if defined VSUSP && !defined VSWTCH
115 # define VSWTCH VSUSP
116 # if defined CSUSP && !defined CSWTCH
117 #  define CSWTCH CSUSP
118 # endif
119 #endif
120 #if defined VSWTCH && !defined CSWTCH
121 # define CSWTCH _POSIX_VDISABLE
122 #endif
123
124 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
125    So the default is to disable `swtch.'  */
126 #if defined __sparc__ && defined __svr4__
127 # undef CSWTCH
128 # define CSWTCH _POSIX_VDISABLE
129 #endif
130
131 #if defined VWERSE && !defined VWERASE  /* AIX-3.2.5 */
132 # define VWERASE VWERSE
133 #endif
134 #if defined VDSUSP && !defined CDSUSP
135 # define CDSUSP Control ('y')
136 #endif
137 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
138 # define VREPRINT VRPRNT
139 #endif
140 #if defined VREPRINT && !defined CRPRNT
141 # define CRPRNT Control ('r')
142 #endif
143 #if defined CREPRINT && !defined CRPRNT
144 # define CRPRNT Control ('r')
145 #endif
146 #if defined VWERASE && !defined CWERASE
147 # define CWERASE Control ('w')
148 #endif
149 #if defined VLNEXT && !defined CLNEXT
150 # define CLNEXT Control ('v')
151 #endif
152 #if defined VDISCARD && !defined VFLUSHO
153 # define VFLUSHO VDISCARD
154 #endif
155 #if defined VFLUSH && !defined VFLUSHO  /* Ultrix 4.2 */
156 # define VFLUSHO VFLUSH
157 #endif
158 #if defined CTLECH && !defined ECHOCTL  /* Ultrix 4.3 */
159 # define ECHOCTL CTLECH
160 #endif
161 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
162 # define ECHOCTL TCTLECH
163 #endif
164 #if defined CRTKIL && !defined ECHOKE   /* Ultrix 4.2 and 4.3 */
165 # define ECHOKE CRTKIL
166 #endif
167 #if defined VFLUSHO && !defined CFLUSHO
168 # define CFLUSHO Control ('o')
169 #endif
170 #if defined VSTATUS && !defined CSTATUS
171 # define CSTATUS Control ('t')
172 #endif
173
174 /* Which speeds to set.  */
175 enum speed_setting
176   {
177     input_speed, output_speed, both_speeds
178   };
179
180 /* What to output and how.  */
181 enum output_type
182   {
183     changed, all, recoverable   /* Default, -a, -g.  */
184   };
185
186 /* Which member(s) of `struct termios' a mode uses.  */
187 enum mode_type
188   {
189     control, input, output, local, combination
190   };
191
192 /* Flags for `struct mode_info'. */
193 #define SANE_SET 1              /* Set in `sane' mode. */
194 #define SANE_UNSET 2            /* Unset in `sane' mode. */
195 #define REV 4                   /* Can be turned off by prepending `-'. */
196 #define OMIT 8                  /* Don't display value. */
197
198 /* Each mode.  */
199 struct mode_info
200   {
201     const char *name;           /* Name given on command line.  */
202     enum mode_type type;        /* Which structure element to change. */
203     char flags;                 /* Setting and display options.  */
204     unsigned long bits;         /* Bits to set for this mode.  */
205     unsigned long mask;         /* Other bits to turn off for this mode.  */
206   };
207
208 static struct mode_info mode_info[] =
209 {
210   {"parenb", control, REV, PARENB, 0},
211   {"parodd", control, REV, PARODD, 0},
212   {"cs5", control, 0, CS5, CSIZE},
213   {"cs6", control, 0, CS6, CSIZE},
214   {"cs7", control, 0, CS7, CSIZE},
215   {"cs8", control, 0, CS8, CSIZE},
216   {"hupcl", control, REV, HUPCL, 0},
217   {"hup", control, REV | OMIT, HUPCL, 0},
218   {"cstopb", control, REV, CSTOPB, 0},
219   {"cread", control, SANE_SET | REV, CREAD, 0},
220   {"clocal", control, REV, CLOCAL, 0},
221 #ifdef CRTSCTS
222   {"crtscts", control, REV, CRTSCTS, 0},
223 #endif
224
225   {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
226   {"brkint", input, SANE_SET | REV, BRKINT, 0},
227   {"ignpar", input, REV, IGNPAR, 0},
228   {"parmrk", input, REV, PARMRK, 0},
229   {"inpck", input, REV, INPCK, 0},
230   {"istrip", input, REV, ISTRIP, 0},
231   {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
232   {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
233   {"icrnl", input, SANE_SET | REV, ICRNL, 0},
234   {"ixon", input, REV, IXON, 0},
235   {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
236   {"tandem", input, REV | OMIT, IXOFF, 0},
237 #ifdef IUCLC
238   {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
239 #endif
240 #ifdef IXANY
241   {"ixany", input, SANE_UNSET | REV, IXANY, 0},
242 #endif
243 #ifdef IMAXBEL
244   {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
245 #endif
246 #ifdef IUTF8
247   {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
248 #endif
249
250   {"opost", output, SANE_SET | REV, OPOST, 0},
251 #ifdef OLCUC
252   {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
253 #endif
254 #ifdef OCRNL
255   {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
256 #endif
257 #ifdef ONLCR
258   {"onlcr", output, SANE_SET | REV, ONLCR, 0},
259 #endif
260 #ifdef ONOCR
261   {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
262 #endif
263 #ifdef ONLRET
264   {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
265 #endif
266 #ifdef OFILL
267   {"ofill", output, SANE_UNSET | REV, OFILL, 0},
268 #endif
269 #ifdef OFDEL
270   {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
271 #endif
272 #ifdef NLDLY
273   {"nl1", output, SANE_UNSET, NL1, NLDLY},
274   {"nl0", output, SANE_SET, NL0, NLDLY},
275 #endif
276 #ifdef CRDLY
277   {"cr3", output, SANE_UNSET, CR3, CRDLY},
278   {"cr2", output, SANE_UNSET, CR2, CRDLY},
279   {"cr1", output, SANE_UNSET, CR1, CRDLY},
280   {"cr0", output, SANE_SET, CR0, CRDLY},
281 #endif
282 #ifdef TABDLY
283   {"tab3", output, SANE_UNSET, TAB3, TABDLY},
284   {"tab2", output, SANE_UNSET, TAB2, TABDLY},
285   {"tab1", output, SANE_UNSET, TAB1, TABDLY},
286   {"tab0", output, SANE_SET, TAB0, TABDLY},
287 #else
288 # ifdef OXTABS
289   {"tab3", output, SANE_UNSET, OXTABS, 0},
290 # endif
291 #endif
292 #ifdef BSDLY
293   {"bs1", output, SANE_UNSET, BS1, BSDLY},
294   {"bs0", output, SANE_SET, BS0, BSDLY},
295 #endif
296 #ifdef VTDLY
297   {"vt1", output, SANE_UNSET, VT1, VTDLY},
298   {"vt0", output, SANE_SET, VT0, VTDLY},
299 #endif
300 #ifdef FFDLY
301   {"ff1", output, SANE_UNSET, FF1, FFDLY},
302   {"ff0", output, SANE_SET, FF0, FFDLY},
303 #endif
304
305   {"isig", local, SANE_SET | REV, ISIG, 0},
306   {"icanon", local, SANE_SET | REV, ICANON, 0},
307 #ifdef IEXTEN
308   {"iexten", local, SANE_SET | REV, IEXTEN, 0},
309 #endif
310   {"echo", local, SANE_SET | REV, ECHO, 0},
311   {"echoe", local, SANE_SET | REV, ECHOE, 0},
312   {"crterase", local, REV | OMIT, ECHOE, 0},
313   {"echok", local, SANE_SET | REV, ECHOK, 0},
314   {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
315   {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
316 #ifdef XCASE
317   {"xcase", local, SANE_UNSET | REV, XCASE, 0},
318 #endif
319 #ifdef TOSTOP
320   {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
321 #endif
322 #ifdef ECHOPRT
323   {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
324   {"prterase", local, REV | OMIT, ECHOPRT, 0},
325 #endif
326 #ifdef ECHOCTL
327   {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
328   {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
329 #endif
330 #ifdef ECHOKE
331   {"echoke", local, SANE_SET | REV, ECHOKE, 0},
332   {"crtkill", local, REV | OMIT, ECHOKE, 0},
333 #endif
334
335   {"evenp", combination, REV | OMIT, 0, 0},
336   {"parity", combination, REV | OMIT, 0, 0},
337   {"oddp", combination, REV | OMIT, 0, 0},
338   {"nl", combination, REV | OMIT, 0, 0},
339   {"ek", combination, OMIT, 0, 0},
340   {"sane", combination, OMIT, 0, 0},
341   {"cooked", combination, REV | OMIT, 0, 0},
342   {"raw", combination, REV | OMIT, 0, 0},
343   {"pass8", combination, REV | OMIT, 0, 0},
344   {"litout", combination, REV | OMIT, 0, 0},
345   {"cbreak", combination, REV | OMIT, 0, 0},
346 #ifdef IXANY
347   {"decctlq", combination, REV | OMIT, 0, 0},
348 #endif
349 #if defined TABDLY || defined OXTABS
350   {"tabs", combination, REV | OMIT, 0, 0},
351 #endif
352 #if defined XCASE && defined IUCLC && defined OLCUC
353   {"lcase", combination, REV | OMIT, 0, 0},
354   {"LCASE", combination, REV | OMIT, 0, 0},
355 #endif
356   {"crt", combination, OMIT, 0, 0},
357   {"dec", combination, OMIT, 0, 0},
358
359   {NULL, control, 0, 0, 0}
360 };
361
362 /* Control character settings.  */
363 struct control_info
364   {
365     const char *name;           /* Name given on command line.  */
366     cc_t saneval;               /* Value to set for `stty sane'.  */
367     size_t offset;              /* Offset in c_cc.  */
368   };
369
370 /* Control characters. */
371
372 static struct control_info control_info[] =
373 {
374   {"intr", CINTR, VINTR},
375   {"quit", CQUIT, VQUIT},
376   {"erase", CERASE, VERASE},
377   {"kill", CKILL, VKILL},
378   {"eof", CEOF, VEOF},
379   {"eol", CEOL, VEOL},
380 #ifdef VEOL2
381   {"eol2", CEOL2, VEOL2},
382 #endif
383 #ifdef VSWTCH
384   {"swtch", CSWTCH, VSWTCH},
385 #endif
386   {"start", CSTART, VSTART},
387   {"stop", CSTOP, VSTOP},
388   {"susp", CSUSP, VSUSP},
389 #ifdef VDSUSP
390   {"dsusp", CDSUSP, VDSUSP},
391 #endif
392 #ifdef VREPRINT
393   {"rprnt", CRPRNT, VREPRINT},
394 #else
395 # ifdef CREPRINT /* HPUX 10.20 needs this */
396   {"rprnt", CRPRNT, CREPRINT},
397 # endif
398 #endif
399 #ifdef VWERASE
400   {"werase", CWERASE, VWERASE},
401 #endif
402 #ifdef VLNEXT
403   {"lnext", CLNEXT, VLNEXT},
404 #endif
405 #ifdef VFLUSHO
406   {"flush", CFLUSHO, VFLUSHO},
407 #endif
408 #ifdef VSTATUS
409   {"status", CSTATUS, VSTATUS},
410 #endif
411
412   /* These must be last because of the display routines. */
413   {"min", 1, VMIN},
414   {"time", 0, VTIME},
415   {NULL, 0, 0}
416 };
417
418 static char const *visible (cc_t ch);
419 static unsigned long int baud_to_value (speed_t speed);
420 static bool recover_mode (char const *arg, struct termios *mode);
421 static int screen_columns (void);
422 static bool set_mode (struct mode_info *info, bool reversed,
423                       struct termios *mode);
424 static unsigned long int integer_arg (const char *s, unsigned long int max);
425 static speed_t string_to_baud (const char *arg);
426 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
427 static void display_all (struct termios *mode, char const *device_name);
428 static void display_changed (struct termios *mode);
429 static void display_recoverable (struct termios *mode);
430 static void display_settings (enum output_type output_type,
431                               struct termios *mode,
432                               const char *device_name);
433 static void display_speed (struct termios *mode, bool fancy);
434 static void display_window_size (bool fancy, char const *device_name);
435 static void sane_mode (struct termios *mode);
436 static void set_control_char (struct control_info *info,
437                               const char *arg,
438                               struct termios *mode);
439 static void set_speed (enum speed_setting type, const char *arg,
440                        struct termios *mode);
441 static void set_window_size (int rows, int cols, char const *device_name);
442
443 /* The width of the screen, for output wrapping. */
444 static int max_col;
445
446 /* Current position, to know when to wrap. */
447 static int current_col;
448
449 static struct option longopts[] =
450 {
451   {"all", no_argument, NULL, 'a'},
452   {"save", no_argument, NULL, 'g'},
453   {"file", required_argument, NULL, 'F'},
454   {GETOPT_HELP_OPTION_DECL},
455   {GETOPT_VERSION_OPTION_DECL},
456   {NULL, 0, NULL, 0}
457 };
458
459 /* The name this program was run with. */
460 char *program_name;
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     fprintf (stderr, _("Try `%s --help' for more information.\n"),
507              program_name);
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 (even 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_bug_reporting_address ();
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   struct termios mode = { 0, };
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;
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   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       struct termios new_mode = { 0, };
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 *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 *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 *
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       if ((*bitsp & mask) == mode_info[i].bits)
1543         {
1544           if (mode_info[i].flags & SANE_UNSET)
1545             {
1546               wrapf ("%s", mode_info[i].name);
1547               empty_line = false;
1548             }
1549         }
1550       else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1551         {
1552           wrapf ("-%s", mode_info[i].name);
1553           empty_line = false;
1554         }
1555     }
1556   if (!empty_line)
1557     putchar ('\n');
1558   current_col = 0;
1559 }
1560
1561 static void
1562 display_all (struct termios *mode, char const *device_name)
1563 {
1564   int i;
1565   tcflag_t *bitsp;
1566   unsigned long mask;
1567   enum mode_type prev_type = control;
1568
1569   display_speed (mode, true);
1570 #ifdef TIOCGWINSZ
1571   display_window_size (true, device_name);
1572 #endif
1573 #ifdef HAVE_C_LINE
1574   wrapf ("line = %d;", mode->c_line);
1575 #endif
1576   putchar ('\n');
1577   current_col = 0;
1578
1579   for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1580     {
1581       /* If swtch is the same as susp, don't print both.  */
1582 #if VSWTCH == VSUSP
1583       if (STREQ (control_info[i].name, "swtch"))
1584         continue;
1585 #endif
1586       /* If eof uses the same slot as min, only print whichever applies.  */
1587 #if VEOF == VMIN
1588       if ((mode->c_lflag & ICANON) == 0
1589           && (STREQ (control_info[i].name, "eof")
1590               || STREQ (control_info[i].name, "eol")))
1591         continue;
1592 #endif
1593       wrapf ("%s = %s;", control_info[i].name,
1594              visible (mode->c_cc[control_info[i].offset]));
1595     }
1596 #if VEOF == VMIN
1597   if ((mode->c_lflag & ICANON) == 0)
1598 #endif
1599     wrapf ("min = %lu; time = %lu;",
1600            (unsigned long int) mode->c_cc[VMIN],
1601            (unsigned long int) mode->c_cc[VTIME]);
1602   if (current_col != 0)
1603     putchar ('\n');
1604   current_col = 0;
1605
1606   for (i = 0; mode_info[i].name != NULL; ++i)
1607     {
1608       if (mode_info[i].flags & OMIT)
1609         continue;
1610       if (mode_info[i].type != prev_type)
1611         {
1612           putchar ('\n');
1613           current_col = 0;
1614           prev_type = mode_info[i].type;
1615         }
1616
1617       bitsp = mode_type_flag (mode_info[i].type, mode);
1618       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1619       if ((*bitsp & mask) == mode_info[i].bits)
1620         wrapf ("%s", mode_info[i].name);
1621       else if (mode_info[i].flags & REV)
1622         wrapf ("-%s", mode_info[i].name);
1623     }
1624   putchar ('\n');
1625   current_col = 0;
1626 }
1627
1628 static void
1629 display_speed (struct termios *mode, bool fancy)
1630 {
1631   if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1632     wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1633            baud_to_value (cfgetospeed (mode)));
1634   else
1635     wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1636            baud_to_value (cfgetispeed (mode)),
1637            baud_to_value (cfgetospeed (mode)));
1638   if (!fancy)
1639     current_col = 0;
1640 }
1641
1642 static void
1643 display_recoverable (struct termios *mode)
1644 {
1645   size_t i;
1646
1647   printf ("%lx:%lx:%lx:%lx",
1648           (unsigned long int) mode->c_iflag,
1649           (unsigned long int) mode->c_oflag,
1650           (unsigned long int) mode->c_cflag,
1651           (unsigned long int) mode->c_lflag);
1652   for (i = 0; i < NCCS; ++i)
1653     printf (":%lx", (unsigned long int) mode->c_cc[i]);
1654   putchar ('\n');
1655 }
1656
1657 /* NOTE: identical to below, modulo use of tcflag_t */
1658 static int
1659 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1660                   char delim)
1661 {
1662   unsigned long ul;
1663   errno = 0;
1664   ul = strtoul (s, p, base);
1665   if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1666     return -1;
1667   *result = ul;
1668   return 0;
1669 }
1670
1671 /* NOTE: identical to above, modulo use of cc_t */
1672 static int
1673 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1674 {
1675   unsigned long ul;
1676   errno = 0;
1677   ul = strtoul (s, p, base);
1678   if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1679     return -1;
1680   *result = ul;
1681   return 0;
1682 }
1683
1684 /* Parse the output of display_recoverable.
1685    Return false if any part of it is invalid.  */
1686 static bool
1687 recover_mode (char const *arg, struct termios *mode)
1688 {
1689   tcflag_t flag[4];
1690   char const *s = arg;
1691   size_t i;
1692   for (i = 0; i < 4; i++)
1693     {
1694       char *p;
1695       if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1696         return false;
1697       s = p + 1;
1698     }
1699   mode->c_iflag = flag[0];
1700   mode->c_oflag = flag[1];
1701   mode->c_cflag = flag[2];
1702   mode->c_lflag = flag[3];
1703
1704   for (i = 0; i < NCCS; ++i)
1705     {
1706       char *p;
1707       char delim = i < NCCS - 1 ? ':' : '\0';
1708       if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1709         return false;
1710       s = p + 1;
1711     }
1712
1713   return true;
1714 }
1715
1716 struct speed_map
1717 {
1718   const char *string;           /* ASCII representation. */
1719   speed_t speed;                /* Internal form. */
1720   unsigned long int value;      /* Numeric value. */
1721 };
1722
1723 static struct speed_map speeds[] =
1724 {
1725   {"0", B0, 0},
1726   {"50", B50, 50},
1727   {"75", B75, 75},
1728   {"110", B110, 110},
1729   {"134", B134, 134},
1730   {"134.5", B134, 134},
1731   {"150", B150, 150},
1732   {"200", B200, 200},
1733   {"300", B300, 300},
1734   {"600", B600, 600},
1735   {"1200", B1200, 1200},
1736   {"1800", B1800, 1800},
1737   {"2400", B2400, 2400},
1738   {"4800", B4800, 4800},
1739   {"9600", B9600, 9600},
1740   {"19200", B19200, 19200},
1741   {"38400", B38400, 38400},
1742   {"exta", B19200, 19200},
1743   {"extb", B38400, 38400},
1744 #ifdef B57600
1745   {"57600", B57600, 57600},
1746 #endif
1747 #ifdef B115200
1748   {"115200", B115200, 115200},
1749 #endif
1750 #ifdef B230400
1751   {"230400", B230400, 230400},
1752 #endif
1753 #ifdef B460800
1754   {"460800", B460800, 460800},
1755 #endif
1756 #ifdef B500000
1757   {"500000", B500000, 500000},
1758 #endif
1759 #ifdef B576000
1760   {"576000", B576000, 576000},
1761 #endif
1762 #ifdef B921600
1763   {"921600", B921600, 921600},
1764 #endif
1765 #ifdef B1000000
1766   {"1000000", B1000000, 1000000},
1767 #endif
1768 #ifdef B1152000
1769   {"1152000", B1152000, 1152000},
1770 #endif
1771 #ifdef B1500000
1772   {"1500000", B1500000, 1500000},
1773 #endif
1774 #ifdef B2000000
1775   {"2000000", B2000000, 2000000},
1776 #endif
1777 #ifdef B2500000
1778   {"2500000", B2500000, 2500000},
1779 #endif
1780 #ifdef B3000000
1781   {"3000000", B3000000, 3000000},
1782 #endif
1783 #ifdef B3500000
1784   {"3500000", B3500000, 3500000},
1785 #endif
1786 #ifdef B4000000
1787   {"4000000", B4000000, 4000000},
1788 #endif
1789   {NULL, 0, 0}
1790 };
1791
1792 static speed_t
1793 string_to_baud (const char *arg)
1794 {
1795   int i;
1796
1797   for (i = 0; speeds[i].string != NULL; ++i)
1798     if (STREQ (arg, speeds[i].string))
1799       return speeds[i].speed;
1800   return (speed_t) -1;
1801 }
1802
1803 static unsigned long int
1804 baud_to_value (speed_t speed)
1805 {
1806   int i;
1807
1808   for (i = 0; speeds[i].string != NULL; ++i)
1809     if (speed == speeds[i].speed)
1810       return speeds[i].value;
1811   return 0;
1812 }
1813
1814 static void
1815 sane_mode (struct termios *mode)
1816 {
1817   int i;
1818   tcflag_t *bitsp;
1819
1820   for (i = 0; control_info[i].name; ++i)
1821     {
1822 #if VMIN == VEOF
1823       if (STREQ (control_info[i].name, "min"))
1824         break;
1825 #endif
1826       mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1827     }
1828
1829   for (i = 0; mode_info[i].name != NULL; ++i)
1830     {
1831       if (mode_info[i].flags & SANE_SET)
1832         {
1833           bitsp = mode_type_flag (mode_info[i].type, mode);
1834           *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1835         }
1836       else if (mode_info[i].flags & SANE_UNSET)
1837         {
1838           bitsp = mode_type_flag (mode_info[i].type, mode);
1839           *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1840         }
1841     }
1842 }
1843
1844 /* Return a string that is the printable representation of character CH.  */
1845 /* Adapted from `cat' by Torbjorn Granlund.  */
1846
1847 static const char *
1848 visible (cc_t ch)
1849 {
1850   static char buf[10];
1851   char *bpout = buf;
1852
1853   if (ch == _POSIX_VDISABLE)
1854     return "<undef>";
1855
1856   if (ch >= 32)
1857     {
1858       if (ch < 127)
1859         *bpout++ = ch;
1860       else if (ch == 127)
1861         {
1862           *bpout++ = '^';
1863           *bpout++ = '?';
1864         }
1865       else
1866         {
1867           *bpout++ = 'M',
1868             *bpout++ = '-';
1869           if (ch >= 128 + 32)
1870             {
1871               if (ch < 128 + 127)
1872                 *bpout++ = ch - 128;
1873               else
1874                 {
1875                   *bpout++ = '^';
1876                   *bpout++ = '?';
1877                 }
1878             }
1879           else
1880             {
1881               *bpout++ = '^';
1882               *bpout++ = ch - 128 + 64;
1883             }
1884         }
1885     }
1886   else
1887     {
1888       *bpout++ = '^';
1889       *bpout++ = ch + 64;
1890     }
1891   *bpout = '\0';
1892   return (const char *) buf;
1893 }
1894
1895 /* Parse string S as an integer, using decimal radix by default,
1896    but allowing octal and hex numbers as in C.  Reject values
1897    larger than MAXVAL.  */
1898
1899 static unsigned long int
1900 integer_arg (const char *s, unsigned long int maxval)
1901 {
1902   unsigned long int value;
1903   if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK
1904       || maxval < value)
1905     {
1906       error (0, 0, _("invalid integer argument %s"), quote (s));
1907       usage (EXIT_FAILURE);
1908     }
1909   return value;
1910 }