*** empty log message ***
[platform/upstream/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   struct termios mode;
733   enum output_type output_type;
734   int optc;
735   int argi = 0;
736   int opti = 1;
737   bool require_set_attr;
738   bool speed_was_set;
739   bool verbose_output;
740   bool recoverable_output;
741   int k;
742   bool noargs = true;
743   char *file_name = NULL;
744   const char *device_name;
745
746   initialize_main (&argc, &argv);
747   program_name = argv[0];
748   setlocale (LC_ALL, "");
749   bindtextdomain (PACKAGE, LOCALEDIR);
750   textdomain (PACKAGE);
751
752   atexit (close_stdout);
753
754   output_type = changed;
755   verbose_output = false;
756   recoverable_output = false;
757
758   /* Don't print error messages for unrecognized options.  */
759   opterr = 0;
760
761   /* If any new options are ever added to stty, the short options MUST
762      NOT allow any ambiguity with the stty settings.  For example, the
763      stty setting "-gagFork" would not be feasible, since it will be
764      parsed as "-g -a -g -F ork".  If you change anything about how
765      stty parses options, be sure it still works with combinations of
766      short and long options, --, POSIXLY_CORRECT, etc.  */
767
768   while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
769                               longopts, NULL))
770          != -1)
771     {
772       switch (optc)
773         {
774         case 'a':
775           verbose_output = true;
776           output_type = all;
777           break;
778
779         case 'g':
780           recoverable_output = true;
781           output_type = recoverable;
782           break;
783
784         case 'F':
785           if (file_name)
786             error (EXIT_FAILURE, 0, _("only one device may be specified"));
787           file_name = optarg;
788           break;
789
790         case_GETOPT_HELP_CHAR;
791
792         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
793
794         default:
795           noargs = false;
796
797           /* Skip the argument containing this unrecognized option;
798              the 2nd pass will analyze it.  */
799           argi += opti;
800
801           /* Restart getopt_long from the first unskipped argument.  */
802           opti = 1;
803           optind = 0;
804
805           break;
806         }
807
808       /* Clear fully-parsed arguments, so they don't confuse the 2nd pass.  */
809       while (opti < optind)
810         argv[argi + opti++] = NULL;
811     }
812
813   /* Specifying both -a and -g gets an error.  */
814   if (verbose_output & recoverable_output)
815     error (EXIT_FAILURE, 0,
816            _("the options for verbose and stty-readable output styles are\n"
817              "mutually exclusive"));
818
819   /* Specifying any other arguments with -a or -g gets an error.  */
820   if (!noargs & (verbose_output | recoverable_output))
821     error (EXIT_FAILURE, 0,
822            _("when specifying an output style, modes may not be set"));
823
824   /* FIXME: it'd be better not to open the file until we've verified
825      that all arguments are valid.  Otherwise, we could end up doing
826      only some of the requested operations and then failing, probably
827      leaving things in an undesirable state.  */
828
829   if (file_name)
830     {
831       int fdflags;
832       device_name = file_name;
833       if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
834         error (EXIT_FAILURE, errno, "%s", device_name);
835       if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
836           || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
837         error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
838                device_name);
839     }
840   else
841     device_name = _("standard input");
842
843   /* Initialize to all zeroes so there is no risk memcmp will report a
844      spurious difference in an uninitialized portion of the structure.  */
845   memset (&mode, 0, sizeof (mode));
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       struct termios new_mode;
1006
1007       if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1008         error (EXIT_FAILURE, errno, "%s", device_name);
1009
1010       /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1011          it performs *any* of the requested operations.  This means it
1012          can report `success' when it has actually failed to perform
1013          some proper subset of the requested operations.  To detect
1014          this partial failure, get the current terminal attributes and
1015          compare them to the requested ones.  */
1016
1017       /* Initialize to all zeroes so there is no risk memcmp will report a
1018          spurious difference in an uninitialized portion of the structure.  */
1019       memset (&new_mode, 0, sizeof (new_mode));
1020       if (tcgetattr (STDIN_FILENO, &new_mode))
1021         error (EXIT_FAILURE, errno, "%s", device_name);
1022
1023       /* Normally, one shouldn't use memcmp to compare structures that
1024          may have `holes' containing uninitialized data, but we have been
1025          careful to initialize the storage of these two variables to all
1026          zeroes.  One might think it more efficient simply to compare the
1027          modified fields, but that would require enumerating those fields --
1028          and not all systems have the same fields in this structure.  */
1029
1030       if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1031         {
1032 #ifdef CIBAUD
1033           /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1034              tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1035              sometimes (m1 != m2).  The only difference is in the four bits
1036              of the c_cflag field corresponding to the baud rate.  To save
1037              Sun users a little confusion, don't report an error if this
1038              happens.  But suppress the error only if we haven't tried to
1039              set the baud rate explicitly -- otherwise we'd never give an
1040              error for a true failure to set the baud rate.  */
1041
1042           new_mode.c_cflag &= (~CIBAUD);
1043           if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1044 #endif
1045             {
1046               error (EXIT_FAILURE, 0,
1047                      _("%s: unable to perform all requested operations"),
1048                      device_name);
1049 #ifdef TESTING
1050               {
1051                 size_t i;
1052                 printf (_("new_mode: mode\n"));
1053                 for (i = 0; i < sizeof (new_mode); i++)
1054                   printf ("0x%02x: 0x%02x\n",
1055                           *(((unsigned char *) &new_mode) + i),
1056                           *(((unsigned char *) &mode) + i));
1057               }
1058 #endif
1059             }
1060         }
1061     }
1062
1063   exit (EXIT_SUCCESS);
1064 }
1065
1066 /* Return false if not applied because not reversible; otherwise
1067    return true.  */
1068
1069 static bool
1070 set_mode (struct mode_info *info, bool reversed, struct termios *mode)
1071 {
1072   tcflag_t *bitsp;
1073
1074   if (reversed && (info->flags & REV) == 0)
1075     return false;
1076
1077   bitsp = mode_type_flag (info->type, mode);
1078
1079   if (bitsp == NULL)
1080     {
1081       /* Combination mode. */
1082       if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1083         {
1084           if (reversed)
1085             mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1086           else
1087             mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1088         }
1089       else if (STREQ (info->name, "oddp"))
1090         {
1091           if (reversed)
1092             mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1093           else
1094             mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1095         }
1096       else if (STREQ (info->name, "nl"))
1097         {
1098           if (reversed)
1099             {
1100               mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1101               mode->c_oflag = (mode->c_oflag
1102 #ifdef ONLCR
1103                                | ONLCR
1104 #endif
1105                 )
1106 #ifdef OCRNL
1107                 & ~OCRNL
1108 #endif
1109 #ifdef ONLRET
1110                 & ~ONLRET
1111 #endif
1112                 ;
1113             }
1114           else
1115             {
1116               mode->c_iflag = mode->c_iflag & ~ICRNL;
1117 #ifdef ONLCR
1118               mode->c_oflag = mode->c_oflag & ~ONLCR;
1119 #endif
1120             }
1121         }
1122       else if (STREQ (info->name, "ek"))
1123         {
1124           mode->c_cc[VERASE] = CERASE;
1125           mode->c_cc[VKILL] = CKILL;
1126         }
1127       else if (STREQ (info->name, "sane"))
1128         sane_mode (mode);
1129       else if (STREQ (info->name, "cbreak"))
1130         {
1131           if (reversed)
1132             mode->c_lflag |= ICANON;
1133           else
1134             mode->c_lflag &= ~ICANON;
1135         }
1136       else if (STREQ (info->name, "pass8"))
1137         {
1138           if (reversed)
1139             {
1140               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1141               mode->c_iflag |= ISTRIP;
1142             }
1143           else
1144             {
1145               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1146               mode->c_iflag &= ~ISTRIP;
1147             }
1148         }
1149       else if (STREQ (info->name, "litout"))
1150         {
1151           if (reversed)
1152             {
1153               mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1154               mode->c_iflag |= ISTRIP;
1155               mode->c_oflag |= OPOST;
1156             }
1157           else
1158             {
1159               mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1160               mode->c_iflag &= ~ISTRIP;
1161               mode->c_oflag &= ~OPOST;
1162             }
1163         }
1164       else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1165         {
1166           if ((info->name[0] == 'r' && reversed)
1167               || (info->name[0] == 'c' && !reversed))
1168             {
1169               /* Cooked mode. */
1170               mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1171               mode->c_oflag |= OPOST;
1172               mode->c_lflag |= ISIG | ICANON;
1173 #if VMIN == VEOF
1174               mode->c_cc[VEOF] = CEOF;
1175 #endif
1176 #if VTIME == VEOL
1177               mode->c_cc[VEOL] = CEOL;
1178 #endif
1179             }
1180           else
1181             {
1182               /* Raw mode. */
1183               mode->c_iflag = 0;
1184               mode->c_oflag &= ~OPOST;
1185               mode->c_lflag &= ~(ISIG | ICANON
1186 #ifdef XCASE
1187                                  | XCASE
1188 #endif
1189                 );
1190               mode->c_cc[VMIN] = 1;
1191               mode->c_cc[VTIME] = 0;
1192             }
1193         }
1194 #ifdef IXANY
1195       else if (STREQ (info->name, "decctlq"))
1196         {
1197           if (reversed)
1198             mode->c_iflag |= IXANY;
1199           else
1200             mode->c_iflag &= ~IXANY;
1201         }
1202 #endif
1203 #ifdef TABDLY
1204       else if (STREQ (info->name, "tabs"))
1205         {
1206           if (reversed)
1207             mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1208           else
1209             mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1210         }
1211 #else
1212 # ifdef OXTABS
1213       else if (STREQ (info->name, "tabs"))
1214         {
1215           if (reversed)
1216             mode->c_oflag = mode->c_oflag | OXTABS;
1217           else
1218             mode->c_oflag = mode->c_oflag & ~OXTABS;
1219         }
1220 # endif
1221 #endif
1222 #if defined XCASE && defined IUCLC && defined OLCUC
1223       else if (STREQ (info->name, "lcase")
1224                || STREQ (info->name, "LCASE"))
1225         {
1226           if (reversed)
1227             {
1228               mode->c_lflag &= ~XCASE;
1229               mode->c_iflag &= ~IUCLC;
1230               mode->c_oflag &= ~OLCUC;
1231             }
1232           else
1233             {
1234               mode->c_lflag |= XCASE;
1235               mode->c_iflag |= IUCLC;
1236               mode->c_oflag |= OLCUC;
1237             }
1238         }
1239 #endif
1240       else if (STREQ (info->name, "crt"))
1241         mode->c_lflag |= ECHOE
1242 #ifdef ECHOCTL
1243           | ECHOCTL
1244 #endif
1245 #ifdef ECHOKE
1246           | ECHOKE
1247 #endif
1248           ;
1249       else if (STREQ (info->name, "dec"))
1250         {
1251           mode->c_cc[VINTR] = 3;        /* ^C */
1252           mode->c_cc[VERASE] = 127;     /* DEL */
1253           mode->c_cc[VKILL] = 21;       /* ^U */
1254           mode->c_lflag |= ECHOE
1255 #ifdef ECHOCTL
1256             | ECHOCTL
1257 #endif
1258 #ifdef ECHOKE
1259             | ECHOKE
1260 #endif
1261             ;
1262 #ifdef IXANY
1263           mode->c_iflag &= ~IXANY;
1264 #endif
1265         }
1266     }
1267   else if (reversed)
1268     *bitsp = *bitsp & ~info->mask & ~info->bits;
1269   else
1270     *bitsp = (*bitsp & ~info->mask) | info->bits;
1271
1272   return true;
1273 }
1274
1275 static void
1276 set_control_char (struct control_info *info, const char *arg,
1277                   struct termios *mode)
1278 {
1279   unsigned long int value;
1280
1281   if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1282     value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1283   else if (arg[0] == '\0' || arg[1] == '\0')
1284     value = to_uchar (arg[0]);
1285   else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1286     value = _POSIX_VDISABLE;
1287   else if (arg[0] == '^' && arg[1] != '\0')     /* Ignore any trailing junk. */
1288     {
1289       if (arg[1] == '?')
1290         value = 127;
1291       else
1292         value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1293     }
1294   else
1295     value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1296   mode->c_cc[info->offset] = value;
1297 }
1298
1299 static void
1300 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1301 {
1302   speed_t baud;
1303
1304   baud = string_to_baud (arg);
1305   if (type == input_speed || type == both_speeds)
1306     cfsetispeed (mode, baud);
1307   if (type == output_speed || type == both_speeds)
1308     cfsetospeed (mode, baud);
1309 }
1310
1311 #ifdef TIOCGWINSZ
1312
1313 static int
1314 get_win_size (int fd, struct winsize *win)
1315 {
1316   int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1317   return err;
1318 }
1319
1320 static void
1321 set_window_size (int rows, int cols, char const *device_name)
1322 {
1323   struct winsize win;
1324
1325   if (get_win_size (STDIN_FILENO, &win))
1326     {
1327       if (errno != EINVAL)
1328         error (EXIT_FAILURE, errno, "%s", device_name);
1329       memset (&win, 0, sizeof (win));
1330     }
1331
1332   if (rows >= 0)
1333     win.ws_row = rows;
1334   if (cols >= 0)
1335     win.ws_col = cols;
1336
1337 # ifdef TIOCSSIZE
1338   /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1339      The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1340      This comment from sys/ttold.h describes Sun's twisted logic - a better
1341      test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1342      At any rate, the problem is gone in Solaris 2.x.
1343
1344      Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1345      but they can be disambiguated by checking whether a "struct ttysize"
1346      structure's "ts_lines" field is greater than 64K or not.  If so,
1347      it's almost certainly a "struct winsize" instead.
1348
1349      At any rate, the bug manifests itself when ws_row == 0; the symptom is
1350      that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1351      ws_ypixel.  Since GNU stty sets rows and columns separately, this bug
1352      caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1353      "stty cols 0 rows 0" would do the right thing.  On a little-endian
1354      machine like the sun386i, the problem is the same, but for ws_col == 0.
1355
1356      The workaround is to do the ioctl once with row and col = 1 to set the
1357      pixel info, and then do it again using a TIOCSSIZE to set rows/cols.  */
1358
1359   if (win.ws_row == 0 || win.ws_col == 0)
1360     {
1361       struct ttysize ttysz;
1362
1363       ttysz.ts_lines = win.ws_row;
1364       ttysz.ts_cols = win.ws_col;
1365
1366       win.ws_row = 1;
1367       win.ws_col = 1;
1368
1369       if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1370         error (EXIT_FAILURE, errno, "%s", device_name);
1371
1372       if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1373         error (EXIT_FAILURE, errno, "%s", device_name);
1374       return;
1375     }
1376 # endif
1377
1378   if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1379     error (EXIT_FAILURE, errno, "%s", device_name);
1380 }
1381
1382 static void
1383 display_window_size (bool fancy, char const *device_name)
1384 {
1385   struct winsize win;
1386
1387   if (get_win_size (STDIN_FILENO, &win))
1388     {
1389       if (errno != EINVAL)
1390         error (EXIT_FAILURE, errno, "%s", device_name);
1391       if (!fancy)
1392         error (EXIT_FAILURE, 0,
1393                _("%s: no size information for this device"), device_name);
1394     }
1395   else
1396     {
1397       wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1398              win.ws_row, win.ws_col);
1399       if (!fancy)
1400         current_col = 0;
1401     }
1402 }
1403 #endif
1404
1405 static int
1406 screen_columns (void)
1407 {
1408 #ifdef TIOCGWINSZ
1409   struct winsize win;
1410
1411   /* With Solaris 2.[123], this ioctl fails and errno is set to
1412      EINVAL for telnet (but not rlogin) sessions.
1413      On ISC 3.0, it fails for the console and the serial port
1414      (but it works for ptys).
1415      It can also fail on any system when stdout isn't a tty.
1416      In case of any failure, just use the default.  */
1417   if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1418     return win.ws_col;
1419 #endif
1420   {
1421     /* Use $COLUMNS if it's in [1..INT_MAX].  */
1422     char *col_string = getenv ("COLUMNS");
1423     long int n_columns;
1424     if (!(col_string != NULL
1425           && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1426           && 0 < n_columns
1427           && n_columns <= INT_MAX))
1428       n_columns = 80;
1429     return n_columns;
1430   }
1431 }
1432
1433 static tcflag_t *
1434 mode_type_flag (enum mode_type type, struct termios *mode)
1435 {
1436   switch (type)
1437     {
1438     case control:
1439       return &mode->c_cflag;
1440
1441     case input:
1442       return &mode->c_iflag;
1443
1444     case output:
1445       return &mode->c_oflag;
1446
1447     case local:
1448       return &mode->c_lflag;
1449
1450     case combination:
1451       return NULL;
1452
1453     default:
1454       abort ();
1455     }
1456 }
1457
1458 static void
1459 display_settings (enum output_type output_type, struct termios *mode,
1460                   char const *device_name)
1461 {
1462   switch (output_type)
1463     {
1464     case changed:
1465       display_changed (mode);
1466       break;
1467
1468     case all:
1469       display_all (mode, device_name);
1470       break;
1471
1472     case recoverable:
1473       display_recoverable (mode);
1474       break;
1475     }
1476 }
1477
1478 static void
1479 display_changed (struct termios *mode)
1480 {
1481   int i;
1482   bool empty_line;
1483   tcflag_t *bitsp;
1484   unsigned long mask;
1485   enum mode_type prev_type = control;
1486
1487   display_speed (mode, true);
1488 #ifdef HAVE_C_LINE
1489   wrapf ("line = %d;", mode->c_line);
1490 #endif
1491   putchar ('\n');
1492   current_col = 0;
1493
1494   empty_line = true;
1495   for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1496     {
1497       if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1498         continue;
1499       /* If swtch is the same as susp, don't print both.  */
1500 #if VSWTCH == VSUSP
1501       if (STREQ (control_info[i].name, "swtch"))
1502         continue;
1503 #endif
1504       /* If eof uses the same slot as min, only print whichever applies.  */
1505 #if VEOF == VMIN
1506       if ((mode->c_lflag & ICANON) == 0
1507           && (STREQ (control_info[i].name, "eof")
1508               || STREQ (control_info[i].name, "eol")))
1509         continue;
1510 #endif
1511
1512       empty_line = false;
1513       wrapf ("%s = %s;", control_info[i].name,
1514              visible (mode->c_cc[control_info[i].offset]));
1515     }
1516   if ((mode->c_lflag & ICANON) == 0)
1517     {
1518       wrapf ("min = %lu; time = %lu;\n",
1519              (unsigned long int) mode->c_cc[VMIN],
1520              (unsigned long int) mode->c_cc[VTIME]);
1521     }
1522   else if (!empty_line)
1523     putchar ('\n');
1524   current_col = 0;
1525
1526   empty_line = true;
1527   for (i = 0; mode_info[i].name != NULL; ++i)
1528     {
1529       if (mode_info[i].flags & OMIT)
1530         continue;
1531       if (mode_info[i].type != prev_type)
1532         {
1533           if (!empty_line)
1534             {
1535               putchar ('\n');
1536               current_col = 0;
1537               empty_line = true;
1538             }
1539           prev_type = mode_info[i].type;
1540         }
1541
1542       bitsp = mode_type_flag (mode_info[i].type, mode);
1543       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1544       if ((*bitsp & mask) == mode_info[i].bits)
1545         {
1546           if (mode_info[i].flags & SANE_UNSET)
1547             {
1548               wrapf ("%s", mode_info[i].name);
1549               empty_line = false;
1550             }
1551         }
1552       else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1553         {
1554           wrapf ("-%s", mode_info[i].name);
1555           empty_line = false;
1556         }
1557     }
1558   if (!empty_line)
1559     putchar ('\n');
1560   current_col = 0;
1561 }
1562
1563 static void
1564 display_all (struct termios *mode, char const *device_name)
1565 {
1566   int i;
1567   tcflag_t *bitsp;
1568   unsigned long mask;
1569   enum mode_type prev_type = control;
1570
1571   display_speed (mode, true);
1572 #ifdef TIOCGWINSZ
1573   display_window_size (true, device_name);
1574 #endif
1575 #ifdef HAVE_C_LINE
1576   wrapf ("line = %d;", mode->c_line);
1577 #endif
1578   putchar ('\n');
1579   current_col = 0;
1580
1581   for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1582     {
1583       /* If swtch is the same as susp, don't print both.  */
1584 #if VSWTCH == VSUSP
1585       if (STREQ (control_info[i].name, "swtch"))
1586         continue;
1587 #endif
1588       /* If eof uses the same slot as min, only print whichever applies.  */
1589 #if VEOF == VMIN
1590       if ((mode->c_lflag & ICANON) == 0
1591           && (STREQ (control_info[i].name, "eof")
1592               || STREQ (control_info[i].name, "eol")))
1593         continue;
1594 #endif
1595       wrapf ("%s = %s;", control_info[i].name,
1596              visible (mode->c_cc[control_info[i].offset]));
1597     }
1598 #if VEOF == VMIN
1599   if ((mode->c_lflag & ICANON) == 0)
1600 #endif
1601     wrapf ("min = %lu; time = %lu;",
1602            (unsigned long int) mode->c_cc[VMIN],
1603            (unsigned long int) mode->c_cc[VTIME]);
1604   if (current_col != 0)
1605     putchar ('\n');
1606   current_col = 0;
1607
1608   for (i = 0; mode_info[i].name != NULL; ++i)
1609     {
1610       if (mode_info[i].flags & OMIT)
1611         continue;
1612       if (mode_info[i].type != prev_type)
1613         {
1614           putchar ('\n');
1615           current_col = 0;
1616           prev_type = mode_info[i].type;
1617         }
1618
1619       bitsp = mode_type_flag (mode_info[i].type, mode);
1620       mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1621       if ((*bitsp & mask) == mode_info[i].bits)
1622         wrapf ("%s", mode_info[i].name);
1623       else if (mode_info[i].flags & REV)
1624         wrapf ("-%s", mode_info[i].name);
1625     }
1626   putchar ('\n');
1627   current_col = 0;
1628 }
1629
1630 static void
1631 display_speed (struct termios *mode, bool fancy)
1632 {
1633   if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1634     wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1635            baud_to_value (cfgetospeed (mode)));
1636   else
1637     wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1638            baud_to_value (cfgetispeed (mode)),
1639            baud_to_value (cfgetospeed (mode)));
1640   if (!fancy)
1641     current_col = 0;
1642 }
1643
1644 static void
1645 display_recoverable (struct termios *mode)
1646 {
1647   size_t i;
1648
1649   printf ("%lx:%lx:%lx:%lx",
1650           (unsigned long int) mode->c_iflag,
1651           (unsigned long int) mode->c_oflag,
1652           (unsigned long int) mode->c_cflag,
1653           (unsigned long int) mode->c_lflag);
1654   for (i = 0; i < NCCS; ++i)
1655     printf (":%lx", (unsigned long int) mode->c_cc[i]);
1656   putchar ('\n');
1657 }
1658
1659 static bool
1660 recover_mode (char const *arg, struct termios *mode)
1661 {
1662   size_t i;
1663   int n;
1664   unsigned long int chr;
1665   unsigned long int iflag, oflag, cflag, lflag;
1666
1667   /* Scan into temporaries since it is too much trouble to figure out
1668      the right format for `tcflag_t'.  */
1669   if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1670               &iflag, &oflag, &cflag, &lflag, &n) != 4)
1671     return false;
1672   mode->c_iflag = iflag;
1673   mode->c_oflag = oflag;
1674   mode->c_cflag = cflag;
1675   mode->c_lflag = lflag;
1676   if (mode->c_iflag != iflag
1677       || mode->c_oflag != oflag
1678       || mode->c_cflag != cflag
1679       || mode->c_lflag != lflag)
1680     return false;
1681   arg += n;
1682   for (i = 0; i < NCCS; ++i)
1683     {
1684       if (sscanf (arg, ":%lx%n", &chr, &n) != 1)
1685         return false;
1686       mode->c_cc[i] = chr;
1687       if (mode->c_cc[i] != chr)
1688         return false;
1689       arg += n;
1690     }
1691
1692   /* Fail if there are too many fields.  */
1693   if (*arg != '\0')
1694     return false;
1695
1696   return true;
1697 }
1698
1699 struct speed_map
1700 {
1701   const char *string;           /* ASCII representation. */
1702   speed_t speed;                /* Internal form. */
1703   unsigned long int value;      /* Numeric value. */
1704 };
1705
1706 static struct speed_map speeds[] =
1707 {
1708   {"0", B0, 0},
1709   {"50", B50, 50},
1710   {"75", B75, 75},
1711   {"110", B110, 110},
1712   {"134", B134, 134},
1713   {"134.5", B134, 134},
1714   {"150", B150, 150},
1715   {"200", B200, 200},
1716   {"300", B300, 300},
1717   {"600", B600, 600},
1718   {"1200", B1200, 1200},
1719   {"1800", B1800, 1800},
1720   {"2400", B2400, 2400},
1721   {"4800", B4800, 4800},
1722   {"9600", B9600, 9600},
1723   {"19200", B19200, 19200},
1724   {"38400", B38400, 38400},
1725   {"exta", B19200, 19200},
1726   {"extb", B38400, 38400},
1727 #ifdef B57600
1728   {"57600", B57600, 57600},
1729 #endif
1730 #ifdef B115200
1731   {"115200", B115200, 115200},
1732 #endif
1733 #ifdef B230400
1734   {"230400", B230400, 230400},
1735 #endif
1736 #ifdef B460800
1737   {"460800", B460800, 460800},
1738 #endif
1739 #ifdef B500000
1740   {"500000", B500000, 500000},
1741 #endif
1742 #ifdef B576000
1743   {"576000", B576000, 576000},
1744 #endif
1745 #ifdef B921600
1746   {"921600", B921600, 921600},
1747 #endif
1748 #ifdef B1000000
1749   {"1000000", B1000000, 1000000},
1750 #endif
1751 #ifdef B1152000
1752   {"1152000", B1152000, 1152000},
1753 #endif
1754 #ifdef B1500000
1755   {"1500000", B1500000, 1500000},
1756 #endif
1757 #ifdef B2000000
1758   {"2000000", B2000000, 2000000},
1759 #endif
1760 #ifdef B2500000
1761   {"2500000", B2500000, 2500000},
1762 #endif
1763 #ifdef B3000000
1764   {"3000000", B3000000, 3000000},
1765 #endif
1766 #ifdef B3500000
1767   {"3500000", B3500000, 3500000},
1768 #endif
1769 #ifdef B4000000
1770   {"4000000", B4000000, 4000000},
1771 #endif
1772   {NULL, 0, 0}
1773 };
1774
1775 static speed_t
1776 string_to_baud (const char *arg)
1777 {
1778   int i;
1779
1780   for (i = 0; speeds[i].string != NULL; ++i)
1781     if (STREQ (arg, speeds[i].string))
1782       return speeds[i].speed;
1783   return (speed_t) -1;
1784 }
1785
1786 static unsigned long int
1787 baud_to_value (speed_t speed)
1788 {
1789   int i;
1790
1791   for (i = 0; speeds[i].string != NULL; ++i)
1792     if (speed == speeds[i].speed)
1793       return speeds[i].value;
1794   return 0;
1795 }
1796
1797 static void
1798 sane_mode (struct termios *mode)
1799 {
1800   int i;
1801   tcflag_t *bitsp;
1802
1803   for (i = 0; control_info[i].name; ++i)
1804     {
1805 #if VMIN == VEOF
1806       if (STREQ (control_info[i].name, "min"))
1807         break;
1808 #endif
1809       mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1810     }
1811
1812   for (i = 0; mode_info[i].name != NULL; ++i)
1813     {
1814       if (mode_info[i].flags & SANE_SET)
1815         {
1816           bitsp = mode_type_flag (mode_info[i].type, mode);
1817           *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1818         }
1819       else if (mode_info[i].flags & SANE_UNSET)
1820         {
1821           bitsp = mode_type_flag (mode_info[i].type, mode);
1822           *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1823         }
1824     }
1825 }
1826
1827 /* Return a string that is the printable representation of character CH.  */
1828 /* Adapted from `cat' by Torbjorn Granlund.  */
1829
1830 static const char *
1831 visible (cc_t ch)
1832 {
1833   static char buf[10];
1834   char *bpout = buf;
1835
1836   if (ch == _POSIX_VDISABLE)
1837     return "<undef>";
1838
1839   if (ch >= 32)
1840     {
1841       if (ch < 127)
1842         *bpout++ = ch;
1843       else if (ch == 127)
1844         {
1845           *bpout++ = '^';
1846           *bpout++ = '?';
1847         }
1848       else
1849         {
1850           *bpout++ = 'M',
1851             *bpout++ = '-';
1852           if (ch >= 128 + 32)
1853             {
1854               if (ch < 128 + 127)
1855                 *bpout++ = ch - 128;
1856               else
1857                 {
1858                   *bpout++ = '^';
1859                   *bpout++ = '?';
1860                 }
1861             }
1862           else
1863             {
1864               *bpout++ = '^';
1865               *bpout++ = ch - 128 + 64;
1866             }
1867         }
1868     }
1869   else
1870     {
1871       *bpout++ = '^';
1872       *bpout++ = ch + 64;
1873     }
1874   *bpout = '\0';
1875   return (const char *) buf;
1876 }
1877
1878 /* Parse string S as an integer, using decimal radix by default,
1879    but allowing octal and hex numbers as in C.  Reject values
1880    larger than MAXVAL.  */
1881
1882 static unsigned long int
1883 integer_arg (const char *s, unsigned long int maxval)
1884 {
1885   unsigned long int value;
1886   if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK
1887       || maxval < value)
1888     {
1889       error (0, 0, _("invalid integer argument %s"), quote (s));
1890       usage (EXIT_FAILURE);
1891     }
1892   return value;
1893 }