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