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