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 <dzo@simtreas.ru> 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] == '-') {
586 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
587 Find the options that have been parsed. This is really
588 gross, but it's needed because stty SETTINGS look like options to
589 getopt(), so we need to work around things in a really horrible
590 way. If any new options are ever added to stty, the short option
591 MUST NOT be a letter which is the first letter of one of the
592 possible stty settings.
594 find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
596 if(find_dev_opt[1]==0) /* -*F /dev/foo */
597 k++; /* skip /dev/foo */
598 continue; /* else -*F/dev/foo - no skip */
600 if(argv[k][0]=='a' || argv[k][0]=='g')
602 /* Is not options - is reverse params */
605 for (i = 0; i < NUM_mode_info; ++i)
606 if (STREQ(argv[k], mode_info[i].name)) {
607 match_found = set_mode(&mode_info[i], reversed, &mode);
608 require_set_attr = 1;
612 if (match_found == 0 && reversed)
613 error_msg_and_die("invalid argument `%s'", --argv[k]);
615 if (match_found == 0)
616 for (i = 0; i < NUM_control_info; ++i)
617 if (STREQ(argv[k], control_info[i].name)) {
619 error_msg_and_die("missing argument to `%s'", argv[k]);
622 set_control_char(&control_info[i], argv[k], &mode);
623 require_set_attr = 1;
627 if (match_found == 0) {
628 if (STREQ(argv[k], "ispeed")) {
630 error_msg_and_die("missing argument to `%s'", argv[k]);
632 set_speed(input_speed, argv[k], &mode);
634 require_set_attr = 1;
635 } else if (STREQ(argv[k], "ospeed")) {
637 error_msg_and_die("missing argument to `%s'", argv[k]);
639 set_speed(output_speed, argv[k], &mode);
641 require_set_attr = 1;
644 else if (STREQ(argv[k], "rows")) {
646 error_msg_and_die("missing argument to `%s'", argv[k]);
648 set_window_size((int) parse_number(argv[k], stty_suffixes),
649 -1, fd, device_name);
650 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
652 error_msg_and_die("missing argument to `%s'", argv[k]);
655 (int) parse_number(argv[k], stty_suffixes),
657 } else if (STREQ(argv[k], "size")) {
658 max_col = screen_columns();
660 display_window_size(0, fd, device_name);
664 else if (STREQ(argv[k], "line")) {
666 error_msg_and_die("missing argument to `%s'", argv[k]);
668 mode.c_line = parse_number(argv[k], stty_suffixes);
669 require_set_attr = 1;
672 else if (STREQ(argv[k], "speed")) {
673 max_col = screen_columns();
674 display_speed(&mode, 0);
675 } else if (recover_mode(argv[k], &mode) == 1)
676 require_set_attr = 1;
677 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
678 set_speed(both_speeds, argv[k], &mode);
680 require_set_attr = 1;
682 error_msg_and_die("invalid argument `%s'", argv[k]);
686 if (require_set_attr) {
687 struct termios new_mode;
689 if (tcsetattr(fd, TCSADRAIN, &mode))
690 perror_msg_and_die("%s", device_name);
692 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
693 it performs *any* of the requested operations. This means it
694 can report `success' when it has actually failed to perform
695 some proper subset of the requested operations. To detect
696 this partial failure, get the current terminal attributes and
697 compare them to the requested ones. */
699 /* Initialize to all zeroes so there is no risk memcmp will report a
700 spurious difference in an uninitialized portion of the structure. */
701 memset(&new_mode, 0, sizeof(new_mode));
702 if (tcgetattr(fd, &new_mode))
703 perror_msg_and_die("%s", device_name);
705 /* Normally, one shouldn't use memcmp to compare structures that
706 may have `holes' containing uninitialized data, but we have been
707 careful to initialize the storage of these two variables to all
708 zeroes. One might think it more efficient simply to compare the
709 modified fields, but that would require enumerating those fields --
710 and not all systems have the same fields in this structure. */
712 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
714 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
715 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
716 sometimes (m1 != m2). The only difference is in the four bits
717 of the c_cflag field corresponding to the baud rate. To save
718 Sun users a little confusion, don't report an error if this
719 happens. But suppress the error only if we haven't tried to
720 set the baud rate explicitly -- otherwise we'd never give an
721 error for a true failure to set the baud rate. */
723 new_mode.c_cflag &= (~CIBAUD);
724 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
726 error_msg_and_die ("%s: unable to perform all requested operations",
734 /* Return 0 if not applied because not reversible; otherwise return 1. */
737 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
741 if (reversed && (info->flags & REV) == 0)
744 bitsp = mode_type_flag(info->type, mode);
747 /* Combination mode. */
748 if (info->name == evenp || info->name == parity) {
750 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
753 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
754 } else if (info->name == stty_oddp) {
756 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
759 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
760 } else if (info->name == stty_nl) {
762 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
763 mode->c_oflag = (mode->c_oflag
776 mode->c_iflag = mode->c_iflag & ~ICRNL;
778 mode->c_oflag = mode->c_oflag & ~ONLCR;
781 } else if (info->name == stty_ek) {
782 mode->c_cc[VERASE] = CERASE;
783 mode->c_cc[VKILL] = CKILL;
784 } else if (info->name == stty_sane)
786 else if (info->name == cbreak) {
788 mode->c_lflag |= ICANON;
790 mode->c_lflag &= ~ICANON;
791 } else if (info->name == stty_pass8) {
793 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
794 mode->c_iflag |= ISTRIP;
796 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
797 mode->c_iflag &= ~ISTRIP;
799 } else if (info->name == litout) {
801 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
802 mode->c_iflag |= ISTRIP;
803 mode->c_oflag |= OPOST;
805 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
806 mode->c_iflag &= ~ISTRIP;
807 mode->c_oflag &= ~OPOST;
809 } else if (info->name == raw || info->name == cooked) {
810 if ((info->name[0] == 'r' && reversed)
811 || (info->name[0] == 'c' && !reversed)) {
813 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
814 mode->c_oflag |= OPOST;
815 mode->c_lflag |= ISIG | ICANON;
817 mode->c_cc[VEOF] = CEOF;
820 mode->c_cc[VEOL] = CEOL;
825 mode->c_oflag &= ~OPOST;
826 mode->c_lflag &= ~(ISIG | ICANON
831 mode->c_cc[VMIN] = 1;
832 mode->c_cc[VTIME] = 0;
836 else if (info->name == decctlq) {
838 mode->c_iflag |= IXANY;
840 mode->c_iflag &= ~IXANY;
844 else if (info->name == stty_tabs) {
846 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
848 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
852 else if (info->name == stty_tabs) {
854 mode->c_oflag = mode->c_oflag | OXTABS;
856 mode->c_oflag = mode->c_oflag & ~OXTABS;
860 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
861 else if (info->name == stty_lcase || info->name == stty_LCASE) {
863 mode->c_lflag &= ~XCASE;
864 mode->c_iflag &= ~IUCLC;
865 mode->c_oflag &= ~OLCUC;
867 mode->c_lflag |= XCASE;
868 mode->c_iflag |= IUCLC;
869 mode->c_oflag |= OLCUC;
873 else if (info->name == stty_crt)
874 mode->c_lflag |= ECHOE
882 else if (info->name == stty_dec) {
883 mode->c_cc[VINTR] = 3; /* ^C */
884 mode->c_cc[VERASE] = 127; /* DEL */
885 mode->c_cc[VKILL] = 21; /* ^U */
886 mode->c_lflag |= ECHOE
895 mode->c_iflag &= ~IXANY;
899 *bitsp = *bitsp & ~info->mask & ~info->bits;
901 *bitsp = (*bitsp & ~info->mask) | info->bits;
907 set_control_char(const struct control_info *info, const char *arg,
908 struct termios *mode)
912 if (info->name == stty_min || info->name == stty_time)
913 value = parse_number(arg, stty_suffixes);
914 else if (arg[0] == '\0' || arg[1] == '\0')
916 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
917 value = _POSIX_VDISABLE;
918 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
922 value = arg[1] & ~0140; /* Non-letters get weird results. */
924 value = parse_number(arg, stty_suffixes);
925 mode->c_cc[info->offset] = value;
929 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
933 baud = string_to_baud(arg);
934 if (type == input_speed || type == both_speeds)
935 cfsetispeed(mode, baud);
936 if (type == output_speed || type == both_speeds)
937 cfsetospeed(mode, baud);
942 static int get_win_size(int fd, struct winsize *win)
944 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
950 set_window_size(int rows, int cols, int fd, const char *device_name)
954 if (get_win_size(fd, &win)) {
956 perror_msg_and_die("%s", device_name);
957 memset(&win, 0, sizeof(win));
966 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
967 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
968 This comment from sys/ttold.h describes Sun's twisted logic - a better
969 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
970 At any rate, the problem is gone in Solaris 2.x. */
972 if (win.ws_row == 0 || win.ws_col == 0) {
973 struct ttysize ttysz;
975 ttysz.ts_lines = win.ws_row;
976 ttysz.ts_cols = win.ws_col;
981 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
982 perror_msg_and_die("%s", device_name);
984 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz))
985 perror_msg_and_die("%s", device_name);
990 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
991 perror_msg_and_die("%s", device_name);
994 static void display_window_size(int fancy, int fd, const char *device_name)
998 if (get_win_size(fd, &win)) {
1000 perror_msg_and_die("%s", device_name);
1002 perror_msg_and_die("%s: no size information for this device",
1005 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1006 win.ws_row, win.ws_col);
1013 static int screen_columns(void)
1018 /* With Solaris 2.[123], this ioctl fails and errno is set to
1019 EINVAL for telnet (but not rlogin) sessions.
1020 On ISC 3.0, it fails for the console and the serial port
1021 (but it works for ptys).
1022 It can also fail on any system when stdout isn't a tty.
1023 In case of any failure, just use the default. */
1024 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1028 if (getenv("COLUMNS"))
1029 return atoi(getenv("COLUMNS"));
1033 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1037 return &mode->c_cflag;
1040 return &mode->c_iflag;
1043 return &mode->c_oflag;
1046 return &mode->c_lflag;
1048 default: /* combination: */
1054 display_settings(enum output_type output_type, struct termios *mode,
1055 int fd, const char *device_name)
1057 switch (output_type) {
1059 display_changed(mode);
1063 display_all(mode, fd, device_name);
1067 display_recoverable(mode);
1072 static void display_changed(struct termios *mode)
1078 enum mode_type prev_type = control;
1080 display_speed(mode, 1);
1082 wrapf("line = %d;", mode->c_line);
1088 for (i = 0; control_info[i].name != stty_min; ++i) {
1089 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1091 /* If swtch is the same as susp, don't print both. */
1093 if (control_info[i].name == stty_swtch)
1096 /* If eof uses the same slot as min, only print whichever applies. */
1098 if ((mode->c_lflag & ICANON) == 0
1099 && (control_info[i].name == stty_eof
1100 || control_info[i].name == stty_eol)) continue;
1104 wrapf("%s = %s;", control_info[i].name,
1105 visible(mode->c_cc[control_info[i].offset]));
1107 if ((mode->c_lflag & ICANON) == 0) {
1108 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1109 (int) mode->c_cc[VTIME]);
1110 } else if (empty_line == 0)
1115 for (i = 0; i < NUM_mode_info; ++i) {
1116 if (mode_info[i].flags & OMIT)
1118 if (mode_info[i].type != prev_type) {
1119 if (empty_line == 0) {
1124 prev_type = mode_info[i].type;
1127 bitsp = mode_type_flag(mode_info[i].type, mode);
1128 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1129 if ((*bitsp & mask) == mode_info[i].bits) {
1130 if (mode_info[i].flags & SANE_UNSET) {
1131 wrapf("%s", mode_info[i].name);
1135 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1137 wrapf("-%s", mode_info[i].name);
1141 if (empty_line == 0)
1147 display_all(struct termios *mode, int fd, const char *device_name)
1152 enum mode_type prev_type = control;
1154 display_speed(mode, 1);
1156 display_window_size(1, fd, device_name);
1159 wrapf("line = %d;", mode->c_line);
1164 for (i = 0; control_info[i].name != stty_min; ++i) {
1165 /* If swtch is the same as susp, don't print both. */
1167 if (control_info[i].name == stty_swtch)
1170 /* If eof uses the same slot as min, only print whichever applies. */
1172 if ((mode->c_lflag & ICANON) == 0
1173 && (control_info[i].name == stty_eof
1174 || control_info[i].name == stty_eol)) continue;
1176 wrapf("%s = %s;", control_info[i].name,
1177 visible(mode->c_cc[control_info[i].offset]));
1180 if ((mode->c_lflag & ICANON) == 0)
1182 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1183 if (current_col != 0)
1187 for (i = 0; i < NUM_mode_info; ++i) {
1188 if (mode_info[i].flags & OMIT)
1190 if (mode_info[i].type != prev_type) {
1193 prev_type = mode_info[i].type;
1196 bitsp = mode_type_flag(mode_info[i].type, mode);
1197 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1198 if ((*bitsp & mask) == mode_info[i].bits)
1199 wrapf("%s", mode_info[i].name);
1200 else if (mode_info[i].flags & REV)
1201 wrapf("-%s", mode_info[i].name);
1207 static void display_speed(struct termios *mode, int fancy)
1209 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode))
1210 wrapf(fancy ? "speed %lu baud;" : "%lu\n",
1211 baud_to_value(cfgetospeed(mode)));
1213 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1214 baud_to_value(cfgetispeed(mode)),
1215 baud_to_value(cfgetospeed(mode)));
1220 static void display_recoverable(struct termios *mode)
1224 printf("%lx:%lx:%lx:%lx",
1225 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1226 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1227 for (i = 0; i < NCCS; ++i)
1228 printf(":%x", (unsigned int) mode->c_cc[i]);
1232 static int recover_mode(char *arg, struct termios *mode)
1236 unsigned long iflag, oflag, cflag, lflag;
1238 /* Scan into temporaries since it is too much trouble to figure out
1239 the right format for `tcflag_t'. */
1240 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1241 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1243 mode->c_iflag = iflag;
1244 mode->c_oflag = oflag;
1245 mode->c_cflag = cflag;
1246 mode->c_lflag = lflag;
1248 for (i = 0; i < NCCS; ++i) {
1249 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1251 mode->c_cc[i] = chr;
1255 /* Fail if there are too many fields. */
1263 speed_t speed; /* Internal form. */
1264 unsigned long value; /* Numeric value. */
1267 static const struct speed_map speeds[] = {
1298 static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
1300 static speed_t string_to_baud(const char *arg)
1304 for (i = 0; i < NUM_SPEEDS; ++i)
1305 if (parse_number(arg, 0) == speeds[i].value)
1306 return speeds[i].speed;
1307 return (speed_t) - 1;
1310 static unsigned long baud_to_value(speed_t speed)
1314 for (i = 0; i < NUM_SPEEDS; ++i)
1315 if (speed == speeds[i].speed)
1316 return speeds[i].value;
1320 static void sane_mode(struct termios *mode)
1325 for (i = 0; i < NUM_control_info; ++i) {
1327 if (control_info[i].name == stty_min)
1330 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1333 for (i = 0; i < NUM_mode_info; ++i) {
1334 if (mode_info[i].flags & SANE_SET) {
1335 bitsp = mode_type_flag(mode_info[i].type, mode);
1336 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1337 } else if (mode_info[i].flags & SANE_UNSET) {
1338 bitsp = mode_type_flag(mode_info[i].type, mode);
1339 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1344 /* Return a string that is the printable representation of character CH. */
1345 /* Adapted from `cat' by Torbjorn Granlund. */
1347 static const char *visible(unsigned int ch)
1349 static char buf[10];
1352 if (ch == _POSIX_VDISABLE)
1358 else if (ch == 127) {
1362 *bpout++ = 'M', *bpout++ = '-';
1363 if (ch >= 128 + 32) {
1365 *bpout++ = ch - 128;
1372 *bpout++ = ch - 128 + 64;
1380 return (const char *) buf;
1385 const char *applet_name = "stty";
1391 c-file-style: "linux"