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