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