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