diff options
author | Jim Meyering <jim@meyering.net> | 1992-11-01 05:44:29 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1992-11-01 05:44:29 +0000 |
commit | ccbd1d7dc5189f4637468a8136f672e60ee0e531 (patch) | |
tree | f07938daa9443c4a699efa77d88eb9eb2c2e663b /src/stty.c | |
parent | 144b82c6c22abaa2a3247dc33b286662a7aa90d9 (diff) | |
download | coreutils-ccbd1d7dc5189f4637468a8136f672e60ee0e531.tar.xz |
Initial revision
Diffstat (limited to 'src/stty.c')
-rw-r--r-- | src/stty.c | 1241 |
1 files changed, 1241 insertions, 0 deletions
diff --git a/src/stty.c b/src/stty.c new file mode 100644 index 000000000..5349af0f2 --- /dev/null +++ b/src/stty.c @@ -0,0 +1,1241 @@ +/* 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 <djm@gnu.ai.mit.edu> */ + +#include <stdio.h> +#include <sys/types.h> +#include <termios.h> +#ifdef _AIX +#include <sys/ioctl.h> /* Needed to get window size. */ +#endif +#ifdef WINSIZE_IN_PTEM +#include <sys/stream.h> +#include <sys/ptem.h> +#endif +#include <getopt.h> +#ifdef __STDC__ +#include <stdarg.h> +#define VA_START(args, lastarg) va_start(args, lastarg) +#else +#include <varargs.h> +#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. */ +}; + +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. */ + +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. */ +int max_col; + +/* Current position, to know when to wrap. */ +int current_col; + +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 "<undef>"; + + 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; +} |