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 Vladimir Oleynik <vodz@usa.net> 2001
34 #include <sys/ioctl.h>
37 #include <sys/param.h>
41 # define STDIN_FILENO 0
45 # define STDOUT_FILENO 1
58 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
61 #ifndef _POSIX_VDISABLE
62 # define _POSIX_VDISABLE ((unsigned char) 0)
65 #define Control(c) ((c) & 0x1f)
66 /* Canonical values for control characters. */
68 # define CINTR Control ('c')
77 # define CKILL Control ('u')
80 # define CEOF Control ('d')
83 # define CEOL _POSIX_VDISABLE
86 # define CSTART Control ('q')
89 # define CSTOP Control ('s')
92 # define CSUSP Control ('z')
94 #if defined(VEOL2) && !defined(CEOL2)
95 # define CEOL2 _POSIX_VDISABLE
97 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
98 #if defined(VSUSP) && !defined(VSWTCH)
100 # define CSWTCH CSUSP
102 #if defined(VSWTCH) && !defined(CSWTCH)
103 # define CSWTCH _POSIX_VDISABLE
106 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
107 So the default is to disable `swtch.' */
108 #if defined (__sparc__) && defined (__svr4__)
110 # define CSWTCH _POSIX_VDISABLE
113 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
114 # define VWERASE VWERSE
116 #if defined(VDSUSP) && !defined (CDSUSP)
117 # define CDSUSP Control ('y')
119 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
120 # define VREPRINT VRPRNT
122 #if defined(VREPRINT) && !defined(CRPRNT)
123 # define CRPRNT Control ('r')
125 #if defined(VWERASE) && !defined(CWERASE)
126 # define CWERASE Control ('w')
128 #if defined(VLNEXT) && !defined(CLNEXT)
129 # define CLNEXT Control ('v')
131 #if defined(VDISCARD) && !defined(VFLUSHO)
132 # define VFLUSHO VDISCARD
134 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
135 # define VFLUSHO VFLUSH
137 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
138 # define ECHOCTL CTLECH
140 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
141 # define ECHOCTL TCTLECH
143 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
144 # define ECHOKE CRTKIL
146 #if defined(VFLUSHO) && !defined(CFLUSHO)
147 # define CFLUSHO Control ('o')
149 #if defined(VSTATUS) && !defined(CSTATUS)
150 # define CSTATUS Control ('t')
153 /* Which speeds to set. */
155 input_speed, output_speed, both_speeds
158 /* What to output and how. */
160 changed, all, recoverable /* Default, -a, -g. */
163 /* Which member(s) of `struct termios' a mode uses. */
165 control, input, output, local, combination
169 static const char evenp [] = "evenp";
170 static const char raw [] = "raw";
171 static const char stty_min [] = "min";
172 static const char stty_time [] = "time";
173 static const char stty_swtch[] = "swtch";
174 static const char stty_eol [] = "eol";
175 static const char stty_eof [] = "eof";
176 static const char parity [] = "parity";
177 static const char stty_oddp [] = "oddp";
178 static const char stty_nl [] = "nl";
179 static const char stty_ek [] = "ek";
180 static const char stty_sane [] = "sane";
181 static const char cbreak [] = "cbreak";
182 static const char stty_pass8[] = "pass8";
183 static const char litout [] = "litout";
184 static const char cooked [] = "cooked";
185 static const char decctlq [] = "decctlq";
186 static const char stty_tabs [] = "tabs";
187 static const char stty_lcase[] = "lcase";
188 static const char stty_LCASE[] = "LCASE";
189 static const char stty_crt [] = "crt";
190 static const char stty_dec [] = "dec";
193 /* Flags for `struct mode_info'. */
194 #define SANE_SET 1 /* Set in `sane' mode. */
195 #define SANE_UNSET 2 /* Unset in `sane' mode. */
196 #define REV 4 /* Can be turned off by prepending `-'. */
197 #define OMIT 8 /* Don't display value. */
201 const char *name; /* Name given on command line. */
202 enum mode_type type; /* Which structure element to change. */
203 char flags; /* Setting and display options. */
204 unsigned long bits; /* Bits to set for this mode. */
205 unsigned long mask; /* Other bits to turn off for this mode. */
208 static const struct mode_info mode_info[] = {
209 {"parenb", control, REV, PARENB, 0 },
210 {"parodd", control, REV, PARODD, 0 },
211 {"cs5", control, 0, CS5, CSIZE},
212 {"cs6", control, 0, CS6, CSIZE},
213 {"cs7", control, 0, CS7, CSIZE},
214 {"cs8", control, 0, CS8, CSIZE},
215 {"hupcl", control, REV, HUPCL, 0 },
216 {"hup", control, REV | OMIT, HUPCL, 0 },
217 {"cstopb", control, REV, CSTOPB, 0 },
218 {"cread", control, SANE_SET | REV, CREAD, 0 },
219 {"clocal", control, REV, CLOCAL, 0 },
221 {"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 },
244 {"opost", output, SANE_SET | REV, OPOST, 0 },
246 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 },
249 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 },
252 {"onlcr", output, SANE_SET | REV, ONLCR, 0 },
255 {"onocr", output, SANE_UNSET | REV, ONOCR, 0 },
258 {"onlret", output, SANE_UNSET | REV, ONLRET, 0 },
261 {"ofill", output, SANE_UNSET | REV, OFILL, 0 },
264 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 },
267 {"nl1", output, SANE_UNSET, NL1, NLDLY},
268 {"nl0", output, SANE_SET, NL0, NLDLY},
271 {"cr3", output, SANE_UNSET, CR3, CRDLY},
272 {"cr2", output, SANE_UNSET, CR2, CRDLY},
273 {"cr1", output, SANE_UNSET, CR1, CRDLY},
274 {"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 },
289 {"bs1", output, SANE_UNSET, BS1, BSDLY},
290 {"bs0", output, SANE_SET, BS0, BSDLY},
293 {"vt1", output, SANE_UNSET, VT1, VTDLY},
294 {"vt0", output, SANE_SET, VT0, VTDLY},
297 {"ff1", output, SANE_UNSET, FF1, FFDLY},
298 {"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 },
329 {evenp, combination, REV | OMIT, 0, 0 },
330 {parity, combination, REV | OMIT, 0, 0 },
331 {stty_oddp, combination, REV | OMIT, 0, 0 },
332 {stty_nl, combination, REV | OMIT, 0, 0 },
333 {stty_ek, combination, OMIT, 0, 0 },
334 {stty_sane, combination, OMIT, 0, 0 },
335 {cooked, combination, REV | OMIT, 0, 0 },
336 {raw, combination, REV | OMIT, 0, 0 },
337 {stty_pass8, combination, REV | OMIT, 0, 0 },
338 {litout, combination, REV | OMIT, 0, 0 },
339 {cbreak, combination, REV | OMIT, 0, 0 },
341 {decctlq, combination, REV | OMIT, 0, 0 },
343 #if defined (TABDLY) || defined (OXTABS)
344 {stty_tabs, combination, REV | OMIT, 0, 0 },
346 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
347 {stty_lcase, combination, REV | OMIT, 0, 0 },
348 {stty_LCASE, combination, REV | OMIT, 0, 0 },
350 {stty_crt, combination, OMIT, 0, 0 },
351 {stty_dec, combination, OMIT, 0, 0 },
354 static const int NUM_mode_info =
356 (sizeof(mode_info) / sizeof(struct mode_info));
358 /* Control character settings. */
359 struct control_info {
360 const char *name; /* Name given on command line. */
361 unsigned char saneval; /* Value to set for `stty sane'. */
362 int offset; /* Offset in c_cc. */
365 /* Control characters. */
367 static const struct control_info control_info[] = {
368 {"intr", CINTR, VINTR},
369 {"quit", CQUIT, VQUIT},
370 {"erase", CERASE, VERASE},
371 {"kill", CKILL, VKILL},
372 {stty_eof, CEOF, VEOF},
373 {stty_eol, CEOL, VEOL},
375 {"eol2", CEOL2, VEOL2},
378 {stty_swtch, CSWTCH, VSWTCH},
380 {"start", CSTART, VSTART},
381 {"stop", CSTOP, VSTOP},
382 {"susp", CSUSP, VSUSP},
384 {"dsusp", CDSUSP, VDSUSP},
387 {"rprnt", CRPRNT, VREPRINT},
390 {"werase", CWERASE, VWERASE},
393 {"lnext", CLNEXT, VLNEXT},
396 {"flush", CFLUSHO, VFLUSHO},
399 {"status", CSTATUS, VSTATUS},
401 /* These must be last because of the display routines. */
403 {stty_time, 0, VTIME},
406 static const int NUM_control_info =
407 (sizeof(control_info) / sizeof(struct control_info));
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(const struct mode_info *info,
415 int reversed, struct termios *mode);
416 static speed_t string_to_baud(const char *arg);
417 static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
418 static void display_all(struct termios *mode, int fd,
419 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,
427 const char *device_name);
428 static void sane_mode(struct termios *mode);
429 static void set_control_char(const struct control_info *info,
430 const char *arg, struct termios *mode);
431 static void set_speed(enum speed_setting type,
432 const char *arg, 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. */
439 /* Current position, to know when to wrap. */
440 static int current_col;
442 /* Print format string MESSAGE and optional args.
443 Wrap to next line first if it won't fit.
444 Print a space first unless MESSAGE will start a new line. */
446 static void wrapf(const char *message, ...)
449 char buf[1024]; /* Plenty long for our needs. */
452 va_start(args, message);
453 vsprintf(buf, message, args);
455 buflen = strlen(buf);
456 if (current_col + (current_col > 0) + buflen >= max_col) {
460 if (current_col > 0) {
465 current_col += buflen;
468 static const struct suffix_mult stty_suffixes[] = {
476 extern int stty_main(int argc, char **argv)
478 extern int main(int argc, char **argv)
482 enum output_type output_type;
484 int require_set_attr;
487 int recoverable_output;
490 char * file_name = NULL;
492 const char *device_name;
494 output_type = changed;
496 recoverable_output = 0;
498 /* Don't print error messages for unrecognized options. */
501 while ((optc = getopt(argc, argv, "agF:")) != -1) {
509 recoverable_output = 1;
510 output_type = recoverable;
515 error_msg_and_die("only one device may be specified");
519 default: /* unrecognized option */
531 /* Specifying both -a and -g gets an error. */
532 if (verbose_output && recoverable_output)
533 error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
535 /* Specifying any other arguments with -a or -g gets an error. */
536 if (!noargs && (verbose_output || recoverable_output))
537 error_msg_and_die ("modes may not be set when specifying an output style");
539 /* FIXME: it'd be better not to open the file until we've verified
540 that all arguments are valid. Otherwise, we could end up doing
541 only some of the requested operations and then failing, probably
542 leaving things in an undesirable state. */
547 device_name = file_name;
548 fd = open(device_name, O_RDONLY | O_NONBLOCK);
550 perror_msg_and_die("%s", device_name);
551 if ((fdflags = fcntl(fd, F_GETFL)) == -1
552 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
553 perror_msg_and_die("%s: couldn't reset non-blocking mode",
557 device_name = "standard input";
560 /* Initialize to all zeroes so there is no risk memcmp will report a
561 spurious difference in an uninitialized portion of the structure. */
562 memset(&mode, 0, sizeof(mode));
563 if (tcgetattr(fd, &mode))
564 perror_msg_and_die("%s", device_name);
566 if (verbose_output || recoverable_output || noargs) {
567 max_col = screen_columns();
569 display_settings(output_type, &mode, fd, device_name);
574 require_set_attr = 0;
581 if (argv[k][0] == '-') {
585 for (i = 0; i < NUM_mode_info; ++i)
586 if (STREQ(argv[k], mode_info[i].name)) {
587 match_found = set_mode(&mode_info[i], reversed, &mode);
588 require_set_attr = 1;
592 if (match_found == 0 && reversed)
593 error_msg_and_die("invalid argument `%s'", --argv[k]);
595 if (match_found == 0)
596 for (i = 0; i < NUM_control_info; ++i)
597 if (STREQ(argv[k], control_info[i].name)) {
599 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;
607 if (match_found == 0) {
608 if (STREQ(argv[k], "ispeed")) {
610 error_msg_and_die("missing argument to `%s'", argv[k]);
612 set_speed(input_speed, argv[k], &mode);
614 require_set_attr = 1;
615 } else if (STREQ(argv[k], "ospeed")) {
617 error_msg_and_die("missing argument to `%s'", argv[k]);
619 set_speed(output_speed, argv[k], &mode);
621 require_set_attr = 1;
624 else if (STREQ(argv[k], "rows")) {
626 error_msg_and_die("missing argument to `%s'", argv[k]);
628 set_window_size((int) parse_number(argv[k], stty_suffixes),
629 -1, fd, device_name);
630 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
632 error_msg_and_die("missing argument to `%s'", argv[k]);
635 (int) parse_number(argv[k], stty_suffixes),
637 } else if (STREQ(argv[k], "size")) {
638 max_col = screen_columns();
640 display_window_size(0, fd, device_name);
644 else if (STREQ(argv[k], "line")) {
646 error_msg_and_die("missing argument to `%s'", argv[k]);
648 mode.c_line = parse_number(argv[k], stty_suffixes);
649 require_set_attr = 1;
652 else if (STREQ(argv[k], "speed")) {
653 max_col = screen_columns();
654 display_speed(&mode, 0);
655 } else if (recover_mode(argv[k], &mode) == 1)
656 require_set_attr = 1;
657 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
658 set_speed(both_speeds, argv[k], &mode);
660 require_set_attr = 1;
662 error_msg_and_die("invalid argument `%s'", argv[k]);
667 if (require_set_attr) {
668 struct termios new_mode;
670 if (tcsetattr(fd, TCSADRAIN, &mode))
671 perror_msg_and_die("%s", device_name);
673 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
674 it performs *any* of the requested operations. This means it
675 can report `success' when it has actually failed to perform
676 some proper subset of the requested operations. To detect
677 this partial failure, get the current terminal attributes and
678 compare them to the requested ones. */
680 /* Initialize to all zeroes so there is no risk memcmp will report a
681 spurious difference in an uninitialized portion of the structure. */
682 memset(&new_mode, 0, sizeof(new_mode));
683 if (tcgetattr(fd, &new_mode))
684 perror_msg_and_die("%s", device_name);
686 /* Normally, one shouldn't use memcmp to compare structures that
687 may have `holes' containing uninitialized data, but we have been
688 careful to initialize the storage of these two variables to all
689 zeroes. One might think it more efficient simply to compare the
690 modified fields, but that would require enumerating those fields --
691 and not all systems have the same fields in this structure. */
693 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
695 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
696 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
697 sometimes (m1 != m2). The only difference is in the four bits
698 of the c_cflag field corresponding to the baud rate. To save
699 Sun users a little confusion, don't report an error if this
700 happens. But suppress the error only if we haven't tried to
701 set the baud rate explicitly -- otherwise we'd never give an
702 error for a true failure to set the baud rate. */
704 new_mode.c_cflag &= (~CIBAUD);
705 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
707 error_msg_and_die ("%s: unable to perform all requested operations",
715 /* Return 0 if not applied because not reversible; otherwise return 1. */
718 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
722 if (reversed && (info->flags & REV) == 0)
725 bitsp = mode_type_flag(info->type, mode);
728 /* Combination mode. */
729 if (info->name == evenp || info->name == parity) {
731 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
734 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
735 } else if (info->name == stty_oddp) {
737 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
740 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
741 } else if (info->name == stty_nl) {
743 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
744 mode->c_oflag = (mode->c_oflag
757 mode->c_iflag = mode->c_iflag & ~ICRNL;
759 mode->c_oflag = mode->c_oflag & ~ONLCR;
762 } else if (info->name == stty_ek) {
763 mode->c_cc[VERASE] = CERASE;
764 mode->c_cc[VKILL] = CKILL;
765 } else if (info->name == stty_sane)
767 else if (info->name == cbreak) {
769 mode->c_lflag |= ICANON;
771 mode->c_lflag &= ~ICANON;
772 } else if (info->name == stty_pass8) {
774 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
775 mode->c_iflag |= ISTRIP;
777 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
778 mode->c_iflag &= ~ISTRIP;
780 } else if (info->name == litout) {
782 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
783 mode->c_iflag |= ISTRIP;
784 mode->c_oflag |= OPOST;
786 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
787 mode->c_iflag &= ~ISTRIP;
788 mode->c_oflag &= ~OPOST;
790 } else if (info->name == raw || info->name == cooked) {
791 if ((info->name[0] == 'r' && reversed)
792 || (info->name[0] == 'c' && !reversed)) {
794 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
795 mode->c_oflag |= OPOST;
796 mode->c_lflag |= ISIG | ICANON;
798 mode->c_cc[VEOF] = CEOF;
801 mode->c_cc[VEOL] = CEOL;
806 mode->c_oflag &= ~OPOST;
807 mode->c_lflag &= ~(ISIG | ICANON
812 mode->c_cc[VMIN] = 1;
813 mode->c_cc[VTIME] = 0;
817 else if (info->name == decctlq) {
819 mode->c_iflag |= IXANY;
821 mode->c_iflag &= ~IXANY;
825 else if (info->name == stty_tabs) {
827 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
829 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
833 else if (info->name == stty_tabs) {
835 mode->c_oflag = mode->c_oflag | OXTABS;
837 mode->c_oflag = mode->c_oflag & ~OXTABS;
841 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
842 else if (info->name == stty_lcase || info->name == stty_LCASE) {
844 mode->c_lflag &= ~XCASE;
845 mode->c_iflag &= ~IUCLC;
846 mode->c_oflag &= ~OLCUC;
848 mode->c_lflag |= XCASE;
849 mode->c_iflag |= IUCLC;
850 mode->c_oflag |= OLCUC;
854 else if (info->name == stty_crt)
855 mode->c_lflag |= ECHOE
863 else if (info->name == stty_dec) {
864 mode->c_cc[VINTR] = 3; /* ^C */
865 mode->c_cc[VERASE] = 127; /* DEL */
866 mode->c_cc[VKILL] = 21; /* ^U */
867 mode->c_lflag |= ECHOE
876 mode->c_iflag &= ~IXANY;
880 *bitsp = *bitsp & ~info->mask & ~info->bits;
882 *bitsp = (*bitsp & ~info->mask) | info->bits;
888 set_control_char(const struct control_info *info, const char *arg,
889 struct termios *mode)
893 if (info->name == stty_min || info->name == stty_time)
894 value = parse_number(arg, stty_suffixes);
895 else if (arg[0] == '\0' || arg[1] == '\0')
897 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
898 value = _POSIX_VDISABLE;
899 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
903 value = arg[1] & ~0140; /* Non-letters get weird results. */
905 value = parse_number(arg, stty_suffixes);
906 mode->c_cc[info->offset] = value;
910 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
914 baud = string_to_baud(arg);
915 if (type == input_speed || type == both_speeds)
916 cfsetispeed(mode, baud);
917 if (type == output_speed || type == both_speeds)
918 cfsetospeed(mode, baud);
923 static int get_win_size(int fd, struct winsize *win)
925 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
931 set_window_size(int rows, int cols, int fd, const char *device_name)
935 if (get_win_size(fd, &win)) {
937 perror_msg_and_die("%s", device_name);
938 memset(&win, 0, sizeof(win));
947 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
948 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
949 This comment from sys/ttold.h describes Sun's twisted logic - a better
950 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
951 At any rate, the problem is gone in Solaris 2.x. */
953 if (win.ws_row == 0 || win.ws_col == 0) {
954 struct ttysize ttysz;
956 ttysz.ts_lines = win.ws_row;
957 ttysz.ts_cols = win.ws_col;
962 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
963 perror_msg_and_die("%s", device_name);
965 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
966 perror_msg_and_die("%s", device_name);
971 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
972 perror_msg_and_die("%s", device_name);
975 static void display_window_size(int fancy, int fd, const char *device_name)
979 if (get_win_size(fd, &win)) {
981 perror_msg_and_die("%s", device_name);
983 perror_msg_and_die("%s: no size information for this device",
986 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
987 win.ws_row, win.ws_col);
994 static int screen_columns(void)
999 /* With Solaris 2.[123], this ioctl fails and errno is set to
1000 EINVAL for telnet (but not rlogin) sessions.
1001 On ISC 3.0, it fails for the console and the serial port
1002 (but it works for ptys).
1003 It can also fail on any system when stdout isn't a tty.
1004 In case of any failure, just use the default. */
1005 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1009 if (getenv("COLUMNS"))
1010 return atoi(getenv("COLUMNS"));
1014 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1018 return &mode->c_cflag;
1021 return &mode->c_iflag;
1024 return &mode->c_oflag;
1027 return &mode->c_lflag;
1029 default: /* combination: */
1035 display_settings(enum output_type output_type, struct termios *mode,
1036 int fd, const char *device_name)
1038 switch (output_type) {
1040 display_changed(mode);
1044 display_all(mode, fd, device_name);
1048 display_recoverable(mode);
1053 static void display_changed(struct termios *mode)
1059 enum mode_type prev_type = control;
1061 display_speed(mode, 1);
1063 wrapf("line = %d;", mode->c_line);
1069 for (i = 0; control_info[i].name != stty_min; ++i) {
1070 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1072 /* If swtch is the same as susp, don't print both. */
1074 if (control_info[i].name == stty_swtch)
1077 /* If eof uses the same slot as min, only print whichever applies. */
1079 if ((mode->c_lflag & ICANON) == 0
1080 && (control_info[i].name == stty_eof
1081 || control_info[i].name == stty_eol)) continue;
1085 wrapf("%s = %s;", control_info[i].name,
1086 visible(mode->c_cc[control_info[i].offset]));
1088 if ((mode->c_lflag & ICANON) == 0) {
1089 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1090 (int) mode->c_cc[VTIME]);
1091 } else if (empty_line == 0)
1096 for (i = 0; i < NUM_mode_info; ++i) {
1097 if (mode_info[i].flags & OMIT)
1099 if (mode_info[i].type != prev_type) {
1100 if (empty_line == 0) {
1105 prev_type = mode_info[i].type;
1108 bitsp = mode_type_flag(mode_info[i].type, mode);
1109 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1110 if ((*bitsp & mask) == mode_info[i].bits) {
1111 if (mode_info[i].flags & SANE_UNSET) {
1112 wrapf("%s", mode_info[i].name);
1116 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1118 wrapf("-%s", mode_info[i].name);
1122 if (empty_line == 0)
1128 display_all(struct termios *mode, int fd, const char *device_name)
1133 enum mode_type prev_type = control;
1135 display_speed(mode, 1);
1137 display_window_size(1, fd, device_name);
1140 wrapf("line = %d;", mode->c_line);
1145 for (i = 0; control_info[i].name != stty_min; ++i) {
1146 /* If swtch is the same as susp, don't print both. */
1148 if (control_info[i].name == stty_swtch)
1151 /* If eof uses the same slot as min, only print whichever applies. */
1153 if ((mode->c_lflag & ICANON) == 0
1154 && (control_info[i].name == stty_eof
1155 || control_info[i].name == stty_eol)) continue;
1157 wrapf("%s = %s;", control_info[i].name,
1158 visible(mode->c_cc[control_info[i].offset]));
1161 if ((mode->c_lflag & ICANON) == 0)
1163 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1164 if (current_col != 0)
1168 for (i = 0; i < NUM_mode_info; ++i) {
1169 if (mode_info[i].flags & OMIT)
1171 if (mode_info[i].type != prev_type) {
1174 prev_type = mode_info[i].type;
1177 bitsp = mode_type_flag(mode_info[i].type, mode);
1178 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1179 if ((*bitsp & mask) == mode_info[i].bits)
1180 wrapf("%s", mode_info[i].name);
1181 else if (mode_info[i].flags & REV)
1182 wrapf("-%s", mode_info[i].name);
1188 static void display_speed(struct termios *mode, int fancy)
1190 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
1191 wrapf(fancy ? "speed %lu baud;" : "%lu\n",
1192 baud_to_value(cfgetospeed(mode)));
1194 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1195 baud_to_value(cfgetispeed(mode)),
1196 baud_to_value(cfgetospeed(mode)));
1201 static void display_recoverable(struct termios *mode)
1205 printf("%lx:%lx:%lx:%lx",
1206 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1207 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1208 for (i = 0; i < NCCS; ++i)
1209 printf(":%x", (unsigned int) mode->c_cc[i]);
1213 static int recover_mode(char *arg, struct termios *mode)
1217 unsigned long iflag, oflag, cflag, lflag;
1219 /* Scan into temporaries since it is too much trouble to figure out
1220 the right format for `tcflag_t'. */
1221 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1222 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1224 mode->c_iflag = iflag;
1225 mode->c_oflag = oflag;
1226 mode->c_cflag = cflag;
1227 mode->c_lflag = lflag;
1229 for (i = 0; i < NCCS; ++i) {
1230 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1232 mode->c_cc[i] = chr;
1236 /* Fail if there are too many fields. */
1244 speed_t speed; /* Internal form. */
1245 unsigned long value; /* Numeric value. */
1248 static const struct speed_map speeds[] = {
1279 static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
1281 static speed_t string_to_baud(const char *arg)
1285 for (i = 0; i < NUM_SPEEDS; ++i)
1286 if (parse_number(arg, 0) == speeds[i].value)
1287 return speeds[i].speed;
1288 return (speed_t) - 1;
1291 static unsigned long baud_to_value(speed_t speed)
1295 for (i = 0; i < NUM_SPEEDS; ++i)
1296 if (speed == speeds[i].speed)
1297 return speeds[i].value;
1301 static void sane_mode(struct termios *mode)
1306 for (i = 0; i < NUM_control_info; ++i) {
1308 if (control_info[i].name == stty_min)
1311 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1314 for (i = 0; i < NUM_mode_info; ++i) {
1315 if (mode_info[i].flags & SANE_SET) {
1316 bitsp = mode_type_flag(mode_info[i].type, mode);
1317 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1318 } else if (mode_info[i].flags & SANE_UNSET) {
1319 bitsp = mode_type_flag(mode_info[i].type, mode);
1320 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1325 /* Return a string that is the printable representation of character CH. */
1326 /* Adapted from `cat' by Torbjorn Granlund. */
1328 static const char *visible(unsigned int ch)
1330 static char buf[10];
1333 if (ch == _POSIX_VDISABLE)
1339 else if (ch == 127) {
1343 *bpout++ = 'M', *bpout++ = '-';
1344 if (ch >= 128 + 32) {
1346 *bpout++ = ch - 128;
1353 *bpout++ = ch - 128 + 64;
1361 return (const char *) buf;
1366 const char *applet_name = "stty";
1372 c-file-style: "linux"