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