1 /*
2  * stty - set the options for a terminal
3  *
4  * Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
5  */
6 /*
7  * Copyright (c) 2003 Gunnar Ritter
8  *
9  * This software is provided 'as-is', without any express or implied
10  * warranty. In no event will the authors be held liable for any damages
11  * arising from the use of this software.
12  *
13  * Permission is granted to anyone to use this software for any purpose,
14  * including commercial applications, and to alter it and redistribute
15  * it freely, subject to the following restrictions:
16  *
17  * 1. The origin of this software must not be misrepresented; you must not
18  *    claim that you wrote the original software. If you use this software
19  *    in a product, an acknowledgment in the product documentation would be
20  *    appreciated but is not required.
21  *
22  * 2. Altered source versions must be plainly marked as such, and must not be
23  *    misrepresented as being the original software.
24  *
25  * 3. This notice may not be removed or altered from any source distribution.
26  */
27 
28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
29 #define	USED	__attribute__ ((used))
30 #elif defined __GNUC__
31 #define	USED	__attribute__ ((unused))
32 #else
33 #define	USED
34 #endif
35 #ifndef	UCB
36 static const char sccsid[] USED = "@(#)stty.sl	1.23 (gritter) 1/22/06";
37 #else	/* UCB */
38 static const char sccsid[] USED = "@(#)/usr/ucb/stty.sl	1.23 (gritter) 1/22/06";
39 #endif	/* UCB */
40 
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <termios.h>
46 #include <unistd.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <libgen.h>
51 #include <ctype.h>
52 #include <locale.h>
53 #include <pathconf.h>
54 #ifndef	TIOCGWINSZ
55 #include <sys/ioctl.h>
56 #endif
57 
58 #ifndef	VSWTCH
59 #ifdef	VSWTC
60 #define	VSWTCH	VSWTC
61 #endif
62 #endif
63 
64 #ifdef	TABDLY
65 static void	tabs(int);
66 #endif
67 static void	evenp(int);
68 static void	oddp(int);
69 static void	spacep(int);
70 static void	markp(int);
71 static void	raw(int);
72 static void	cooked(int);
73 static void	nl(int);
74 static void	sane(int);
75 #ifdef	OFDEL
76 static void	fill(int);
77 #endif
78 #ifdef	XCASE
79 static void	lcase(int);
80 #endif
81 static void	ek(int);
82 #if 0
83 static void	tty33(int);
84 static void	tty37(int);
85 static void	vt05(int);
86 static void	tn300(int);
87 static void	ti700(int);
88 static void	tek(int);
89 #endif
90 static void	rows(int);
91 static void	columns(int);
92 static void	ypixels(int);
93 static void	xpixels(int);
94 static void	vmin(int);
95 static void	vtime(int);
96 static void	line(int);
97 #ifdef	UCB
98 static void	litout(int);
99 static void	pass8(int);
100 static void	crt(int);
101 static void	dec(int);
102 #endif	/* UCB */
103 
104 static const struct	mode {
105 	const char	*m_name;	/* name of mode */
106 	void	(*m_func)(int);		/* handler function */
107 	long	m_val;			/* flag value */
108 	long	m_dfl;			/* default (not sane!) value */
109 	int	m_flg;			/* print flags:
110 					     01 print regardless of difference
111 					     02 print only if -a is not set
112 					     04 print only if -a is set
113 					    010 print under all circumstances
114 					    020 print only if equal
115 					    040 ignore for printing
116 					   0100 ignore for setting
117 					   0200 use m_dfl as mask
118 					   0400 print only if equal even if -a
119 					  01000 negate for setting
120 					*/
121 	enum {
122 		M_SEPAR,		/* separator */
123 		M_NSEPAR,		/* new separator */
124 		M_IFLAG,		/* in c_iflag */
125 		M_OFLAG,		/* in c_oflag */
126 		M_CFLAG,		/* in c_cflag */
127 		M_PCFLAG,		/* in c_cflag, but printed w/o -a */
128 		M_LFLAG,		/* in c_lflag */
129 		M_CC,			/* in c_cc */
130 		M_FUNCT,		/* handled via function */
131 		M_INVAL			/* invalid */
132 	}	m_type;
133 } modes[] = {
134 	{ "oddp",	0, PARENB|PARODD,PARENB|PARODD,0122,	M_PCFLAG },
135 	{ "evenp",	0, PARENB|PARODD,PARENB,	0122,	M_PCFLAG },
136 	{ "parity",	0, PARENB,	0,	0122,	M_PCFLAG },
137 	{ "cstopb",	0,	CSTOPB,	0,	02,	M_PCFLAG },
138 	{ "hupcl",	0,	HUPCL,	0,	02,	M_PCFLAG },
139 	{ "cread",	0,	CREAD,	CREAD,	02,	M_PCFLAG },
140 	{ "clocal",	0,	CLOCAL,	0,	02,	M_PCFLAG },
141 	{ "intr",	0,	VINTR,	'\177',	0,	M_CC },
142 	{ "quit",	0,	VQUIT,	'\34',	0,	M_CC },
143 	{ "erase",	0,	VERASE,	'#',	0,	M_CC },
144 	{ "kill",	0,	VKILL,	'@',	0,	M_CC },
145 	{ "\n",		0,	0,	0,	04,	M_NSEPAR },
146 	{ "eof",	0,	VEOF,	'\4',	0,	M_CC },
147 	{ "eol",	0,	VEOL,	'\0',	0,	M_CC },
148 	{ "eol2",	0,	VEOL2,	'\0',	0,	M_CC },
149 #ifdef	VSWTCH
150 	{ "swtch",	0,	VSWTCH,	'\32',	0,	M_CC },
151 #endif
152 	{ "\n",		0,	0,	0,	04,	M_NSEPAR },
153 	{ "start",	0,	VSTART,	'\21',	0,	M_CC },
154 	{ "stop",	0,	VSTOP,	'\23',	0,	M_CC },
155 	{ "susp",	0,	VSUSP,	'\32',	0,	M_CC },
156 #ifdef	VDSUSP
157 	{ "dsusp",	0,	VDSUSP,	'\31',	0,	M_CC },
158 #else
159 	{ "dsusp",	0,	-1,	'\0',	0,	M_CC },
160 #endif
161 	{ "\n",		0,	0,	0,	04,	M_NSEPAR },
162 #ifdef	VREPRINT
163 	{ "rprnt",	0,	VREPRINT,'\22',	0,	M_CC },
164 #else
165 	{ "rprnt",	0,	-1,	'\0',	0,	M_CC },
166 #endif
167 #ifdef	VDISCARD
168 	{ "flush",	0,	VDISCARD,'\17',	0,	M_CC },
169 #else
170 	{ "flush",	0,	-1,	'\0',	0,	M_CC },
171 #endif
172 #ifdef	VWERASE
173 	{ "werase",	0,	VWERASE,'\27',	0,	M_CC },
174 #else
175 	{ "werase",	0,	-1,	'\0',	0,	M_CC },
176 #endif
177 	{ "lnext",	0,	VLNEXT,	'\26',	0,	M_CC },
178 	{ "\n",		0,	0,	0,	010,	M_SEPAR },
179 	{ "parenb",	0,	PARENB,	0,	04,	M_CFLAG },
180 	{ "parodd",	0,	PARODD,	0,	04,	M_CFLAG },
181 	{ "cs5",	0,	CS5,	CSIZE,	0604,	M_CFLAG },
182 	{ "cs6",	0,	CS6,	CSIZE,	0604,	M_CFLAG },
183 	{ "cs7",	0,	CS7,	CSIZE,	0604,	M_CFLAG },
184 	{ "cs8",	0,	CS8,	CSIZE,	0604,	M_CFLAG },
185 	{ "cstopb",	0,	CSTOPB,	0,	04,	M_CFLAG },
186 	{ "hupcl",	0,	HUPCL,	0,	04,	M_CFLAG },
187 	{ "hup",	0,	HUPCL,	0,	040,	M_CFLAG },
188 	{ "cread",	0,	CREAD,	CREAD,	04,	M_CFLAG },
189 	{ "clocal",	0,	CLOCAL,	0,	04,	M_CFLAG },
190 #ifdef	LOBLK
191 	{ "loblk",	0,	LOBLK,	0,	04,	M_CFLAG },
192 #else
193 	{ "loblk",	0,	0,	0,	04,	M_INVAL },
194 #endif
195 #ifdef	PAREXT
196 	{ "parext",	0,	PAREXT,	0,	04,	M_CFLAG },
197 #else
198 	{ "parext",	0,	0,	0,	04,	M_INVAL },
199 #endif
200 	{ "\n",		0,	0,	0,	04,	M_SEPAR },
201 	{ "ignbrk",	0,	IGNBRK,	0,	0,	M_IFLAG },
202 	{ "brkint",	0,	BRKINT,	0,	04,	M_IFLAG },
203 #ifndef	UCB
204 	{ "brkint",	0,IGNBRK|BRKINT,BRKINT,	0122,	M_IFLAG },
205 #else	/* UCB */
206 	{ "brkint",	0,	0,	BRKINT,	0122,	M_IFLAG },
207 #endif	/* UCB */
208 	{ "ignpar",	0,	IGNPAR,	IGNPAR,	04,	M_IFLAG },
209 	{ "inpck",	0,	INPCK,	INPCK,	0102,	M_IFLAG },
210 	{ "ignpar",	0,INPCK|IGNPAR,	IGNPAR,	0102,	M_IFLAG },
211 	{ "parmrk",	0,	PARMRK,	0,	0,	M_IFLAG },
212 	{ "inpck",	0,	INPCK,	INPCK,	04,	M_IFLAG },
213 	{ "istrip",	0,	ISTRIP,	ISTRIP,	0,	M_IFLAG },
214 	{ "inlcr",	0,	INLCR,	0,	0,	M_IFLAG },
215 	{ "igncr",	0,	IGNCR,	0,	0,	M_IFLAG },
216 #ifndef	UCB
217 	{ "icrnl",	0,	ICRNL,	0,	0,	M_IFLAG },
218 #else	/* UCB */
219 	{ "icrnl",	0,	ICRNL,	ICRNL,	0,	M_IFLAG },
220 #endif	/* UCB */
221 #ifdef	IUCLC
222 	{ "iuclc",	0,	IUCLC,	0,	0,	M_IFLAG },
223 #endif
224 	{ "\n",		0,	0,	0,	04,	M_SEPAR },
225 	{ "ixon",	0,	IXON,	IXON,	04,	M_IFLAG },
226 #ifndef	UCB
227 	{ "ixany",	0,	IXANY,	IXANY,	04,	M_IFLAG },
228 #else	/* UCB */
229 	{ "ixany",	0,	IXANY,	0,	0,	M_IFLAG },
230 	{ "decctlq",	0,	IXANY,	0,	01040,	M_IFLAG },
231 #endif	/* UCB */
232 	{ "ixon",	0,	0,	IXON,	0302,	M_IFLAG },
233 	{ "ixoff",	0,	IXOFF,	0,	0,	M_IFLAG },
234 #ifdef	UCB
235 	{ "tandem",	0,	IXOFF,	0,	040,	M_IFLAG },
236 #endif	/* UCB */
237 	{ "imaxbel",	0,	IMAXBEL,0,	0,	M_IFLAG },
238 #ifdef	IUTF8
239 	{ "iutf8",	0,	IUTF8,	0,	0,	M_IFLAG },
240 #endif
241 	{ "\n",		0,	0,	0,	04,	M_SEPAR },
242 	{ "isig",	0,	ISIG,	ISIG,	04,	M_LFLAG },
243 	{ "icanon",	0,	ICANON,	ICANON,	04,	M_LFLAG },
244 	{ "cbreak",	0,	ICANON,	0,	01040,	M_LFLAG },
245 #ifdef	XCASE
246 	{ "xcase",	0,	XCASE,	0,	04,	M_LFLAG },
247 #endif
248 	{ "opost",	0,	OPOST,	OPOST,	0102,	M_OFLAG },
249 #ifdef	OLCUC
250 	{ "olcuc",	0,	OLCUC,	0,	0102,	M_OFLAG },
251 #endif
252 #ifndef	UCB
253 	{ "onlcr",	0,	ONLCR,	0,	0102,	M_OFLAG },
254 #else	/* UCB */
255 	{ "onlcr",	0,	ONLCR,	ONLCR,	0102,	M_OFLAG },
256 #endif	/* UCB */
257 	{ "ocrnl",	0,	OCRNL,	0,	0102,	M_OFLAG },
258 	{ "onocr",	0,	ONOCR,	0,	0102,	M_OFLAG },
259 	{ "onlret",	0,	ONLRET,	0,	0102,	M_OFLAG },
260 #if defined (OFILL) && defined (OFDEL)
261 	{ "nul-fill",	0,	OFILL,OFILL|OFDEL,0202,	M_OFLAG },
262 	{ "del-fill",	0,OFILL|OFDEL,OFILL|OFDEL,0202,	M_OFLAG },
263 #endif
264 #ifdef	TAB1
265 	{ "tab1",	0,	TAB1,	TABDLY,	0302,	M_OFLAG },
266 #endif
267 #ifdef	TAB2
268 	{ "tab2",	0,	TAB2,	TABDLY,	0302,	M_OFLAG },
269 #endif
270 #ifdef	TAB3
271 	{ "tab3",	0,	TAB3,	TABDLY,	0302,	M_OFLAG },
272 #endif
273 	{ "\n",		0,	0,	0,	02,	M_SEPAR },
274 	{ "isig",	0,	ISIG,	ISIG,	0102,	M_LFLAG },
275 	{ "icanon",	0,	ICANON,	ICANON,	0102,	M_LFLAG },
276 #ifdef	XCASE
277 	{ "xcase",	0,	XCASE,	0,	0102,	M_LFLAG },
278 #endif
279 #ifndef	UCB
280 	{ "echo",	0,	ECHO,	ECHO,	01,	M_LFLAG },
281 	{ "echoe",	0,	ECHOE,	ECHOE,	01,	M_LFLAG },
282 	{ "echok",	0,	ECHOK,	ECHOK,	01,	M_LFLAG },
283 #else	/* UCB */
284 	{ "echo",	0,	ECHO,	ECHO,	0,	M_LFLAG },
285 	{ "echoe",	0,	ECHOE,	ECHOE,	04,	M_LFLAG },
286 	{ "crterase",	0,	ECHOE,	0,	040,	M_LFLAG },
287 	{ "echok",	0,	ECHOK,	ECHOK,	0,	M_LFLAG },
288 	{ "lfkc",	0,	ECHOK,	0,	040,	M_LFLAG },
289 	{ "echoe",	0,ECHOE|ECHOKE,	ECHOE,	0122,	M_LFLAG },
290 	{ "-echoke",	0,ECHOE|ECHOKE,	ECHOE,	0122,	M_LFLAG },
291 	{ "echoprt",	0,ECHOE|ECHOPRT,0,	0122,	M_LFLAG },
292 	{ "crt",	0,ECHOE|ECHOKE,ECHOE|ECHOKE,0302,M_LFLAG },
293 #endif	/* UCB */
294 	{ "lfkc",	0,	ECHOK,	0,	040,	M_LFLAG },
295 	{ "echonl",	0,	ECHONL,	0,	0,	M_LFLAG },
296 	{ "noflsh",	0,	NOFLSH,	0,	0,	M_LFLAG },
297 	{ "\n",		0,	0,	0,	04,	M_NSEPAR },
298 	{ "tostop",	0,	TOSTOP,	0,	0,	M_LFLAG },
299 #ifndef	UCB
300 	{ "echoctl",	0,	ECHOCTL,0,	0,	M_LFLAG },
301 #else	/* UCB */
302 	{ "echoctl",	0,	ECHOCTL,ECHOCTL,0,	M_LFLAG },
303 	{ "ctlecho",	0,	ECHOCTL,0,	040,	M_LFLAG },
304 	{ "prterase",	0,	ECHOPRT,0,	040,	M_LFLAG },
305 #endif	/* UCB */
306 	{ "echoprt",	0,	ECHOPRT,0,	04,	M_LFLAG },
307 #ifndef	UCB
308 	{ "echoke",	0,	ECHOKE,	0,	0,	M_LFLAG },
309 #else	/* UCB */
310 	{ "echoke",	0,	ECHOKE,	0,	04,	M_LFLAG },
311 	{ "crtkill",	0,	ECHOKE,	0,	040,	M_LFLAG },
312 #endif	/* UCB */
313 	{ "defecho",	0,	0,	0,	0,	M_INVAL },
314 	{ "flusho",	0,	FLUSHO,	0,	0,	M_LFLAG },
315 	{ "pendin",	0,	PENDIN,	0,	0,	M_LFLAG },
316 	{ "iexten",	0,	IEXTEN,	0,	0,	M_LFLAG },
317 	{ "\n",		0,	0,	0,	04,	M_SEPAR },
318 	{ "opost",	0,	OPOST,	OPOST,	04,	M_OFLAG },
319 #ifdef	OLCUC
320 	{ "olcuc",	0,	OLCUC,	0,	04,	M_OFLAG },
321 #endif
322 	{ "onlcr",	0,	ONLCR,	0,	04,	M_OFLAG },
323 	{ "ocrnl",	0,	OCRNL,	0,	04,	M_OFLAG },
324 	{ "onocr",	0,	ONOCR,	0,	04,	M_OFLAG },
325 	{ "onlret",	0,	ONLRET,	0,	04,	M_OFLAG },
326 #ifdef	OFILL
327 	{ "ofill",	0,	OFILL,	0,	04,	M_OFLAG },
328 #endif
329 #ifdef	OFDEL
330 	{ "ofdel",	0,	OFDEL,	0,	04,	M_OFLAG },
331 #endif
332 #ifdef	TAB1
333 	{ "tab1",	0,	TAB1,	TABDLY,	0704,	M_OFLAG },
334 #endif
335 #ifdef	TAB2
336 	{ "tab2",	0,	TAB2,	TABDLY,	0704,	M_OFLAG },
337 #endif
338 #ifdef	TAB3
339 	{ "tab3",	0,	TAB3,	TABDLY,	0704,	M_OFLAG },
340 #endif
341 	{ "\n",		0,	0,	0,	04,	M_SEPAR },
342 #ifdef	NL0
343 	{ "nl0",	0,	NL0,	NLDLY,	0240,	M_OFLAG },
344 #endif
345 #ifdef	NL1
346 	{ "nl1",	0,	NL1,	NLDLY,	0240,	M_OFLAG },
347 #endif
348 #ifdef	CR0
349 	{ "cr0",	0,	CR0,	CRDLY,	0240,	M_OFLAG },
350 #endif
351 #ifdef	CR1
352 	{ "cr1",	0,	CR1,	CRDLY,	0240,	M_OFLAG },
353 #endif
354 #ifdef	CR2
355 	{ "cr2",	0,	CR2,	CRDLY,	0240,	M_OFLAG },
356 #endif
357 #ifdef	CR3
358 	{ "cr3",	0,	CR3,	CRDLY,	0240,	M_OFLAG },
359 #endif
360 #ifdef	TAB0
361 	{ "tab0",	0,	TAB0,	TABDLY,	0240,	M_OFLAG },
362 #endif
363 #ifdef	TAB1
364 	{ "tab1",	0,	TAB1,	TABDLY,	0240,	M_OFLAG },
365 #endif
366 #ifdef	TAB2
367 	{ "tab2",	0,	TAB2,	TABDLY,	0240,	M_OFLAG },
368 #endif
369 #ifdef	TAB3
370 	{ "tab3",	0,	TAB3,	TABDLY,	0240,	M_OFLAG },
371 #endif
372 #ifdef	TABDLY
373 	{ "tabs",	tabs,	0,	0,	0240,	M_FUNCT },
374 #endif
375 #ifdef	BS0
376 	{ "bs0",	0,	BS0,	BSDLY,	0240,	M_OFLAG },
377 #endif
378 #ifdef	BS1
379 	{ "bs1",	0,	BS1,	BSDLY,	0240,	M_OFLAG },
380 #endif
381 #ifdef	FF0
382 	{ "ff0",	0,	FF0,	FFDLY,	0240,	M_OFLAG },
383 #endif
384 #ifdef	FF1
385 	{ "ff1",	0,	FF1,	FFDLY,	0240,	M_OFLAG },
386 #endif
387 #ifdef	VT0
388 	{ "vt0",	0,	VT0,	VTDLY,	0240,	M_OFLAG },
389 #endif
390 #ifdef	VT1
391 	{ "vt1",	0,	VT1,	VTDLY,	0240,	M_OFLAG },
392 #endif
393 #ifdef	CRTSCTS
394 	{ "ctsxon",	0,	CRTSCTS,0,	040,	M_OFLAG },
395 #endif	/* CRTSCTS */
396 	{ "evenp",	evenp,	0,	0,	040,	M_FUNCT },
397 	{ "parity",	evenp,	0,	0,	040,	M_FUNCT },
398 	{ "oddp",	oddp,	0,	0,	040,	M_FUNCT },
399 	{ "spacep",	spacep,	0,	0,	040,	M_FUNCT },
400 	{ "markp",	markp,	0,	0,	040,	M_FUNCT },
401 	{ "raw",	raw,	0,	0,	040,	M_FUNCT },
402 	{ "cooked",	cooked,	0,	0,	040,	M_FUNCT },
403 	{ "nl",		nl,	0,	0,	040,	M_FUNCT },
404 #ifdef	XCASE
405 	{ "lcase",	lcase,	0,	0,	040,	M_FUNCT },
406 	{ "LCASE",	lcase,	0,	0,	040,	M_FUNCT },
407 #endif
408 	{ "ek",		ek,	0,	0,	040,	M_FUNCT },
409 	{ "sane",	sane,	0,	0,	040,	M_FUNCT },
410 #ifdef	OFDEL
411 	{ "fill",	fill,	0,	0,	040,	M_FUNCT },
412 #endif
413 #if 0
414 	{ "tty33",	tty33,	0,	0,	040,	M_FUNCT },
415 	{ "tty37",	tty37,	0,	0,	040,	M_FUNCT },
416 	{ "vt05",	vt05,	0,	0,	040,	M_FUNCT },
417 	{ "tn300",	tn300,	0,	0,	040,	M_FUNCT },
418 	{ "ti700",	ti700,	0,	0,	040,	M_FUNCT },
419 	{ "tek",	tek,	0,	0,	040,	M_FUNCT },
420 #endif
421 	{ "rows",	rows,	0,	0,	040,	M_FUNCT },
422 	{ "columns",	columns,0,	0,	040,	M_FUNCT },
423 #ifdef	UCB
424 	{ "cols",	columns,0,	0,	040,	M_FUNCT },
425 #endif	/* UCB */
426 	{ "ypixels",	ypixels,0,	0,	040,	M_FUNCT },
427 	{ "xpixels",	xpixels,0,	0,	040,	M_FUNCT },
428 	{ "min",	vmin,	0,	0,	040,	M_FUNCT },
429 	{ "time",	vtime,	0,	0,	040,	M_FUNCT },
430 	{ "line",	line,	0,	0,	040,	M_FUNCT },
431 #ifdef	UCB
432 	{ "litout",	litout,	0,	0,	040,	M_FUNCT },
433 	{ "pass8",	pass8,	0,	0,	040,	M_FUNCT },
434 	{ "crt",	crt,	0,	0,	040,	M_FUNCT },
435 	{ "dec",	dec,	0,	0,	040,	M_FUNCT },
436 #endif	/* UCB */
437 	{ 0,		0,	0,	0,	0,	M_INVAL }
438 };
439 
440 static const struct {
441 	const char	*s_str;
442 	speed_t	s_val;
443 } speeds[] = {
444 	{ "0",		B0 },
445 	{ "50",		B50 },
446 	{ "75",		B75 },
447 	{ "110",	B110 },
448 	{ "134",	B134 },
449 	{ "134.5",	B134 },
450 	{ "150",	B150 },
451 	{ "200",	B200 },
452 	{ "300",	B300 },
453 	{ "600",	B600 },
454 	{ "1200",	B1200 },
455 	{ "1800",	B1800 },
456 	{ "2400",	B2400 },
457 	{ "4800",	B4800 },
458 	{ "9600",	B9600 },
459 	{ "19200",	B19200 },
460 	{ "19.2",	B19200 },
461 	{ "38400",	B38400 },
462 	{ "38.4",	B38400 },
463 #ifdef	B57600
464 	{ "57600",	B57600 },
465 #endif	/* B57600 */
466 #ifdef	B115200
467 	{ "115200",	B115200 },
468 #endif	/* B115200 */
469 #ifdef	B230400
470 	{ "230400",	B230400 },
471 #endif	/* B230400 */
472 #ifdef	B460800
473 	{ "460800",	B460800 },
474 #endif	/* B460800 */
475 #ifdef	B500000
476 	{ "500000",	B500000 },
477 #endif	/* B500000 */
478 #ifdef	B576000
479 	{ "576000",	B576000 },
480 #endif	/* B576000 */
481 #ifdef	B921600
482 	{ "921600",	B921600 },
483 #endif	/* B921600 */
484 #ifdef	B1000000
485 	{ "1000000",	B1000000 },
486 #endif	/* B1000000 */
487 #ifdef	B1152000
488 	{ "1152000",	B1152000 },
489 #endif	/* B1152000 */
490 #ifdef	B1500000
491 	{ "1500000",	B1500000 },
492 #endif	/* B1500000 */
493 #ifdef	B2000000
494 	{ "2000000",	B2000000 },
495 #endif	/* B2000000 */
496 #ifdef	B2500000
497 	{ "2500000",	B2500000 },
498 #endif	/* B2500000 */
499 #ifdef	B3000000
500 	{ "3000000",	B3000000 },
501 #endif	/* B3000000 */
502 #ifdef	B3500000
503 	{ "3500000",	B3500000 },
504 #endif	/* B3500000 */
505 #ifdef	B4000000
506 	{ "4000000",	B4000000 },
507 #endif	/* B4000000 */
508 #ifdef	EXTA
509 	{ "exta",	EXTA },
510 #endif	/* EXTA */
511 #ifdef	EXTB
512 	{ "extb",	EXTB },
513 #endif	/* EXTB */
514 	{ 0,		0 }
515 };
516 
517 static const char	*progname;
518 static const char	**args;
519 static struct termios	ts;
520 static struct winsize	ws;
521 static int		wschange;	/* ws was changed */
522 static long		vdis;		/* VDISABLE character */
523 extern int		sysv3;
524 
525 static void	usage(void);
526 static void	getattr(int);
527 static void	list(int, int);
528 static int	listmode(tcflag_t, struct mode, int, int);
529 static int	listchar(cc_t *, struct mode, int, int);
530 static const char	*baudrate(speed_t c);
531 static void	set(void);
532 static void	setmod(tcflag_t *, struct mode, int);
533 static void	setchr(cc_t *, struct mode);
534 static void	inval(void);
535 static void	glist(void);
536 static void	gset(void);
537 #ifdef	UCB
538 static void	hlist(int);
539 static void	speed(void);
540 static void	size(void);
541 #endif	/* UCB */
542 
543 #ifndef	UCB
544 #define	STTYFD	0
545 #else	/* UCB */
546 #define	STTYFD	1
547 #endif	/* UCB */
548 
549 int
main(int argc,char ** argv)550 main(int argc, char **argv)
551 {
552 	int	dds;
553 
554 	progname = basename(argv[0]);
555 	setlocale(LC_CTYPE, "");
556 #ifndef	UCB
557 	if (getenv("SYSV3") != NULL)
558 		sysv3 = 1;
559 	getattr(STTYFD);
560 #endif	/* !UCB */
561 	if (argc >= 2 && strcmp(argv[1], "--") == 0) {
562 		argc--, argv++;
563 		dds = 1;
564 	} else
565 		dds = 0;
566 	args = argc ? (const char **)&argv[1] : (const char **)&argv[0];
567 	if(!dds && argc == 2 && argv[1][0] == '-' && argv[1][1] &&
568 			argv[1][2] == '\0') {
569 		switch (argv[1][1]) {
570 		case 'a':
571 #ifdef	UCB
572 		getattr(STTYFD);
573 #endif	/* UCB */
574 			list(1, 0);
575 			break;
576 		case 'g':
577 #ifdef	UCB
578 		getattr(-1);
579 #endif	/* UCB */
580 			glist();
581 			break;
582 #ifdef	UCB
583 		case 'h':
584 		getattr(STTYFD);
585 			hlist(1);
586 			break;
587 #endif	/* UCB */
588 		default:
589 			usage();
590 		}
591 	} else if (argc == 1) {
592 #ifdef	UCB
593 		getattr(STTYFD);
594 #endif	/* UCB */
595 		list(0, 0);
596 #ifdef	UCB
597 	} else if (argc == 2 && strcmp(argv[1], "all") == 0) {
598 		getattr(STTYFD);
599 		hlist(0);
600 	} else if (argc == 2 && strcmp(argv[1], "everything") == 0) {
601 		getattr(STTYFD);
602 		hlist(1);
603 	} else if (argc == 2 && strcmp(argv[1], "speed") == 0) {
604 		getattr(-1);
605 		speed();
606 	} else if (argc == 2 && strcmp(argv[1], "size") == 0) {
607 		getattr(-1);
608 		size();
609 #endif	/* UCB */
610 	} else {
611 #ifdef	UCB
612 		getattr(STTYFD);
613 #endif	/* UCB */
614 		set();
615 		if (tcsetattr(STTYFD, TCSADRAIN, &ts) < 0 ||
616 				wschange && ioctl(STTYFD, TIOCSWINSZ, &ws) < 0)
617 			perror(progname);
618 	}
619 	return 0;
620 }
621 
622 static void
usage(void)623 usage(void)
624 {
625 	fprintf(stderr, "usage: %s [-ag] [modes]\n", progname);
626 	exit(2);
627 }
628 
629 static void
getattr(int fd)630 getattr(int fd)
631 {
632 #ifdef	UCB
633 	const char	devtty[] = "/dev/tty";
634 
635 	if (fd < 0 && (fd = open(devtty, O_RDONLY)) < 0) {
636 		fprintf(stderr, "%s: Cannot open %s: %s\n",
637 				progname, devtty, strerror(errno));
638 		exit(2);
639 	}
640 #endif	/* UCB */
641 	if (tcgetattr(fd, &ts) < 0) {
642 		perror(progname);
643 		exit(2);
644 	}
645 	if (ioctl(fd, TIOCGWINSZ, &ws) < 0) {
646 		ws.ws_row = 0;
647 		ws.ws_col = 0;
648 		ws.ws_xpixel = 0;
649 		ws.ws_ypixel = 0;
650 	}
651 #if !defined (__FreeBSD__) && !defined (__DragonFly__) && !defined (__APPLE__)
652 	vdis = fpathconf(fd, _PC_VDISABLE) & 0377;
653 #else
654 	vdis = '\377' & 0377;
655 #endif
656 }
657 
658 static void
list(int aflag,int hflag)659 list(int aflag, int hflag)
660 {
661 	int	i, d = 0;
662 	speed_t	is, os;
663 
664 	is = cfgetispeed(&ts);
665 	os = cfgetospeed(&ts);
666 	if (is == os)
667 		printf("speed %s baud;", baudrate(is));
668 	else
669 		printf("ispeed %s baud; ospeed %s baud;",
670 				baudrate(is), baudrate(os));
671 	if (aflag == 0) {
672 		for (i = 0; modes[i].m_name; i++) {
673 			if (modes[i].m_type == M_PCFLAG)
674 				d += listmode(ts.c_cflag, modes[i], aflag, 1);
675 		}
676 		d = 0;
677 	}
678 	if (sysv3 && aflag == 0) {
679 		putchar('\n');
680 	} else {
681 		putchar(sysv3 ? ' ' : '\n');
682 		printf("rows = %d%s columns = %d; "
683 				"ypixels = %d%s xpixels = %d%s\n",
684 			(int)ws.ws_row,
685 			aflag&&hflag ? "" : ";",
686 			(int)ws.ws_col,
687 			(int)ws.ws_ypixel,
688 			aflag&&hflag ? "" : ";",
689 			(int)ws.ws_xpixel,
690 			aflag&&hflag ? "" : ";");
691 	}
692 	if ((ts.c_lflag&ICANON) == 0)
693 		printf("min = %d; time = %d;\n",
694 				(int)ts.c_cc[VMIN], (int)ts.c_cc[VTIME]);
695 	for (i = 0; modes[i].m_name; i++) {
696 		if (modes[i].m_flg&040)
697 			continue;
698 		switch (modes[i].m_type) {
699 		case M_NSEPAR:
700 			if (sysv3)
701 				break;
702 		case M_SEPAR:
703 			if (d && (modes[i].m_flg&8 ||
704 					(modes[i].m_flg&(aflag?2:4)) == 0)) {
705 				fputs(modes[i].m_name, stdout);
706 				d = 0;
707 			}
708 			break;
709 		case M_IFLAG:
710 			d += listmode(ts.c_iflag, modes[i], aflag, d);
711 			break;
712 		case M_OFLAG:
713 			d += listmode(ts.c_oflag, modes[i], aflag, d);
714 			break;
715 		case M_CFLAG:
716 			d += listmode(ts.c_cflag, modes[i], aflag, d);
717 			break;
718 		case M_LFLAG:
719 			d += listmode(ts.c_lflag, modes[i], aflag, d);
720 			break;
721 		case M_CC:
722 			if (hflag == 0)
723 				d += listchar(ts.c_cc, modes[i], aflag, d);
724 			break;
725 		}
726 		if (d >= 72 && aflag == 0) {
727 			putchar('\n');
728 			d = 0;
729 		}
730 	}
731 	if (d && aflag == 0)
732 		putchar('\n');
733 }
734 
735 static int
listmode(tcflag_t flag,struct mode m,int aflag,int space)736 listmode(tcflag_t flag, struct mode m, int aflag, int space)
737 {
738 	int	n = 0;
739 
740 	if (m.m_flg&010 || (m.m_flg & (aflag?2:4)) == 0 &&
741 			(m.m_flg&0200 ? (flag&m.m_dfl) == m.m_val :
742 			 m.m_flg&020 ? (flag&m.m_val) == m.m_dfl :
743 				(flag&m.m_val) != m.m_dfl)
744 			| m.m_flg&1 |
745 			(aflag != 0) ^ ((m.m_flg&(aflag?0400:0)) != 0)) {
746 		if (space) {
747 			putchar(' ');
748 			n++;
749 		}
750 		if ((flag&m.m_val) == 0) {
751 			putchar('-');
752 			n++;
753 		}
754 		n += printf("%s", m.m_name);
755 	}
756 	return n;
757 }
758 
759 static int
listchar(cc_t * cc,struct mode m,int aflag,int space)760 listchar(cc_t *cc, struct mode m, int aflag, int space)
761 {
762 	int	n = 0;
763 	char	c = m.m_val >= 0 ? cc[m.m_val] : vdis;
764 
765 	if (m.m_flg&8 || (m.m_flg & (aflag?2:4)) == 0 &&
766 			c != (m.m_dfl?m.m_dfl:vdis) | m.m_flg&1 |
767 			(aflag != 0) ^ ((m.m_flg&(aflag?0400:0)) != 0)) {
768 		if (space) {
769 			putchar(' ');
770 			n++;
771 		}
772 		n += printf("%s ", m.m_name);
773 		if ((c&0377) == vdis)
774 			n += printf(sysv3 ? "<undef>" : "= <undef>");
775 		else {
776 			printf("= ");
777 			if (c & 0200) {
778 				c &= 0177;
779 				putchar('-');
780 				n++;
781 			}
782 			if ((c&037) == c)
783 				n += printf("^%c", c | (sysv3 ? 0100 : 0140));
784 			else if (c == '\177')
785 				n += printf("DEL");
786 			else {
787 				putchar(c & 0377);
788 				n++;
789 			}
790 		}
791 		putchar(';');
792 		n++;
793 	}
794 	return n;
795 }
796 
797 static const char *
baudrate(speed_t c)798 baudrate(speed_t c)
799 {
800 	int	i;
801 
802 	for (i = 0; speeds[i].s_str; i++)
803 		if (speeds[i].s_val == c)
804 			return speeds[i].s_str;
805 	return "-1";
806 }
807 
808 static void
set(void)809 set(void)
810 {
811 	int	i, gotcha, not, sspeed = 0;
812 	speed_t	ispeed0, ospeed0, ispeed1, ospeed1;
813 	const char	*ap;
814 	struct termios	tc;
815 
816 	ispeed0 = ispeed1 = cfgetispeed(&ts);
817 	ospeed0 = ospeed1 = cfgetospeed(&ts);
818 	while (*args) {
819 		for (i = 0; speeds[i].s_str; i++)
820 			if (strcmp(speeds[i].s_str, *args) == 0) {
821 				ispeed1 = ospeed1 = speeds[i].s_val;
822 				sspeed |= 3;
823 				goto next;
824 			}
825 		gotcha = 0;
826 		if (**args == '-') {
827 			not = 1;
828 			ap = &args[0][1];
829 		} else {
830 			not = 0;
831 			ap = *args;
832 		}
833 		for (i = 0; modes[i].m_name; i++) {
834 			if (modes[i].m_type == M_SEPAR || modes[i].m_flg&0100)
835 				continue;
836 			if (strcmp(modes[i].m_name, ap) == 0) {
837 				gotcha++;
838 				switch (modes[i].m_type) {
839 				case M_IFLAG:
840 					setmod(&ts.c_iflag, modes[i], not);
841 					break;
842 				case M_OFLAG:
843 					setmod(&ts.c_oflag, modes[i], not);
844 					break;
845 				case M_CFLAG:
846 				case M_PCFLAG:
847 					setmod(&ts.c_cflag, modes[i], not);
848 					break;
849 				case M_LFLAG:
850 					setmod(&ts.c_lflag, modes[i], not);
851 					break;
852 				case M_CC:
853 					if (not)
854 						inval();
855 					setchr(ts.c_cc, modes[i]);
856 					break;
857 				case M_FUNCT:
858 					modes[i].m_func(not);
859 					break;
860 				}
861 			}
862 		}
863 		if (gotcha)
864 			goto next;
865 		if (strcmp(*args, "ispeed") == 0) {
866 			if (*++args == NULL)
867 				break;
868 			if (atol(*args) == 0) {
869 				ispeed1 = ospeed1;
870 				sspeed |= 1;
871 				goto next;
872 			} else for (i = 0; speeds[i].s_str; i++)
873 				if (strcmp(speeds[i].s_str, *args) == 0) {
874 					ispeed1 = speeds[i].s_val;
875 					sspeed |= 1;
876 					goto next;
877 				}
878 			inval();
879 		}
880 		if (strcmp(*args, "ospeed") == 0) {
881 			if (*++args == NULL)
882 				break;
883 			for (i = 0; speeds[i].s_str; i++)
884 				if (strcmp(speeds[i].s_str, *args) == 0) {
885 					ospeed1 = speeds[i].s_val;
886 					sspeed |= 2;
887 					goto next;
888 				}
889 			inval();
890 		}
891 		gset();
892 	next:	args++;
893 	}
894 	if (sspeed) {
895 		if (sspeed == 3 && ispeed1 != ospeed1 && ospeed1 != B0) {
896 			tc = ts;
897 			cfsetispeed(&tc, ispeed1);
898 			if (cfgetospeed(&tc) == cfgetospeed(&ts)) {
899 				tc = ts;
900 				cfsetospeed(&tc, ospeed1);
901 				if (cfgetispeed(&tc) == cfgetispeed(&ts)) {
902 					cfsetispeed(&ts, ispeed1);
903 					cfsetospeed(&ts, ospeed1);
904 				}
905 			}
906 		} else {
907 			if (ispeed0 != ispeed1)
908 				cfsetispeed(&ts, ispeed1);
909 			if (ospeed0 != ospeed1)
910 				cfsetospeed(&ts, ospeed1);
911 		}
912 	}
913 }
914 
915 static void
setmod(tcflag_t * t,struct mode m,int not)916 setmod(tcflag_t *t, struct mode m, int not)
917 {
918 	if (m.m_flg&0200) {
919 		if (not)
920 			inval();
921 		*t = *t&~(tcflag_t)m.m_dfl | m.m_val;
922 	} else {
923 		if (not ^ (m.m_flg&01000) != 0)
924 			*t &= ~(tcflag_t)m.m_val;
925 		else
926 			*t |= m.m_val;
927 	}
928 }
929 
930 static void
setchr(cc_t * cc,struct mode m)931 setchr(cc_t *cc, struct mode m)
932 {
933 	if (args[1] == NULL)
934 		return;
935 	args++;
936 	if (m.m_val < 0)
937 		return;
938 	if (**args == '^') {
939 		if (args[0][1] == '-')
940 			cc[m.m_val] = vdis;
941 		else if (args[0][1] == '?')
942 			cc[m.m_val] = '\177';
943 		else
944 			cc[m.m_val] = args[0][1] & 037;
945 	} else if (strcmp(*args, "undef") == 0)
946 		cc[m.m_val] = vdis;
947 	else
948 		cc[m.m_val] = **args;
949 }
950 
951 static void
inval(void)952 inval(void)
953 {
954 	fprintf(stderr, "unknown mode: %s\n", *args);
955 	exit(2);
956 }
957 
958 #ifdef	TABDLY
959 static void
tabs(int not)960 tabs(int not)
961 {
962 	ts.c_oflag &= ~(tcflag_t)TABDLY;
963 	ts.c_oflag |= not ? TAB3 : TAB0;
964 }
965 #endif
966 
967 static void
evenp(int not)968 evenp(int not)
969 {
970 	if (not) {
971 		ts.c_cflag &= ~(tcflag_t)PARENB;
972 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS8;
973 	} else {
974 		ts.c_cflag |= PARENB;
975 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS7;
976 	}
977 }
978 
979 static void
oddp(int not)980 oddp(int not)
981 {
982 	if (not) {
983 		ts.c_cflag &= ~(tcflag_t)(PARENB|PARODD);
984 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS8;
985 	} else {
986 		ts.c_cflag |= PARENB|PARODD;
987 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS7;
988 	}
989 }
990 
991 static void
spacep(int not)992 spacep(int not)
993 {
994 	evenp(not);
995 }
996 
997 static void
markp(int not)998 markp(int not)
999 {
1000 	oddp(not);
1001 }
1002 
1003 static void
raw(int not)1004 raw(int not)
1005 {
1006 	if (not) {
1007 		ts.c_cc[VEOF] = ts.c_cc[VMIN] = '\4';
1008 		ts.c_cc[VEOL] = ts.c_cc[VTIME] = vdis;
1009 		ts.c_oflag |= OPOST;
1010 		ts.c_lflag |= ISIG|ICANON;
1011 	} else {
1012 		ts.c_cc[VEOF] = ts.c_cc[VMIN] = 1;
1013 		ts.c_cc[VEOL] = ts.c_cc[VTIME] = 1;
1014 		ts.c_oflag &= ~(tcflag_t)OPOST;
1015 		ts.c_lflag &= ~(tcflag_t)(ISIG|ICANON);
1016 	}
1017 }
1018 
1019 static void
cooked(int not)1020 cooked(int not)
1021 {
1022 	if (not)
1023 		inval();
1024 	raw(1);
1025 }
1026 
1027 static void
nl(int not)1028 nl(int not)
1029 {
1030 	if (not) {
1031 		ts.c_iflag |= ICRNL;
1032 		ts.c_oflag |= ONLCR;
1033 		ts.c_iflag &= ~(tcflag_t)(INLCR|IGNCR);
1034 		ts.c_oflag &= ~(tcflag_t)(OCRNL|ONLRET);
1035 	} else {
1036 		ts.c_iflag &= ~(tcflag_t)ICRNL;
1037 		ts.c_oflag &= ~(tcflag_t)ONLCR;
1038 	}
1039 }
1040 
1041 static void
sane(int not)1042 sane(int not)
1043 {
1044 	speed_t	ispeed, ospeed;
1045 
1046 	if (not)
1047 		inval();
1048 	ispeed = cfgetispeed(&ts);
1049 	ospeed = cfgetospeed(&ts);
1050 	ts.c_cc[VINTR] = '\3';
1051 	ts.c_cc[VQUIT] = '\34';
1052 	ts.c_cc[VERASE] = '\10';
1053 	ts.c_cc[VKILL] = '\25';
1054 	ts.c_cc[VEOF] = '\4';
1055 	ts.c_cc[VEOL] = vdis;
1056 	ts.c_cc[VEOL2] = vdis;
1057 #ifdef	VSWTCH
1058 	ts.c_cc[VSWTCH] = vdis;
1059 #endif
1060 	ts.c_cc[VSTART] = '\21';
1061 	ts.c_cc[VSTOP] = '\23';
1062 	ts.c_cc[VSUSP] = '\32';
1063 #ifdef	VREPRINT
1064 	ts.c_cc[VREPRINT] = '\22';
1065 #endif
1066 #ifdef	VDISCARD
1067 	ts.c_cc[VDISCARD] = '\17';
1068 #endif
1069 #ifdef	VWERASE
1070 	ts.c_cc[VWERASE] = '\27';
1071 #endif
1072 	ts.c_cc[VLNEXT] = '\26';
1073 	ts.c_cflag = CS8|CREAD;
1074 	ts.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOKE|IEXTEN;
1075 	ts.c_iflag = BRKINT|IGNPAR|ICRNL|IXON|IMAXBEL;
1076 #ifdef	IUTF8
1077 	if (MB_CUR_MAX > 1) {
1078 		wchar_t	wc;
1079 		if (mbtowc(&wc, "\303\266", 2) == 2 && wc == 0xF6 &&
1080 				mbtowc(&wc, "\342\202\254", 3) == 3 &&
1081 				wc == 0x20AC)
1082 			ts.c_iflag |= IUTF8;
1083 	}
1084 #endif	/* IUTF8 */
1085 	ts.c_oflag = OPOST|ONLCR;
1086 	cfsetispeed(&ts, ispeed);
1087 	cfsetospeed(&ts, ospeed);
1088 }
1089 
1090 #ifdef	OFDEL
1091 static void
fill(int not)1092 fill(int not)
1093 {
1094 	if (not)
1095 		ts.c_oflag &= ~(tcflag_t)(OFILL|OFDEL);
1096 	else {
1097 		ts.c_oflag |= OFILL;
1098 		ts.c_oflag &= ~(tcflag_t)OFDEL;
1099 	}
1100 }
1101 #endif
1102 
1103 #ifdef	XCASE
1104 static void
lcase(int not)1105 lcase(int not)
1106 {
1107 	if (not) {
1108 		ts.c_lflag &= ~(tcflag_t)XCASE;
1109 		ts.c_iflag &= ~(tcflag_t)IUCLC;
1110 		ts.c_oflag &= ~(tcflag_t)OLCUC;
1111 	} else {
1112 		ts.c_lflag |= XCASE;
1113 		ts.c_iflag |= IUCLC;
1114 		ts.c_oflag |= OLCUC;
1115 	}
1116 }
1117 #endif
1118 
1119 static void
ek(int not)1120 ek(int not)
1121 {
1122 	if (not)
1123 		inval();
1124 	ts.c_cc[VERASE] = '\10';
1125 	ts.c_cc[VKILL] = '\25';
1126 }
1127 
1128 #if 0
1129 static void
1130 tty33(int not)
1131 {
1132 	if (not)
1133 		inval();
1134 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1135 	ts.c_oflag |= CR1;
1136 }
1137 
1138 static void
1139 tty37(int not)
1140 {
1141 	if (not)
1142 		inval();
1143 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1144 	ts.c_oflag |= NL1|CR2|TAB1|FF1|VT1;
1145 }
1146 
1147 static void
1148 vt05(int not)
1149 {
1150 	if (not)
1151 		inval();
1152 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1153 	ts.c_oflag |= NL1;
1154 }
1155 
1156 static void
1157 tn300(int not)
1158 {
1159 	if (not)
1160 		inval();
1161 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1162 	ts.c_oflag |= CR1;
1163 }
1164 
1165 static void
1166 ti700(int not)
1167 {
1168 	if (not)
1169 		inval();
1170 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1171 	ts.c_oflag |= CR2;
1172 }
1173 
1174 static void
1175 tek(int not)
1176 {
1177 	if (not)
1178 		inval();
1179 	ts.c_oflag &= ~(tcflag_t)(NLDLY|CRDLY|TABDLY|BSDLY|FFDLY|VTDLY);
1180 	ts.c_oflag |= FF1;
1181 }
1182 #endif
1183 
1184 static void
rows(int not)1185 rows(int not)
1186 {
1187 	if (not)
1188 		inval();
1189 	if (args[1] == NULL)
1190 		return;
1191 	wschange = 1;
1192 	ws.ws_row = atoi(*++args);
1193 }
1194 
1195 static void
columns(int not)1196 columns(int not)
1197 {
1198 	if (not)
1199 		inval();
1200 	if (args[1] == NULL)
1201 		return;
1202 	wschange = 1;
1203 	ws.ws_col = atoi(*++args);
1204 }
1205 
1206 static void
ypixels(int not)1207 ypixels(int not)
1208 {
1209 	if (not)
1210 		inval();
1211 	if (args[1] == NULL)
1212 		return;
1213 	wschange = 1;
1214 	ws.ws_ypixel = atoi(*++args);
1215 }
1216 
1217 static void
xpixels(int not)1218 xpixels(int not)
1219 {
1220 	if (not)
1221 		inval();
1222 	if (args[1] == NULL)
1223 		return;
1224 	wschange = 1;
1225 	ws.ws_xpixel = atoi(*++args);
1226 }
1227 
1228 static void
vmin(int not)1229 vmin(int not)
1230 {
1231 	if (not)
1232 		inval();
1233 	if (args[1] == NULL)
1234 		return;
1235 	ts.c_cc[VMIN] = atoi(*++args);
1236 }
1237 
1238 static void
vtime(int not)1239 vtime(int not)
1240 {
1241 	if (not)
1242 		inval();
1243 	if (args[1] == NULL)
1244 		return;
1245 	ts.c_cc[VTIME] = atoi(*++args);
1246 }
1247 
1248 
1249 static void
line(int not)1250 line(int not)
1251 {
1252 	if (not)
1253 		inval();
1254 	if (args[1] == NULL)
1255 		return;
1256 #ifdef	__linux__
1257 	ts.c_line = atoi(*++args);
1258 #endif
1259 }
1260 
1261 static const char gfmt[] ="%lx:%lx:%lx:%lx:"
1262 		"%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x";
1263 
1264 static void
glist(void)1265 glist(void)
1266 {
1267 	printf(gfmt,	(long)ts.c_iflag,
1268 			(long)ts.c_oflag,
1269 			(long)ts.c_cflag,
1270 			(long)ts.c_lflag,
1271 			(int)ts.c_cc[VINTR],
1272 			(int)ts.c_cc[VQUIT],
1273 			(int)ts.c_cc[VERASE],
1274 			(int)ts.c_cc[VKILL],
1275 			(int)ts.c_cc[VEOF],
1276 			(int)ts.c_cc[VEOL],
1277 			(int)ts.c_cc[VEOL2],
1278 #ifdef	VSWTCH
1279 			(int)ts.c_cc[VSWTCH],
1280 #else
1281 			(int)vdis,
1282 #endif
1283 			(int)ts.c_cc[VSTART],
1284 			(int)ts.c_cc[VSTOP],
1285 			(int)ts.c_cc[VSUSP],
1286 #ifdef	VDSUSP
1287 			(int)ts.c_cc[VDSUSP],
1288 #else
1289 			(int)vdis,
1290 #endif
1291 #ifdef	VREPRINT
1292 			(int)ts.c_cc[VREPRINT],
1293 #else
1294 			(int)vdis,
1295 #endif
1296 #ifdef	VDISCARD
1297 			(int)ts.c_cc[VDISCARD],
1298 #else
1299 			(int)vdis,
1300 #endif
1301 #ifdef	VWERASE
1302 			(int)ts.c_cc[VWERASE],
1303 #else
1304 			(int)vdis,
1305 #endif
1306 			(int)ts.c_cc[VLNEXT],
1307 			(int)ts.c_cc[VMIN],
1308 			(int)ts.c_cc[VTIME]);
1309 	putchar('\n');
1310 }
1311 
1312 static void
gset(void)1313 gset(void)
1314 {
1315 	long	iflag, oflag, cflag, lflag;
1316 	int	vintr, vquit, verase, vkill,
1317 		veof, veol, veol2, vswtch,
1318 		vstart, vstop, vsusp, vdsusp,
1319 		vrprnt, vflush, vwerase, vlnext,
1320 		vmin, vtime;
1321 
1322 	if (sscanf(*args, gfmt,
1323 			&iflag, &oflag, &cflag, &lflag,
1324 			&vintr, &vquit, &verase, &vkill,
1325 			&veof, &veol, &veol2, &vswtch,
1326 			&vstart, &vstop, &vsusp, &vdsusp,
1327 			&vrprnt, &vflush, &vwerase, &vlnext,
1328 			&vmin, &vtime) != 22)
1329 		inval();
1330 	ts.c_iflag = iflag;
1331 	ts.c_oflag = oflag;
1332 	ts.c_cflag = cflag;
1333 	ts.c_lflag = lflag;
1334 	ts.c_cc[VINTR] = vintr;
1335 	ts.c_cc[VQUIT] = vquit;
1336 	ts.c_cc[VKILL] = vkill;
1337 	ts.c_cc[VEOF] = veof;
1338 	ts.c_cc[VEOL] = veol;
1339 	ts.c_cc[VEOL2] = veol2;
1340 #ifdef	VSWTCH
1341 	ts.c_cc[VSWTCH] = vswtch;
1342 #endif
1343 	ts.c_cc[VSTART] = vstart;
1344 	ts.c_cc[VSTOP] = vstop;
1345 	ts.c_cc[VSUSP] = vsusp;
1346 #ifdef	VDSUSP
1347 	ts.c_cc[VDSUSP] = vdsusp;
1348 #endif
1349 #ifdef	VREPRINT
1350 	ts.c_cc[VREPRINT] = vrprnt;
1351 #endif
1352 #ifdef	VDISCARD
1353 	ts.c_cc[VDISCARD] = vflush;
1354 #endif
1355 #ifdef	VWERASE
1356 	ts.c_cc[VWERASE] = vwerase;
1357 #endif
1358 	ts.c_cc[VLNEXT] = vlnext;
1359 	ts.c_cc[VMIN] = vmin;
1360 	ts.c_cc[VTIME] = vtime;
1361 }
1362 
1363 #ifdef	UCB
1364 static void
hchar(int c,int c2,int spc)1365 hchar(int c, int c2, int spc)
1366 {
1367 	int	n = 0;
1368 
1369 chr:	if (c != vdis) {
1370 		if (c & 0200) {
1371 			c &= 0177;
1372 			n += printf("M-");
1373 		}
1374 		if ((c&037) == c)
1375 			n += printf("^%c", c | 0100);
1376 		else if (c == '\177')
1377 			n += printf("^?");
1378 		else {
1379 			putchar(c);
1380 			n++;
1381 		}
1382 	}
1383 	if (c2 != EOF) {
1384 		putchar('/');
1385 		n++;
1386 		c = c2;
1387 		c2 = EOF;
1388 		goto chr;
1389 	}
1390 	if (spc)
1391 		while (n++ < 7)
1392 			putchar(' ');
1393 }
1394 
1395 static void
hlist(int aflag)1396 hlist(int aflag)
1397 {
1398 	list(aflag, 1);
1399 	printf("erase  kill   werase rprnt  flush  lnext  "
1400 			"susp   intr   quit   stop   eof\n");
1401 	hchar(ts.c_cc[VERASE]&0377, EOF, 1);
1402 	hchar(ts.c_cc[VKILL]&0377, EOF, 1);
1403 #ifdef	VWERASE
1404 	hchar(ts.c_cc[VWERASE]&0377, EOF, 1);
1405 #else
1406 	hchar(vdis, EOF, 1);
1407 #endif
1408 #ifdef	VREPRINT
1409 	hchar(ts.c_cc[VREPRINT]&0377, EOF, 1);
1410 #else
1411 	hchar(vdis, EOF, 1);
1412 #endif
1413 #ifdef	VDISCARD
1414 	hchar(ts.c_cc[VDISCARD]&0377, EOF, 1);
1415 #else
1416 	hchar(vdis, EOF, 1);
1417 #endif
1418 	hchar(ts.c_cc[VLNEXT]&0377, EOF, 1);
1419 	hchar(ts.c_cc[VSUSP]&0377, EOF, 1);
1420 	hchar(ts.c_cc[VINTR]&0377, EOF, 1);
1421 	hchar(ts.c_cc[VQUIT]&0377, EOF, 1);
1422 	hchar(ts.c_cc[VSTOP]&0377, ts.c_cc[VSTART]&0377, 1);
1423 	hchar(ts.c_cc[VEOF]&0377, EOF, 1);
1424 	putchar('\n');
1425 }
1426 
1427 static void
speed(void)1428 speed(void)
1429 {
1430 	printf("%s\n", baudrate(cfgetospeed(&ts)));
1431 }
1432 
1433 static void
size(void)1434 size(void)
1435 {
1436 	printf("%d %d\n", (int)ws.ws_row, (int)ws.ws_col);
1437 }
1438 
1439 static void
litout(int not)1440 litout(int not)
1441 {
1442 	if (not) {
1443 		ts.c_cflag |= PARENB;
1444 		ts.c_iflag |= ISTRIP;
1445 		ts.c_oflag |= OPOST;
1446 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS7;
1447 	} else {
1448 		ts.c_cflag &= ~(tcflag_t)PARENB;
1449 		ts.c_iflag &= ~(tcflag_t)ISTRIP;
1450 		ts.c_oflag &= ~(tcflag_t)OPOST;
1451 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS8;
1452 	}
1453 }
1454 
1455 static void
pass8(int not)1456 pass8(int not)
1457 {
1458 	if (not) {
1459 		ts.c_cflag |= PARENB;
1460 		ts.c_iflag |= ISTRIP;
1461 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS7;
1462 	} else {
1463 		ts.c_cflag &= ~(tcflag_t)PARENB;
1464 		ts.c_iflag &= ~(tcflag_t)ISTRIP;
1465 		ts.c_cflag = ts.c_cflag&~(tcflag_t)CSIZE | CS8;
1466 	}
1467 }
1468 
1469 static void
crt(int not)1470 crt(int not)
1471 {
1472 	if (not)
1473 		inval();
1474 	ts.c_lflag |= ECHOE|ECHOCTL;
1475 	if (cfgetospeed(&ts) >= B1200)
1476 		ts.c_lflag |= ECHOKE;
1477 }
1478 
1479 static void
dec(int not)1480 dec(int not)
1481 {
1482 	if (not)
1483 		inval();
1484 	ts.c_cc[VERASE] = '\177';
1485 	ts.c_cc[VKILL] = '\25';
1486 	ts.c_cc[VINTR] = '\3';
1487 	ts.c_iflag &= ~(tcflag_t)IXANY;
1488 	crt(not);
1489 }
1490 #endif	/* UCB */
1491