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