xref: /onnv-gate/usr/src/lib/libcmd/common/stty.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1992-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                                                                      *
204887Schin ***********************************************************************/
214887Schin #pragma prototyped
224887Schin /*
234887Schin  * stty.c
244887Schin  * Written by David Korn
254887Schin  * Tue Apr  4 10:46:00 EDT 1995
264887Schin  */
274887Schin 
284887Schin static const char usage[] =
2910898Sroland.mainz@nrubsig.org "[-?@(#)$Id: stty (AT&T Research) 2008-11-10 $\n]"
304887Schin USAGE_LICENSE
314887Schin "[+NAME?stty - set or get terminal modes]"
324887Schin "[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device "
334887Schin 	"that is the current standard input; without arguments, it writes "
344887Schin 	"the settings of certain modes to standard output.]"
354887Schin 
364887Schin "[a:all?Writes to standard output all of the mode settings.]"
374887Schin "[g:save?Writes the current settings to standard output in a form that can "
384887Schin 	"be used as an argument to another \bstty\b command.  The \brows\b "
394887Schin 	"and \bcolumns\b values are not included.]"
408462SApril.Chin@Sun.COM "[t:terminal-group?Print the terminal group id of the device, -1 if unknown.]"
414887Schin "\n"
424887Schin "\n[mode ...]\n"
434887Schin "\n"
444887Schin "[+EXTENDED DESCRIPTION?Modes are specified either as a single name or "
454887Schin 	"as a name followed by a value.  As indicated below, many of the "
464887Schin 	"mode names can be preceded by a \b-\b to negate its meaning.  "
474887Schin 	"Modes are listed by group corresponding to field in the "
484887Schin 	"\btermios\b structure defined in \b<termios.h>\b.  Modes "
494887Schin 	"in the last group are implemented using options in the previous "
504887Schin 	"groups.  Note that many combinations of modes make no sense, but "
514887Schin 	"no sanity checking is performed.  The modes are selected from the "
524887Schin 	"following:]{\fabc\f}"
534887Schin 
544887Schin "[+EXIT STATUS?]{"
554887Schin       "[+0?All modes reported or set successfully.]"
564887Schin         "[+>0?Standard input not a terminaol or one or more modes failed.]"
574887Schin "}"
584887Schin "[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]"
594887Schin ;
604887Schin 
614887Schin #include	<cmd.h>
624887Schin #include	<ccode.h>
634887Schin #include	<ctype.h>
644887Schin #include	<ast_tty.h>
654887Schin #if _sys_ioctl
664887Schin #include	<sys/ioctl.h>
674887Schin #endif
684887Schin 
694887Schin #define C(x)	ERROR_catalog(x)
704887Schin 
714887Schin #ifndef _POSIX_VDISABLE
724887Schin #   define _POSIX_VDISABLE 0
734887Schin #endif
744887Schin 
754887Schin #ifndef NCCS
764887Schin #   ifdef NCC
774887Schin #	define NCCS	NCC
784887Schin #   else
794887Schin #	define NCCS	elementsof(((struct termio*)0)->c_cc)
804887Schin #   endif
814887Schin #endif
824887Schin 
834887Schin /* command options */
844887Schin #define A_FLAG	1
854887Schin #define G_FLAG	2
868462SApril.Chin@Sun.COM #define T_FLAG	4
874887Schin 
884887Schin /* termios fields */
894887Schin #define C_FLAG	1
904887Schin #define C_LINE	2
914887Schin #define C_SPEED	3
924887Schin #define I_FLAG	4
934887Schin #define O_FLAG	5
944887Schin #define L_FLAG	6
954887Schin #define T_CHAR	7
964887Schin #define W_SIZE	8
974887Schin 
984887Schin #define BIT	1
994887Schin #define BITS	2
1004887Schin #define NUM	3
1014887Schin #define CHAR	4
1024887Schin #define SPEED	5
1034887Schin #define SIZE	6
1044887Schin #define MIXED	7
1054887Schin #define SANE	8
1064887Schin #define COOKED	9
1074887Schin #define CASE	10
1084887Schin #define TABS	11
1094887Schin #define WIND	12
1104887Schin 
1114887Schin #undef	SS			/* who co-opted this namespace?	*/
1124887Schin 
1134887Schin #define IG	0x0001		/* ignore display		*/
1144887Schin #define NL	0x0002		/* entry ends line of display	*/
1154887Schin #define SS	0x0004		/* set in sane mode		*/
1164887Schin #define US	0x0010		/* unset in sane mode		*/
1174887Schin 
1184887Schin typedef struct tty_s
1194887Schin {
1204887Schin 	const char	name[8];
1214887Schin 	unsigned char	type;
1224887Schin 	unsigned char	field;
1234887Schin 	short		flags;
1244887Schin 	unsigned long	mask;
1254887Schin 	unsigned long	val;
1264887Schin 	const char	description[76];
1274887Schin } Tty_t;
1284887Schin 
1294887Schin static const Tty_t Ttable[] =
1304887Schin {
1314887Schin #ifdef CBAUD
1324887Schin { "ispeed",	NUM,	C_SPEED,0,	CBAUD, 0, C("\an\a is the input baud rate") },
1334887Schin { "ospeed",	NUM,	C_SPEED,0,	CBAUD, 0, C("\an\a is the output baud rate") },
1344887Schin { "speed",	NUM,	C_SPEED,IG,	CBAUD },
1354887Schin #endif
1364887Schin { "0",		SPEED,	C_FLAG,	0,	B0 },
1374887Schin { "50",		SPEED,	C_FLAG,	0,	B50 },
1384887Schin { "75",		SPEED,	C_FLAG,	0,	B75 },
1394887Schin { "110",	SPEED,	C_FLAG,	0,	B110 },
1404887Schin { "134",	SPEED,	C_FLAG,	0,	B134 },
1414887Schin { "150",	SPEED,	C_FLAG,	0,	B150 },
1424887Schin { "200",	SPEED,	C_FLAG,	0,	B200 },
1434887Schin { "300",	SPEED,	C_FLAG,	0,	B300 },
1444887Schin { "600",	SPEED,	C_FLAG,	0,	B600 },
1454887Schin { "1200",	SPEED,	C_FLAG,	0,	B1200 },
1464887Schin { "1800",	SPEED,	C_FLAG,	0,	B1800 },
1474887Schin { "2400",	SPEED,	C_FLAG,	0,	B2400 },
1484887Schin { "4800",	SPEED,	C_FLAG,	0,	B4800 },
1494887Schin { "9600",	SPEED,	C_FLAG,	0,	B9600 },
1504887Schin { "19200",	SPEED,	C_FLAG,	0,	B19200 },
1514887Schin { "38400",	SPEED,	C_FLAG,	0,	B38400 },
1524887Schin 
1534887Schin #ifdef TIOCSWINSZ
1544887Schin { "rows",	WIND,	W_SIZE,	IG,	0, 24, C("\an\a is the number of lines for display") },
1554887Schin { "cols",	WIND,	W_SIZE,	IG,	1, 80, C("\an\a is the number of columns for display") },
1564887Schin { "columns",	WIND,	W_SIZE,	IG,	1, 80, C("Same as \bcols\b") },
1574887Schin #endif
1584887Schin { "intr",	CHAR,	T_CHAR,	SS,	VINTR, 'C', C("Send an interrupt signal") },
1594887Schin { "quit",	CHAR,	T_CHAR,	SS,	VQUIT, '|', C("Send a quit signal") },
1604887Schin { "erase",	CHAR,	T_CHAR,	SS,	VERASE, 'H', C("Erase the last character entered") },
1614887Schin { "kill",	CHAR,	T_CHAR,	NL|SS,	VKILL, 'U', C("Erase the current line") },
1624887Schin { "eof",	CHAR,	T_CHAR,	SS,	VEOF, 'D', C("Send an end of file") },
1634887Schin #ifdef VEOL2
1644887Schin { "eol2",	CHAR,	T_CHAR,	US,	VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") },
1654887Schin #endif /* VEOL2 */
1664887Schin #ifdef VSWTCH
1674887Schin { "swtch",	CHAR,	T_CHAR,	US,	VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") },
1684887Schin #endif /* VSWTCH */
1694887Schin { "eol",	CHAR,	T_CHAR,	NL|US,	VEOL, _POSIX_VDISABLE, C("End the line") },
1704887Schin #ifdef VSTART
1714887Schin { "start",	CHAR,	T_CHAR,	SS,	VSTART, 'Q', C("Restart the output after stopping it") },
1724887Schin #endif /* VSTART */
1734887Schin #ifdef VSTOP
1744887Schin { "stop",	CHAR,	T_CHAR,	SS,	VSTOP, 'S', C("Stop the output") },
1754887Schin #endif /* VSTOP */
1764887Schin #ifdef VDSUSP
1774887Schin { "dsusp",	CHAR,	T_CHAR,	SS,	VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") },
1784887Schin #endif /* VDSUSP */
1794887Schin #ifdef VSUSP
1804887Schin { "susp",	CHAR,	T_CHAR,	NL|SS,	VSUSP, 'Z', C("Send a terminal stop signal") },
1814887Schin #endif /* VSUSP */
1824887Schin #ifdef VREPRINT
1834887Schin { "rprnt",	CHAR,	T_CHAR,	SS,	VREPRINT, 'R', C("Redraw the current line") },
1844887Schin #endif /* VREPRINT */
1854887Schin #ifdef VDISCARD
1864887Schin { "flush",	CHAR,	T_CHAR,	SS,	VDISCARD, 'O', C("Discard output") },
1874887Schin #endif /* VDISCARD */
1884887Schin #ifdef VWERASE
1894887Schin { "werase",	CHAR,	T_CHAR,	SS,	VWERASE, 'W', C("Erase the last word entered") },
1904887Schin #endif /* VWERASE */
1914887Schin #ifdef VLNEXT
1924887Schin { "lnext",	CHAR,	T_CHAR,	NL|SS,	VLNEXT, 'V', C("Enter the next input character literally") },
1934887Schin #endif /* VLNEXT */
1944887Schin 
1954887Schin #if _mem_c_line_termios
1964887Schin { "line",	NUM,	C_LINE,	0,	0, 0, C("Line discipline number") },
1974887Schin #endif
1984887Schin { "min",	NUM,	T_CHAR,	0,	VMIN, 0, C("Mininmum number of characters to read in raw mode") },
1994887Schin { "time",	NUM,	T_CHAR,	0,	VTIME, 0, C("Number of .1 second intervals with raw mode") },
2004887Schin 
2014887Schin { "parenb",	BIT,	C_FLAG,	0,	PARENB,	PARENB, C("Enable (disable) parity generation and detection") },
2024887Schin { "parodd",	BIT,	C_FLAG,	0,	PARODD, PARODD, C("Use odd (even) parity") },
2034887Schin #ifdef PAREXT
2044887Schin { "parext",	BIT,	C_FLAG,	0,	PAREXT, PAREXT },
2054887Schin #endif /* PAREXT */
2064887Schin #ifdef CREAD
2074887Schin { "cread",	BIT,	C_FLAG,	SS,	CREAD, CREAD, C("Enable (disable) input") },
2084887Schin #endif /* CREAD */
2094887Schin { "cs5",	SIZE,	C_FLAG,	0,	CSIZE,	CS5 , C("Char size 5") },
2104887Schin { "cs6",	SIZE,	C_FLAG,	0,	CSIZE,	CS6 , C("Char size 6") },
2114887Schin { "cs7",	SIZE,	C_FLAG,	0,	CSIZE,	CS7 , C("Char size 7") },
2124887Schin { "cs8",	SIZE,	C_FLAG,	0,	CSIZE,	CS8 , C("Char size 8") },
2134887Schin { "hupcl",	BIT,	C_FLAG,	0,	HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") },
2144887Schin { "hup",	BIT,	C_FLAG,	IG,	HUPCL, HUPCL, C("Same as \bhupcl\b") },
2154887Schin { "cstopb",	BIT,	C_FLAG,	0,	CSTOPB, CSTOPB, C("Use two (one) stop bits") },
2164887Schin #ifdef CRTSCTS
2174887Schin { "crtscts",	BIT,	C_FLAG,	0,	CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") },
2184887Schin #endif /* CRTSCTS */
2194887Schin { "clocal",	BIT,	C_FLAG,	NL,	CLOCAL, CLOCAL, C("Disable (enable) modem control signals") },
2204887Schin 
2214887Schin { "ignbrk",	BIT,	I_FLAG,	US,	IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") },
2224887Schin { "brkint",	BIT,	I_FLAG,	SS,	BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") },
2234887Schin { "ignpar",	BIT,	I_FLAG,	0,	IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") },
2244887Schin { "parmrk",	BIT,	I_FLAG,	0,	PARMRK, PARMRK, C("Mark (do not mark) parity errors") },
2254887Schin { "inpck",	BIT,	I_FLAG,	0,	INPCK, INPCK, C("Enable (disable) input parity checking") },
2264887Schin { "istrip",	BIT,	I_FLAG,	0,	ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") },
2274887Schin { "inlcr",	BIT,	I_FLAG,	US,	INLCR, INLCR, C("Translate (do not translate) carriage return to newline") },
2284887Schin { "igncr",	BIT,	I_FLAG,	US,	IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") },
2294887Schin #ifdef IUCLC
2304887Schin { "iuclc",	BIT,	I_FLAG,	US,	IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") },
2314887Schin #endif /* IUCLC */
2324887Schin { "ixon",	BIT,	I_FLAG,	0,	IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") },
2334887Schin #ifdef IXANY
2344887Schin { "ixany",	BIT,	I_FLAG,	US,	IXANY, IXANY, C("Any character (only start character) can restart output.") },
2354887Schin { "decctlq",	BIT,	I_FLAG,	IG,	IXANY, 0, C("Same as \b-ixany\b") },
2364887Schin #endif /* IXANY */
2374887Schin { "ixoff",	BIT,	I_FLAG,	US,	IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") },
2384887Schin #ifdef IMAXBEL
2394887Schin { "imaxbel",	BIT,	I_FLAG,	SS,	IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") },
2404887Schin #endif /* IMAXBEL */
2414887Schin { "icrnl",	BIT,	I_FLAG,	NL|SS,	ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") },
2424887Schin 
2434887Schin { "isig",	BIT,	L_FLAG,	SS,	ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") },
2444887Schin { "icanon",	BIT,	L_FLAG,	SS,	ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") },
2454887Schin { "icannon",	BIT,	L_FLAG,	SS,	ICANON, ICANON },
2464887Schin #ifdef IEXTEN
2474887Schin { "iexten",	BIT,	L_FLAG,	SS,	IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") },
2484887Schin #endif /* IEXTEN */
2494887Schin { "echo",	BIT,	L_FLAG,	SS,	ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") },
2504887Schin { "echoe",	BIT,	L_FLAG,	SS,	ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") },
2514887Schin { "echok",	BIT,	L_FLAG,	SS,	ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") },
2524887Schin #ifdef ECHOKE
2534887Schin { "echoke",	BIT,	L_FLAG,	SS,	ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") },
2544887Schin #endif
2554887Schin { "lfkc",	BIT,	L_FLAG,	IG,	ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") },
2564887Schin { "echonl",	BIT,	L_FLAG,	SS,	ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" },
2574887Schin #ifdef ECHOCTL
2584887Schin { "echoctl",	BIT,	L_FLAG,	SS,	ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") },
2594887Schin #else
2604887Schin #define ECHOCTL		0
2614887Schin #endif /* ECHOCTL */
2624887Schin #ifdef ECHOPRT
2634887Schin { "echoprt",	BIT,	L_FLAG,	US,	ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") },
2644887Schin #else
2654887Schin #define ECHOPRT		0
2664887Schin #endif /* ECHOPRT */
2674887Schin #ifdef XCASE
2684887Schin { "xcase",	BIT,	L_FLAG,	US,	XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") },
2694887Schin #endif /* XCASE */
2704887Schin #ifdef DEFECHO
2714887Schin { "defecho",	BIT,	L_FLAG,	0,	DEFECHO, DEFECHO },
2724887Schin #endif /* DEFECHO */
2734887Schin #ifdef FLUSHO
2744887Schin { "flusho",	BIT,	L_FLAG,	0,	FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") },
2754887Schin #endif /* FLUSHO */
2764887Schin #ifdef PENDIN
2774887Schin { "pendin",	BIT,	L_FLAG,	0,	PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") },
2784887Schin #endif /* PENDIN */
2794887Schin { "noflsh",	BIT,	L_FLAG,	US,	NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") },
2804887Schin #ifdef TOSTOP
2814887Schin { "tostop",	BIT,	L_FLAG,	NL|US,	TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") },
2824887Schin #endif /* TOSTOP */
2834887Schin #ifdef OLCUC
2844887Schin { "olcuc",	BIT,	O_FLAG,	US,	OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") },
2854887Schin #endif /* OLCUC */
2864887Schin #ifdef ONLCR
2874887Schin { "onlcr",	BIT,	O_FLAG,	SS,	ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") },
2884887Schin #endif /* ONLCR */
2894887Schin #ifdef ONLRET
2904887Schin { "onlret",	BIT,	O_FLAG,	US,	ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") },
2914887Schin #endif /* ONLRET */
2924887Schin #ifdef OCRNL
2934887Schin { "ocrnl",	BIT,	O_FLAG,	US,	OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") },
2944887Schin #endif /* OCRNL */
2954887Schin #ifdef ONOCR
2964887Schin { "onocr",	BIT,	O_FLAG,	US,	ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") },
2974887Schin #endif /* ONOCR */
2984887Schin #ifdef OFILL
2994887Schin { "ofill",	BIT,	O_FLAG,	US,	OFILL, OFILL, C("Use fill characters (use timing) for delays") },
3004887Schin #endif /* OFILL */
3014887Schin #ifdef OFDEL
3024887Schin { "ofdel",	BIT,	O_FLAG,	US,	OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") },
3034887Schin #endif /* OFDEL */
3044887Schin { "opost",	BIT,	O_FLAG,	SS,	OPOST, OPOST, C(" Postprocess (do not postprocess) output") },
3054887Schin #ifdef CRDLY
3064887Schin { "cr0",	BITS,	O_FLAG,	IG|SS,	CRDLY, CR0  },
3074887Schin { "cr1",	BITS,	O_FLAG,	US,	CRDLY, CR1  },
3084887Schin { "cr2",	BITS,	O_FLAG,	US,	CRDLY, CR2  },
3094887Schin { "cr3",	BITS,	O_FLAG,	US,	CRDLY, CR3  },
3104887Schin #endif
3114887Schin #ifdef NLDLY
3124887Schin { "nl0",	BITS,	O_FLAG,	IG|US,	NLDLY, NL0  },
3134887Schin { "nl1",	BITS,	O_FLAG,	US,	NLDLY, NL1  },
3144887Schin #endif
3154887Schin #ifdef TABDLY
3164887Schin { "tabs",	TABS,	O_FLAG,	IG,	TABDLY, TAB3, C("Preserve (expand to spaces) tabs") },
3178462SApril.Chin@Sun.COM #ifdef TAB0
3184887Schin { "tab0",	BITS,	O_FLAG,	IG|SS,	TABDLY, TAB0  },
3198462SApril.Chin@Sun.COM #endif
3208462SApril.Chin@Sun.COM #ifdef TAB1
3214887Schin { "tab1",	BITS,	O_FLAG,	US,	TABDLY, TAB1  },
3228462SApril.Chin@Sun.COM #endif
3238462SApril.Chin@Sun.COM #ifdef TAB2
3244887Schin { "tab2",	BITS,	O_FLAG,	US,	TABDLY, TAB2  },
3258462SApril.Chin@Sun.COM #endif
3264887Schin { "tab3",	BITS,	O_FLAG,	US,	TABDLY, TAB3  },
3274887Schin #endif
3284887Schin #ifdef BSDLY
3294887Schin { "bs0",	BITS,	O_FLAG,	IG|SS,	BSDLY, BS0 },
3304887Schin { "bs1",	BITS,	O_FLAG,	US,	BSDLY, BS1  },
3314887Schin #endif
3324887Schin #ifdef VTDLY
3334887Schin { "vt0",	BITS,	O_FLAG,	IG|SS,	VTDLY, VT0  },
3344887Schin { "vt1",	BITS,	O_FLAG,	US,	VTDLY, VT1  },
3354887Schin #endif
3364887Schin #ifdef FFDLY
3374887Schin { "ff0",	BITS,	O_FLAG,	IG|SS,	FFDLY, FF0 },
3384887Schin { "ff1",	BITS,	O_FLAG,	US,	FFDLY, FF1 },
3394887Schin #endif
3404887Schin { "",		MIXED,	O_FLAG,	NL|IG },
3414887Schin 
3424887Schin { "evenp",	MIXED,	C_FLAG,	IG,	PARENB, 0, C("Same as \bparenb -parodd cs7\b") },
3434887Schin { "oddp",	MIXED,	C_FLAG,	IG,	PARODD, 0, C("Same as \bparenb parodd cs7\b") },
3444887Schin { "parity",	MIXED,	C_FLAG,	IG,	0, 0, C("Same as parenb \b-parodd cs7\b") },
3454887Schin { "ek",		MIXED,	C_FLAG,	IG,	0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") },
3464887Schin { "sane",	SANE,	C_FLAG,	IG,	0, 0, C("Reset all modes to some reasonable values") },
3474887Schin { "cooked",	COOKED,	C_FLAG,	IG,	0, 0, C("Disable raw input and output") },
3484887Schin { "raw",	COOKED,	C_FLAG,	IG,	0, 0, C("Enable raw input and output") },
3494887Schin { "lcase",	CASE,	C_FLAG,	IG,	0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") },
3504887Schin { "LCASE",	CASE,	C_FLAG,	IG,	0 , 0, C("Same as \blcase\b") }
3514887Schin };
3524887Schin 
3534887Schin #if CC_NATIVE == CC_ASCII
3544887Schin #define cntl(x)		(((x)=='?')?0177:((x)&037))
3554887Schin #else
3564887Schin #define cntl(x)		(((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE))
3574887Schin #endif
3584887Schin 
sane(register struct termios * sp)3594887Schin static void sane(register struct termios *sp)
3604887Schin {
3614887Schin 	register const Tty_t*	tp;
3624887Schin 
3634887Schin 	for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++)
3644887Schin 		if (tp->flags & (SS|US))
3654887Schin 			switch (tp->type)
3664887Schin 			{
3674887Schin 			case BIT:
3684887Schin 			case BITS:
3694887Schin 				switch (tp->field)
3704887Schin 				{
3714887Schin 				case C_FLAG:
3724887Schin 					if (tp->flags & SS)
3734887Schin 						sp->c_cflag |= tp->mask;
3744887Schin 					else
3754887Schin 						sp->c_cflag &= ~tp->mask;
3764887Schin 					break;
3774887Schin 				case I_FLAG:
3784887Schin 					if (tp->flags & SS)
3794887Schin 						sp->c_iflag |= tp->mask;
3804887Schin 					else
3814887Schin 						sp->c_iflag &= ~tp->mask;
3824887Schin 					break;
3834887Schin 				case O_FLAG:
3844887Schin 					if (tp->flags & SS)
3854887Schin 						sp->c_oflag |= tp->mask;
3864887Schin 					else
3874887Schin 						sp->c_oflag &= ~tp->mask;
3884887Schin 					break;
3894887Schin 				case L_FLAG:
3904887Schin 					if (tp->flags & SS)
3914887Schin 						sp->c_lflag |= tp->mask;
3924887Schin 					else
3934887Schin 						sp->c_lflag &= ~tp->mask;
3944887Schin 					break;
3954887Schin 				}
3964887Schin 				break;
3974887Schin 			case CHAR:
3984887Schin 				sp->c_cc[tp->mask] = cntl(tp->val);
3994887Schin 				break;
4004887Schin 			}
4014887Schin }
4024887Schin 
gin(char * arg,struct termios * sp)4034887Schin static int gin(char *arg,struct termios *sp)
4044887Schin {
4054887Schin 	register int i;
4064887Schin 	if(*arg++ != ':')
4074887Schin 		return(0);
4084887Schin 	sp->c_iflag = strtol(arg,&arg,16);
4094887Schin 	if(*arg++ != ':')
4104887Schin 		return(0);
4114887Schin 	sp->c_oflag = strtol(arg,&arg,16);
4124887Schin 	if(*arg++ != ':')
4134887Schin 		return(0);
4144887Schin 	sp->c_cflag = strtol(arg,&arg,16);
4154887Schin 	if(*arg++ != ':')
4164887Schin 		return(0);
4174887Schin 	sp->c_lflag = strtol(arg,&arg,16);
4184887Schin 	if(*arg++ != ':')
4194887Schin 		return(0);
4204887Schin 	for(i=0;i< NCCS; i++)
4214887Schin 	{
4224887Schin 		sp->c_cc[i] = strtol(arg,&arg,16);
4234887Schin 		if(*arg++ != ':')
4244887Schin 			return(0);
4254887Schin 	}
4264887Schin #if _mem_c_line_termios
4274887Schin 	sp->c_line =
4284887Schin #endif
4294887Schin 		strtol(arg,&arg,16);
4304887Schin 	if(*arg++ != ':')
4314887Schin 		return(0);
4324887Schin 	i = strtol(arg,&arg,16);
4334887Schin 	if(*arg++ != ':')
4344887Schin 		return(0);
4354887Schin 	cfsetispeed(sp, i);
4364887Schin 	i = strtol(arg,&arg,16);
4374887Schin 	if(*arg++ != ':')
4384887Schin 		return(0);
4394887Schin 	cfsetospeed(sp, i);
4404887Schin 	if(*arg)
4414887Schin 		return(0);
4424887Schin 	return(1);
4434887Schin }
4444887Schin 
gout(struct termios * sp)4454887Schin static void gout(struct termios *sp)
4464887Schin {
4474887Schin 	register int i;
4484887Schin 	sfprintf(sfstdout,":%x",sp->c_iflag);
4494887Schin 	sfprintf(sfstdout,":%x",sp->c_oflag);
4504887Schin 	sfprintf(sfstdout,":%x",sp->c_cflag);
4514887Schin 	sfprintf(sfstdout,":%x",sp->c_lflag);
4524887Schin 	for(i=0;i< NCCS; i++)
4534887Schin 		sfprintf(sfstdout,":%x",sp->c_cc[i]);
4544887Schin #if _mem_c_line_termios
4554887Schin 	sfprintf(sfstdout,":%x", sp->c_line);
4564887Schin #else
4574887Schin 	sfprintf(sfstdout,":%x", 0);
4584887Schin #endif
4594887Schin 	sfprintf(sfstdout,":%x",cfgetispeed(sp));
4604887Schin 	sfprintf(sfstdout,":%x",cfgetospeed(sp));
4614887Schin 	sfprintf(sfstdout,":\n");
4624887Schin }
4634887Schin 
output(struct termios * sp,int flags)4644887Schin static void output(struct termios *sp, int flags)
4654887Schin {
4664887Schin 	const Tty_t *tp;
4674887Schin 	struct termios tty;
4684887Schin 	register int delim = ' ';
4694887Schin 	register int i,off,off2;
4704887Schin 	char schar[2];
4714887Schin 	unsigned int ispeed = cfgetispeed(sp);
4724887Schin 	unsigned int ospeed = cfgetospeed(sp);
4734887Schin 	if(flags&G_FLAG)
4744887Schin 	{
4754887Schin 		gout(sp);
4764887Schin 		return;
4774887Schin 	}
4784887Schin 	tty = *sp;
4794887Schin 	sane(&tty);
4804887Schin 	for(i=0; i < elementsof(Ttable); i++)
4814887Schin 	{
4824887Schin 		tp= &Ttable[i];
4834887Schin 		if(tp->flags&IG)
4844887Schin 		{
4854887Schin 			if(tp->flags&NL)
4864887Schin 				sfputc(sfstdout,'\n');
4874887Schin 			continue;
4884887Schin 		}
4894887Schin 		switch(tp->type)
4904887Schin 		{
4914887Schin 		    case BIT:
4924887Schin 		    case BITS:
4938462SApril.Chin@Sun.COM 			off = off2 = 1;
4944887Schin 			switch(tp->field)
4954887Schin 			{
4964887Schin 			    case C_FLAG:
4974887Schin 				if(sp->c_cflag&tp->mask)
4984887Schin 					off = 0;
4994887Schin 				if(tty.c_cflag&tp->mask)
5004887Schin 					off2 = 0;
5014887Schin 				break;
5024887Schin 			    case I_FLAG:
5034887Schin 				if(sp->c_iflag&tp->mask)
5044887Schin 					off = 0;
5054887Schin 				if(tty.c_iflag&tp->mask)
5064887Schin 					off2 = 0;
5074887Schin 				break;
5084887Schin 			    case O_FLAG:
5094887Schin 				if((sp->c_oflag&tp->mask)==tp->val)
5104887Schin 					off = 0;
5114887Schin 				if(tty.c_oflag&tp->mask)
5124887Schin 					off2 = 0;
5134887Schin 				break;
5144887Schin 			    case L_FLAG:
5154887Schin 				if(sp->c_lflag&tp->mask)
5164887Schin 					off = 0;
5174887Schin 				if(tty.c_lflag&tp->mask)
5184887Schin 					off2 = 0;
5194887Schin 			}
5204887Schin 			if(tp->flags&NL)
5214887Schin 				delim = '\n';
5224887Schin 			if(!flags && off==off2)
5234887Schin 				continue;
5244887Schin 			if(!off)
5254887Schin 				sfprintf(sfstdout,"%s%c",tp->name,delim);
5264887Schin 			else if(tp->type==BIT)
5274887Schin 				sfprintf(sfstdout,"-%s%c",tp->name,delim);
5284887Schin 			delim = ' ';
5294887Schin 			break;
5304887Schin 
5314887Schin 		    case CHAR:
5324887Schin 			off = sp->c_cc[tp->mask];
5334887Schin 			if(tp->flags&NL)
5344887Schin 				delim = '\n';
5354887Schin 			if(!flags && off==(unsigned char)tty.c_cc[tp->mask])
5364887Schin 				continue;
5374887Schin 			if(off==_POSIX_VDISABLE)
5384887Schin 				sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim);
5394887Schin 			else if(isprint(off&0xff))
5404887Schin 				sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim);
5414887Schin 			else
5424887Schin #if CC_NATIVE == CC_ASCII
5434887Schin 			sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim);
5444887Schin #else
5454887Schin 			{
5464887Schin 				off = ccmapc(off, CC_NATIVE, CC_ASCII);
5474887Schin 				sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim);
5484887Schin 			}
5494887Schin #endif
5504887Schin 			delim = ' ';
5514887Schin 			break;
5524887Schin 		    case SIZE:
5534887Schin 			if((sp->c_cflag&CSIZE)!=tp->mask)
5544887Schin 				continue;
5554887Schin 			if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE))
5564887Schin 				sfprintf(sfstdout,"%s ",tp->name);
5574887Schin 			break;
5584887Schin 		    case SPEED:
5594887Schin 			if(tp->mask==ispeed)
5604887Schin 			{
5614887Schin 				if(ispeed!=ospeed)
5624887Schin 					schar[0]='i';
5634887Schin 				else
5644887Schin 					schar[0]=0;
5654887Schin 			}
5664887Schin 			else if(tp->mask==ospeed)
5674887Schin 				schar[0]='o';
5684887Schin 			else
5694887Schin 				continue;
5704887Schin 			schar[1] = 0;
5714887Schin #ifdef TIOCSWINSZ
5724887Schin 			{
5734887Schin 				struct winsize win;
5744887Schin 				off = ioctl(0,TIOCGWINSZ,&win);
5754887Schin 				if(off>=0)
5764887Schin 					sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col);
5774887Schin 			}
5784887Schin 			if(off<0)
5794887Schin #endif
5804887Schin 				sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name);
5814887Schin 		}
5824887Schin 	}
5834887Schin 	if(delim=='\n')
5844887Schin 		sfputc(sfstdout,'\n');
5854887Schin }
5864887Schin 
lookup(const char * name)5874887Schin static const Tty_t *lookup(const char *name)
5884887Schin {
5894887Schin 	register int i;
5904887Schin 	for(i=0; i < elementsof(Ttable); i++)
5914887Schin 	{
5924887Schin 		if(strcmp(Ttable[i].name,name)==0)
5934887Schin 			return(&Ttable[i]);
5944887Schin 	}
5954887Schin 	return(0);
5964887Schin 
5974887Schin }
5984887Schin 
getspeed(unsigned long val)5994887Schin static const Tty_t *getspeed(unsigned long val)
6004887Schin {
6014887Schin 	register int i;
6024887Schin 	for(i=0; i < elementsof(Ttable); i++)
6034887Schin 	{
6044887Schin 		if(Ttable[i].type==SPEED && Ttable[i].mask==val)
6054887Schin 			return(&Ttable[i]);
6064887Schin 	}
6074887Schin 	return(0);
6084887Schin }
6094887Schin 
gettchar(register const char * cp)6104887Schin static int gettchar(register const char *cp)
6114887Schin {
6124887Schin 	if(*cp==0)
6134887Schin 		return(-1);
6144887Schin 	if(cp[1]==0)
6154887Schin 		return((unsigned)cp[0]);
6164887Schin 	if(*cp=='^' && cp[1] && cp[2]==0)
6174887Schin 	{
6184887Schin 		switch(cp[1])
6194887Schin 		{
6204887Schin 		    case '-':
6214887Schin 			return(-1);
6224887Schin 		    default:
6234887Schin 			return(cntl(cp[1]));
6244887Schin 		}
6254887Schin 	}
6264887Schin 	if(streq(cp,"undef") || streq(cp,"<undef>"))
6274887Schin 		return(-1);
6284887Schin 	return(*((unsigned char*)cp));
6294887Schin }
6304887Schin 
set(char * argv[],struct termios * sp)6314887Schin static void set(char *argv[], struct termios *sp)
6324887Schin {
6334887Schin 	const Tty_t *tp;
6344887Schin 	register int c,off;
6354887Schin 	char *cp;
6364887Schin 	char *ep;
6374887Schin 	while(cp = *argv++)
6384887Schin 	{
6394887Schin 		off = 0;
6404887Schin 		if(*cp=='-')
6414887Schin 		{
6424887Schin 			cp++;
6434887Schin 			off=1;
6444887Schin 		}
6454887Schin 		if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS)))
6464887Schin 			error(ERROR_exit(1),"%s: unknown mode",cp);
6474887Schin 		switch(tp->type)
6484887Schin 		{
6494887Schin 		    case CHAR:
6504887Schin 			if(off)
6514887Schin 				error(ERROR_exit(1),"%s: unknown mode",cp);
6524887Schin 			if(!*argv)
6534887Schin 				error(ERROR_exit(1),"missing argument to %s",cp);
6544887Schin 			c = gettchar(*argv++);
6554887Schin 			if(c>=0)
6564887Schin 				sp->c_cc[tp->mask] = c;
6574887Schin 			else
6584887Schin 				sp->c_cc[tp->mask] = _POSIX_VDISABLE;
6594887Schin 			break;
6604887Schin 		    case BIT: case BITS:
6614887Schin 			switch(tp->field)
6624887Schin 			{
6634887Schin 			    case C_FLAG:
6644887Schin 				if(off)
6654887Schin 					sp->c_cflag &= ~tp->mask;
6664887Schin 				else
6674887Schin 					sp->c_cflag |= tp->mask;
6684887Schin 				break;
6694887Schin 			    case I_FLAG:
6704887Schin 				if(off)
6714887Schin 					sp->c_iflag &= ~tp->mask;
6724887Schin 				else
6734887Schin 					sp->c_iflag |= tp->mask;
6744887Schin 				break;
6754887Schin 			    case O_FLAG:
6764887Schin 				sp->c_oflag &= ~tp->mask;
6774887Schin 				sp->c_oflag |= tp->val;
6784887Schin 				break;
6794887Schin 			    case L_FLAG:
6804887Schin 				if(off)
6814887Schin 					sp->c_lflag &= ~tp->mask;
6824887Schin 				else
6834887Schin 					sp->c_lflag |= tp->mask;
6844887Schin 				break;
6854887Schin 			}
6864887Schin 			break;
6874887Schin 		    case TABS:
6884887Schin 			sp->c_oflag &= ~tp->mask;
6894887Schin 			if(off)
6904887Schin 				sp->c_oflag |= tp->val;
6914887Schin 			break;
6924887Schin #ifdef TIOCSWINSZ
6934887Schin 		    case WIND:
6944887Schin 		    {
6954887Schin 			struct winsize win;
6964887Schin 			int n;
6974887Schin 			if(ioctl(0,TIOCGWINSZ,&win)<0)
6984887Schin 				error(ERROR_system(1),"cannot set %s",tp->name);
6994887Schin 			if(!(cp= *argv))
7004887Schin 			{
7014887Schin 				sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row);
7024887Schin 				break;
7034887Schin 			}
7044887Schin 			argv++;
7054887Schin 			n=strtol(cp,&cp,10);
7064887Schin 			if(*cp)
7074887Schin 				error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name);
7084887Schin 			if(tp->mask)
7094887Schin 				win.ws_col = n;
7104887Schin 			else
7114887Schin 				win.ws_row = n;
7124887Schin 			if(ioctl(0,TIOCSWINSZ,&win)<0)
7134887Schin 				error(ERROR_system(1),"cannot set %s",tp->name);
7144887Schin 			break;
7154887Schin 		    }
7164887Schin #endif
7174887Schin 		    case NUM:
7184887Schin 			cp = *argv;
7194887Schin 			if (!cp)
7204887Schin 			{
7214887Schin 				if (tp->field == C_SPEED)
7224887Schin 				{
7234887Schin 					if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp)))
7244887Schin 						sfprintf(sfstdout, "%s\n", tp->name);
7254887Schin 					break;
7264887Schin 				}
7274887Schin 				error(ERROR_exit(1), "%s: missing numeric argument", tp->name);
7284887Schin 			}
7294887Schin 			argv++;
7304887Schin 			c = (int)strtol(cp, &ep, 10);
7314887Schin 			if (*ep)
7324887Schin 				error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp);
7334887Schin 			switch (tp->field)
7344887Schin 			{
7354887Schin #if _mem_c_line_termios
7364887Schin 			case C_LINE:
7374887Schin 				sp->c_line = c;
7384887Schin 				break;
7394887Schin #endif
7404887Schin 			case C_SPEED:
7414887Schin 				if(getspeed(c))
7424887Schin 				{
7434887Schin 					if (*tp->name != 'o')
7444887Schin 						cfsetispeed(sp, c);
7454887Schin 					if (*tp->name != 'i')
7464887Schin 						cfsetospeed(sp, c);
7474887Schin 				}
7484887Schin 				else
7494887Schin 					error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp);
7504887Schin 				break;
7514887Schin 			case T_CHAR:
7524887Schin 				sp->c_cc[tp->mask] = c;
7534887Schin 				break;
7544887Schin 			}
7554887Schin 			break;
7564887Schin 		    case SPEED:
7574887Schin 			cfsetospeed(sp, tp->mask);
7584887Schin 			cfsetispeed(sp, tp->mask);
7594887Schin 			break;
7604887Schin 		    case SIZE:
7614887Schin 			sp->c_cflag &= ~CSIZE;
7624887Schin 			sp->c_cflag |= tp->mask;
7634887Schin 			break;
7644887Schin 		    case SANE:
7654887Schin 			sane(sp);
7664887Schin 			break;
7674887Schin #if defined(OLCUC) && defined(IUCLC)
7684887Schin 		    case CASE:
7694887Schin 			if(off)
7704887Schin 			{
7714887Schin 				sp->c_iflag |= IUCLC;
7724887Schin 				sp->c_oflag |= OLCUC;
7734887Schin 			}
7744887Schin 			else
7754887Schin 			{
7764887Schin 				sp->c_iflag &= ~IUCLC;
7774887Schin 				sp->c_oflag &= ~OLCUC;
7784887Schin 			}
7794887Schin 			break;
7804887Schin #endif /* OLCUC && IUCLC */
7814887Schin 		}
7824887Schin 	}
7834887Schin }
7844887Schin 
7854887Schin 
listchars(Sfio_t * sp,int type)7864887Schin static void listchars(Sfio_t *sp,int type)
7874887Schin {
7884887Schin 	int i,c;
7894887Schin 	c = (type==CHAR?'c':'n');
7904887Schin 	for(i=0; i < elementsof(Ttable); i++)
7914887Schin 	{
7924887Schin 		if(Ttable[i].type==type && *Ttable[i].description)
7934887Schin 			sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description);
7944887Schin 	}
7954887Schin }
7964887Schin 
listgroup(Sfio_t * sp,int type,const char * description)7974887Schin static void listgroup(Sfio_t *sp,int type, const char *description)
7984887Schin {
7994887Schin 	int i;
8004887Schin 	sfprintf(sp,"[+");
8014887Schin 	for(i=0; i < elementsof(Ttable); i++)
8024887Schin 	{
8034887Schin 		if(Ttable[i].type==type)
8044887Schin 			sfprintf(sp,"%s ",Ttable[i].name);
8054887Schin 	}
8064887Schin 	sfprintf(sp,"?%s.]",description);
8074887Schin }
8084887Schin 
listmask(Sfio_t * sp,unsigned int mask,const char * description)8094887Schin static void listmask(Sfio_t *sp,unsigned int mask,const char *description)
8104887Schin {
8114887Schin 	int i;
8124887Schin 	sfprintf(sp,"[+");
8134887Schin 	for(i=0; i < elementsof(Ttable); i++)
8144887Schin 	{
8154887Schin 		if(Ttable[i].mask==mask && Ttable[i].type==BITS)
8164887Schin 			sfprintf(sp,"%s ",Ttable[i].name);
8174887Schin 	}
8184887Schin 	sfprintf(sp,"?%s.]",description);
8194887Schin }
8204887Schin 
listfields(Sfio_t * sp,int field)8214887Schin static void listfields(Sfio_t *sp,int field)
8224887Schin {
8234887Schin 	int i;
8244887Schin 	for(i=0; i < elementsof(Ttable); i++)
8254887Schin 	{
8264887Schin 		if(Ttable[i].field==field &&  Ttable[i].type==BIT && *Ttable[i].description)
8274887Schin 			sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description);
8284887Schin 	}
8294887Schin }
8304887Schin 
listmode(Sfio_t * sp,const char * name)8314887Schin static void listmode(Sfio_t *sp,const char *name)
8324887Schin {
8334887Schin 	sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description);
8344887Schin }
8354887Schin 
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)8364887Schin static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
8374887Schin {
8384887Schin 	NoP(op);
8394887Schin 	NoP(s);
8404887Schin 	NoP(dp);
8414887Schin 	sfprintf(sp,"[+Control Modes.]{");
8424887Schin 	listfields(sp,C_FLAG);
8434887Schin 	listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given.  A value of \b0\b causes immediate hangup");
8444887Schin 	listchars(sp,NUM);
8454887Schin 	listgroup(sp,SIZE,"Number of bits in a character");
8464887Schin 	sfprintf(sp,"}[+Input Modes.]{");
8474887Schin 	listfields(sp,I_FLAG);
8484887Schin 	sfprintf(sp,"}[+Output Modes.]{");
8494887Schin 	listfields(sp,O_FLAG);
8504887Schin #ifdef CRDLY
8514887Schin 	listmask(sp,CRDLY,"Carriage return delay style");
8524887Schin #endif
8534887Schin #ifdef NLDLY
8544887Schin 	listmask(sp,NLDLY,"Newline delay style");
8554887Schin #endif
8564887Schin #ifdef TABDLY
8574887Schin 	listmask(sp,TABDLY,"Horizontal tab delay style");
8584887Schin #endif
8594887Schin #ifdef BSDLY
8604887Schin 	listmask(sp,BSDLY,"Backspace delay style");
8614887Schin #endif
8624887Schin #ifdef FFDLY
8634887Schin 	listmask(sp,FFDLY,"Form feed delay style");
8644887Schin #endif
8654887Schin #ifdef VTDLY
8664887Schin 	listmask(sp,VTDLY,"Vertical tab delay style");
8674887Schin #endif
8684887Schin 	sfprintf(sp,"}[+Local Modes.]{");
8694887Schin 	listfields(sp,L_FLAG);
8704887Schin 	sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty "
8714887Schin 		"string then the control assignment is disabled.]{");
8724887Schin 	listchars(sp,WIND);
8734887Schin 	listchars(sp,CHAR);
8744887Schin 	sfprintf(sp,"}[+Combination Modes.]{");
8754887Schin 	listmode(sp,"ek");
8764887Schin 	listmode(sp,"evenp");
8774887Schin 	listmode(sp,"lcase");
8784887Schin 	listmode(sp,"oddp");
8794887Schin 	listmode(sp,"parity");
8804887Schin 	listmode(sp,"sane");
8814887Schin 	listmode(sp,"tabs");
8824887Schin 	listmode(sp,"LCASE");
8834887Schin 	sfputc(sp,'}');
8844887Schin 	return(1);
8854887Schin }
8864887Schin 
8878462SApril.Chin@Sun.COM #ifndef _lib_tcgetpgrp
8888462SApril.Chin@Sun.COM #  ifdef TIOCGPGRP
8898462SApril.Chin@Sun.COM 	   static int _i_;
8908462SApril.Chin@Sun.COM #	   define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
8918462SApril.Chin@Sun.COM #  else
8928462SApril.Chin@Sun.COM #	   define tcgetpgrp(a) (-1)
8938462SApril.Chin@Sun.COM #  endif /* TIOCGPGRP */
8948462SApril.Chin@Sun.COM #endif /* _lib_tcgetpgrp */
8958462SApril.Chin@Sun.COM 
8964887Schin int
b_stty(int argc,char ** argv,void * context)8974887Schin b_stty(int argc, char** argv, void* context)
8984887Schin {
8994887Schin 	struct termios		tty;
9004887Schin 	register int		n;
9014887Schin 	register int		flags = 0;
9024887Schin 	const Tty_t*		tp;
9034887Schin 	Optdisc_t		disc;
9044887Schin 
9054887Schin 	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE);
9064887Schin 	if (tcgetattr(0, &tty) < 0)
9074887Schin 		error(ERROR_system(1),"not a tty");
9084887Schin 	memset(&disc, 0, sizeof(disc));
9094887Schin 	disc.version = OPT_VERSION;
9104887Schin 	disc.infof = infof;
9114887Schin 	opt_info.disc = &disc;
9124887Schin 	for (;;)
9134887Schin 	{
9144887Schin 		switch (n = optget(argv, usage))
9154887Schin 		{
9164887Schin 		case 'a':
9174887Schin 		case 'g':
91810898Sroland.mainz@nrubsig.org 		case 't':
9194887Schin 			if (!opt_info.offset || !argv[opt_info.index][opt_info.offset])
9204887Schin 			{
9214887Schin 				switch (n)
9224887Schin 				{
9234887Schin 				case 'a':
9244887Schin 					flags |= A_FLAG;
9254887Schin 					break;
9264887Schin 				case 'g':
9274887Schin 					flags |= G_FLAG;
9284887Schin 					break;
92910898Sroland.mainz@nrubsig.org 				case 't':
93010898Sroland.mainz@nrubsig.org 					flags |= T_FLAG;
93110898Sroland.mainz@nrubsig.org 					break;
9324887Schin 				}
9334887Schin 				continue;
9344887Schin 			}
9354887Schin 			/*FALLTHROUGH*/
9364887Schin 		case ':':
9374887Schin 			if (!opt_info.offset)
9384887Schin 				error(2, "%s", opt_info.arg);
9394887Schin 			else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS))
9404887Schin 				error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]);
9414887Schin 			break;
9424887Schin 		case '?':
9434887Schin 			error(ERROR_usage(2), "%s", opt_info.arg);
9444887Schin 			break;
9454887Schin 		}
9464887Schin 		break;
9474887Schin 	}
9484887Schin 	argv += opt_info.index;
9498462SApril.Chin@Sun.COM 	if (error_info.errors || (flags && *argv) || (flags&(flags-1)))
9504887Schin 		error(ERROR_usage(2), "%s", optusage(NiL));
9518462SApril.Chin@Sun.COM 	if (flags & T_FLAG)
9528462SApril.Chin@Sun.COM 		sfprintf(sfstdout, "%d\n", tcgetpgrp(0));
9538462SApril.Chin@Sun.COM 	else if (*argv)
9544887Schin 	{
9554887Schin 		if (!argv[1] && **argv == ':')
9564887Schin 			gin(*argv, &tty);
9574887Schin 		else
9584887Schin 			set(argv, &tty);
9594887Schin 		if (tcsetattr(0, TCSANOW, &tty) < 0)
9604887Schin 			error(ERROR_system(1), "cannot set tty");
9614887Schin 	}
9624887Schin 	else
9634887Schin 		output(&tty, flags);
9644887Schin 	return error_info.errors;
9654887Schin }
966