1/*	$OpenBSD: key.c,v 1.18 2019/06/28 13:35:00 deraadt Exp $	*/
2/*	$NetBSD: key.c,v 1.11 1995/09/07 06:57:11 jtc Exp $	*/
3
4/*-
5 * Copyright (c) 1991, 1993, 1994
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <sys/ioctl.h>
35
36#include <err.h>
37#include <errno.h>
38#include <limits.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <termios.h>
43
44#include "stty.h"
45#include "extern.h"
46
47__BEGIN_DECLS
48void	f_all(struct info *);
49void	f_cbreak(struct info *);
50void	f_columns(struct info *);
51void	f_dec(struct info *);
52void	f_ek(struct info *);
53void	f_everything(struct info *);
54void	f_extproc(struct info *);
55void	f_ispeed(struct info *);
56void	f_lcase(struct info *);
57void	f_nl(struct info *);
58void	f_ospeed(struct info *);
59void	f_raw(struct info *);
60void	f_rows(struct info *);
61void	f_sane(struct info *);
62void	f_size(struct info *);
63void	f_speed(struct info *);
64void	f_ostart(struct info *);
65void	f_ostop(struct info *);
66void	f_tty(struct info *);
67__END_DECLS
68
69static struct key {
70	char *name;				/* name */
71	void (*f)(struct info *);		/* function */
72#define	F_NEEDARG	0x01			/* needs an argument */
73#define	F_OFFOK		0x02			/* can turn off */
74	int flags;
75} keys[] = {
76	{ "all",	f_all,		0 },
77	{ "cbreak",	f_cbreak,	F_OFFOK },
78	{ "cols",	f_columns,	F_NEEDARG },
79	{ "columns",	f_columns,	F_NEEDARG },
80	{ "cooked", 	f_sane,		0 },
81	{ "dec",	f_dec,		0 },
82	{ "ek",		f_ek,		0 },
83	{ "everything",	f_everything,	0 },
84	{ "extproc",	f_extproc,	F_OFFOK },
85	{ "ispeed",	f_ispeed,	F_NEEDARG },
86	{ "lcase", 	f_lcase,	0 },
87	{ "new",	f_tty,		0 },
88	{ "nl",		f_nl,		F_OFFOK },
89	{ "old",	f_tty,		0 },
90	{ "ospeed",	f_ospeed,	F_NEEDARG },
91	{ "ostart",	f_ostart,	0 },
92	{ "ostop",	f_ostop,	0 },
93	{ "raw",	f_raw,		F_OFFOK },
94	{ "rows",	f_rows,		F_NEEDARG },
95	{ "sane",	f_sane,		0 },
96	{ "size",	f_size,		0 },
97	{ "speed",	f_speed,	0 },
98	{ "tty",	f_tty,		0 },
99};
100
101static int
102c_key(const void *a, const void *b)
103{
104
105	return (strcmp(((struct key *)a)->name, ((struct key *)b)->name));
106}
107
108int
109ksearch(char ***argvp, struct info *ip)
110{
111	char *name;
112	struct key *kp, tmp;
113
114	name = **argvp;
115	if (*name == '-') {
116		ip->off = 1;
117		++name;
118	} else
119		ip->off = 0;
120
121	tmp.name = name;
122	if (!(kp = (struct key *)bsearch(&tmp, keys,
123	    sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
124		return (0);
125	if (!(kp->flags & F_OFFOK) && ip->off) {
126		warnx("illegal option -- -%s", name);
127		usage();
128	}
129	if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) {
130		warnx("option requires an argument -- %s", name);
131		usage();
132	}
133	kp->f(ip);
134	return (1);
135}
136
137void
138f_all(struct info *ip)
139{
140	print(&ip->t, &ip->win, ip->ldisc, BSD);
141}
142
143void
144f_cbreak(struct info *ip)
145{
146
147	if (ip->off)
148		f_sane(ip);
149	else {
150		ip->t.c_iflag |= BRKINT|IXON|IMAXBEL;
151		ip->t.c_oflag |= OPOST;
152		ip->t.c_lflag |= ISIG|IEXTEN;
153		ip->t.c_lflag &= ~ICANON;
154		ip->set = 1;
155	}
156}
157
158void
159f_columns(struct info *ip)
160{
161	const char *error;
162
163	ip->win.ws_col = strtonum(ip->arg, 0, USHRT_MAX, &error);
164	if (error)
165		err(1, "cols %s", ip->arg);
166	ip->wset = 1;
167}
168
169void
170f_dec(struct info *ip)
171{
172
173	ip->t.c_cc[VERASE] = (u_char)0177;
174	ip->t.c_cc[VKILL] = CTRL('u');
175	ip->t.c_cc[VINTR] = CTRL('c');
176	ip->t.c_lflag &= ~ECHOPRT;
177	ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
178	ip->t.c_iflag &= ~IXANY;
179	ip->set = 1;
180}
181
182void
183f_ek(struct info *ip)
184{
185
186	ip->t.c_cc[VERASE] = CERASE;
187	ip->t.c_cc[VKILL] = CKILL;
188	ip->set = 1;
189}
190
191void
192f_everything(struct info *ip)
193{
194
195	print(&ip->t, &ip->win, ip->ldisc, BSD);
196}
197
198void
199f_extproc(struct info *ip)
200{
201
202	if (ip->off) {
203		int tmp = 0;
204		(void)ioctl(ip->fd, TIOCEXT, &tmp);
205	} else {
206		int tmp = 1;
207		(void)ioctl(ip->fd, TIOCEXT, &tmp);
208	}
209	ip->set = 1;
210}
211
212void
213f_ispeed(struct info *ip)
214{
215	const char *errstr;
216	speed_t speed;
217
218	speed = strtonum(ip->arg, 0, UINT_MAX, &errstr);
219	if (errstr)
220		err(1, "ispeed %s", ip->arg);
221	cfsetispeed(&ip->t, speed);
222	ip->set = 1;
223}
224
225void
226f_lcase(struct info *ip)
227{
228	if (ip->off) {
229		ip->t.c_iflag &= ~IUCLC;
230		ip->t.c_oflag &= ~OLCUC;
231		ip->t.c_lflag &= ~XCASE;
232	} else {
233		ip->t.c_iflag |= IUCLC;
234		ip->t.c_oflag |= OLCUC;
235		ip->t.c_lflag |= XCASE;
236	}
237	ip->set = 1;
238}
239
240void
241f_nl(struct info *ip)
242{
243
244	if (ip->off) {
245		ip->t.c_iflag |= ICRNL;
246		ip->t.c_oflag |= ONLCR;
247	} else {
248		ip->t.c_iflag &= ~ICRNL;
249		ip->t.c_oflag &= ~ONLCR;
250	}
251	ip->set = 1;
252}
253
254void
255f_ospeed(struct info *ip)
256{
257	const char *errstr;
258	speed_t speed;
259
260	speed = strtonum(ip->arg, 0, UINT_MAX, &errstr);
261	if (errstr)
262		err(1, "ospeed %s", ip->arg);
263	cfsetospeed(&ip->t, speed);
264	ip->set = 1;
265}
266
267void
268f_raw(struct info *ip)
269{
270
271	if (ip->off)
272		f_sane(ip);
273	else {
274		cfmakeraw(&ip->t);
275		ip->t.c_cflag &= ~(CSIZE|PARENB);
276		ip->t.c_cflag |= CS8;
277		ip->set = 1;
278	}
279}
280
281void
282f_rows(struct info *ip)
283{
284	const char *error;
285
286	ip->win.ws_row = strtonum(ip->arg, 0, USHRT_MAX, &error);
287	if (error)
288		err(1, "rows %s", ip->arg);
289	ip->wset = 1;
290}
291
292void
293f_sane(struct info *ip)
294{
295
296	ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & (CLOCAL|CRTSCTS));
297	ip->t.c_iflag = TTYDEF_IFLAG;
298	ip->t.c_iflag |= ICRNL;
299	/* preserve user-preference flags in lflag */
300#define	LKEEP	(ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
301	ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP);
302	ip->t.c_oflag = TTYDEF_OFLAG;
303	ip->set = 1;
304}
305
306void
307f_size(struct info *ip)
308{
309
310	(void)printf("%d %d\n", ip->win.ws_row, ip->win.ws_col);
311}
312
313void
314f_speed(struct info *ip)
315{
316
317	(void)printf("%d\n", cfgetospeed(&ip->t));
318}
319
320void
321f_tty(struct info *ip)
322{
323	int tmp;
324
325	tmp = TTYDISC;
326	if (ioctl(ip->fd, TIOCSETD, &tmp) == -1)
327		err(1, "TIOCSETD");
328}
329
330void
331f_ostart(struct info *ip)
332{
333	if (ioctl(ip->fd, TIOCSTART) == -1)
334		err(1, "TIOCSTART");
335}
336
337void
338f_ostop(struct info *ip)
339{
340	if (ioctl(ip->fd, TIOCSTOP) == -1)
341		err(1, "TIOCSTOP");
342}
343