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