1/*-
2 * Copyright (c) 1980, 1991, 1993
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 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31
32__FBSDID("$FreeBSD$");
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1980, 1991, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif
39
40#ifndef lint
41static const char sccsid[] = "@(#)tset.c	8.1 (Berkeley) 6/9/93";
42#endif
43
44#include <sys/types.h>
45#include <sys/ioctl.h>
46
47#include <ctype.h>
48#include <err.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <termcap.h>
53#include <termios.h>
54#include <unistd.h>
55
56#include "extern.h"
57
58void	obsolete(char *[]);
59void	report(const char *, int, u_int);
60void	usage(void);
61
62struct termios mode, oldmode;
63
64int	erasech;		/* new erase character */
65int	intrchar;		/* new interrupt character */
66int	isreset;		/* invoked as reset */
67int	killch;			/* new kill character */
68int	Lines, Columns;		/* window size */
69speed_t	Ospeed;
70
71int
72main(int argc, char *argv[])
73{
74#ifdef TIOCGWINSZ
75	struct winsize win;
76#endif
77	int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper;
78	char *p, *tcapbuf;
79	const char *ttype;
80
81	if (tcgetattr(STDERR_FILENO, &mode) < 0)
82		err(1, "standard error");
83
84	oldmode = mode;
85	Ospeed = cfgetospeed(&mode);
86
87	if ((p = strrchr(*argv, '/')))
88		++p;
89	else
90		p = *argv;
91	usingupper = isupper(*p);
92	if (!strcasecmp(p, "reset")) {
93		isreset = 1;
94		reset_mode();
95	}
96
97	obsolete(argv);
98	noinit = noset = quiet = Sflag = sflag = showterm = 0;
99	while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != -1) {
100		switch (ch) {
101		case '-':		/* display term only */
102			noset = 1;
103			break;
104		case 'a':		/* OBSOLETE: map identifier to type */
105			add_mapping("arpanet", optarg);
106			break;
107		case 'd':		/* OBSOLETE: map identifier to type */
108			add_mapping("dialup", optarg);
109			break;
110		case 'e':		/* erase character */
111			erasech = optarg[0] == '^' && optarg[1] != '\0' ?
112			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
113			    optarg[0];
114			break;
115		case 'I':		/* no initialization strings */
116			noinit = 1;
117			break;
118		case 'i':		/* interrupt character */
119			intrchar = optarg[0] == '^' && optarg[1] != '\0' ?
120			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
121			    optarg[0];
122			break;
123		case 'k':		/* kill character */
124			killch = optarg[0] == '^' && optarg[1] != '\0' ?
125			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
126			    optarg[0];
127			break;
128		case 'm':		/* map identifier to type */
129			add_mapping(NULL, optarg);
130			break;
131		case 'n':		/* OBSOLETE: set new tty driver */
132			break;
133		case 'p':		/* OBSOLETE: map identifier to type */
134			add_mapping("plugboard", optarg);
135			break;
136		case 'Q':		/* don't output control key settings */
137			quiet = 1;
138			break;
139		case 'S':		/* output TERM/TERMCAP strings */
140			Sflag = 1;
141			break;
142		case 'r':		/* display term on stderr */
143			showterm = 1;
144			break;
145		case 's':		/* output TERM/TERMCAP strings */
146			sflag = 1;
147			break;
148		case '?':
149		default:
150			usage();
151		}
152	}
153	argc -= optind;
154	argv += optind;
155
156	if (argc > 1)
157		usage();
158
159	ttype = get_termcap_entry(*argv, &tcapbuf);
160
161	if (!noset) {
162		Columns = tgetnum("co");
163		Lines = tgetnum("li");
164
165#ifdef TIOCGWINSZ
166		/* Set window size */
167		(void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
168		if (win.ws_row == 0 && win.ws_col == 0 &&
169		    Lines > 0 && Columns > 0) {
170			win.ws_row = Lines;
171			win.ws_col = Columns;
172			(void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
173		}
174#endif
175		set_control_chars();
176		set_conversions(usingupper);
177
178		if (!noinit)
179			set_init();
180
181		/* Set the modes if they've changed. */
182		if (memcmp(&mode, &oldmode, sizeof(mode)))
183			tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
184	}
185
186	if (noset)
187		(void)printf("%s\n", ttype);
188	else {
189		if (showterm)
190			(void)fprintf(stderr, "Terminal type is %s.\n", ttype);
191		/*
192		 * If erase, kill and interrupt characters could have been
193		 * modified and not -Q, display the changes.
194		 */
195		if (!quiet) {
196			report("Erase", VERASE, CERASE);
197			report("Kill", VKILL, CKILL);
198			report("Interrupt", VINTR, CINTR);
199		}
200	}
201
202	if (Sflag) {
203		(void)printf("%s ", ttype);
204		if (strlen(tcapbuf) > 0)
205			wrtermcap(tcapbuf);
206	}
207
208	if (sflag) {
209		/*
210		 * Figure out what shell we're using.  A hack, we look for an
211		 * environmental variable SHELL ending in "csh".
212		 */
213		if ((p = getenv("SHELL")) &&
214		    !strcmp(p + strlen(p) - 3, "csh")) {
215			printf("set noglob;\nsetenv TERM %s;\n", ttype);
216			if (strlen(tcapbuf) > 0) {
217				printf("setenv TERMCAP '");
218				wrtermcap(tcapbuf);
219				printf("';\n");
220			}
221			printf("unset noglob;\n");
222		} else {
223			printf("TERM=%s;\n", ttype);
224			if (strlen(tcapbuf) > 0) {
225				printf("TERMCAP='");
226				wrtermcap(tcapbuf);
227				printf("';\nexport TERMCAP;\n");
228			}
229			printf("export TERM;\n");
230		}
231	}
232
233	exit(0);
234}
235
236/*
237 * Tell the user if a control key has been changed from the default value.
238 */
239void
240report(const char *name, int which, u_int def)
241{
242	u_int old, new;
243
244	new = mode.c_cc[which];
245	old = oldmode.c_cc[which];
246
247	if (old == new && old == def)
248		return;
249
250	(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
251
252	if (new == 010)
253		(void)fprintf(stderr, "backspace.\n");
254	else if (new == 0177)
255		(void)fprintf(stderr, "delete.\n");
256	else if (new < 040) {
257		new ^= 0100;
258		(void)fprintf(stderr, "control-%c (^%c).\n", new, new);
259	} else
260		(void)fprintf(stderr, "%c.\n", new);
261}
262
263/*
264 * Convert the obsolete argument form into something that getopt can handle.
265 * This means that -e, -i and -k get default arguments supplied for them.
266 */
267void
268obsolete(char *argv[])
269{
270	for (; *argv; ++argv) {
271		if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') ||
272		    (argv[0][1] != 'e' && argv[0][1] != 'i' && argv[0][1] != 'k') ||
273			argv[0][2] != '\0')
274			continue;
275		switch(argv[0][1]) {
276		case 'e':
277			argv[0] = strdup("-e^H");
278			break;
279		case 'i':
280			argv[0] = strdup("-i^C");
281			break;
282		case 'k':
283			argv[0] = strdup("-k^U");
284			break;
285		}
286	}
287}
288
289void
290usage(void)
291{
292	(void)fprintf(stderr, "%s\n%s\n",
293"usage: tset  [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]",
294"       reset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]");
295	exit(1);
296}
297
298