1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1992-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * stty.c
1N/A * Written by David Korn
1N/A * Tue Apr 4 10:46:00 EDT 1995
1N/A */
1N/A
1N/Astatic const char usage[] =
1N/A"[-?@(#)$Id: stty (AT&T Research) 2010-04-01 $\n]"
1N/AUSAGE_LICENSE
1N/A"[+NAME?stty - set or get terminal modes]"
1N/A"[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device "
1N/A "that is the current standard input; without arguments, it writes the "
1N/A "settings of certain modes to standard output.]"
1N/A"[a:all?Writes to standard output all of the mode settings.]"
1N/A"[f|F:fd|file?Use \afd\a as the terminal fd.]#[fd:=0]"
1N/A"[g:save?Writes the current settings to standard output in a form that "
1N/A "can be used as an argument to another \bstty\b command. The \brows\b "
1N/A "and \bcolumns\b values are not included.]"
1N/A"[t:terminal-group?Print the terminal group id of the device, -1 if "
1N/A "unknown.]"
1N/A"\n"
1N/A"\n[mode ...]\n"
1N/A"\n"
1N/A"[+EXTENDED DESCRIPTION?Modes are specified either as a single name or "
1N/A "as a name followed by a value. As indicated below, many of the mode "
1N/A "names can be preceded by a \b-\b to negate its meaning. Modes are "
1N/A "listed by group corresponding to field in the \btermios\b structure "
1N/A "defined in \b<termios.h>\b. Modes in the last group are implemented "
1N/A "using options in the previous groups. Note that many combinations of "
1N/A "modes make no sense, but no sanity checking is performed. The modes are "
1N/A "selected from the following:]"
1N/A "{\fabc\f}"
1N/A"[+EXIT STATUS?]"
1N/A "{"
1N/A "[+0?All modes reported or set successfully.]"
1N/A "[+>0?Standard input not a terminaol or one or more modes "
1N/A "failed.]"
1N/A "}"
1N/A"[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]"
1N/A;
1N/A
1N/A#include <cmd.h>
1N/A#include <ccode.h>
1N/A#include <ctype.h>
1N/A#include <ast_tty.h>
1N/A#if _sys_ioctl
1N/A#include <sys/ioctl.h>
1N/A#endif
1N/A
1N/A#define C(x) ERROR_catalog(x)
1N/A
1N/A#ifndef _POSIX_VDISABLE
1N/A# define _POSIX_VDISABLE 0
1N/A#endif
1N/A
1N/A#ifndef NCCS
1N/A# ifdef NCC
1N/A# define NCCS NCC
1N/A# else
1N/A# define NCCS elementsof(((struct termio*)0)->c_cc)
1N/A# endif
1N/A#endif
1N/A
1N/A/* command options */
1N/A#define A_FLAG 1
1N/A#define G_FLAG 2
1N/A#define T_FLAG 4
1N/A
1N/A/* termios fields */
1N/A#define C_FLAG 1
1N/A#define C_LINE 2
1N/A#define C_SPEED 3
1N/A#define I_FLAG 4
1N/A#define O_FLAG 5
1N/A#define L_FLAG 6
1N/A#define T_CHAR 7
1N/A#define W_SIZE 8
1N/A
1N/A#define BIT 1
1N/A#define BITS 2
1N/A#define NUM 3
1N/A#define CHAR 4
1N/A#define SPEED 5
1N/A#define SIZE 6
1N/A#define MIXED 7
1N/A#define SANE 8
1N/A#define COOKED 9
1N/A#define CASE 10
1N/A#define TABS 11
1N/A#define WIND 12
1N/A
1N/A#undef SS /* who co-opted this namespace? */
1N/A
1N/A#define IG 0x0001 /* ignore display */
1N/A#define NL 0x0002 /* entry ends line of display */
1N/A#define SS 0x0004 /* set in sane mode */
1N/A#define US 0x0010 /* unset in sane mode */
1N/A
1N/Atypedef struct tty_s
1N/A{
1N/A const char name[8];
1N/A unsigned char type;
1N/A unsigned char field;
1N/A short flags;
1N/A unsigned long mask;
1N/A unsigned long val;
1N/A const char description[76];
1N/A} Tty_t;
1N/A
1N/Astatic const Tty_t Ttable[] =
1N/A{
1N/A#ifdef CBAUD
1N/A{ "ispeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the input baud rate") },
1N/A{ "ospeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the output baud rate") },
1N/A{ "speed", NUM, C_SPEED,IG, CBAUD },
1N/A#endif
1N/A{ "0", SPEED, C_FLAG, 0, B0 },
1N/A{ "50", SPEED, C_FLAG, 0, B50 },
1N/A{ "75", SPEED, C_FLAG, 0, B75 },
1N/A{ "110", SPEED, C_FLAG, 0, B110 },
1N/A{ "134", SPEED, C_FLAG, 0, B134 },
1N/A{ "150", SPEED, C_FLAG, 0, B150 },
1N/A{ "200", SPEED, C_FLAG, 0, B200 },
1N/A{ "300", SPEED, C_FLAG, 0, B300 },
1N/A{ "600", SPEED, C_FLAG, 0, B600 },
1N/A{ "1200", SPEED, C_FLAG, 0, B1200 },
1N/A{ "1800", SPEED, C_FLAG, 0, B1800 },
1N/A{ "2400", SPEED, C_FLAG, 0, B2400 },
1N/A{ "4800", SPEED, C_FLAG, 0, B4800 },
1N/A{ "9600", SPEED, C_FLAG, 0, B9600 },
1N/A{ "19200", SPEED, C_FLAG, 0, B19200 },
1N/A{ "38400", SPEED, C_FLAG, 0, B38400 },
1N/A
1N/A#ifdef TIOCSWINSZ
1N/A{ "rows", WIND, W_SIZE, IG, 0, 24, C("\an\a is the number of lines for display") },
1N/A{ "cols", WIND, W_SIZE, IG, 1, 80, C("\an\a is the number of columns for display") },
1N/A{ "columns", WIND, W_SIZE, IG, 1, 80, C("Same as \bcols\b") },
1N/A#endif
1N/A{ "intr", CHAR, T_CHAR, SS, VINTR, 'C', C("Send an interrupt signal") },
1N/A{ "quit", CHAR, T_CHAR, SS, VQUIT, '|', C("Send a quit signal") },
1N/A{ "erase", CHAR, T_CHAR, SS, VERASE, 'H', C("Erase the last character entered") },
1N/A{ "kill", CHAR, T_CHAR, NL|SS, VKILL, 'U', C("Erase the current line") },
1N/A{ "eof", CHAR, T_CHAR, SS, VEOF, 'D', C("Send an end of file") },
1N/A#ifdef VEOL2
1N/A{ "eol2", CHAR, T_CHAR, US, VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") },
1N/A#endif /* VEOL2 */
1N/A#ifdef VSWTCH
1N/A{ "swtch", CHAR, T_CHAR, US, VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") },
1N/A#endif /* VSWTCH */
1N/A{ "eol", CHAR, T_CHAR, NL|US, VEOL, _POSIX_VDISABLE, C("End the line") },
1N/A#ifdef VSTART
1N/A{ "start", CHAR, T_CHAR, SS, VSTART, 'Q', C("Restart the output after stopping it") },
1N/A#endif /* VSTART */
1N/A#ifdef VSTOP
1N/A{ "stop", CHAR, T_CHAR, SS, VSTOP, 'S', C("Stop the output") },
1N/A#endif /* VSTOP */
1N/A#ifdef VDSUSP
1N/A{ "dsusp", CHAR, T_CHAR, SS, VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") },
1N/A#endif /* VDSUSP */
1N/A#ifdef VSUSP
1N/A{ "susp", CHAR, T_CHAR, NL|SS, VSUSP, 'Z', C("Send a terminal stop signal") },
1N/A#endif /* VSUSP */
1N/A#ifdef VREPRINT
1N/A{ "rprnt", CHAR, T_CHAR, SS, VREPRINT, 'R', C("Redraw the current line") },
1N/A#endif /* VREPRINT */
1N/A#ifdef VDISCARD
1N/A{ "flush", CHAR, T_CHAR, SS, VDISCARD, 'O', C("Discard output") },
1N/A#endif /* VDISCARD */
1N/A#ifdef VWERASE
1N/A{ "werase", CHAR, T_CHAR, SS, VWERASE, 'W', C("Erase the last word entered") },
1N/A#endif /* VWERASE */
1N/A#ifdef VLNEXT
1N/A{ "lnext", CHAR, T_CHAR, NL|SS, VLNEXT, 'V', C("Enter the next input character literally") },
1N/A#endif /* VLNEXT */
1N/A
1N/A#if _mem_c_line_termios
1N/A{ "line", NUM, C_LINE, 0, 0, 0, C("Line discipline number") },
1N/A#endif
1N/A{ "min", NUM, T_CHAR, 0, VMIN, 0, C("Mininmum number of characters to read in raw mode") },
1N/A{ "time", NUM, T_CHAR, 0, VTIME, 0, C("Number of .1 second intervals with raw mode") },
1N/A
1N/A{ "parenb", BIT, C_FLAG, 0, PARENB, PARENB, C("Enable (disable) parity generation and detection") },
1N/A{ "parodd", BIT, C_FLAG, 0, PARODD, PARODD, C("Use odd (even) parity") },
1N/A#ifdef PAREXT
1N/A{ "parext", BIT, C_FLAG, 0, PAREXT, PAREXT },
1N/A#endif /* PAREXT */
1N/A#ifdef CREAD
1N/A{ "cread", BIT, C_FLAG, SS, CREAD, CREAD, C("Enable (disable) input") },
1N/A#endif /* CREAD */
1N/A{ "cs5", SIZE, C_FLAG, 0, CSIZE, CS5 , C("Char size 5") },
1N/A{ "cs6", SIZE, C_FLAG, 0, CSIZE, CS6 , C("Char size 6") },
1N/A{ "cs7", SIZE, C_FLAG, 0, CSIZE, CS7 , C("Char size 7") },
1N/A{ "cs8", SIZE, C_FLAG, 0, CSIZE, CS8 , C("Char size 8") },
1N/A{ "hupcl", BIT, C_FLAG, 0, HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") },
1N/A{ "hup", BIT, C_FLAG, IG, HUPCL, HUPCL, C("Same as \bhupcl\b") },
1N/A{ "cstopb", BIT, C_FLAG, 0, CSTOPB, CSTOPB, C("Use two (one) stop bits") },
1N/A#ifdef CRTSCTS
1N/A{ "crtscts", BIT, C_FLAG, 0, CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") },
1N/A#endif /* CRTSCTS */
1N/A{ "clocal", BIT, C_FLAG, NL, CLOCAL, CLOCAL, C("Disable (enable) modem control signals") },
1N/A
1N/A{ "ignbrk", BIT, I_FLAG, US, IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") },
1N/A{ "brkint", BIT, I_FLAG, SS, BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") },
1N/A{ "ignpar", BIT, I_FLAG, 0, IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") },
1N/A{ "parmrk", BIT, I_FLAG, 0, PARMRK, PARMRK, C("Mark (do not mark) parity errors") },
1N/A{ "inpck", BIT, I_FLAG, 0, INPCK, INPCK, C("Enable (disable) input parity checking") },
1N/A{ "istrip", BIT, I_FLAG, 0, ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") },
1N/A{ "inlcr", BIT, I_FLAG, US, INLCR, INLCR, C("Translate (do not translate) carriage return to newline") },
1N/A{ "igncr", BIT, I_FLAG, US, IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") },
1N/A#ifdef IUCLC
1N/A{ "iuclc", BIT, I_FLAG, US, IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") },
1N/A#endif /* IUCLC */
1N/A{ "ixon", BIT, I_FLAG, 0, IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") },
1N/A#ifdef IXANY
1N/A{ "ixany", BIT, I_FLAG, US, IXANY, IXANY, C("Any character (only start character) can restart output.") },
1N/A{ "decctlq", BIT, I_FLAG, IG, IXANY, 0, C("Same as \b-ixany\b") },
1N/A#endif /* IXANY */
1N/A{ "ixoff", BIT, I_FLAG, US, IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") },
1N/A#ifdef IMAXBEL
1N/A{ "imaxbel", BIT, I_FLAG, SS, IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") },
1N/A#endif /* IMAXBEL */
1N/A{ "icrnl", BIT, I_FLAG, NL|SS, ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") },
1N/A
1N/A{ "isig", BIT, L_FLAG, SS, ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") },
1N/A{ "icanon", BIT, L_FLAG, SS, ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") },
1N/A{ "icannon", BIT, L_FLAG, SS, ICANON, ICANON },
1N/A#ifdef IEXTEN
1N/A{ "iexten", BIT, L_FLAG, SS, IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") },
1N/A#endif /* IEXTEN */
1N/A{ "echo", BIT, L_FLAG, SS, ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") },
1N/A{ "echoe", BIT, L_FLAG, SS, ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") },
1N/A{ "echok", BIT, L_FLAG, SS, ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") },
1N/A#ifdef ECHOKE
1N/A{ "echoke", BIT, L_FLAG, SS, ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") },
1N/A#endif
1N/A{ "lfkc", BIT, L_FLAG, IG, ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") },
1N/A{ "echonl", BIT, L_FLAG, SS, ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" },
1N/A#ifdef ECHOCTL
1N/A{ "echoctl", BIT, L_FLAG, SS, ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") },
1N/A#else
1N/A#define ECHOCTL 0
1N/A#endif /* ECHOCTL */
1N/A#ifdef ECHOPRT
1N/A{ "echoprt", BIT, L_FLAG, US, ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") },
1N/A#else
1N/A#define ECHOPRT 0
1N/A#endif /* ECHOPRT */
1N/A#ifdef XCASE
1N/A{ "xcase", BIT, L_FLAG, US, XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") },
1N/A#endif /* XCASE */
1N/A#ifdef DEFECHO
1N/A{ "defecho", BIT, L_FLAG, 0, DEFECHO, DEFECHO },
1N/A#endif /* DEFECHO */
1N/A#ifdef FLUSHO
1N/A{ "flusho", BIT, L_FLAG, 0, FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") },
1N/A#endif /* FLUSHO */
1N/A#ifdef PENDIN
1N/A{ "pendin", BIT, L_FLAG, 0, PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") },
1N/A#endif /* PENDIN */
1N/A{ "noflsh", BIT, L_FLAG, US, NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") },
1N/A#ifdef TOSTOP
1N/A{ "tostop", BIT, L_FLAG, NL|US, TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") },
1N/A#endif /* TOSTOP */
1N/A#ifdef OLCUC
1N/A{ "olcuc", BIT, O_FLAG, US, OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") },
1N/A#endif /* OLCUC */
1N/A#ifdef ONLCR
1N/A{ "onlcr", BIT, O_FLAG, SS, ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") },
1N/A#endif /* ONLCR */
1N/A#ifdef ONLRET
1N/A{ "onlret", BIT, O_FLAG, US, ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") },
1N/A#endif /* ONLRET */
1N/A#ifdef OCRNL
1N/A{ "ocrnl", BIT, O_FLAG, US, OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") },
1N/A#endif /* OCRNL */
1N/A#ifdef ONOCR
1N/A{ "onocr", BIT, O_FLAG, US, ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") },
1N/A#endif /* ONOCR */
1N/A#ifdef OFILL
1N/A{ "ofill", BIT, O_FLAG, US, OFILL, OFILL, C("Use fill characters (use timing) for delays") },
1N/A#endif /* OFILL */
1N/A#ifdef OFDEL
1N/A{ "ofdel", BIT, O_FLAG, US, OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") },
1N/A#endif /* OFDEL */
1N/A{ "opost", BIT, O_FLAG, SS, OPOST, OPOST, C(" Postprocess (do not postprocess) output") },
1N/A#ifdef CRDLY
1N/A{ "cr0", BITS, O_FLAG, IG|SS, CRDLY, CR0 },
1N/A{ "cr1", BITS, O_FLAG, US, CRDLY, CR1 },
1N/A{ "cr2", BITS, O_FLAG, US, CRDLY, CR2 },
1N/A{ "cr3", BITS, O_FLAG, US, CRDLY, CR3 },
1N/A#endif
1N/A#ifdef NLDLY
1N/A{ "nl0", BITS, O_FLAG, IG|US, NLDLY, NL0 },
1N/A{ "nl1", BITS, O_FLAG, US, NLDLY, NL1 },
1N/A#endif
1N/A#ifdef TABDLY
1N/A{ "tabs", TABS, O_FLAG, IG, TABDLY, TAB3, C("Preserve (expand to spaces) tabs") },
1N/A#ifdef TAB0
1N/A{ "tab0", BITS, O_FLAG, IG|SS, TABDLY, TAB0 },
1N/A#endif
1N/A#ifdef TAB1
1N/A{ "tab1", BITS, O_FLAG, US, TABDLY, TAB1 },
1N/A#endif
1N/A#ifdef TAB2
1N/A{ "tab2", BITS, O_FLAG, US, TABDLY, TAB2 },
1N/A#endif
1N/A{ "tab3", BITS, O_FLAG, US, TABDLY, TAB3 },
1N/A#endif
1N/A#ifdef BSDLY
1N/A{ "bs0", BITS, O_FLAG, IG|SS, BSDLY, BS0 },
1N/A{ "bs1", BITS, O_FLAG, US, BSDLY, BS1 },
1N/A#endif
1N/A#ifdef VTDLY
1N/A{ "vt0", BITS, O_FLAG, IG|SS, VTDLY, VT0 },
1N/A{ "vt1", BITS, O_FLAG, US, VTDLY, VT1 },
1N/A#endif
1N/A#ifdef FFDLY
1N/A{ "ff0", BITS, O_FLAG, IG|SS, FFDLY, FF0 },
1N/A{ "ff1", BITS, O_FLAG, US, FFDLY, FF1 },
1N/A#endif
1N/A{ "", MIXED, O_FLAG, NL|IG },
1N/A
1N/A{ "evenp", MIXED, C_FLAG, IG, PARENB, 0, C("Same as \bparenb -parodd cs7\b") },
1N/A{ "oddp", MIXED, C_FLAG, IG, PARODD, 0, C("Same as \bparenb parodd cs7\b") },
1N/A{ "parity", MIXED, C_FLAG, IG, 0, 0, C("Same as parenb \b-parodd cs7\b") },
1N/A{ "ek", MIXED, C_FLAG, IG, 0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") },
1N/A{ "sane", SANE, C_FLAG, IG, 0, 0, C("Reset all modes to some reasonable values") },
1N/A{ "cooked", COOKED, C_FLAG, IG, 0, 0, C("Disable raw input and output") },
1N/A{ "raw", COOKED, C_FLAG, IG, 0, 0, C("Enable raw input and output") },
1N/A{ "lcase", CASE, C_FLAG, IG, 0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") },
1N/A{ "LCASE", CASE, C_FLAG, IG, 0 , 0, C("Same as \blcase\b") }
1N/A};
1N/A
1N/A#if CC_NATIVE == CC_ASCII
1N/A#define cntl(x) (((x)=='?')?0177:((x)&037))
1N/A#else
1N/A#define cntl(x) (((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE))
1N/A#endif
1N/A
1N/Astatic void sane(register struct termios *sp)
1N/A{
1N/A register const Tty_t* tp;
1N/A
1N/A for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++)
1N/A if (tp->flags & (SS|US))
1N/A switch (tp->type)
1N/A {
1N/A case BIT:
1N/A case BITS:
1N/A switch (tp->field)
1N/A {
1N/A case C_FLAG:
1N/A if (tp->flags & SS)
1N/A sp->c_cflag |= tp->mask;
1N/A else
1N/A sp->c_cflag &= ~tp->mask;
1N/A break;
1N/A case I_FLAG:
1N/A if (tp->flags & SS)
1N/A sp->c_iflag |= tp->mask;
1N/A else
1N/A sp->c_iflag &= ~tp->mask;
1N/A break;
1N/A case O_FLAG:
1N/A if (tp->flags & SS)
1N/A sp->c_oflag |= tp->mask;
1N/A else
1N/A sp->c_oflag &= ~tp->mask;
1N/A break;
1N/A case L_FLAG:
1N/A if (tp->flags & SS)
1N/A sp->c_lflag |= tp->mask;
1N/A else
1N/A sp->c_lflag &= ~tp->mask;
1N/A break;
1N/A }
1N/A break;
1N/A case CHAR:
1N/A sp->c_cc[tp->mask] = cntl(tp->val);
1N/A break;
1N/A }
1N/A}
1N/A
1N/Astatic int gin(char *arg,struct termios *sp)
1N/A{
1N/A register int i;
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A sp->c_iflag = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A sp->c_oflag = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A sp->c_cflag = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A sp->c_lflag = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A for(i=0;i< NCCS; i++)
1N/A {
1N/A sp->c_cc[i] = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A }
1N/A#if _mem_c_line_termios
1N/A sp->c_line =
1N/A#endif
1N/A strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A i = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A cfsetispeed(sp, i);
1N/A i = strtol(arg,&arg,16);
1N/A if(*arg++ != ':')
1N/A return(0);
1N/A cfsetospeed(sp, i);
1N/A if(*arg)
1N/A return(0);
1N/A return(1);
1N/A}
1N/A
1N/Astatic void gout(struct termios *sp)
1N/A{
1N/A register int i;
1N/A sfprintf(sfstdout,":%x",sp->c_iflag);
1N/A sfprintf(sfstdout,":%x",sp->c_oflag);
1N/A sfprintf(sfstdout,":%x",sp->c_cflag);
1N/A sfprintf(sfstdout,":%x",sp->c_lflag);
1N/A for(i=0;i< NCCS; i++)
1N/A sfprintf(sfstdout,":%x",sp->c_cc[i]);
1N/A#if _mem_c_line_termios
1N/A sfprintf(sfstdout,":%x", sp->c_line);
1N/A#else
1N/A sfprintf(sfstdout,":%x", 0);
1N/A#endif
1N/A sfprintf(sfstdout,":%x",cfgetispeed(sp));
1N/A sfprintf(sfstdout,":%x",cfgetospeed(sp));
1N/A sfprintf(sfstdout,":\n");
1N/A}
1N/A
1N/Astatic void output(struct termios *sp, int flags)
1N/A{
1N/A const Tty_t *tp;
1N/A struct termios tty;
1N/A register int delim = ' ';
1N/A register int i,off,off2;
1N/A char schar[2];
1N/A unsigned int ispeed = cfgetispeed(sp);
1N/A unsigned int ospeed = cfgetospeed(sp);
1N/A if(flags&G_FLAG)
1N/A {
1N/A gout(sp);
1N/A return;
1N/A }
1N/A tty = *sp;
1N/A sane(&tty);
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A tp= &Ttable[i];
1N/A if(tp->flags&IG)
1N/A {
1N/A if(tp->flags&NL)
1N/A sfputc(sfstdout,'\n');
1N/A continue;
1N/A }
1N/A switch(tp->type)
1N/A {
1N/A case BIT:
1N/A case BITS:
1N/A off = off2 = 1;
1N/A switch(tp->field)
1N/A {
1N/A case C_FLAG:
1N/A if(sp->c_cflag&tp->mask)
1N/A off = 0;
1N/A if(tty.c_cflag&tp->mask)
1N/A off2 = 0;
1N/A break;
1N/A case I_FLAG:
1N/A if(sp->c_iflag&tp->mask)
1N/A off = 0;
1N/A if(tty.c_iflag&tp->mask)
1N/A off2 = 0;
1N/A break;
1N/A case O_FLAG:
1N/A if((sp->c_oflag&tp->mask)==tp->val)
1N/A off = 0;
1N/A if(tty.c_oflag&tp->mask)
1N/A off2 = 0;
1N/A break;
1N/A case L_FLAG:
1N/A if(sp->c_lflag&tp->mask)
1N/A off = 0;
1N/A if(tty.c_lflag&tp->mask)
1N/A off2 = 0;
1N/A }
1N/A if(tp->flags&NL)
1N/A delim = '\n';
1N/A if(!flags && off==off2)
1N/A continue;
1N/A if(!off)
1N/A sfprintf(sfstdout,"%s%c",tp->name,delim);
1N/A else if(tp->type==BIT)
1N/A sfprintf(sfstdout,"-%s%c",tp->name,delim);
1N/A delim = ' ';
1N/A break;
1N/A
1N/A case CHAR:
1N/A off = sp->c_cc[tp->mask];
1N/A if(tp->flags&NL)
1N/A delim = '\n';
1N/A if(!flags && off==(unsigned char)tty.c_cc[tp->mask])
1N/A continue;
1N/A if(off==_POSIX_VDISABLE)
1N/A sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim);
1N/A else if(isprint(off&0xff))
1N/A sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim);
1N/A else
1N/A#if CC_NATIVE == CC_ASCII
1N/A sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim);
1N/A#else
1N/A {
1N/A off = ccmapc(off, CC_NATIVE, CC_ASCII);
1N/A sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim);
1N/A }
1N/A#endif
1N/A delim = ' ';
1N/A break;
1N/A case SIZE:
1N/A if((sp->c_cflag&CSIZE)!=tp->mask)
1N/A continue;
1N/A if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE))
1N/A sfprintf(sfstdout,"%s ",tp->name);
1N/A break;
1N/A case SPEED:
1N/A if(tp->mask==ispeed)
1N/A {
1N/A if(ispeed!=ospeed)
1N/A schar[0]='i';
1N/A else
1N/A schar[0]=0;
1N/A }
1N/A else if(tp->mask==ospeed)
1N/A schar[0]='o';
1N/A else
1N/A continue;
1N/A schar[1] = 0;
1N/A#ifdef TIOCSWINSZ
1N/A {
1N/A struct winsize win;
1N/A off = ioctl(0,TIOCGWINSZ,&win);
1N/A if(off>=0)
1N/A sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col);
1N/A }
1N/A if(off<0)
1N/A#endif
1N/A sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name);
1N/A }
1N/A }
1N/A if(delim=='\n')
1N/A sfputc(sfstdout,'\n');
1N/A}
1N/A
1N/Astatic const Tty_t *lookup(const char *name)
1N/A{
1N/A register int i;
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(strcmp(Ttable[i].name,name)==0)
1N/A return(&Ttable[i]);
1N/A }
1N/A return(0);
1N/A
1N/A}
1N/A
1N/Astatic const Tty_t *getspeed(unsigned long val)
1N/A{
1N/A register int i;
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(Ttable[i].type==SPEED && Ttable[i].mask==val)
1N/A return(&Ttable[i]);
1N/A }
1N/A return(0);
1N/A}
1N/A
1N/Astatic int gettchar(register const char *cp)
1N/A{
1N/A if(*cp==0)
1N/A return(-1);
1N/A if(cp[1]==0)
1N/A return((unsigned)cp[0]);
1N/A if(*cp=='^' && cp[1] && cp[2]==0)
1N/A {
1N/A switch(cp[1])
1N/A {
1N/A case '-':
1N/A return(-1);
1N/A default:
1N/A return(cntl(cp[1]));
1N/A }
1N/A }
1N/A if(streq(cp,"undef") || streq(cp,"<undef>"))
1N/A return(-1);
1N/A return(*((unsigned char*)cp));
1N/A}
1N/A
1N/Astatic void set(char *argv[], struct termios *sp)
1N/A{
1N/A const Tty_t *tp;
1N/A register int c,off;
1N/A char *cp;
1N/A char *ep;
1N/A while(cp = *argv++)
1N/A {
1N/A off = 0;
1N/A if(*cp=='-')
1N/A {
1N/A cp++;
1N/A off=1;
1N/A }
1N/A if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS)))
1N/A error(ERROR_exit(1),"%s: unknown mode",cp);
1N/A switch(tp->type)
1N/A {
1N/A case CHAR:
1N/A if(off)
1N/A error(ERROR_exit(1),"%s: unknown mode",cp);
1N/A if(!*argv)
1N/A error(ERROR_exit(1),"missing argument to %s",cp);
1N/A c = gettchar(*argv++);
1N/A if(c>=0)
1N/A sp->c_cc[tp->mask] = c;
1N/A else
1N/A sp->c_cc[tp->mask] = _POSIX_VDISABLE;
1N/A break;
1N/A case BIT: case BITS:
1N/A switch(tp->field)
1N/A {
1N/A case C_FLAG:
1N/A if(off)
1N/A sp->c_cflag &= ~tp->mask;
1N/A else
1N/A sp->c_cflag |= tp->mask;
1N/A break;
1N/A case I_FLAG:
1N/A if(off)
1N/A sp->c_iflag &= ~tp->mask;
1N/A else
1N/A sp->c_iflag |= tp->mask;
1N/A break;
1N/A case O_FLAG:
1N/A sp->c_oflag &= ~tp->mask;
1N/A sp->c_oflag |= tp->val;
1N/A break;
1N/A case L_FLAG:
1N/A if(off)
1N/A sp->c_lflag &= ~tp->mask;
1N/A else
1N/A sp->c_lflag |= tp->mask;
1N/A break;
1N/A }
1N/A break;
1N/A case TABS:
1N/A sp->c_oflag &= ~tp->mask;
1N/A if(off)
1N/A sp->c_oflag |= tp->val;
1N/A break;
1N/A#ifdef TIOCSWINSZ
1N/A case WIND:
1N/A {
1N/A struct winsize win;
1N/A int n;
1N/A if(ioctl(0,TIOCGWINSZ,&win)<0)
1N/A error(ERROR_system(1),"cannot set %s",tp->name);
1N/A if(!(cp= *argv))
1N/A {
1N/A sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row);
1N/A break;
1N/A }
1N/A argv++;
1N/A n=strtol(cp,&cp,10);
1N/A if(*cp)
1N/A error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name);
1N/A if(tp->mask)
1N/A win.ws_col = n;
1N/A else
1N/A win.ws_row = n;
1N/A if(ioctl(0,TIOCSWINSZ,&win)<0)
1N/A error(ERROR_system(1),"cannot set %s",tp->name);
1N/A break;
1N/A }
1N/A#endif
1N/A case NUM:
1N/A cp = *argv;
1N/A if (!cp)
1N/A {
1N/A if (tp->field == C_SPEED)
1N/A {
1N/A if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp)))
1N/A sfprintf(sfstdout, "%s\n", tp->name);
1N/A break;
1N/A }
1N/A error(ERROR_exit(1), "%s: missing numeric argument", tp->name);
1N/A }
1N/A argv++;
1N/A c = (int)strtol(cp, &ep, 10);
1N/A if (*ep)
1N/A error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp);
1N/A switch (tp->field)
1N/A {
1N/A#if _mem_c_line_termios
1N/A case C_LINE:
1N/A sp->c_line = c;
1N/A break;
1N/A#endif
1N/A case C_SPEED:
1N/A if(getspeed(c))
1N/A {
1N/A if (*tp->name != 'o')
1N/A cfsetispeed(sp, c);
1N/A if (*tp->name != 'i')
1N/A cfsetospeed(sp, c);
1N/A }
1N/A else
1N/A error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp);
1N/A break;
1N/A case T_CHAR:
1N/A sp->c_cc[tp->mask] = c;
1N/A break;
1N/A }
1N/A break;
1N/A case SPEED:
1N/A cfsetospeed(sp, tp->mask);
1N/A cfsetispeed(sp, tp->mask);
1N/A break;
1N/A case SIZE:
1N/A sp->c_cflag &= ~CSIZE;
1N/A sp->c_cflag |= tp->mask;
1N/A break;
1N/A case SANE:
1N/A sane(sp);
1N/A break;
1N/A#if defined(OLCUC) && defined(IUCLC)
1N/A case CASE:
1N/A if(off)
1N/A {
1N/A sp->c_iflag |= IUCLC;
1N/A sp->c_oflag |= OLCUC;
1N/A }
1N/A else
1N/A {
1N/A sp->c_iflag &= ~IUCLC;
1N/A sp->c_oflag &= ~OLCUC;
1N/A }
1N/A break;
1N/A#endif /* OLCUC && IUCLC */
1N/A }
1N/A }
1N/A}
1N/A
1N/A
1N/Astatic void listchars(Sfio_t *sp,int type)
1N/A{
1N/A int i,c;
1N/A c = (type==CHAR?'c':'n');
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(Ttable[i].type==type && *Ttable[i].description)
1N/A sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description);
1N/A }
1N/A}
1N/A
1N/Astatic void listgroup(Sfio_t *sp,int type, const char *description)
1N/A{
1N/A int i;
1N/A sfprintf(sp,"[+");
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(Ttable[i].type==type)
1N/A sfprintf(sp,"%s ",Ttable[i].name);
1N/A }
1N/A sfprintf(sp,"?%s.]",description);
1N/A}
1N/A
1N/Astatic void listmask(Sfio_t *sp,unsigned int mask,const char *description)
1N/A{
1N/A int i;
1N/A sfprintf(sp,"[+");
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(Ttable[i].mask==mask && Ttable[i].type==BITS)
1N/A sfprintf(sp,"%s ",Ttable[i].name);
1N/A }
1N/A sfprintf(sp,"?%s.]",description);
1N/A}
1N/A
1N/Astatic void listfields(Sfio_t *sp,int field)
1N/A{
1N/A int i;
1N/A for(i=0; i < elementsof(Ttable); i++)
1N/A {
1N/A if(Ttable[i].field==field && Ttable[i].type==BIT && *Ttable[i].description)
1N/A sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description);
1N/A }
1N/A}
1N/A
1N/Astatic void listmode(Sfio_t *sp,const char *name)
1N/A{
1N/A sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description);
1N/A}
1N/A
1N/Astatic int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
1N/A{
1N/A NoP(op);
1N/A NoP(s);
1N/A NoP(dp);
1N/A sfprintf(sp,"[+Control Modes.]{");
1N/A listfields(sp,C_FLAG);
1N/A listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given. A value of \b0\b causes immediate hangup");
1N/A listchars(sp,NUM);
1N/A listgroup(sp,SIZE,"Number of bits in a character");
1N/A sfprintf(sp,"}[+Input Modes.]{");
1N/A listfields(sp,I_FLAG);
1N/A sfprintf(sp,"}[+Output Modes.]{");
1N/A listfields(sp,O_FLAG);
1N/A#ifdef CRDLY
1N/A listmask(sp,CRDLY,"Carriage return delay style");
1N/A#endif
1N/A#ifdef NLDLY
1N/A listmask(sp,NLDLY,"Newline delay style");
1N/A#endif
1N/A#ifdef TABDLY
1N/A listmask(sp,TABDLY,"Horizontal tab delay style");
1N/A#endif
1N/A#ifdef BSDLY
1N/A listmask(sp,BSDLY,"Backspace delay style");
1N/A#endif
1N/A#ifdef FFDLY
1N/A listmask(sp,FFDLY,"Form feed delay style");
1N/A#endif
1N/A#ifdef VTDLY
1N/A listmask(sp,VTDLY,"Vertical tab delay style");
1N/A#endif
1N/A sfprintf(sp,"}[+Local Modes.]{");
1N/A listfields(sp,L_FLAG);
1N/A sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty "
1N/A "string then the control assignment is disabled.]{");
1N/A listchars(sp,WIND);
1N/A listchars(sp,CHAR);
1N/A sfprintf(sp,"}[+Combination Modes.]{");
1N/A listmode(sp,"ek");
1N/A listmode(sp,"evenp");
1N/A listmode(sp,"lcase");
1N/A listmode(sp,"oddp");
1N/A listmode(sp,"parity");
1N/A listmode(sp,"sane");
1N/A listmode(sp,"tabs");
1N/A listmode(sp,"LCASE");
1N/A sfputc(sp,'}');
1N/A return(1);
1N/A}
1N/A
1N/A#ifndef _lib_tcgetpgrp
1N/A# ifdef TIOCGPGRP
1N/A static int _i_;
1N/A# define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
1N/A# else
1N/A# define tcgetpgrp(a) (-1)
1N/A# endif /* TIOCGPGRP */
1N/A#endif /* _lib_tcgetpgrp */
1N/A
1N/Aint
1N/Ab_stty(int argc, char** argv, void* context)
1N/A{
1N/A struct termios tty;
1N/A register int n;
1N/A register int flags = 0;
1N/A int fd = 0;
1N/A const Tty_t* tp;
1N/A Optdisc_t disc;
1N/A
1N/A cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE);
1N/A memset(&disc, 0, sizeof(disc));
1N/A disc.version = OPT_VERSION;
1N/A disc.infof = infof;
1N/A opt_info.disc = &disc;
1N/A for (;;)
1N/A {
1N/A switch (n = optget(argv, usage))
1N/A {
1N/A case 'f':
1N/A fd = (int)opt_info.num;
1N/A continue;
1N/A case 'a':
1N/A case 'g':
1N/A case 't':
1N/A if (!opt_info.offset || !argv[opt_info.index][opt_info.offset])
1N/A {
1N/A switch (n)
1N/A {
1N/A case 'a':
1N/A flags |= A_FLAG;
1N/A break;
1N/A case 'g':
1N/A flags |= G_FLAG;
1N/A break;
1N/A case 't':
1N/A flags |= T_FLAG;
1N/A break;
1N/A }
1N/A continue;
1N/A }
1N/A /*FALLTHROUGH*/
1N/A case ':':
1N/A if (!opt_info.offset)
1N/A error(2, "%s", opt_info.arg);
1N/A else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS))
1N/A error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]);
1N/A break;
1N/A case '?':
1N/A error(ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A break;
1N/A }
1N/A argv += opt_info.index;
1N/A if (error_info.errors || (flags && *argv) || (flags&(flags-1)))
1N/A error(ERROR_usage(2), "%s", optusage(NiL));
1N/A if (tcgetattr(fd, &tty) < 0)
1N/A error(ERROR_system(1), "not a tty");
1N/A if (flags & T_FLAG)
1N/A sfprintf(sfstdout, "%d\n", tcgetpgrp(0));
1N/A else if (*argv)
1N/A {
1N/A if (!argv[1] && **argv == ':')
1N/A gin(*argv, &tty);
1N/A else
1N/A set(argv, &tty);
1N/A if (tcsetattr(0, TCSANOW, &tty) < 0)
1N/A error(ERROR_system(1), "cannot set tty");
1N/A }
1N/A else
1N/A output(&tty, flags);
1N/A return error_info.errors;
1N/A}