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