/* stty -- change and print terminal line settings Copyright (C) 1990, 1991 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Usage: stty [-ag] [--all] [--save] [setting...] Options: -a, --all Write all current settings to stdout in human-readable form. -g, --save Write all current settings to stdout in stty-readable form. If no args are given, write to stdout the baud rate and settings that have been changed from their defaults. Mode reading and changes are done on stdin. David MacKenzie */ #include #include #include #ifdef _AIX #include /* Needed to get window size. */ #endif #ifdef WINSIZE_IN_PTEM #include #include #endif #include #ifdef __STDC__ #include #define VA_START(args, lastarg) va_start(args, lastarg) #else #include #define VA_START(args, lastarg) va_start(args) #endif #include "system.h" #if defined(GWINSZ_BROKEN) /* Such as for SCO UNIX 3.2.2. */ #undef TIOCGWINSZ #endif #ifndef _POSIX_VDISABLE #define _POSIX_VDISABLE ((unsigned char) 0) #endif #define Control(c) ((c) & 0x1f) /* Canonical values for control characters. */ #ifndef CINTR #define CINTR Control ('c') #endif #ifndef CQUIT #define CQUIT 28 #endif #ifndef CERASE #define CERASE 127 #endif #ifndef CKILL #define CKILL Control ('u') #endif #ifndef CEOF #define CEOF Control ('d') #endif #ifndef CEOL #define CEOL _POSIX_VDISABLE #endif #ifndef CSTART #define CSTART Control ('q') #endif #ifndef CSTOP #define CSTOP Control ('s') #endif #ifndef CSUSP #define CSUSP Control ('z') #endif #if defined(VEOL2) && !defined(CEOL2) #define CEOL2 _POSIX_VDISABLE #endif #if defined(VSWTCH) && !defined(CSWTCH) #define CSWTCH _POSIX_VDISABLE #endif #if defined(VDSUSP) && !defined (CDSUSP) #define CDSUSP Control ('y') #endif #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */ #define VREPRINT VRPRNT #endif #if defined(VREPRINT) && !defined(CRPRNT) #define CRPRNT Control ('r') #endif #if defined(VWERASE) && !defined(CWERASE) #define CWERASE Control ('w') #endif #if defined(VLNEXT) && !defined(CLNEXT) #define CLNEXT Control ('v') #endif char *visible (); unsigned long baud_to_value (); int recover_mode (); int screen_columns (); int set_mode (); long integer_arg (); speed_t string_to_baud (); tcflag_t *mode_type_flag (); void display_all (); void display_changed (); void display_recoverable (); void display_settings (); void display_speed (); void display_window_size (); void error (); void sane_mode (); void set_control_char (); void set_speed (); void set_window_size (); /* Which speeds to set. */ enum speed_setting { input_speed, output_speed, both_speeds }; /* What to output and how. */ enum output_type { changed, all, recoverable /* Default, -a, -g. */ }; /* Which member(s) of `struct termios' a mode uses. */ enum mode_type { control, input, output, local, combination }; /* Flags for `struct mode_info'. */ #define SANE_SET 1 /* Set in `sane' mode. */ #define SANE_UNSET 2 /* Unset in `sane' mode. */ #define REV 4 /* Can be turned off by prepending `-'. */ #define OMIT 8 /* Don't display value. */ /* Each mode. */ struct mode_info { char *name; /* Name given on command line. */ enum mode_type type; /* Which structure element to change. */ char flags; /* Setting and display options. */ unsigned long bits; /* Bits to set for this mode. */ unsigned long mask; /* Other bits to turn off for this mode. */ }; static struct mode_info mode_info[] = { {"parenb", control, REV, PARENB, 0}, {"parodd", control, REV, PARODD, 0}, {"cs5", control, 0, CS5, CSIZE}, {"cs6", control, 0, CS6, CSIZE}, {"cs7", control, 0, CS7, CSIZE}, {"cs8", control, 0, CS8, CSIZE}, {"hupcl", control, REV, HUPCL, 0}, {"hup", control, REV | OMIT, HUPCL, 0}, {"cstopb", control, REV, CSTOPB, 0}, {"cread", control, SANE_SET | REV, CREAD, 0}, {"clocal", control, REV, CLOCAL, 0}, #ifdef CRTSCTS {"crtscts", control, REV, CRTSCTS, 0}, #endif {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0}, {"brkint", input, SANE_SET | REV, BRKINT, 0}, {"ignpar", input, REV, IGNPAR, 0}, {"parmrk", input, REV, PARMRK, 0}, {"inpck", input, REV, INPCK, 0}, {"istrip", input, REV, ISTRIP, 0}, {"inlcr", input, SANE_UNSET | REV, INLCR, 0}, {"igncr", input, SANE_UNSET | REV, IGNCR, 0}, {"icrnl", input, SANE_SET | REV, ICRNL, 0}, {"ixon", input, REV, IXON, 0}, {"ixoff", input, SANE_UNSET | REV, IXOFF, 0}, {"tandem", input, REV | OMIT, IXOFF, 0}, #ifdef IUCLC {"iuclc", input, SANE_UNSET | REV, IUCLC, 0}, #endif #ifdef IXANY {"ixany", input, SANE_UNSET | REV, IXANY, 0}, #endif #ifdef IMAXBEL {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0}, #endif {"opost", output, SANE_SET | REV, OPOST, 0}, #ifdef OLCUC {"olcuc", output, SANE_UNSET | REV, OLCUC, 0}, #endif #ifdef OCRNL {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0}, #endif #ifdef ONLCR {"onlcr", output, SANE_SET | REV, ONLCR, 0}, #endif #ifdef ONOCR {"onocr", output, SANE_UNSET | REV, ONOCR, 0}, #endif #ifdef ONLRET {"onlret", output, SANE_UNSET | REV, ONLRET, 0}, #endif #ifdef OFILL {"ofill", output, SANE_UNSET | REV, OFILL, 0}, #endif #ifdef OFDEL {"ofdel", output, SANE_UNSET | REV, OFDEL, 0}, #endif #ifdef NLDLY {"nl1", output, SANE_UNSET, NL1, NLDLY}, {"nl0", output, SANE_SET, NL0, NLDLY}, #endif #ifdef CRDLY {"cr3", output, SANE_UNSET, CR3, CRDLY}, {"cr2", output, SANE_UNSET, CR2, CRDLY}, {"cr1", output, SANE_UNSET, CR1, CRDLY}, {"cr0", output, SANE_SET, CR0, CRDLY}, #endif #ifdef TABDLY {"tab3", output, SANE_UNSET, TAB3, TABDLY}, {"tab2", output, SANE_UNSET, TAB2, TABDLY}, {"tab1", output, SANE_UNSET, TAB1, TABDLY}, {"tab0", output, SANE_SET, TAB0, TABDLY}, #endif #ifdef BSDLY {"bs1", output, SANE_UNSET, BS1, BSDLY}, {"bs0", output, SANE_SET, BS0, BSDLY}, #endif #ifdef VTDLY {"vt1", output, SANE_UNSET, VT1, VTDLY}, {"vt0", output, SANE_SET, VT0, VTDLY}, #endif #ifdef FFDLY {"ff1", output, SANE_UNSET, FF1, FFDLY}, {"ff0", output, SANE_SET, FF0, FFDLY}, #endif {"isig", local, SANE_SET | REV, ISIG, 0}, {"icanon", local, SANE_SET | REV, ICANON, 0}, #ifdef IEXTEN {"iexten", local, SANE_SET | REV, IEXTEN, 0}, #endif {"echo", local, SANE_SET | REV, ECHO, 0}, {"echoe", local, SANE_SET | REV, ECHOE, 0}, {"crterase", local, REV | OMIT, ECHOE, 0}, {"echok", local, SANE_SET | REV, ECHOK, 0}, {"echonl", local, SANE_UNSET | REV, ECHONL, 0}, {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0}, #ifdef XCASE {"xcase", local, SANE_UNSET | REV, XCASE, 0}, #endif #ifdef TOSTOP {"tostop", local, SANE_UNSET | REV, TOSTOP, 0}, #endif #ifdef ECHOPRT {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0}, {"prterase", local, REV | OMIT, ECHOPRT, 0}, #endif #ifdef ECHOCTL {"echoctl", local, SANE_SET | REV, ECHOCTL, 0}, {"ctlecho", local, REV | OMIT, ECHOCTL, 0}, #endif #ifdef ECHOKE {"echoke", local, SANE_SET | REV, ECHOKE, 0}, {"crtkill", local, REV | OMIT, ECHOKE, 0}, #endif {"evenp", combination, REV | OMIT, 0, 0}, {"parity", combination, REV | OMIT, 0, 0}, {"oddp", combination, REV | OMIT, 0, 0}, {"nl", combination, REV | OMIT, 0, 0}, {"ek", combination, OMIT, 0, 0}, {"sane", combination, OMIT, 0, 0}, {"cooked", combination, REV | OMIT, 0, 0}, {"raw", combination, REV | OMIT, 0, 0}, {"pass8", combination, REV | OMIT, 0, 0}, {"litout", combination, REV | OMIT, 0, 0}, {"cbreak", combination, REV | OMIT, 0, 0}, #ifdef IXANY {"decctlq", combination, REV | OMIT, 0, 0}, #endif #ifdef TABDLY {"tabs", combination, REV | OMIT, 0, 0}, #endif #if defined(XCASE) && defined(IUCLC) && defined(OLCUC) {"lcase", combination, REV | OMIT, 0, 0}, {"LCASE", combination, REV | OMIT, 0, 0}, #endif {"crt", combination, OMIT, 0, 0}, {"dec", combination, OMIT, 0, 0}, {NULL, control, 0, 0, 0} }; /* Control character settings. */ struct control_info { char *name; /* Name given on command line. */ unsigned char saneval; /* Value to set for `stty sane'. */ int offset; /* Offset in c_cc. */ }; /* Control characters. */ static struct control_info control_info[] = { {"intr", CINTR, VINTR}, {"quit", CQUIT, VQUIT}, {"erase", CERASE, VERASE}, {"kill", CKILL, VKILL}, {"eof", CEOF, VEOF}, {"eol", CEOL, VEOL}, #ifdef VEOL2 {"eol2", CEOL2, VEOL2}, #endif #ifdef VSWTCH {"swtch", CSWTCH, VSWTCH}, #endif {"start", CSTART, VSTART}, {"stop", CSTOP, VSTOP}, {"susp", CSUSP, VSUSP}, #ifdef VDSUSP {"dsusp", CDSUSP, VDSUSP}, #endif #ifdef VREPRINT {"rprnt", CRPRNT, VREPRINT}, #endif #ifdef VWERASE {"werase", CWERASE, VWERASE}, #endif #ifdef VLNEXT {"lnext", CLNEXT, VLNEXT}, #endif /* These must be last because of the display routines. */ {"min", 1, VMIN}, {"time", 0, VTIME}, {NULL, 0, 0} }; /* The width of the screen, for output wrapping. */ static int max_col; /* Current position, to know when to wrap. */ static int current_col; static struct option longopts[] = { {"all", 0, NULL, 'a'}, {"save", 0, NULL, 'g'}, {NULL, 0, NULL, 0} }; /* The name this program was run with. */ char *program_name; /* Print format string MESSAGE and optional args. Wrap to next line first if it won't fit. Print a space first unless MESSAGE will start a new line. */ /* VARARGS */ void #ifdef __STDC__ wrapf (char *message, ...) #else wrapf (message, va_alist) char *message; va_dcl #endif { va_list args; char buf[1024]; /* Plenty long for our needs. */ int buflen; VA_START (args, message); vsprintf (buf, message, args); va_end (args); buflen = strlen (buf); if (current_col + buflen >= max_col) { putchar ('\n'); current_col = 0; } if (current_col > 0) { putchar (' '); current_col++; } fputs (buf, stdout); current_col += buflen; } void main (argc, argv) int argc; char **argv; { struct termios mode; enum output_type output_type = changed; int optc; program_name = argv[0]; opterr = 0; while ((optc = getopt_long (argc, argv, "ag", longopts, (int *) 0)) != EOF) { if (optc == 'a') output_type = all; else if (optc == 'g') output_type = recoverable; else break; } if (tcgetattr (0, &mode)) error (1, errno, "standard input"); max_col = screen_columns (); current_col = 0; if (optind == argc) { if (optc == '?') error (1, 0, "invalid argument `%s'", argv[--optind]); display_settings (output_type, &mode); exit (0); } while (optind < argc) { int match_found = 0; int reversed = 0; int i; if (argv[optind][0] == '-') { ++argv[optind]; reversed = 1; } for (i = 0; mode_info[i].name != NULL; ++i) { if (!strcmp (argv[optind], mode_info[i].name)) { match_found = set_mode (&mode_info[i], reversed, &mode); break; } } if (match_found == 0 && reversed) error (1, 0, "invalid argument `%s'", --argv[optind]); if (match_found == 0) { for (i = 0; control_info[i].name != NULL; ++i) { if (!strcmp (argv[optind], control_info[i].name)) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); match_found = 1; ++optind; set_control_char (&control_info[i], argv[optind], &mode); break; } } } if (match_found == 0) { if (!strcmp (argv[optind], "ispeed")) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); ++optind; set_speed (input_speed, argv[optind], &mode); } else if (!strcmp (argv[optind], "ospeed")) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); ++optind; set_speed (output_speed, argv[optind], &mode); } #ifdef TIOCGWINSZ else if (!strcmp (argv[optind], "rows")) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); ++optind; set_window_size ((int) integer_arg (argv[optind]), -1); } else if (!strcmp (argv[optind], "cols") || !strcmp (argv[optind], "columns")) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); ++optind; set_window_size (-1, (int) integer_arg (argv[optind])); } else if (!strcmp (argv[optind], "size")) display_window_size (0); #endif #ifdef HAVE_C_LINE else if (!strcmp (argv[optind], "line")) { if (optind == argc - 1) error (1, 0, "missing argument to `%s'", argv[optind]); ++optind; mode.c_line = integer_arg (argv[optind]); } #endif else if (!strcmp (argv[optind], "speed")) display_speed (&mode, 0); else if (string_to_baud (argv[optind]) != (speed_t) -1) set_speed (both_speeds, argv[optind], &mode); else if (recover_mode (argv[optind], &mode) == 0) error (1, 0, "invalid argument `%s'", argv[optind]); } optind++; } if (tcsetattr (0, TCSADRAIN, &mode)) error (1, errno, "standard input"); exit (0); } /* Return 0 if not applied because not reversible; otherwise return 1. */ int set_mode (info, reversed, mode) struct mode_info *info; int reversed; struct termios *mode; { tcflag_t *bitsp; if (reversed && (info->flags & REV) == 0) return 0; bitsp = mode_type_flag (info->type, mode); if (bitsp == NULL) { /* Combination mode. */ if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity")) { if (reversed) mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; else mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; } else if (!strcmp (info->name, "oddp")) { if (reversed) mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; else mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; } else if (!strcmp (info->name, "nl")) { if (reversed) { mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; mode->c_oflag = (mode->c_oflag #ifdef ONLCR | ONLCR #endif ) #ifdef OCRNL & ~OCRNL #endif #ifdef ONLRET & ~ONLRET #endif ; } else { mode->c_iflag = mode->c_iflag & ~ICRNL; #ifdef ONLCR mode->c_oflag = mode->c_oflag & ~ONLCR; #endif } } else if (!strcmp (info->name, "ek")) { mode->c_cc[VERASE] = CERASE; mode->c_cc[VKILL] = CKILL; } else if (!strcmp (info->name, "sane")) sane_mode (mode); else if (!strcmp (info->name, "cbreak")) { if (reversed) mode->c_lflag |= ICANON; else mode->c_lflag &= ~ICANON; } else if (!strcmp (info->name, "pass8")) { if (reversed) { mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; mode->c_iflag |= ISTRIP; } else { mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; mode->c_iflag &= ~ISTRIP; } } else if (!strcmp (info->name, "litout")) { if (reversed) { mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; mode->c_iflag |= ISTRIP; mode->c_oflag |= OPOST; } else { mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; mode->c_iflag &= ~ISTRIP; mode->c_oflag &= ~OPOST; } } else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked")) { if ((info->name[0] == 'r' && reversed) || (info->name[0] == 'c' && !reversed)) { /* Cooked mode. */ mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; mode->c_oflag |= OPOST; mode->c_lflag |= ISIG | ICANON; #if VMIN == VEOF mode->c_cc[VEOF] = CEOF; #endif #if VTIME == VEOL mode->c_cc[VEOL] = CEOL; #endif } else { /* Raw mode. */ mode->c_iflag = 0; mode->c_oflag &= ~OPOST; mode->c_lflag &= ~(ISIG | ICANON #ifdef XCASE | XCASE #endif ); mode->c_cc[VMIN] = 1; mode->c_cc[VTIME] = 0; } } #ifdef IXANY else if (!strcmp (info->name, "decctlq")) { if (reversed) mode->c_iflag |= IXANY; else mode->c_iflag &= ~IXANY; } #endif #ifdef TABDLY else if (!strcmp (info->name, "tabs")) { if (reversed) mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; else mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; } #endif #if defined(XCASE) && defined(IUCLC) && defined(OLCUC) else if (!strcmp (info->name, "lcase") || !strcmp (info->name, "LCASE")) { if (reversed) { mode->c_lflag &= ~XCASE; mode->c_iflag &= ~IUCLC; mode->c_oflag &= ~OLCUC; } else { mode->c_lflag |= XCASE; mode->c_iflag |= IUCLC; mode->c_oflag |= OLCUC; } } #endif else if (!strcmp (info->name, "crt")) mode->c_lflag |= ECHOE #ifdef ECHOCTL | ECHOCTL #endif #ifdef ECHOKE | ECHOKE #endif ; else if (!strcmp (info->name, "dec")) { mode->c_cc[VINTR] = 3; /* ^C */ mode->c_cc[VERASE] = 127; /* DEL */ mode->c_cc[VKILL] = 21; /* ^U */ mode->c_lflag |= ECHOE #ifdef ECHOCTL | ECHOCTL #endif #ifdef ECHOKE | ECHOKE #endif ; #ifdef IXANY mode->c_iflag &= ~IXANY; #endif } } else if (reversed) *bitsp = *bitsp & ~info->mask & ~info->bits; else *bitsp = (*bitsp & ~info->mask) | info->bits; return 1; } void set_control_char (info, arg, mode) struct control_info *info; char *arg; struct termios *mode; { unsigned char value; if (!strcmp (info->name, "min") || !strcmp (info->name, "time")) value = integer_arg (arg); else if (arg[0] == '\0' || arg[1] == '\0') value = arg[0]; else if (!strcmp (arg, "^-") || !strcmp (arg, "undef")) value = _POSIX_VDISABLE; else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */ { if (arg[1] == '?') value = 127; else value = arg[1] & ~0140; /* Non-letters get weird results. */ } else value = integer_arg (arg); mode->c_cc[info->offset] = value; } void set_speed (type, arg, mode) enum speed_setting type; char *arg; struct termios *mode; { speed_t baud; baud = string_to_baud (arg); if (type == input_speed || type == both_speeds) cfsetispeed (mode, baud); if (type == output_speed || type == both_speeds) cfsetospeed (mode, baud); } #ifdef TIOCGWINSZ void set_window_size (rows, cols) int rows, cols; { struct winsize win; if (ioctl (0, TIOCGWINSZ, (char *) &win)) error (1, errno, "standard input"); if (rows >= 0) win.ws_row = rows; if (cols >= 0) win.ws_col = cols; if (ioctl (0, TIOCSWINSZ, (char *) &win)) error (1, errno, "standard input"); } void display_window_size (fancy) int fancy; { struct winsize win; if (ioctl (0, TIOCGWINSZ, (char *) &win)) error (1, errno, "standard input"); wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n", win.ws_row, win.ws_col); if (!fancy) current_col = 0; } #endif int screen_columns () { #ifdef TIOCGWINSZ struct winsize win; if (ioctl (0, TIOCGWINSZ, (char *) &win)) error (1, errno, "standard input"); if (win.ws_col > 0) return win.ws_col; #endif if (getenv ("COLUMNS")) return atoi (getenv ("COLUMNS")); return 80; } tcflag_t * mode_type_flag (type, mode) enum mode_type type; struct termios *mode; { switch (type) { case control: return &mode->c_cflag; case input: return &mode->c_iflag; case output: return &mode->c_oflag; case local: return &mode->c_lflag; case combination: return NULL; } } void display_settings (output_type, mode) enum output_type output_type; struct termios *mode; { switch (output_type) { case changed: display_changed (mode); break; case all: display_all (mode); break; case recoverable: display_recoverable (mode); break; } } void display_changed (mode) struct termios *mode; { int i; int empty_line; tcflag_t *bitsp; unsigned long mask; enum mode_type prev_type = control; display_speed (mode, 1); #ifdef HAVE_C_LINE wrapf ("line = %d;", mode->c_line); #endif putchar ('\n'); current_col = 0; empty_line = 1; for (i = 0; strcmp (control_info[i].name, "min"); ++i) { if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) continue; empty_line = 0; wrapf ("%s = %s;", control_info[i].name, visible (mode->c_cc[control_info[i].offset])); } if ((mode->c_lflag & ICANON) == 0) { wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], (int) mode->c_cc[VTIME]); } else if (empty_line == 0) putchar ('\n'); current_col = 0; empty_line = 1; for (i = 0; mode_info[i].name != NULL; ++i) { if (mode_info[i].flags & OMIT) continue; if (mode_info[i].type != prev_type) { if (empty_line == 0) { putchar ('\n'); current_col = 0; empty_line = 1; } prev_type = mode_info[i].type; } bitsp = mode_type_flag (mode_info[i].type, mode); mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; if ((*bitsp & mask) == mode_info[i].bits) { if (mode_info[i].flags & SANE_UNSET) { wrapf ("%s", mode_info[i].name); empty_line = 0; } } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) { wrapf ("-%s", mode_info[i].name); empty_line = 0; } } if (empty_line == 0) putchar ('\n'); current_col = 0; } void display_all (mode) struct termios *mode; { int i; tcflag_t *bitsp; unsigned long mask; enum mode_type prev_type = control; display_speed (mode, 1); #ifdef TIOCGWINSZ display_window_size (1); #endif #ifdef HAVE_C_LINE wrapf ("line = %d;", mode->c_line); #endif putchar ('\n'); current_col = 0; for (i = 0; strcmp (control_info[i].name, "min"); ++i) { wrapf ("%s = %s;", control_info[i].name, visible (mode->c_cc[control_info[i].offset])); } wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]); current_col = 0; for (i = 0; mode_info[i].name != NULL; ++i) { if (mode_info[i].flags & OMIT) continue; if (mode_info[i].type != prev_type) { putchar ('\n'); current_col = 0; prev_type = mode_info[i].type; } bitsp = mode_type_flag (mode_info[i].type, mode); mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; if ((*bitsp & mask) == mode_info[i].bits) wrapf ("%s", mode_info[i].name); else if (mode_info[i].flags & REV) wrapf ("-%s", mode_info[i].name); } putchar ('\n'); current_col = 0; } void display_speed (mode, fancy) struct termios *mode; int fancy; { if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode)) wrapf (fancy ? "speed %lu baud;" : "%lu\n", baud_to_value (cfgetospeed (mode))); else wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", baud_to_value (cfgetispeed (mode)), baud_to_value (cfgetospeed (mode))); if (!fancy) current_col = 0; } void display_recoverable (mode) struct termios *mode; { int i; printf ("%lx:%lx:%lx:%lx", (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); for (i = 0; i < NCCS; ++i) printf (":%x", (unsigned int) mode->c_cc[i]); putchar ('\n'); } int recover_mode (arg, mode) char *arg; struct termios *mode; { int i, n; unsigned int chr; unsigned long iflag, oflag, cflag, lflag; /* Scan into temporaries since it is too much trouble to figure out the right format for `tcflag_t'. */ if (sscanf (arg, "%lx:%lx:%lx:%lx%n", &iflag, &oflag, &cflag, &lflag, &n) != 4) return 0; mode->c_iflag = iflag; mode->c_oflag = oflag; mode->c_cflag = cflag; mode->c_lflag = lflag; arg += n; for (i = 0; i < NCCS; ++i) { if (sscanf (arg, ":%x%n", &chr, &n) != 1) return 0; mode->c_cc[i] = chr; arg += n; } return 1; } struct speed_map { char *string; /* ASCII representation. */ speed_t speed; /* Internal form. */ unsigned long value; /* Numeric value. */ }; struct speed_map speeds[] = { {"0", B0, 0}, {"50", B50, 50}, {"75", B75, 75}, {"110", B110, 110}, {"134", B134, 134}, {"134.5", B134, 134}, {"150", B150, 150}, {"200", B200, 200}, {"300", B300, 300}, {"600", B600, 600}, {"1200", B1200, 1200}, {"1800", B1800, 1800}, {"2400", B2400, 2400}, {"4800", B4800, 4800}, {"9600", B9600, 9600}, {"19200", B19200, 19200}, {"38400", B38400, 38400}, {"exta", B19200, 19200}, {"extb", B38400, 38400}, #ifdef B57600 {"57600", B57600, 57600}, #endif #ifdef B115200 {"115200", B115200, 115200}, #endif {NULL, 0, 0} }; speed_t string_to_baud (arg) char *arg; { int i; for (i = 0; speeds[i].string != NULL; ++i) if (!strcmp (arg, speeds[i].string)) return speeds[i].speed; return (speed_t) -1; } unsigned long baud_to_value (speed) speed_t speed; { int i; for (i = 0; speeds[i].string != NULL; ++i) if (speed == speeds[i].speed) return speeds[i].value; return 0; } void sane_mode (mode) struct termios *mode; { int i; tcflag_t *bitsp; for (i = 0; control_info[i].name; ++i) { #if VMIN == VEOF if (!strcmp (control_info[i].name, "min")) break; #endif mode->c_cc[control_info[i].offset] = control_info[i].saneval; } for (i = 0; mode_info[i].name != NULL; ++i) { if (mode_info[i].flags & SANE_SET) { bitsp = mode_type_flag (mode_info[i].type, mode); *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; } else if (mode_info[i].flags & SANE_UNSET) { bitsp = mode_type_flag (mode_info[i].type, mode); *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; } } } /* Return a string that is the printable representation of character CH. */ /* Adapted from `cat' by Torbjorn Granlund. */ char * visible (ch) unsigned char ch; { static char buf[10]; char *bpout = buf; if (ch == _POSIX_VDISABLE) return ""; if (ch >= 32) { if (ch < 127) *bpout++ = ch; else if (ch == 127) { *bpout++ = '^'; *bpout++ = '?'; } else { *bpout++ = 'M', *bpout++ = '-'; if (ch >= 128 + 32) { if (ch < 128 + 127) *bpout++ = ch - 128; else { *bpout++ = '^'; *bpout++ = '?'; } } else { *bpout++ = '^'; *bpout++ = ch - 128 + 64; } } } else { *bpout++ = '^'; *bpout++ = ch + 64; } *bpout = '\0'; return buf; } /* Parse string S as an integer, using decimal radix by default, but allowing octal and hex numbers as in C. */ /* From `od' by Richard Stallman. */ long integer_arg (s) char *s; { long value; int radix = 10; char *p = s; int c; if (*p != '0') radix = 10; else if (*++p == 'x') { radix = 16; p++; } else radix = 8; value = 0; while (((c = *p++) >= '0' && c <= '9') || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z')) { value *= radix; if (c >= '0' && c <= '9') value += c - '0'; else value += (c & ~40) - 'A'; } if (c == 'b') value *= 512; else if (c == 'B') value *= 1024; else p--; if (*p) error (1, 0, "invalid integer argument `%s'", s); return value; }