summaryrefslogtreecommitdiff
path: root/src/stty.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1992-11-01 05:44:29 +0000
committerJim Meyering <jim@meyering.net>1992-11-01 05:44:29 +0000
commitccbd1d7dc5189f4637468a8136f672e60ee0e531 (patch)
treef07938daa9443c4a699efa77d88eb9eb2c2e663b /src/stty.c
parent144b82c6c22abaa2a3247dc33b286662a7aa90d9 (diff)
downloadcoreutils-ccbd1d7dc5189f4637468a8136f672e60ee0e531.tar.xz
Initial revision
Diffstat (limited to 'src/stty.c')
-rw-r--r--src/stty.c1241
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;
+}