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