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