xref: /titanic_51/usr/src/lib/libcmd/common/stty.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
1*da2e3ebdSchin /***********************************************************************
2*da2e3ebdSchin *                                                                      *
3*da2e3ebdSchin *               This software is part of the ast package               *
4*da2e3ebdSchin *           Copyright (c) 1992-2007 AT&T Knowledge Ventures            *
5*da2e3ebdSchin *                      and is licensed under the                       *
6*da2e3ebdSchin *                  Common Public License, Version 1.0                  *
7*da2e3ebdSchin *                      by AT&T Knowledge Ventures                      *
8*da2e3ebdSchin *                                                                      *
9*da2e3ebdSchin *                A copy of the License is available at                 *
10*da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*da2e3ebdSchin *                                                                      *
13*da2e3ebdSchin *              Information and Software Systems Research               *
14*da2e3ebdSchin *                            AT&T Research                             *
15*da2e3ebdSchin *                           Florham Park NJ                            *
16*da2e3ebdSchin *                                                                      *
17*da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18*da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19*da2e3ebdSchin *                                                                      *
20*da2e3ebdSchin ***********************************************************************/
21*da2e3ebdSchin #pragma prototyped
22*da2e3ebdSchin /*
23*da2e3ebdSchin  * stty.c
24*da2e3ebdSchin  * Written by David Korn
25*da2e3ebdSchin  * Tue Apr  4 10:46:00 EDT 1995
26*da2e3ebdSchin  */
27*da2e3ebdSchin 
28*da2e3ebdSchin static const char usage[] =
29*da2e3ebdSchin "[-?@(#)$Id: stty (AT&T Research) 2006-10-31 $\n]"
30*da2e3ebdSchin USAGE_LICENSE
31*da2e3ebdSchin "[+NAME?stty - set or get terminal modes]"
32*da2e3ebdSchin "[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device "
33*da2e3ebdSchin 	"that is the current standard input; without arguments, it writes "
34*da2e3ebdSchin 	"the settings of certain modes to standard output.]"
35*da2e3ebdSchin 
36*da2e3ebdSchin "[a:all?Writes to standard output all of the mode settings.]"
37*da2e3ebdSchin "[g:save?Writes the current settings to standard output in a form that can "
38*da2e3ebdSchin 	"be used as an argument to another \bstty\b command.  The \brows\b "
39*da2e3ebdSchin 	"and \bcolumns\b values are not included.]"
40*da2e3ebdSchin "\n"
41*da2e3ebdSchin "\n[mode ...]\n"
42*da2e3ebdSchin "\n"
43*da2e3ebdSchin "[+EXTENDED DESCRIPTION?Modes are specified either as a single name or "
44*da2e3ebdSchin 	"as a name followed by a value.  As indicated below, many of the "
45*da2e3ebdSchin 	"mode names can be preceded by a \b-\b to negate its meaning.  "
46*da2e3ebdSchin 	"Modes are listed by group corresponding to field in the "
47*da2e3ebdSchin 	"\btermios\b structure defined in \b<termios.h>\b.  Modes "
48*da2e3ebdSchin 	"in the last group are implemented using options in the previous "
49*da2e3ebdSchin 	"groups.  Note that many combinations of modes make no sense, but "
50*da2e3ebdSchin 	"no sanity checking is performed.  The modes are selected from the "
51*da2e3ebdSchin 	"following:]{\fabc\f}"
52*da2e3ebdSchin 
53*da2e3ebdSchin "[+EXIT STATUS?]{"
54*da2e3ebdSchin       "[+0?All modes reported or set successfully.]"
55*da2e3ebdSchin         "[+>0?Standard input not a terminaol or one or more modes failed.]"
56*da2e3ebdSchin "}"
57*da2e3ebdSchin "[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]"
58*da2e3ebdSchin ;
59*da2e3ebdSchin 
60*da2e3ebdSchin 
61*da2e3ebdSchin #include	<cmd.h>
62*da2e3ebdSchin #include	<ccode.h>
63*da2e3ebdSchin #include	<ctype.h>
64*da2e3ebdSchin #include	<ast_tty.h>
65*da2e3ebdSchin #if _sys_ioctl
66*da2e3ebdSchin #include	<sys/ioctl.h>
67*da2e3ebdSchin #endif
68*da2e3ebdSchin 
69*da2e3ebdSchin #define C(x)	ERROR_catalog(x)
70*da2e3ebdSchin 
71*da2e3ebdSchin #ifndef _POSIX_VDISABLE
72*da2e3ebdSchin #   define _POSIX_VDISABLE 0
73*da2e3ebdSchin #endif
74*da2e3ebdSchin 
75*da2e3ebdSchin #ifndef NCCS
76*da2e3ebdSchin #   ifdef NCC
77*da2e3ebdSchin #	define NCCS	NCC
78*da2e3ebdSchin #   else
79*da2e3ebdSchin #	define NCCS	elementsof(((struct termio*)0)->c_cc)
80*da2e3ebdSchin #   endif
81*da2e3ebdSchin #endif
82*da2e3ebdSchin 
83*da2e3ebdSchin /* command options */
84*da2e3ebdSchin #define A_FLAG	1
85*da2e3ebdSchin #define G_FLAG	2
86*da2e3ebdSchin 
87*da2e3ebdSchin /* termios fields */
88*da2e3ebdSchin #define C_FLAG	1
89*da2e3ebdSchin #define C_LINE	2
90*da2e3ebdSchin #define C_SPEED	3
91*da2e3ebdSchin #define I_FLAG	4
92*da2e3ebdSchin #define O_FLAG	5
93*da2e3ebdSchin #define L_FLAG	6
94*da2e3ebdSchin #define T_CHAR	7
95*da2e3ebdSchin #define W_SIZE	8
96*da2e3ebdSchin 
97*da2e3ebdSchin #define BIT	1
98*da2e3ebdSchin #define BITS	2
99*da2e3ebdSchin #define NUM	3
100*da2e3ebdSchin #define CHAR	4
101*da2e3ebdSchin #define SPEED	5
102*da2e3ebdSchin #define SIZE	6
103*da2e3ebdSchin #define MIXED	7
104*da2e3ebdSchin #define SANE	8
105*da2e3ebdSchin #define COOKED	9
106*da2e3ebdSchin #define CASE	10
107*da2e3ebdSchin #define TABS	11
108*da2e3ebdSchin #define WIND	12
109*da2e3ebdSchin 
110*da2e3ebdSchin #undef	SS			/* who co-opted this namespace?	*/
111*da2e3ebdSchin 
112*da2e3ebdSchin #define IG	0x0001		/* ignore display		*/
113*da2e3ebdSchin #define NL	0x0002		/* entry ends line of display	*/
114*da2e3ebdSchin #define SS	0x0004		/* set in sane mode		*/
115*da2e3ebdSchin #define US	0x0010		/* unset in sane mode		*/
116*da2e3ebdSchin 
117*da2e3ebdSchin typedef struct tty_s
118*da2e3ebdSchin {
119*da2e3ebdSchin 	const char	name[8];
120*da2e3ebdSchin 	unsigned char	type;
121*da2e3ebdSchin 	unsigned char	field;
122*da2e3ebdSchin 	short		flags;
123*da2e3ebdSchin 	unsigned long	mask;
124*da2e3ebdSchin 	unsigned long	val;
125*da2e3ebdSchin 	const char	description[76];
126*da2e3ebdSchin } Tty_t;
127*da2e3ebdSchin 
128*da2e3ebdSchin static const Tty_t Ttable[] =
129*da2e3ebdSchin {
130*da2e3ebdSchin #ifdef CBAUD
131*da2e3ebdSchin { "ispeed",	NUM,	C_SPEED,0,	CBAUD, 0, C("\an\a is the input baud rate") },
132*da2e3ebdSchin { "ospeed",	NUM,	C_SPEED,0,	CBAUD, 0, C("\an\a is the output baud rate") },
133*da2e3ebdSchin { "speed",	NUM,	C_SPEED,IG,	CBAUD },
134*da2e3ebdSchin #endif
135*da2e3ebdSchin { "0",		SPEED,	C_FLAG,	0,	B0 },
136*da2e3ebdSchin { "50",		SPEED,	C_FLAG,	0,	B50 },
137*da2e3ebdSchin { "75",		SPEED,	C_FLAG,	0,	B75 },
138*da2e3ebdSchin { "110",	SPEED,	C_FLAG,	0,	B110 },
139*da2e3ebdSchin { "134",	SPEED,	C_FLAG,	0,	B134 },
140*da2e3ebdSchin { "150",	SPEED,	C_FLAG,	0,	B150 },
141*da2e3ebdSchin { "200",	SPEED,	C_FLAG,	0,	B200 },
142*da2e3ebdSchin { "300",	SPEED,	C_FLAG,	0,	B300 },
143*da2e3ebdSchin { "600",	SPEED,	C_FLAG,	0,	B600 },
144*da2e3ebdSchin { "1200",	SPEED,	C_FLAG,	0,	B1200 },
145*da2e3ebdSchin { "1800",	SPEED,	C_FLAG,	0,	B1800 },
146*da2e3ebdSchin { "2400",	SPEED,	C_FLAG,	0,	B2400 },
147*da2e3ebdSchin { "4800",	SPEED,	C_FLAG,	0,	B4800 },
148*da2e3ebdSchin { "9600",	SPEED,	C_FLAG,	0,	B9600 },
149*da2e3ebdSchin { "19200",	SPEED,	C_FLAG,	0,	B19200 },
150*da2e3ebdSchin { "38400",	SPEED,	C_FLAG,	0,	B38400 },
151*da2e3ebdSchin 
152*da2e3ebdSchin #ifdef TIOCSWINSZ
153*da2e3ebdSchin { "rows",	WIND,	W_SIZE,	IG,	0, 24, C("\an\a is the number of lines for display") },
154*da2e3ebdSchin { "cols",	WIND,	W_SIZE,	IG,	1, 80, C("\an\a is the number of columns for display") },
155*da2e3ebdSchin { "columns",	WIND,	W_SIZE,	IG,	1, 80, C("Same as \bcols\b") },
156*da2e3ebdSchin #endif
157*da2e3ebdSchin { "intr",	CHAR,	T_CHAR,	SS,	VINTR, 'C', C("Send an interrupt signal") },
158*da2e3ebdSchin { "quit",	CHAR,	T_CHAR,	SS,	VQUIT, '|', C("Send a quit signal") },
159*da2e3ebdSchin { "erase",	CHAR,	T_CHAR,	SS,	VERASE, 'H', C("Erase the last character entered") },
160*da2e3ebdSchin { "kill",	CHAR,	T_CHAR,	NL|SS,	VKILL, 'U', C("Erase the current line") },
161*da2e3ebdSchin { "eof",	CHAR,	T_CHAR,	SS,	VEOF, 'D', C("Send an end of file") },
162*da2e3ebdSchin #ifdef VEOL2
163*da2e3ebdSchin { "eol2",	CHAR,	T_CHAR,	US,	VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") },
164*da2e3ebdSchin #endif /* VEOL2 */
165*da2e3ebdSchin #ifdef VSWTCH
166*da2e3ebdSchin { "swtch",	CHAR,	T_CHAR,	US,	VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") },
167*da2e3ebdSchin #endif /* VSWTCH */
168*da2e3ebdSchin { "eol",	CHAR,	T_CHAR,	NL|US,	VEOL, _POSIX_VDISABLE, C("End the line") },
169*da2e3ebdSchin #ifdef VSTART
170*da2e3ebdSchin { "start",	CHAR,	T_CHAR,	SS,	VSTART, 'Q', C("Restart the output after stopping it") },
171*da2e3ebdSchin #endif /* VSTART */
172*da2e3ebdSchin #ifdef VSTOP
173*da2e3ebdSchin { "stop",	CHAR,	T_CHAR,	SS,	VSTOP, 'S', C("Stop the output") },
174*da2e3ebdSchin #endif /* VSTOP */
175*da2e3ebdSchin #ifdef VDSUSP
176*da2e3ebdSchin { "dsusp",	CHAR,	T_CHAR,	SS,	VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") },
177*da2e3ebdSchin #endif /* VDSUSP */
178*da2e3ebdSchin #ifdef VSUSP
179*da2e3ebdSchin { "susp",	CHAR,	T_CHAR,	NL|SS,	VSUSP, 'Z', C("Send a terminal stop signal") },
180*da2e3ebdSchin #endif /* VSUSP */
181*da2e3ebdSchin #ifdef VREPRINT
182*da2e3ebdSchin { "rprnt",	CHAR,	T_CHAR,	SS,	VREPRINT, 'R', C("Redraw the current line") },
183*da2e3ebdSchin #endif /* VREPRINT */
184*da2e3ebdSchin #ifdef VDISCARD
185*da2e3ebdSchin { "flush",	CHAR,	T_CHAR,	SS,	VDISCARD, 'O', C("Discard output") },
186*da2e3ebdSchin #endif /* VDISCARD */
187*da2e3ebdSchin #ifdef VWERASE
188*da2e3ebdSchin { "werase",	CHAR,	T_CHAR,	SS,	VWERASE, 'W', C("Erase the last word entered") },
189*da2e3ebdSchin #endif /* VWERASE */
190*da2e3ebdSchin #ifdef VLNEXT
191*da2e3ebdSchin { "lnext",	CHAR,	T_CHAR,	NL|SS,	VLNEXT, 'V', C("Enter the next input character literally") },
192*da2e3ebdSchin #endif /* VLNEXT */
193*da2e3ebdSchin 
194*da2e3ebdSchin #if _mem_c_line_termios
195*da2e3ebdSchin { "line",	NUM,	C_LINE,	0,	0, 0, C("Line discipline number") },
196*da2e3ebdSchin #endif
197*da2e3ebdSchin { "min",	NUM,	T_CHAR,	0,	VMIN, 0, C("Mininmum number of characters to read in raw mode") },
198*da2e3ebdSchin { "time",	NUM,	T_CHAR,	0,	VTIME, 0, C("Number of .1 second intervals with raw mode") },
199*da2e3ebdSchin 
200*da2e3ebdSchin { "parenb",	BIT,	C_FLAG,	0,	PARENB,	PARENB, C("Enable (disable) parity generation and detection") },
201*da2e3ebdSchin { "parodd",	BIT,	C_FLAG,	0,	PARODD, PARODD, C("Use odd (even) parity") },
202*da2e3ebdSchin #ifdef PAREXT
203*da2e3ebdSchin { "parext",	BIT,	C_FLAG,	0,	PAREXT, PAREXT },
204*da2e3ebdSchin #endif /* PAREXT */
205*da2e3ebdSchin #ifdef CREAD
206*da2e3ebdSchin { "cread",	BIT,	C_FLAG,	SS,	CREAD, CREAD, C("Enable (disable) input") },
207*da2e3ebdSchin #endif /* CREAD */
208*da2e3ebdSchin { "cs5",	SIZE,	C_FLAG,	0,	CSIZE,	CS5 , C("Char size 5") },
209*da2e3ebdSchin { "cs6",	SIZE,	C_FLAG,	0,	CSIZE,	CS6 , C("Char size 6") },
210*da2e3ebdSchin { "cs7",	SIZE,	C_FLAG,	0,	CSIZE,	CS7 , C("Char size 7") },
211*da2e3ebdSchin { "cs8",	SIZE,	C_FLAG,	0,	CSIZE,	CS8 , C("Char size 8") },
212*da2e3ebdSchin { "hupcl",	BIT,	C_FLAG,	0,	HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") },
213*da2e3ebdSchin { "hup",	BIT,	C_FLAG,	IG,	HUPCL, HUPCL, C("Same as \bhupcl\b") },
214*da2e3ebdSchin { "cstopb",	BIT,	C_FLAG,	0,	CSTOPB, CSTOPB, C("Use two (one) stop bits") },
215*da2e3ebdSchin #ifdef CRTSCTS
216*da2e3ebdSchin { "crtscts",	BIT,	C_FLAG,	0,	CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") },
217*da2e3ebdSchin #endif /* CRTSCTS */
218*da2e3ebdSchin { "clocal",	BIT,	C_FLAG,	NL,	CLOCAL, CLOCAL, C("Disable (enable) modem control signals") },
219*da2e3ebdSchin 
220*da2e3ebdSchin { "ignbrk",	BIT,	I_FLAG,	US,	IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") },
221*da2e3ebdSchin { "brkint",	BIT,	I_FLAG,	SS,	BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") },
222*da2e3ebdSchin { "ignpar",	BIT,	I_FLAG,	0,	IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") },
223*da2e3ebdSchin { "parmrk",	BIT,	I_FLAG,	0,	PARMRK, PARMRK, C("Mark (do not mark) parity errors") },
224*da2e3ebdSchin { "inpck",	BIT,	I_FLAG,	0,	INPCK, INPCK, C("Enable (disable) input parity checking") },
225*da2e3ebdSchin { "istrip",	BIT,	I_FLAG,	0,	ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") },
226*da2e3ebdSchin { "inlcr",	BIT,	I_FLAG,	US,	INLCR, INLCR, C("Translate (do not translate) carriage return to newline") },
227*da2e3ebdSchin { "igncr",	BIT,	I_FLAG,	US,	IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") },
228*da2e3ebdSchin #ifdef IUCLC
229*da2e3ebdSchin { "iuclc",	BIT,	I_FLAG,	US,	IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") },
230*da2e3ebdSchin #endif /* IUCLC */
231*da2e3ebdSchin { "ixon",	BIT,	I_FLAG,	0,	IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") },
232*da2e3ebdSchin #ifdef IXANY
233*da2e3ebdSchin { "ixany",	BIT,	I_FLAG,	US,	IXANY, IXANY, C("Any character (only start character) can restart output.") },
234*da2e3ebdSchin { "decctlq",	BIT,	I_FLAG,	IG,	IXANY, 0, C("Same as \b-ixany\b") },
235*da2e3ebdSchin #endif /* IXANY */
236*da2e3ebdSchin { "ixoff",	BIT,	I_FLAG,	US,	IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") },
237*da2e3ebdSchin #ifdef IMAXBEL
238*da2e3ebdSchin { "imaxbel",	BIT,	I_FLAG,	SS,	IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") },
239*da2e3ebdSchin #endif /* IMAXBEL */
240*da2e3ebdSchin { "icrnl",	BIT,	I_FLAG,	NL|SS,	ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") },
241*da2e3ebdSchin 
242*da2e3ebdSchin { "isig",	BIT,	L_FLAG,	SS,	ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") },
243*da2e3ebdSchin { "icanon",	BIT,	L_FLAG,	SS,	ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") },
244*da2e3ebdSchin { "icannon",	BIT,	L_FLAG,	SS,	ICANON, ICANON },
245*da2e3ebdSchin #ifdef IEXTEN
246*da2e3ebdSchin { "iexten",	BIT,	L_FLAG,	SS,	IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") },
247*da2e3ebdSchin #endif /* IEXTEN */
248*da2e3ebdSchin { "echo",	BIT,	L_FLAG,	SS,	ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") },
249*da2e3ebdSchin { "echoe",	BIT,	L_FLAG,	SS,	ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") },
250*da2e3ebdSchin { "echok",	BIT,	L_FLAG,	SS,	ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") },
251*da2e3ebdSchin #ifdef ECHOKE
252*da2e3ebdSchin { "echoke",	BIT,	L_FLAG,	SS,	ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") },
253*da2e3ebdSchin #endif
254*da2e3ebdSchin { "lfkc",	BIT,	L_FLAG,	IG,	ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") },
255*da2e3ebdSchin { "echonl",	BIT,	L_FLAG,	SS,	ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" },
256*da2e3ebdSchin #ifdef ECHOCTL
257*da2e3ebdSchin { "echoctl",	BIT,	L_FLAG,	SS,	ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") },
258*da2e3ebdSchin #else
259*da2e3ebdSchin #define ECHOCTL		0
260*da2e3ebdSchin #endif /* ECHOCTL */
261*da2e3ebdSchin #ifdef ECHOPRT
262*da2e3ebdSchin { "echoprt",	BIT,	L_FLAG,	US,	ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") },
263*da2e3ebdSchin #else
264*da2e3ebdSchin #define ECHOPRT		0
265*da2e3ebdSchin #endif /* ECHOPRT */
266*da2e3ebdSchin #ifdef XCASE
267*da2e3ebdSchin { "xcase",	BIT,	L_FLAG,	US,	XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") },
268*da2e3ebdSchin #endif /* XCASE */
269*da2e3ebdSchin #ifdef DEFECHO
270*da2e3ebdSchin { "defecho",	BIT,	L_FLAG,	0,	DEFECHO, DEFECHO },
271*da2e3ebdSchin #endif /* DEFECHO */
272*da2e3ebdSchin #ifdef FLUSHO
273*da2e3ebdSchin { "flusho",	BIT,	L_FLAG,	0,	FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") },
274*da2e3ebdSchin #endif /* FLUSHO */
275*da2e3ebdSchin #ifdef PENDIN
276*da2e3ebdSchin { "pendin",	BIT,	L_FLAG,	0,	PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") },
277*da2e3ebdSchin #endif /* PENDIN */
278*da2e3ebdSchin { "noflsh",	BIT,	L_FLAG,	US,	NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") },
279*da2e3ebdSchin #ifdef TOSTOP
280*da2e3ebdSchin { "tostop",	BIT,	L_FLAG,	NL|US,	TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") },
281*da2e3ebdSchin #endif /* TOSTOP */
282*da2e3ebdSchin #ifdef OLCUC
283*da2e3ebdSchin { "olcuc",	BIT,	O_FLAG,	US,	OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") },
284*da2e3ebdSchin #endif /* OLCUC */
285*da2e3ebdSchin #ifdef ONLCR
286*da2e3ebdSchin { "onlcr",	BIT,	O_FLAG,	SS,	ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") },
287*da2e3ebdSchin #endif /* ONLCR */
288*da2e3ebdSchin #ifdef ONLRET
289*da2e3ebdSchin { "onlret",	BIT,	O_FLAG,	US,	ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") },
290*da2e3ebdSchin #endif /* ONLRET */
291*da2e3ebdSchin #ifdef OCRNL
292*da2e3ebdSchin { "ocrnl",	BIT,	O_FLAG,	US,	OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") },
293*da2e3ebdSchin #endif /* OCRNL */
294*da2e3ebdSchin #ifdef ONOCR
295*da2e3ebdSchin { "onocr",	BIT,	O_FLAG,	US,	ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") },
296*da2e3ebdSchin #endif /* ONOCR */
297*da2e3ebdSchin #ifdef OFILL
298*da2e3ebdSchin { "ofill",	BIT,	O_FLAG,	US,	OFILL, OFILL, C("Use fill characters (use timing) for delays") },
299*da2e3ebdSchin #endif /* OFILL */
300*da2e3ebdSchin #ifdef OFDEL
301*da2e3ebdSchin { "ofdel",	BIT,	O_FLAG,	US,	OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") },
302*da2e3ebdSchin #endif /* OFDEL */
303*da2e3ebdSchin { "opost",	BIT,	O_FLAG,	SS,	OPOST, OPOST, C(" Postprocess (do not postprocess) output") },
304*da2e3ebdSchin #ifdef CRDLY
305*da2e3ebdSchin { "cr0",	BITS,	O_FLAG,	IG|SS,	CRDLY, CR0  },
306*da2e3ebdSchin { "cr1",	BITS,	O_FLAG,	US,	CRDLY, CR1  },
307*da2e3ebdSchin { "cr2",	BITS,	O_FLAG,	US,	CRDLY, CR2  },
308*da2e3ebdSchin { "cr3",	BITS,	O_FLAG,	US,	CRDLY, CR3  },
309*da2e3ebdSchin #endif
310*da2e3ebdSchin #ifdef NLDLY
311*da2e3ebdSchin { "nl0",	BITS,	O_FLAG,	IG|US,	NLDLY, NL0  },
312*da2e3ebdSchin { "nl1",	BITS,	O_FLAG,	US,	NLDLY, NL1  },
313*da2e3ebdSchin #endif
314*da2e3ebdSchin #ifdef TABDLY
315*da2e3ebdSchin { "tabs",	TABS,	O_FLAG,	IG,	TABDLY, TAB3, C("Preserve (expand to spaces) tabs") },
316*da2e3ebdSchin { "tab0",	BITS,	O_FLAG,	IG|SS,	TABDLY, TAB0  },
317*da2e3ebdSchin { "tab1",	BITS,	O_FLAG,	US,	TABDLY, TAB1  },
318*da2e3ebdSchin { "tab2",	BITS,	O_FLAG,	US,	TABDLY, TAB2  },
319*da2e3ebdSchin { "tab3",	BITS,	O_FLAG,	US,	TABDLY, TAB3  },
320*da2e3ebdSchin #endif
321*da2e3ebdSchin #ifdef BSDLY
322*da2e3ebdSchin { "bs0",	BITS,	O_FLAG,	IG|SS,	BSDLY, BS0 },
323*da2e3ebdSchin { "bs1",	BITS,	O_FLAG,	US,	BSDLY, BS1  },
324*da2e3ebdSchin #endif
325*da2e3ebdSchin #ifdef VTDLY
326*da2e3ebdSchin { "vt0",	BITS,	O_FLAG,	IG|SS,	VTDLY, VT0  },
327*da2e3ebdSchin { "vt1",	BITS,	O_FLAG,	US,	VTDLY, VT1  },
328*da2e3ebdSchin #endif
329*da2e3ebdSchin #ifdef FFDLY
330*da2e3ebdSchin { "ff0",	BITS,	O_FLAG,	IG|SS,	FFDLY, FF0 },
331*da2e3ebdSchin { "ff1",	BITS,	O_FLAG,	US,	FFDLY, FF1 },
332*da2e3ebdSchin #endif
333*da2e3ebdSchin { "",		MIXED,	O_FLAG,	NL|IG },
334*da2e3ebdSchin 
335*da2e3ebdSchin { "evenp",	MIXED,	C_FLAG,	IG,	PARENB, 0, C("Same as \bparenb -parodd cs7\b") },
336*da2e3ebdSchin { "oddp",	MIXED,	C_FLAG,	IG,	PARODD, 0, C("Same as \bparenb parodd cs7\b") },
337*da2e3ebdSchin { "parity",	MIXED,	C_FLAG,	IG,	0, 0, C("Same as parenb \b-parodd cs7\b") },
338*da2e3ebdSchin { "ek",		MIXED,	C_FLAG,	IG,	0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") },
339*da2e3ebdSchin { "sane",	SANE,	C_FLAG,	IG,	0, 0, C("Reset all modes to some reasonable values") },
340*da2e3ebdSchin { "cooked",	COOKED,	C_FLAG,	IG,	0, 0, C("Disable raw input and output") },
341*da2e3ebdSchin { "raw",	COOKED,	C_FLAG,	IG,	0, 0, C("Enable raw input and output") },
342*da2e3ebdSchin { "lcase",	CASE,	C_FLAG,	IG,	0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") },
343*da2e3ebdSchin { "LCASE",	CASE,	C_FLAG,	IG,	0 , 0, C("Same as \blcase\b") }
344*da2e3ebdSchin };
345*da2e3ebdSchin 
346*da2e3ebdSchin #if CC_NATIVE == CC_ASCII
347*da2e3ebdSchin #define cntl(x)		(((x)=='?')?0177:((x)&037))
348*da2e3ebdSchin #else
349*da2e3ebdSchin #define cntl(x)		(((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE))
350*da2e3ebdSchin #endif
351*da2e3ebdSchin 
352*da2e3ebdSchin static void sane(register struct termios *sp)
353*da2e3ebdSchin {
354*da2e3ebdSchin 	register const Tty_t*	tp;
355*da2e3ebdSchin 
356*da2e3ebdSchin 	for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++)
357*da2e3ebdSchin 		if (tp->flags & (SS|US))
358*da2e3ebdSchin 			switch (tp->type)
359*da2e3ebdSchin 			{
360*da2e3ebdSchin 			case BIT:
361*da2e3ebdSchin 			case BITS:
362*da2e3ebdSchin 				switch (tp->field)
363*da2e3ebdSchin 				{
364*da2e3ebdSchin 				case C_FLAG:
365*da2e3ebdSchin 					if (tp->flags & SS)
366*da2e3ebdSchin 						sp->c_cflag |= tp->mask;
367*da2e3ebdSchin 					else
368*da2e3ebdSchin 						sp->c_cflag &= ~tp->mask;
369*da2e3ebdSchin 					break;
370*da2e3ebdSchin 				case I_FLAG:
371*da2e3ebdSchin 					if (tp->flags & SS)
372*da2e3ebdSchin 						sp->c_iflag |= tp->mask;
373*da2e3ebdSchin 					else
374*da2e3ebdSchin 						sp->c_iflag &= ~tp->mask;
375*da2e3ebdSchin 					break;
376*da2e3ebdSchin 				case O_FLAG:
377*da2e3ebdSchin 					if (tp->flags & SS)
378*da2e3ebdSchin 						sp->c_oflag |= tp->mask;
379*da2e3ebdSchin 					else
380*da2e3ebdSchin 						sp->c_oflag &= ~tp->mask;
381*da2e3ebdSchin 					break;
382*da2e3ebdSchin 				case L_FLAG:
383*da2e3ebdSchin 					if (tp->flags & SS)
384*da2e3ebdSchin 						sp->c_lflag |= tp->mask;
385*da2e3ebdSchin 					else
386*da2e3ebdSchin 						sp->c_lflag &= ~tp->mask;
387*da2e3ebdSchin 					break;
388*da2e3ebdSchin 				}
389*da2e3ebdSchin 				break;
390*da2e3ebdSchin 			case CHAR:
391*da2e3ebdSchin 				sp->c_cc[tp->mask] = cntl(tp->val);
392*da2e3ebdSchin 				break;
393*da2e3ebdSchin 			}
394*da2e3ebdSchin }
395*da2e3ebdSchin 
396*da2e3ebdSchin static int gin(char *arg,struct termios *sp)
397*da2e3ebdSchin {
398*da2e3ebdSchin 	register int i;
399*da2e3ebdSchin 	if(*arg++ != ':')
400*da2e3ebdSchin 		return(0);
401*da2e3ebdSchin 	sp->c_iflag = strtol(arg,&arg,16);
402*da2e3ebdSchin 	if(*arg++ != ':')
403*da2e3ebdSchin 		return(0);
404*da2e3ebdSchin 	sp->c_oflag = strtol(arg,&arg,16);
405*da2e3ebdSchin 	if(*arg++ != ':')
406*da2e3ebdSchin 		return(0);
407*da2e3ebdSchin 	sp->c_cflag = strtol(arg,&arg,16);
408*da2e3ebdSchin 	if(*arg++ != ':')
409*da2e3ebdSchin 		return(0);
410*da2e3ebdSchin 	sp->c_lflag = strtol(arg,&arg,16);
411*da2e3ebdSchin 	if(*arg++ != ':')
412*da2e3ebdSchin 		return(0);
413*da2e3ebdSchin 	for(i=0;i< NCCS; i++)
414*da2e3ebdSchin 	{
415*da2e3ebdSchin 		sp->c_cc[i] = strtol(arg,&arg,16);
416*da2e3ebdSchin 		if(*arg++ != ':')
417*da2e3ebdSchin 			return(0);
418*da2e3ebdSchin 	}
419*da2e3ebdSchin #if _mem_c_line_termios
420*da2e3ebdSchin 	sp->c_line =
421*da2e3ebdSchin #endif
422*da2e3ebdSchin 		strtol(arg,&arg,16);
423*da2e3ebdSchin 	if(*arg++ != ':')
424*da2e3ebdSchin 		return(0);
425*da2e3ebdSchin 	i = strtol(arg,&arg,16);
426*da2e3ebdSchin 	if(*arg++ != ':')
427*da2e3ebdSchin 		return(0);
428*da2e3ebdSchin 	cfsetispeed(sp, i);
429*da2e3ebdSchin 	i = strtol(arg,&arg,16);
430*da2e3ebdSchin 	if(*arg++ != ':')
431*da2e3ebdSchin 		return(0);
432*da2e3ebdSchin 	cfsetospeed(sp, i);
433*da2e3ebdSchin 	if(*arg)
434*da2e3ebdSchin 		return(0);
435*da2e3ebdSchin 	return(1);
436*da2e3ebdSchin }
437*da2e3ebdSchin 
438*da2e3ebdSchin static void gout(struct termios *sp)
439*da2e3ebdSchin {
440*da2e3ebdSchin 	register int i;
441*da2e3ebdSchin 	sfprintf(sfstdout,":%x",sp->c_iflag);
442*da2e3ebdSchin 	sfprintf(sfstdout,":%x",sp->c_oflag);
443*da2e3ebdSchin 	sfprintf(sfstdout,":%x",sp->c_cflag);
444*da2e3ebdSchin 	sfprintf(sfstdout,":%x",sp->c_lflag);
445*da2e3ebdSchin 	for(i=0;i< NCCS; i++)
446*da2e3ebdSchin 		sfprintf(sfstdout,":%x",sp->c_cc[i]);
447*da2e3ebdSchin #if _mem_c_line_termios
448*da2e3ebdSchin 	sfprintf(sfstdout,":%x", sp->c_line);
449*da2e3ebdSchin #else
450*da2e3ebdSchin 	sfprintf(sfstdout,":%x", 0);
451*da2e3ebdSchin #endif
452*da2e3ebdSchin 	sfprintf(sfstdout,":%x",cfgetispeed(sp));
453*da2e3ebdSchin 	sfprintf(sfstdout,":%x",cfgetospeed(sp));
454*da2e3ebdSchin 	sfprintf(sfstdout,":\n");
455*da2e3ebdSchin }
456*da2e3ebdSchin 
457*da2e3ebdSchin static void output(struct termios *sp, int flags)
458*da2e3ebdSchin {
459*da2e3ebdSchin 	const Tty_t *tp;
460*da2e3ebdSchin 	struct termios tty;
461*da2e3ebdSchin 	register int delim = ' ';
462*da2e3ebdSchin 	register int i,off,off2;
463*da2e3ebdSchin 	char schar[2];
464*da2e3ebdSchin 	unsigned int ispeed = cfgetispeed(sp);
465*da2e3ebdSchin 	unsigned int ospeed = cfgetospeed(sp);
466*da2e3ebdSchin 	if(flags&G_FLAG)
467*da2e3ebdSchin 	{
468*da2e3ebdSchin 		gout(sp);
469*da2e3ebdSchin 		return;
470*da2e3ebdSchin 	}
471*da2e3ebdSchin 	tty = *sp;
472*da2e3ebdSchin 	sane(&tty);
473*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
474*da2e3ebdSchin 	{
475*da2e3ebdSchin 		tp= &Ttable[i];
476*da2e3ebdSchin 		if(tp->flags&IG)
477*da2e3ebdSchin 		{
478*da2e3ebdSchin 			if(tp->flags&NL)
479*da2e3ebdSchin 				sfputc(sfstdout,'\n');
480*da2e3ebdSchin 			continue;
481*da2e3ebdSchin 		}
482*da2e3ebdSchin 		switch(tp->type)
483*da2e3ebdSchin 		{
484*da2e3ebdSchin 		    case BIT:
485*da2e3ebdSchin 		    case BITS:
486*da2e3ebdSchin 			off = 1;
487*da2e3ebdSchin 			switch(tp->field)
488*da2e3ebdSchin 			{
489*da2e3ebdSchin 			    case C_FLAG:
490*da2e3ebdSchin 				if(sp->c_cflag&tp->mask)
491*da2e3ebdSchin 					off = 0;
492*da2e3ebdSchin 				if(tty.c_cflag&tp->mask)
493*da2e3ebdSchin 					off2 = 0;
494*da2e3ebdSchin 				break;
495*da2e3ebdSchin 			    case I_FLAG:
496*da2e3ebdSchin 				if(sp->c_iflag&tp->mask)
497*da2e3ebdSchin 					off = 0;
498*da2e3ebdSchin 				if(tty.c_iflag&tp->mask)
499*da2e3ebdSchin 					off2 = 0;
500*da2e3ebdSchin 				break;
501*da2e3ebdSchin 			    case O_FLAG:
502*da2e3ebdSchin 				if((sp->c_oflag&tp->mask)==tp->val)
503*da2e3ebdSchin 					off = 0;
504*da2e3ebdSchin 				if(tty.c_oflag&tp->mask)
505*da2e3ebdSchin 					off2 = 0;
506*da2e3ebdSchin 				break;
507*da2e3ebdSchin 			    case L_FLAG:
508*da2e3ebdSchin 				if(sp->c_lflag&tp->mask)
509*da2e3ebdSchin 					off = 0;
510*da2e3ebdSchin 				if(tty.c_lflag&tp->mask)
511*da2e3ebdSchin 					off2 = 0;
512*da2e3ebdSchin 			}
513*da2e3ebdSchin 			if(tp->flags&NL)
514*da2e3ebdSchin 				delim = '\n';
515*da2e3ebdSchin 			if(!flags && off==off2)
516*da2e3ebdSchin 				continue;
517*da2e3ebdSchin 			if(!off)
518*da2e3ebdSchin 				sfprintf(sfstdout,"%s%c",tp->name,delim);
519*da2e3ebdSchin 			else if(tp->type==BIT)
520*da2e3ebdSchin 				sfprintf(sfstdout,"-%s%c",tp->name,delim);
521*da2e3ebdSchin 			delim = ' ';
522*da2e3ebdSchin 			break;
523*da2e3ebdSchin 
524*da2e3ebdSchin 		    case CHAR:
525*da2e3ebdSchin 			off = sp->c_cc[tp->mask];
526*da2e3ebdSchin 			if(tp->flags&NL)
527*da2e3ebdSchin 				delim = '\n';
528*da2e3ebdSchin 			if(!flags && off==(unsigned char)tty.c_cc[tp->mask])
529*da2e3ebdSchin 				continue;
530*da2e3ebdSchin 			if(off==_POSIX_VDISABLE)
531*da2e3ebdSchin 				sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim);
532*da2e3ebdSchin 			else if(isprint(off&0xff))
533*da2e3ebdSchin 				sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim);
534*da2e3ebdSchin 			else
535*da2e3ebdSchin #if CC_NATIVE == CC_ASCII
536*da2e3ebdSchin 			sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim);
537*da2e3ebdSchin #else
538*da2e3ebdSchin 			{
539*da2e3ebdSchin 				off = ccmapc(off, CC_NATIVE, CC_ASCII);
540*da2e3ebdSchin 				sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim);
541*da2e3ebdSchin 			}
542*da2e3ebdSchin #endif
543*da2e3ebdSchin 			delim = ' ';
544*da2e3ebdSchin 			break;
545*da2e3ebdSchin 		    case SIZE:
546*da2e3ebdSchin 			if((sp->c_cflag&CSIZE)!=tp->mask)
547*da2e3ebdSchin 				continue;
548*da2e3ebdSchin 			if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE))
549*da2e3ebdSchin 				sfprintf(sfstdout,"%s ",tp->name);
550*da2e3ebdSchin 			break;
551*da2e3ebdSchin 		    case SPEED:
552*da2e3ebdSchin 			if(tp->mask==ispeed)
553*da2e3ebdSchin 			{
554*da2e3ebdSchin 				if(ispeed!=ospeed)
555*da2e3ebdSchin 					schar[0]='i';
556*da2e3ebdSchin 				else
557*da2e3ebdSchin 					schar[0]=0;
558*da2e3ebdSchin 			}
559*da2e3ebdSchin 			else if(tp->mask==ospeed)
560*da2e3ebdSchin 				schar[0]='o';
561*da2e3ebdSchin 			else
562*da2e3ebdSchin 				continue;
563*da2e3ebdSchin 			schar[1] = 0;
564*da2e3ebdSchin #ifdef TIOCSWINSZ
565*da2e3ebdSchin 			{
566*da2e3ebdSchin 				struct winsize win;
567*da2e3ebdSchin 				off = ioctl(0,TIOCGWINSZ,&win);
568*da2e3ebdSchin 				if(off>=0)
569*da2e3ebdSchin 					sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col);
570*da2e3ebdSchin 			}
571*da2e3ebdSchin 			if(off<0)
572*da2e3ebdSchin #endif
573*da2e3ebdSchin 				sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name);
574*da2e3ebdSchin 		}
575*da2e3ebdSchin 	}
576*da2e3ebdSchin 	if(delim=='\n')
577*da2e3ebdSchin 		sfputc(sfstdout,'\n');
578*da2e3ebdSchin }
579*da2e3ebdSchin 
580*da2e3ebdSchin static const Tty_t *lookup(const char *name)
581*da2e3ebdSchin {
582*da2e3ebdSchin 	register int i;
583*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
584*da2e3ebdSchin 	{
585*da2e3ebdSchin 		if(strcmp(Ttable[i].name,name)==0)
586*da2e3ebdSchin 			return(&Ttable[i]);
587*da2e3ebdSchin 	}
588*da2e3ebdSchin 	return(0);
589*da2e3ebdSchin 
590*da2e3ebdSchin }
591*da2e3ebdSchin 
592*da2e3ebdSchin static const Tty_t *getspeed(unsigned long val)
593*da2e3ebdSchin {
594*da2e3ebdSchin 	register int i;
595*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
596*da2e3ebdSchin 	{
597*da2e3ebdSchin 		if(Ttable[i].type==SPEED && Ttable[i].mask==val)
598*da2e3ebdSchin 			return(&Ttable[i]);
599*da2e3ebdSchin 	}
600*da2e3ebdSchin 	return(0);
601*da2e3ebdSchin }
602*da2e3ebdSchin 
603*da2e3ebdSchin static int gettchar(register const char *cp)
604*da2e3ebdSchin {
605*da2e3ebdSchin 	if(*cp==0)
606*da2e3ebdSchin 		return(-1);
607*da2e3ebdSchin 	if(cp[1]==0)
608*da2e3ebdSchin 		return((unsigned)cp[0]);
609*da2e3ebdSchin 	if(*cp=='^' && cp[1] && cp[2]==0)
610*da2e3ebdSchin 	{
611*da2e3ebdSchin 		switch(cp[1])
612*da2e3ebdSchin 		{
613*da2e3ebdSchin 		    case '-':
614*da2e3ebdSchin 			return(-1);
615*da2e3ebdSchin 		    default:
616*da2e3ebdSchin 			return(cntl(cp[1]));
617*da2e3ebdSchin 		}
618*da2e3ebdSchin 	}
619*da2e3ebdSchin 	if(streq(cp,"undef") || streq(cp,"<undef>"))
620*da2e3ebdSchin 		return(-1);
621*da2e3ebdSchin 	return(*((unsigned char*)cp));
622*da2e3ebdSchin }
623*da2e3ebdSchin 
624*da2e3ebdSchin static void set(char *argv[], struct termios *sp)
625*da2e3ebdSchin {
626*da2e3ebdSchin 	const Tty_t *tp;
627*da2e3ebdSchin 	register int c,off;
628*da2e3ebdSchin 	char *cp;
629*da2e3ebdSchin 	char *ep;
630*da2e3ebdSchin 	while(cp = *argv++)
631*da2e3ebdSchin 	{
632*da2e3ebdSchin 		off = 0;
633*da2e3ebdSchin 		if(*cp=='-')
634*da2e3ebdSchin 		{
635*da2e3ebdSchin 			cp++;
636*da2e3ebdSchin 			off=1;
637*da2e3ebdSchin 		}
638*da2e3ebdSchin 		if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS)))
639*da2e3ebdSchin 			error(ERROR_exit(1),"%s: unknown mode",cp);
640*da2e3ebdSchin 		switch(tp->type)
641*da2e3ebdSchin 		{
642*da2e3ebdSchin 		    case CHAR:
643*da2e3ebdSchin 			if(off)
644*da2e3ebdSchin 				error(ERROR_exit(1),"%s: unknown mode",cp);
645*da2e3ebdSchin 			if(!*argv)
646*da2e3ebdSchin 				error(ERROR_exit(1),"missing argument to %s",cp);
647*da2e3ebdSchin 			c = gettchar(*argv++);
648*da2e3ebdSchin 			if(c>=0)
649*da2e3ebdSchin 				sp->c_cc[tp->mask] = c;
650*da2e3ebdSchin 			else
651*da2e3ebdSchin 				sp->c_cc[tp->mask] = _POSIX_VDISABLE;
652*da2e3ebdSchin 			break;
653*da2e3ebdSchin 		    case BIT: case BITS:
654*da2e3ebdSchin 			switch(tp->field)
655*da2e3ebdSchin 			{
656*da2e3ebdSchin 			    case C_FLAG:
657*da2e3ebdSchin 				if(off)
658*da2e3ebdSchin 					sp->c_cflag &= ~tp->mask;
659*da2e3ebdSchin 				else
660*da2e3ebdSchin 					sp->c_cflag |= tp->mask;
661*da2e3ebdSchin 				break;
662*da2e3ebdSchin 			    case I_FLAG:
663*da2e3ebdSchin 				if(off)
664*da2e3ebdSchin 					sp->c_iflag &= ~tp->mask;
665*da2e3ebdSchin 				else
666*da2e3ebdSchin 					sp->c_iflag |= tp->mask;
667*da2e3ebdSchin 				break;
668*da2e3ebdSchin 			    case O_FLAG:
669*da2e3ebdSchin 				sp->c_oflag &= ~tp->mask;
670*da2e3ebdSchin 				sp->c_oflag |= tp->val;
671*da2e3ebdSchin 				break;
672*da2e3ebdSchin 			    case L_FLAG:
673*da2e3ebdSchin 				if(off)
674*da2e3ebdSchin 					sp->c_lflag &= ~tp->mask;
675*da2e3ebdSchin 				else
676*da2e3ebdSchin 					sp->c_lflag |= tp->mask;
677*da2e3ebdSchin 				break;
678*da2e3ebdSchin 			}
679*da2e3ebdSchin 			break;
680*da2e3ebdSchin 		    case TABS:
681*da2e3ebdSchin 			sp->c_oflag &= ~tp->mask;
682*da2e3ebdSchin 			if(off)
683*da2e3ebdSchin 				sp->c_oflag |= tp->val;
684*da2e3ebdSchin 			break;
685*da2e3ebdSchin #ifdef TIOCSWINSZ
686*da2e3ebdSchin 		    case WIND:
687*da2e3ebdSchin 		    {
688*da2e3ebdSchin 			struct winsize win;
689*da2e3ebdSchin 			int n;
690*da2e3ebdSchin 			if(ioctl(0,TIOCGWINSZ,&win)<0)
691*da2e3ebdSchin 				error(ERROR_system(1),"cannot set %s",tp->name);
692*da2e3ebdSchin 			if(!(cp= *argv))
693*da2e3ebdSchin 			{
694*da2e3ebdSchin 				sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row);
695*da2e3ebdSchin 				break;
696*da2e3ebdSchin 			}
697*da2e3ebdSchin 			argv++;
698*da2e3ebdSchin 			n=strtol(cp,&cp,10);
699*da2e3ebdSchin 			if(*cp)
700*da2e3ebdSchin 				error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name);
701*da2e3ebdSchin 			if(tp->mask)
702*da2e3ebdSchin 				win.ws_col = n;
703*da2e3ebdSchin 			else
704*da2e3ebdSchin 				win.ws_row = n;
705*da2e3ebdSchin 			if(ioctl(0,TIOCSWINSZ,&win)<0)
706*da2e3ebdSchin 				error(ERROR_system(1),"cannot set %s",tp->name);
707*da2e3ebdSchin 			break;
708*da2e3ebdSchin 		    }
709*da2e3ebdSchin #endif
710*da2e3ebdSchin 		    case NUM:
711*da2e3ebdSchin 			cp = *argv;
712*da2e3ebdSchin 			if (!cp)
713*da2e3ebdSchin 			{
714*da2e3ebdSchin 				if (tp->field == C_SPEED)
715*da2e3ebdSchin 				{
716*da2e3ebdSchin 					if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp)))
717*da2e3ebdSchin 						sfprintf(sfstdout, "%s\n", tp->name);
718*da2e3ebdSchin 					break;
719*da2e3ebdSchin 				}
720*da2e3ebdSchin 				error(ERROR_exit(1), "%s: missing numeric argument", tp->name);
721*da2e3ebdSchin 			}
722*da2e3ebdSchin 			argv++;
723*da2e3ebdSchin 			c = (int)strtol(cp, &ep, 10);
724*da2e3ebdSchin 			if (*ep)
725*da2e3ebdSchin 				error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp);
726*da2e3ebdSchin 			switch (tp->field)
727*da2e3ebdSchin 			{
728*da2e3ebdSchin #if _mem_c_line_termios
729*da2e3ebdSchin 			case C_LINE:
730*da2e3ebdSchin 				sp->c_line = c;
731*da2e3ebdSchin 				break;
732*da2e3ebdSchin #endif
733*da2e3ebdSchin 			case C_SPEED:
734*da2e3ebdSchin 				if(getspeed(c))
735*da2e3ebdSchin 				{
736*da2e3ebdSchin 					if (*tp->name != 'o')
737*da2e3ebdSchin 						cfsetispeed(sp, c);
738*da2e3ebdSchin 					if (*tp->name != 'i')
739*da2e3ebdSchin 						cfsetospeed(sp, c);
740*da2e3ebdSchin 				}
741*da2e3ebdSchin 				else
742*da2e3ebdSchin 					error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp);
743*da2e3ebdSchin 				break;
744*da2e3ebdSchin 			case T_CHAR:
745*da2e3ebdSchin 				sp->c_cc[tp->mask] = c;
746*da2e3ebdSchin 				break;
747*da2e3ebdSchin 			}
748*da2e3ebdSchin 			break;
749*da2e3ebdSchin 		    case SPEED:
750*da2e3ebdSchin 			cfsetospeed(sp, tp->mask);
751*da2e3ebdSchin 			cfsetispeed(sp, tp->mask);
752*da2e3ebdSchin 			break;
753*da2e3ebdSchin 		    case SIZE:
754*da2e3ebdSchin 			sp->c_cflag &= ~CSIZE;
755*da2e3ebdSchin 			sp->c_cflag |= tp->mask;
756*da2e3ebdSchin 			break;
757*da2e3ebdSchin 		    case SANE:
758*da2e3ebdSchin 			sane(sp);
759*da2e3ebdSchin 			break;
760*da2e3ebdSchin #if defined(OLCUC) && defined(IUCLC)
761*da2e3ebdSchin 		    case CASE:
762*da2e3ebdSchin 			if(off)
763*da2e3ebdSchin 			{
764*da2e3ebdSchin 				sp->c_iflag |= IUCLC;
765*da2e3ebdSchin 				sp->c_oflag |= OLCUC;
766*da2e3ebdSchin 			}
767*da2e3ebdSchin 			else
768*da2e3ebdSchin 			{
769*da2e3ebdSchin 				sp->c_iflag &= ~IUCLC;
770*da2e3ebdSchin 				sp->c_oflag &= ~OLCUC;
771*da2e3ebdSchin 			}
772*da2e3ebdSchin 			break;
773*da2e3ebdSchin #endif /* OLCUC && IUCLC */
774*da2e3ebdSchin 		}
775*da2e3ebdSchin 	}
776*da2e3ebdSchin }
777*da2e3ebdSchin 
778*da2e3ebdSchin 
779*da2e3ebdSchin static void listchars(Sfio_t *sp,int type)
780*da2e3ebdSchin {
781*da2e3ebdSchin 	int i,c;
782*da2e3ebdSchin 	c = (type==CHAR?'c':'n');
783*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
784*da2e3ebdSchin 	{
785*da2e3ebdSchin 		if(Ttable[i].type==type && *Ttable[i].description)
786*da2e3ebdSchin 			sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description);
787*da2e3ebdSchin 	}
788*da2e3ebdSchin }
789*da2e3ebdSchin 
790*da2e3ebdSchin static void listgroup(Sfio_t *sp,int type, const char *description)
791*da2e3ebdSchin {
792*da2e3ebdSchin 	int i;
793*da2e3ebdSchin 	sfprintf(sp,"[+");
794*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
795*da2e3ebdSchin 	{
796*da2e3ebdSchin 		if(Ttable[i].type==type)
797*da2e3ebdSchin 			sfprintf(sp,"%s ",Ttable[i].name);
798*da2e3ebdSchin 	}
799*da2e3ebdSchin 	sfprintf(sp,"?%s.]",description);
800*da2e3ebdSchin }
801*da2e3ebdSchin 
802*da2e3ebdSchin static void listmask(Sfio_t *sp,unsigned int mask,const char *description)
803*da2e3ebdSchin {
804*da2e3ebdSchin 	int i;
805*da2e3ebdSchin 	sfprintf(sp,"[+");
806*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
807*da2e3ebdSchin 	{
808*da2e3ebdSchin 		if(Ttable[i].mask==mask && Ttable[i].type==BITS)
809*da2e3ebdSchin 			sfprintf(sp,"%s ",Ttable[i].name);
810*da2e3ebdSchin 	}
811*da2e3ebdSchin 	sfprintf(sp,"?%s.]",description);
812*da2e3ebdSchin }
813*da2e3ebdSchin 
814*da2e3ebdSchin static void listfields(Sfio_t *sp,int field)
815*da2e3ebdSchin {
816*da2e3ebdSchin 	int i;
817*da2e3ebdSchin 	for(i=0; i < elementsof(Ttable); i++)
818*da2e3ebdSchin 	{
819*da2e3ebdSchin 		if(Ttable[i].field==field &&  Ttable[i].type==BIT && *Ttable[i].description)
820*da2e3ebdSchin 			sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description);
821*da2e3ebdSchin 	}
822*da2e3ebdSchin }
823*da2e3ebdSchin 
824*da2e3ebdSchin static void listmode(Sfio_t *sp,const char *name)
825*da2e3ebdSchin {
826*da2e3ebdSchin 	sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description);
827*da2e3ebdSchin }
828*da2e3ebdSchin 
829*da2e3ebdSchin static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
830*da2e3ebdSchin {
831*da2e3ebdSchin 	NoP(op);
832*da2e3ebdSchin 	NoP(s);
833*da2e3ebdSchin 	NoP(dp);
834*da2e3ebdSchin 	sfprintf(sp,"[+Control Modes.]{");
835*da2e3ebdSchin 	listfields(sp,C_FLAG);
836*da2e3ebdSchin 	listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given.  A value of \b0\b causes immediate hangup");
837*da2e3ebdSchin 	listchars(sp,NUM);
838*da2e3ebdSchin 	listgroup(sp,SIZE,"Number of bits in a character");
839*da2e3ebdSchin 	sfprintf(sp,"}[+Input Modes.]{");
840*da2e3ebdSchin 	listfields(sp,I_FLAG);
841*da2e3ebdSchin 	sfprintf(sp,"}[+Output Modes.]{");
842*da2e3ebdSchin 	listfields(sp,O_FLAG);
843*da2e3ebdSchin #ifdef CRDLY
844*da2e3ebdSchin 	listmask(sp,CRDLY,"Carriage return delay style");
845*da2e3ebdSchin #endif
846*da2e3ebdSchin #ifdef NLDLY
847*da2e3ebdSchin 	listmask(sp,NLDLY,"Newline delay style");
848*da2e3ebdSchin #endif
849*da2e3ebdSchin #ifdef TABDLY
850*da2e3ebdSchin 	listmask(sp,TABDLY,"Horizontal tab delay style");
851*da2e3ebdSchin #endif
852*da2e3ebdSchin #ifdef BSDLY
853*da2e3ebdSchin 	listmask(sp,BSDLY,"Backspace delay style");
854*da2e3ebdSchin #endif
855*da2e3ebdSchin #ifdef FFDLY
856*da2e3ebdSchin 	listmask(sp,FFDLY,"Form feed delay style");
857*da2e3ebdSchin #endif
858*da2e3ebdSchin #ifdef VTDLY
859*da2e3ebdSchin 	listmask(sp,VTDLY,"Vertical tab delay style");
860*da2e3ebdSchin #endif
861*da2e3ebdSchin 	sfprintf(sp,"}[+Local Modes.]{");
862*da2e3ebdSchin 	listfields(sp,L_FLAG);
863*da2e3ebdSchin 	sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty "
864*da2e3ebdSchin 		"string then the control assignment is disabled.]{");
865*da2e3ebdSchin 	listchars(sp,WIND);
866*da2e3ebdSchin 	listchars(sp,CHAR);
867*da2e3ebdSchin 	sfprintf(sp,"}[+Combination Modes.]{");
868*da2e3ebdSchin 	listmode(sp,"ek");
869*da2e3ebdSchin 	listmode(sp,"evenp");
870*da2e3ebdSchin 	listmode(sp,"lcase");
871*da2e3ebdSchin 	listmode(sp,"oddp");
872*da2e3ebdSchin 	listmode(sp,"parity");
873*da2e3ebdSchin 	listmode(sp,"sane");
874*da2e3ebdSchin 	listmode(sp,"tabs");
875*da2e3ebdSchin 	listmode(sp,"LCASE");
876*da2e3ebdSchin 	sfputc(sp,'}');
877*da2e3ebdSchin 	return(1);
878*da2e3ebdSchin }
879*da2e3ebdSchin 
880*da2e3ebdSchin int
881*da2e3ebdSchin b_stty(int argc, char** argv, void* context)
882*da2e3ebdSchin {
883*da2e3ebdSchin 	struct termios		tty;
884*da2e3ebdSchin 	register int		n;
885*da2e3ebdSchin 	register int		flags = 0;
886*da2e3ebdSchin 	const Tty_t*		tp;
887*da2e3ebdSchin 	Optdisc_t		disc;
888*da2e3ebdSchin 
889*da2e3ebdSchin 	cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE);
890*da2e3ebdSchin 	if (tcgetattr(0, &tty) < 0)
891*da2e3ebdSchin 		error(ERROR_system(1),"not a tty");
892*da2e3ebdSchin 	memset(&disc, 0, sizeof(disc));
893*da2e3ebdSchin 	disc.version = OPT_VERSION;
894*da2e3ebdSchin 	disc.infof = infof;
895*da2e3ebdSchin 	opt_info.disc = &disc;
896*da2e3ebdSchin 	for (;;)
897*da2e3ebdSchin 	{
898*da2e3ebdSchin 		switch (n = optget(argv, usage))
899*da2e3ebdSchin 		{
900*da2e3ebdSchin 		case 'a':
901*da2e3ebdSchin 		case 'g':
902*da2e3ebdSchin 			if (!opt_info.offset || !argv[opt_info.index][opt_info.offset])
903*da2e3ebdSchin 			{
904*da2e3ebdSchin 				switch (n)
905*da2e3ebdSchin 				{
906*da2e3ebdSchin 				case 'a':
907*da2e3ebdSchin 					flags |= A_FLAG;
908*da2e3ebdSchin 					break;
909*da2e3ebdSchin 				case 'g':
910*da2e3ebdSchin 					flags |= G_FLAG;
911*da2e3ebdSchin 					break;
912*da2e3ebdSchin 				}
913*da2e3ebdSchin 				continue;
914*da2e3ebdSchin 			}
915*da2e3ebdSchin 			/*FALLTHROUGH*/
916*da2e3ebdSchin 		case ':':
917*da2e3ebdSchin 			if (!opt_info.offset)
918*da2e3ebdSchin 				error(2, "%s", opt_info.arg);
919*da2e3ebdSchin 			else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS))
920*da2e3ebdSchin 				error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]);
921*da2e3ebdSchin 			break;
922*da2e3ebdSchin 		case '?':
923*da2e3ebdSchin 			error(ERROR_usage(2), "%s", opt_info.arg);
924*da2e3ebdSchin 			break;
925*da2e3ebdSchin 		}
926*da2e3ebdSchin 		break;
927*da2e3ebdSchin 	}
928*da2e3ebdSchin 	argv += opt_info.index;
929*da2e3ebdSchin 	if (error_info.errors || (flags && *argv))
930*da2e3ebdSchin 		error(ERROR_usage(2), "%s", optusage(NiL));
931*da2e3ebdSchin 	if (*argv)
932*da2e3ebdSchin 	{
933*da2e3ebdSchin 		if (!argv[1] && **argv == ':')
934*da2e3ebdSchin 			gin(*argv, &tty);
935*da2e3ebdSchin 		else
936*da2e3ebdSchin 			set(argv, &tty);
937*da2e3ebdSchin 		if (tcsetattr(0, TCSANOW, &tty) < 0)
938*da2e3ebdSchin 			error(ERROR_system(1), "cannot set tty");
939*da2e3ebdSchin 	}
940*da2e3ebdSchin 	else
941*da2e3ebdSchin 		output(&tty, flags);
942*da2e3ebdSchin 	return error_info.errors;
943*da2e3ebdSchin }
944