1 /* vi: set sw=4 ts=4: */
2 /* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
14 /* Usage: stty [-ag] [-F device] [setting...]
17 -a Write all current settings to stdout in human-readable form.
18 -g Write all current settings to stdout in stty-readable form.
19 -F Open and use the specified device instead of stdin
21 If no args are given, write to stdout the baud rate and settings that
22 have been changed from their defaults. Mode reading and changes
23 are done on the specified device, or stdin if none was specified.
25 David MacKenzie <djm@gnu.ai.mit.edu>
27 Special for busybox ported by vodz@usa.net 2001
33 #include <sys/ioctl.h>
36 #include <sys/param.h>
40 # define STDIN_FILENO 0
44 # define STDOUT_FILENO 1
57 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
60 #ifndef _POSIX_VDISABLE
61 # define _POSIX_VDISABLE ((unsigned char) 0)
64 #define Control(c) ((c) & 0x1f)
65 /* Canonical values for control characters. */
67 # define CINTR Control ('c')
76 # define CKILL Control ('u')
79 # define CEOF Control ('d')
82 # define CEOL _POSIX_VDISABLE
85 # define CSTART Control ('q')
88 # define CSTOP Control ('s')
91 # define CSUSP Control ('z')
93 #if defined(VEOL2) && !defined(CEOL2)
94 # define CEOL2 _POSIX_VDISABLE
96 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
97 #if defined(VSUSP) && !defined(VSWTCH)
101 #if defined(VSWTCH) && !defined(CSWTCH)
102 # define CSWTCH _POSIX_VDISABLE
105 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
106 So the default is to disable `swtch.' */
107 #if defined (__sparc__) && defined (__svr4__)
109 # define CSWTCH _POSIX_VDISABLE
112 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
113 # define VWERASE VWERSE
115 #if defined(VDSUSP) && !defined (CDSUSP)
116 # define CDSUSP Control ('y')
118 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
119 # define VREPRINT VRPRNT
121 #if defined(VREPRINT) && !defined(CRPRNT)
122 # define CRPRNT Control ('r')
124 #if defined(VWERASE) && !defined(CWERASE)
125 # define CWERASE Control ('w')
127 #if defined(VLNEXT) && !defined(CLNEXT)
128 # define CLNEXT Control ('v')
130 #if defined(VDISCARD) && !defined(VFLUSHO)
131 # define VFLUSHO VDISCARD
133 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
134 # define VFLUSHO VFLUSH
136 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
137 # define ECHOCTL CTLECH
139 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
140 # define ECHOCTL TCTLECH
142 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
143 # define ECHOKE CRTKIL
145 #if defined(VFLUSHO) && !defined(CFLUSHO)
146 # define CFLUSHO Control ('o')
148 #if defined(VSTATUS) && !defined(CSTATUS)
149 # define CSTATUS Control ('t')
152 /* Which speeds to set. */
154 input_speed, output_speed, both_speeds
157 /* What to output and how. */
159 changed, all, recoverable /* Default, -a, -g. */
162 /* Which member(s) of `struct termios' a mode uses. */
164 control, input, output, local, combination
168 static const char evenp[] = "evenp";
169 static const char raw[] = "raw";
170 static const char stty_min[] = "min";
171 static const char stty_time[] = "time";
172 static const char stty_swtch[] = "swtch";
173 static const char stty_eol[] = "eol";
174 static const char stty_eof[] = "eof";
175 static const char parity[] = "parity";
176 static const char stty_oddp[] = "oddp";
177 static const char stty_nl[] = "nl";
178 static const char stty_ek[] = "ek";
179 static const char stty_sane[] = "sane";
180 static const char cbreak[] = "cbreak";
181 static const char stty_pass8[] = "pass8";
182 static const char litout[] = "litout";
183 static const char cooked[] = "cooked";
184 static const char decctlq[] = "decctlq";
185 static const char stty_tabs[] = "tabs";
186 static const char stty_lcase[] = "lcase";
187 static const char stty_LCASE[] = "LCASE";
188 static const char stty_crt[] = "crt";
189 static const char stty_dec[] = "dec";
192 /* Flags for `struct mode_info'. */
193 #define SANE_SET 1 /* Set in `sane' mode. */
194 #define SANE_UNSET 2 /* Unset in `sane' mode. */
195 #define REV 4 /* Can be turned off by prepending `-'. */
196 #define OMIT 8 /* Don't display value. */
200 const char *name; /* Name given on command line. */
201 enum mode_type type; /* Which structure element to change. */
202 char flags; /* Setting and display options. */
203 unsigned long bits; /* Bits to set for this mode. */
204 unsigned long mask; /* Other bits to turn off for this mode. */
207 static const struct mode_info mode_info[] = {
208 {"parenb", control, REV, PARENB, 0},
209 {"parodd", control, REV, PARODD, 0},
210 {"cs5", control, 0, CS5, CSIZE},
211 {"cs6", control, 0, CS6, CSIZE},
212 {"cs7", control, 0, CS7, CSIZE},
213 {"cs8", control, 0, CS8, CSIZE},
214 {"hupcl", control, REV, HUPCL, 0},
215 {"hup", control, REV | OMIT, HUPCL, 0},
216 {"cstopb", control, REV, CSTOPB, 0},
217 {"cread", control, SANE_SET | REV, CREAD, 0},
218 {"clocal", control, REV, CLOCAL, 0},
220 {"crtscts", control, REV, CRTSCTS, 0},
223 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
224 {"brkint", input, SANE_SET | REV, BRKINT, 0},
225 {"ignpar", input, REV, IGNPAR, 0},
226 {"parmrk", input, REV, PARMRK, 0},
227 {"inpck", input, REV, INPCK, 0},
228 {"istrip", input, REV, ISTRIP, 0},
229 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
230 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
231 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
232 {"ixon", input, REV, IXON, 0},
233 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
234 {"tandem", input, REV | OMIT, IXOFF, 0},
236 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
239 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
242 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
245 {"opost", output, SANE_SET | REV, OPOST, 0},
247 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
250 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
253 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
256 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
259 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
262 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
265 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
268 {"nl1", output, SANE_UNSET, NL1, NLDLY},
269 {"nl0", output, SANE_SET, NL0, NLDLY},
272 {"cr3", output, SANE_UNSET, CR3, CRDLY},
273 {"cr2", output, SANE_UNSET, CR2, CRDLY},
274 {"cr1", output, SANE_UNSET, CR1, CRDLY},
275 {"cr0", output, SANE_SET, CR0, CRDLY},
278 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
279 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
280 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
281 {"tab0", output, SANE_SET, TAB0, TABDLY},
284 {"tab3", output, SANE_UNSET, OXTABS, 0},
288 {"bs1", output, SANE_UNSET, BS1, BSDLY},
289 {"bs0", output, SANE_SET, BS0, BSDLY},
292 {"vt1", output, SANE_UNSET, VT1, VTDLY},
293 {"vt0", output, SANE_SET, VT0, VTDLY},
296 {"ff1", output, SANE_UNSET, FF1, FFDLY},
297 {"ff0", output, SANE_SET, FF0, FFDLY},
300 {"isig", local, SANE_SET | REV, ISIG, 0},
301 {"icanon", local, SANE_SET | REV, ICANON, 0},
303 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
305 {"echo", local, SANE_SET | REV, ECHO, 0},
306 {"echoe", local, SANE_SET | REV, ECHOE, 0},
307 {"crterase", local, REV | OMIT, ECHOE, 0},
308 {"echok", local, SANE_SET | REV, ECHOK, 0},
309 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
310 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
312 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
315 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
318 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
319 {"prterase", local, REV | OMIT, ECHOPRT, 0},
322 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
323 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
326 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
327 {"crtkill", local, REV | OMIT, ECHOKE, 0},
330 {evenp, combination, REV | OMIT, 0, 0},
331 {parity, combination, REV | OMIT, 0, 0},
332 {stty_oddp, combination, REV | OMIT, 0, 0},
333 {stty_nl, combination, REV | OMIT, 0, 0},
334 {stty_ek, combination, OMIT, 0, 0},
335 {stty_sane, combination, OMIT, 0, 0},
336 {cooked, combination, REV | OMIT, 0, 0},
337 {raw, combination, REV | OMIT, 0, 0},
338 {stty_pass8, combination, REV | OMIT, 0, 0},
339 {litout, combination, REV | OMIT, 0, 0},
340 {cbreak, combination, REV | OMIT, 0, 0},
342 {decctlq, combination, REV | OMIT, 0, 0},
344 #if defined (TABDLY) || defined (OXTABS)
345 {stty_tabs, combination, REV | OMIT, 0, 0},
347 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
348 {stty_lcase, combination, REV | OMIT, 0, 0},
349 {stty_LCASE, combination, REV | OMIT, 0, 0},
351 {stty_crt, combination, OMIT, 0, 0},
352 {stty_dec, combination, OMIT, 0, 0},
355 static const int NUM_mode_info =
357 (sizeof(mode_info) / sizeof(struct mode_info));
359 /* Control character settings. */
360 struct control_info {
361 const char *name; /* Name given on command line. */
362 unsigned char saneval; /* Value to set for `stty sane'. */
363 int offset; /* Offset in c_cc. */
366 /* Control characters. */
368 static const struct control_info control_info[] = {
369 {"intr", CINTR, VINTR},
370 {"quit", CQUIT, VQUIT},
371 {"erase", CERASE, VERASE},
372 {"kill", CKILL, VKILL},
373 {stty_eof, CEOF, VEOF},
374 {stty_eol, CEOL, VEOL},
376 {"eol2", CEOL2, VEOL2},
379 {stty_swtch, CSWTCH, VSWTCH},
381 {"start", CSTART, VSTART},
382 {"stop", CSTOP, VSTOP},
383 {"susp", CSUSP, VSUSP},
385 {"dsusp", CDSUSP, VDSUSP},
388 {"rprnt", CRPRNT, VREPRINT},
391 {"werase", CWERASE, VWERASE},
394 {"lnext", CLNEXT, VLNEXT},
397 {"flush", CFLUSHO, VFLUSHO},
400 {"status", CSTATUS, VSTATUS},
403 /* These must be last because of the display routines. */
405 {stty_time, 0, VTIME},
408 static const int NUM_control_info =
409 (sizeof(control_info) / sizeof(struct control_info));
412 static const char *visible(unsigned int ch);
413 static unsigned long baud_to_value(speed_t speed);
414 static int recover_mode(char *arg, struct termios *mode);
415 static int screen_columns(void);
416 static int set_mode(const struct mode_info *info,
417 int reversed, struct termios *mode);
418 static speed_t string_to_baud(const char *arg);
419 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode);
420 static void display_all(struct termios *mode, int fd,
421 const char *device_name);
422 static void display_changed(struct termios *mode);
423 static void display_recoverable(struct termios *mode);
424 static void display_settings(enum output_type output_type,
425 struct termios *mode, int fd,
426 const char *device_name);
427 static void display_speed(struct termios *mode, int fancy);
428 static void display_window_size(int fancy, int fd,
429 const char *device_name);
430 static void sane_mode(struct termios *mode);
431 static void set_control_char(const struct control_info *info,
432 const char *arg, struct termios *mode);
433 static void set_speed(enum speed_setting type,
434 const char *arg, struct termios *mode);
435 static void set_window_size(int rows, int cols, int fd,
437 const char *device_name);
439 /* The width of the screen, for output wrapping. */
442 /* Current position, to know when to wrap. */
443 static int current_col;
445 /* Print format string MESSAGE and optional args.
446 Wrap to next line first if it won't fit.
447 Print a space first unless MESSAGE will start a new line. */
449 static void wrapf(const char *message, ...)
452 char buf[1024]; /* Plenty long for our needs. */
455 va_start(args, message);
456 vsprintf(buf, message, args);
458 buflen = strlen(buf);
459 if (current_col + (current_col > 0) + buflen >= max_col) {
463 if (current_col > 0) {
468 current_col += buflen;
471 static const struct suffix_mult stty_suffixes[] = {
478 extern int stty_main(int argc, char **argv)
481 enum output_type output_type;
483 int require_set_attr;
486 int recoverable_output;
489 char *file_name = NULL;
491 const char *device_name;
493 output_type = changed;
495 recoverable_output = 0;
497 /* Don't print error messages for unrecognized options. */
500 while ((optc = getopt(argc, argv, "agF:")) != -1) {
508 recoverable_output = 1;
509 output_type = recoverable;
514 error_msg_and_die("only one device may be specified");
518 default: /* unrecognized option */
530 /* Specifying both -a and -g gets an error. */
531 if (verbose_output && recoverable_output)
532 error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
534 /* Specifying any other arguments with -a or -g gets an error. */
535 if (!noargs && (verbose_output || recoverable_output))
536 error_msg_and_die ("modes may not be set when specifying an output style");
538 /* FIXME: it'd be better not to open the file until we've verified
539 that all arguments are valid. Otherwise, we could end up doing
540 only some of the requested operations and then failing, probably
541 leaving things in an undesirable state. */
546 device_name = file_name;
547 fd = open(device_name, O_RDONLY | O_NONBLOCK);
549 perror_msg_and_die("%s", device_name);
550 if ((fdflags = fcntl(fd, F_GETFL)) == -1
551 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
552 perror_msg_and_die("%s: couldn't reset non-blocking mode",
556 device_name = "standard input";
559 /* Initialize to all zeroes so there is no risk memcmp will report a
560 spurious difference in an uninitialized portion of the structure. */
561 memset(&mode, 0, sizeof(mode));
562 if (tcgetattr(fd, &mode))
563 perror_msg_and_die("%s", device_name);
565 if (verbose_output || recoverable_output || noargs) {
566 max_col = screen_columns();
568 display_settings(output_type, &mode, fd, device_name);
573 require_set_attr = 0;
580 if (argv[k][0] == '-') {
584 for (i = 0; i < NUM_mode_info; ++i) {
585 if (STREQ(argv[k], mode_info[i].name)) {
586 match_found = set_mode(&mode_info[i], reversed, &mode);
587 require_set_attr = 1;
591 if (match_found == 0 && reversed) {
592 error_msg_and_die("invalid argument `%s'", --argv[k]);
594 if (match_found == 0) {
595 for (i = 0; i < NUM_control_info; ++i) {
596 if (STREQ(argv[k], control_info[i].name)) {
598 error_msg_and_die("missing argument to `%s'", argv[k]);
602 set_control_char(&control_info[i], argv[k], &mode);
603 require_set_attr = 1;
608 if (match_found == 0) {
609 if (STREQ(argv[k], "ispeed")) {
611 error_msg_and_die("missing argument to `%s'", argv[k]);
614 set_speed(input_speed, argv[k], &mode);
616 require_set_attr = 1;
617 } else if (STREQ(argv[k], "ospeed")) {
619 error_msg_and_die("missing argument to `%s'", argv[k]);
622 set_speed(output_speed, argv[k], &mode);
624 require_set_attr = 1;
627 else if (STREQ(argv[k], "rows")) {
629 error_msg_and_die("missing argument to `%s'", argv[k]);
632 set_window_size((int) parse_number(argv[k], stty_suffixes),
633 -1, fd, device_name);
634 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
636 error_msg_and_die("missing argument to `%s'", argv[k]);
640 (int) parse_number(argv[k], stty_suffixes),
642 } else if (STREQ(argv[k], "size")) {
643 max_col = screen_columns();
645 display_window_size(0, fd, device_name);
649 else if (STREQ(argv[k], "line")) {
651 error_msg_and_die("missing argument to `%s'", argv[k]);
654 mode.c_line = parse_number(argv[k], stty_suffixes);
655 require_set_attr = 1;
658 else if (STREQ(argv[k], "speed")) {
659 max_col = screen_columns();
660 display_speed(&mode, 0);
661 } else if (string_to_baud(argv[k]) != (speed_t) - 1) {
662 set_speed(both_speeds, argv[k], &mode);
664 require_set_attr = 1;
666 if (recover_mode(argv[k], &mode) == 0) {
667 error_msg_and_die("invalid argument `%s'", argv[k]);
669 require_set_attr = 1;
675 if (require_set_attr) {
676 struct termios new_mode;
678 if (tcsetattr(fd, TCSADRAIN, &mode))
679 perror_msg_and_die("%s", device_name);
681 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
682 it performs *any* of the requested operations. This means it
683 can report `success' when it has actually failed to perform
684 some proper subset of the requested operations. To detect
685 this partial failure, get the current terminal attributes and
686 compare them to the requested ones. */
688 /* Initialize to all zeroes so there is no risk memcmp will report a
689 spurious difference in an uninitialized portion of the structure. */
690 memset(&new_mode, 0, sizeof(new_mode));
691 if (tcgetattr(fd, &new_mode))
692 perror_msg_and_die("%s", device_name);
694 /* Normally, one shouldn't use memcmp to compare structures that
695 may have `holes' containing uninitialized data, but we have been
696 careful to initialize the storage of these two variables to all
697 zeroes. One might think it more efficient simply to compare the
698 modified fields, but that would require enumerating those fields --
699 and not all systems have the same fields in this structure. */
701 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
703 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
704 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
705 sometimes (m1 != m2). The only difference is in the four bits
706 of the c_cflag field corresponding to the baud rate. To save
707 Sun users a little confusion, don't report an error if this
708 happens. But suppress the error only if we haven't tried to
709 set the baud rate explicitly -- otherwise we'd never give an
710 error for a true failure to set the baud rate. */
712 new_mode.c_cflag &= (~CIBAUD);
713 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
716 error_msg_and_die ("%s: unable to perform all requested operations",
722 printf("new_mode: mode\n");
723 for (i = 0; i < sizeof(new_mode); i++)
724 printf("0x%02x: 0x%02x\n",
725 *(((unsigned char *) &new_mode) + i),
726 *(((unsigned char *) &mode) + i));
736 /* Return 0 if not applied because not reversible; otherwise return 1. */
739 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
743 if (reversed && (info->flags & REV) == 0)
746 bitsp = mode_type_flag(info->type, mode);
749 /* Combination mode. */
750 if (info->name == evenp || info->name == parity) {
752 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
755 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
756 } else if (info->name == stty_oddp) {
758 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
761 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
762 } else if (info->name == stty_nl) {
764 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
765 mode->c_oflag = (mode->c_oflag
778 mode->c_iflag = mode->c_iflag & ~ICRNL;
780 mode->c_oflag = mode->c_oflag & ~ONLCR;
783 } else if (info->name == stty_ek) {
784 mode->c_cc[VERASE] = CERASE;
785 mode->c_cc[VKILL] = CKILL;
786 } else if (info->name == stty_sane)
788 else if (info->name == cbreak) {
790 mode->c_lflag |= ICANON;
792 mode->c_lflag &= ~ICANON;
793 } else if (info->name == stty_pass8) {
795 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
796 mode->c_iflag |= ISTRIP;
798 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
799 mode->c_iflag &= ~ISTRIP;
801 } else if (info->name == litout) {
803 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
804 mode->c_iflag |= ISTRIP;
805 mode->c_oflag |= OPOST;
807 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
808 mode->c_iflag &= ~ISTRIP;
809 mode->c_oflag &= ~OPOST;
811 } else if (info->name == raw || info->name == cooked) {
812 if ((info->name[0] == 'r' && reversed)
813 || (info->name[0] == 'c' && !reversed)) {
815 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
816 mode->c_oflag |= OPOST;
817 mode->c_lflag |= ISIG | ICANON;
819 mode->c_cc[VEOF] = CEOF;
822 mode->c_cc[VEOL] = CEOL;
827 mode->c_oflag &= ~OPOST;
828 mode->c_lflag &= ~(ISIG | ICANON
833 mode->c_cc[VMIN] = 1;
834 mode->c_cc[VTIME] = 0;
838 else if (info->name == decctlq) {
840 mode->c_iflag |= IXANY;
842 mode->c_iflag &= ~IXANY;
846 else if (info->name == stty_tabs) {
848 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
850 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
854 else if (info->name == stty_tabs) {
856 mode->c_oflag = mode->c_oflag | OXTABS;
858 mode->c_oflag = mode->c_oflag & ~OXTABS;
862 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
863 else if (info->name == stty_lcase || info->name == stty_LCASE) {
865 mode->c_lflag &= ~XCASE;
866 mode->c_iflag &= ~IUCLC;
867 mode->c_oflag &= ~OLCUC;
869 mode->c_lflag |= XCASE;
870 mode->c_iflag |= IUCLC;
871 mode->c_oflag |= OLCUC;
875 else if (info->name == stty_crt)
876 mode->c_lflag |= ECHOE
884 else if (info->name == stty_dec) {
885 mode->c_cc[VINTR] = 3; /* ^C */
886 mode->c_cc[VERASE] = 127; /* DEL */
887 mode->c_cc[VKILL] = 21; /* ^U */
888 mode->c_lflag |= ECHOE
897 mode->c_iflag &= ~IXANY;
901 *bitsp = *bitsp & ~info->mask & ~info->bits;
903 *bitsp = (*bitsp & ~info->mask) | info->bits;
909 set_control_char(const struct control_info *info, const char *arg,
910 struct termios *mode)
914 if (info->name == stty_min || info->name == stty_time)
915 value = parse_number(arg, stty_suffixes);
916 else if (arg[0] == '\0' || arg[1] == '\0')
918 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
919 value = _POSIX_VDISABLE;
920 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
924 value = arg[1] & ~0140; /* Non-letters get weird results. */
926 value = parse_number(arg, stty_suffixes);
927 mode->c_cc[info->offset] = value;
931 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
935 baud = string_to_baud(arg);
936 if (type == input_speed || type == both_speeds)
937 cfsetispeed(mode, baud);
938 if (type == output_speed || type == both_speeds)
939 cfsetospeed(mode, baud);
944 static int get_win_size(int fd, struct winsize *win)
946 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
952 set_window_size(int rows, int cols, int fd, const char *device_name)
956 if (get_win_size(fd, &win)) {
958 perror_msg_and_die("%s", device_name);
959 memset(&win, 0, sizeof(win));
968 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
969 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
970 This comment from sys/ttold.h describes Sun's twisted logic - a better
971 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
972 At any rate, the problem is gone in Solaris 2.x. */
974 if (win.ws_row == 0 || win.ws_col == 0) {
975 struct ttysize ttysz;
977 ttysz.ts_lines = win.ws_row;
978 ttysz.ts_cols = win.ws_col;
983 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
984 perror_msg_and_die("%s", device_name);
986 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
987 perror_msg_and_die("%s", device_name);
992 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
993 perror_msg_and_die("%s", device_name);
996 static void display_window_size(int fancy, int fd, const char *device_name)
1000 if (get_win_size(fd, &win)) {
1001 if (errno != EINVAL)
1002 perror_msg_and_die("%s", device_name);
1004 perror_msg_and_die("%s: no size information for this device",
1007 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1008 win.ws_row, win.ws_col);
1015 static int screen_columns(void)
1020 /* With Solaris 2.[123], this ioctl fails and errno is set to
1021 EINVAL for telnet (but not rlogin) sessions.
1022 On ISC 3.0, it fails for the console and the serial port
1023 (but it works for ptys).
1024 It can also fail on any system when stdout isn't a tty.
1025 In case of any failure, just use the default. */
1026 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1030 if (getenv("COLUMNS"))
1031 return atoi(getenv("COLUMNS"));
1035 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1039 return &mode->c_cflag;
1042 return &mode->c_iflag;
1045 return &mode->c_oflag;
1048 return &mode->c_lflag;
1050 default: /* combination: */
1056 display_settings(enum output_type output_type, struct termios *mode,
1057 int fd, const char *device_name)
1059 switch (output_type) {
1061 display_changed(mode);
1065 display_all(mode, fd, device_name);
1069 display_recoverable(mode);
1074 static void display_changed(struct termios *mode)
1080 enum mode_type prev_type = control;
1082 display_speed(mode, 1);
1084 wrapf("line = %d;", mode->c_line);
1090 for (i = 0; control_info[i].name != stty_min; ++i) {
1091 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1093 /* If swtch is the same as susp, don't print both. */
1095 if (control_info[i].name == stty_swtch)
1098 /* If eof uses the same slot as min, only print whichever applies. */
1100 if ((mode->c_lflag & ICANON) == 0
1101 && (control_info[i].name == stty_eof
1102 || control_info[i].name == stty_eol)) continue;
1106 wrapf("%s = %s;", control_info[i].name,
1107 visible(mode->c_cc[control_info[i].offset]));
1109 if ((mode->c_lflag & ICANON) == 0) {
1110 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1111 (int) mode->c_cc[VTIME]);
1112 } else if (empty_line == 0)
1117 for (i = 0; i < NUM_mode_info; ++i) {
1118 if (mode_info[i].flags & OMIT)
1120 if (mode_info[i].type != prev_type) {
1121 if (empty_line == 0) {
1126 prev_type = mode_info[i].type;
1129 bitsp = mode_type_flag(mode_info[i].type, mode);
1130 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1131 if ((*bitsp & mask) == mode_info[i].bits) {
1132 if (mode_info[i].flags & SANE_UNSET) {
1133 wrapf("%s", mode_info[i].name);
1137 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1139 wrapf("-%s", mode_info[i].name);
1143 if (empty_line == 0)
1149 display_all(struct termios *mode, int fd, const char *device_name)
1154 enum mode_type prev_type = control;
1156 display_speed(mode, 1);
1158 display_window_size(1, fd, device_name);
1161 wrapf("line = %d;", mode->c_line);
1166 for (i = 0; control_info[i].name != stty_min; ++i) {
1167 /* If swtch is the same as susp, don't print both. */
1169 if (control_info[i].name == stty_swtch)
1172 /* If eof uses the same slot as min, only print whichever applies. */
1174 if ((mode->c_lflag & ICANON) == 0
1175 && (control_info[i].name == stty_eof
1176 || control_info[i].name == stty_eol)) continue;
1178 wrapf("%s = %s;", control_info[i].name,
1179 visible(mode->c_cc[control_info[i].offset]));
1182 if ((mode->c_lflag & ICANON) == 0)
1184 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1185 if (current_col != 0)
1189 for (i = 0; i < NUM_mode_info; ++i) {
1190 if (mode_info[i].flags & OMIT)
1192 if (mode_info[i].type != prev_type) {
1195 prev_type = mode_info[i].type;
1198 bitsp = mode_type_flag(mode_info[i].type, mode);
1199 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1200 if ((*bitsp & mask) == mode_info[i].bits)
1201 wrapf("%s", mode_info[i].name);
1202 else if (mode_info[i].flags & REV)
1203 wrapf("-%s", mode_info[i].name);
1209 static void display_speed(struct termios *mode, int fancy)
1211 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
1212 wrapf(fancy ? "speed %lu baud;" : "%lu\n",
1213 baud_to_value(cfgetospeed(mode)));
1215 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1216 baud_to_value(cfgetispeed(mode)),
1217 baud_to_value(cfgetospeed(mode)));
1222 static void display_recoverable(struct termios *mode)
1226 printf("%lx:%lx:%lx:%lx",
1227 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1228 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1229 for (i = 0; i < NCCS; ++i)
1230 printf(":%x", (unsigned int) mode->c_cc[i]);
1234 static int recover_mode(char *arg, struct termios *mode)
1238 unsigned long iflag, oflag, cflag, lflag;
1240 /* Scan into temporaries since it is too much trouble to figure out
1241 the right format for `tcflag_t'. */
1242 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1243 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1245 mode->c_iflag = iflag;
1246 mode->c_oflag = oflag;
1247 mode->c_cflag = cflag;
1248 mode->c_lflag = lflag;
1250 for (i = 0; i < NCCS; ++i) {
1251 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1253 mode->c_cc[i] = chr;
1257 /* Fail if there are too many fields. */
1265 speed_t speed; /* Internal form. */
1266 unsigned long value; /* Numeric value. */
1269 static const struct speed_map speeds[] = {
1300 static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
1302 static speed_t string_to_baud(const char *arg)
1306 for (i = 0; i < NUM_SPEEDS; ++i)
1307 if (parse_number(arg, 0) == speeds[i].value)
1308 return speeds[i].speed;
1309 return (speed_t) - 1;
1312 static unsigned long baud_to_value(speed_t speed)
1316 for (i = 0; i < NUM_SPEEDS; ++i)
1317 if (speed == speeds[i].speed)
1318 return speeds[i].value;
1322 static void sane_mode(struct termios *mode)
1327 for (i = 0; i < NUM_control_info; ++i) {
1329 if (control_info[i].name == stty_min)
1332 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1335 for (i = 0; i < NUM_mode_info; ++i) {
1336 if (mode_info[i].flags & SANE_SET) {
1337 bitsp = mode_type_flag(mode_info[i].type, mode);
1338 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1339 } else if (mode_info[i].flags & SANE_UNSET) {
1340 bitsp = mode_type_flag(mode_info[i].type, mode);
1341 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1346 /* Return a string that is the printable representation of character CH. */
1347 /* Adapted from `cat' by Torbjorn Granlund. */
1349 static const char *visible(unsigned int ch)
1351 static char buf[10];
1354 if (ch == _POSIX_VDISABLE)
1360 else if (ch == 127) {
1364 *bpout++ = 'M', *bpout++ = '-';
1365 if (ch >= 128 + 32) {
1367 *bpout++ = ch - 128;
1374 *bpout++ = ch - 128 + 64;
1382 return (const char *) buf;
1387 c-file-style: "linux"