xref: /netbsd-src/usr.bin/tset/tset.c (revision be0c033d10de50f9dd7b8e5007ed807884682fdf)
1*be0c033dSjoerg /*	$NetBSD: tset.c,v 1.20 2011/09/06 18:34:12 joerg Exp $	*/
2fb937a59Sjtc 
3dab5e017Scgd /*-
4fb937a59Sjtc  * Copyright (c) 1980, 1991, 1993
5fb937a59Sjtc  *	The Regents of the University of California.  All rights reserved.
6dab5e017Scgd  *
7dab5e017Scgd  * Redistribution and use in source and binary forms, with or without
8dab5e017Scgd  * modification, are permitted provided that the following conditions
9dab5e017Scgd  * are met:
10dab5e017Scgd  * 1. Redistributions of source code must retain the above copyright
11dab5e017Scgd  *    notice, this list of conditions and the following disclaimer.
12dab5e017Scgd  * 2. Redistributions in binary form must reproduce the above copyright
13dab5e017Scgd  *    notice, this list of conditions and the following disclaimer in the
14dab5e017Scgd  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
16dab5e017Scgd  *    may be used to endorse or promote products derived from this software
17dab5e017Scgd  *    without specific prior written permission.
18dab5e017Scgd  *
19dab5e017Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20dab5e017Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21dab5e017Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22dab5e017Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23dab5e017Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24dab5e017Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25dab5e017Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26dab5e017Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27dab5e017Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28dab5e017Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29dab5e017Scgd  * SUCH DAMAGE.
30dab5e017Scgd  */
31dab5e017Scgd 
322aa5d6b7Slukem #include <sys/cdefs.h>
3398e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993\
3498e5374cSlukem  The Regents of the University of California.  All rights reserved.");
35*be0c033dSjoerg __RCSID("$NetBSD: tset.c,v 1.20 2011/09/06 18:34:12 joerg Exp $");
36dab5e017Scgd 
37dab5e017Scgd #include <sys/types.h>
388d582663Scgd #include <sys/ioctl.h>
39dab5e017Scgd #include <ctype.h>
40bfd39f4aSlukem #include <err.h>
412aa5d6b7Slukem #include <errno.h>
422aa5d6b7Slukem #include <stdio.h>
432aa5d6b7Slukem #include <stdlib.h>
44dab5e017Scgd #include <string.h>
4598eb8895Sroy #include <term.h>
462aa5d6b7Slukem #include <termios.h>
472aa5d6b7Slukem #include <unistd.h>
48dab5e017Scgd #include "extern.h"
49dab5e017Scgd 
50*be0c033dSjoerg static void	obsolete(char *[]);
51*be0c033dSjoerg static void	report(const char *, int, u_int);
52*be0c033dSjoerg __dead static void	usage(void);
53dab5e017Scgd 
54dab5e017Scgd struct termios mode, oldmode;
55dab5e017Scgd 
56dab5e017Scgd int	isreset;		/* invoked as reset */
5798eb8895Sroy int	nlines, ncolumns;	/* window size */
58dab5e017Scgd 
59dab5e017Scgd int
main(int argc,char * argv[])60*be0c033dSjoerg main(int argc, char *argv[])
61dab5e017Scgd {
62dab5e017Scgd #ifdef TIOCGWINSZ
63dab5e017Scgd 	struct winsize win;
64dab5e017Scgd #endif
6598eb8895Sroy 	int ch, noinit, noset, quiet, sflag, showterm;
66dc8f6bbdSchs 	int erasechar = 0, intrchar = 0, killchar = 0;
678500b4e7Sblymn 	int usingupper;
6898eb8895Sroy 	char *p;
6998eb8895Sroy 	const char *k1, *k2;
70b223acf6Smycroft 	const char *ttype;
71dab5e017Scgd 
72dab5e017Scgd 	if (tcgetattr(STDERR_FILENO, &mode) < 0)
73bfd39f4aSlukem 		err(1, "standard error");
74dab5e017Scgd 
75dab5e017Scgd 	oldmode = mode;
76dab5e017Scgd 	ospeed = cfgetospeed(&mode);
77dab5e017Scgd 
782aa5d6b7Slukem 	if ((p = strrchr(*argv, '/')) != NULL)
79dab5e017Scgd 		++p;
80dab5e017Scgd 	else
81dab5e017Scgd 		p = *argv;
82af1827b7Schristos 	usingupper = isupper((unsigned char)*p);
83dab5e017Scgd 	if (!strcasecmp(p, "reset")) {
84dab5e017Scgd 		isreset = 1;
85dab5e017Scgd 		reset_mode();
86dab5e017Scgd 	}
87dab5e017Scgd 
88dab5e017Scgd 	obsolete(argv);
8998eb8895Sroy 	noinit = noset = quiet = sflag = showterm = 0;
908500b4e7Sblymn 	while ((ch = getopt(argc, argv, "-a:d:e:EIi:k:m:np:QSrs")) != -1) {
91dab5e017Scgd 		switch (ch) {
928d582663Scgd 		case '-':		/* display term only */
93dab5e017Scgd 			noset = 1;
94dab5e017Scgd 			break;
95dab5e017Scgd 		case 'a':		/* OBSOLETE: map identifier to type */
96dab5e017Scgd 			add_mapping("arpanet", optarg);
97dab5e017Scgd 			break;
98dab5e017Scgd 		case 'd':		/* OBSOLETE: map identifier to type */
99dab5e017Scgd 			add_mapping("dialup", optarg);
100dab5e017Scgd 			break;
101dab5e017Scgd 		case 'e':		/* erase character */
102dab5e017Scgd 			erasechar = optarg[0] == '^' && optarg[1] != '\0' ?
103dab5e017Scgd 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
104dab5e017Scgd 			    optarg[0];
105dab5e017Scgd 			break;
10698eb8895Sroy 		case 'E':		/* -E does not make sense for terminfo
10798eb8895Sroy 					   should this be noisy? */
1088500b4e7Sblymn 			break;
1098d582663Scgd 		case 'I':		/* no initialization strings */
110dab5e017Scgd 			noinit = 1;
111dab5e017Scgd 			break;
112dab5e017Scgd 		case 'i':		/* interrupt character */
113dab5e017Scgd 			intrchar = optarg[0] == '^' && optarg[1] != '\0' ?
114dab5e017Scgd 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
115dab5e017Scgd 			    optarg[0];
116dab5e017Scgd 			break;
117dab5e017Scgd 		case 'k':		/* kill character */
118dab5e017Scgd 			killchar = optarg[0] == '^' && optarg[1] != '\0' ?
119dab5e017Scgd 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
120dab5e017Scgd 			    optarg[0];
121dab5e017Scgd 			break;
122dab5e017Scgd 		case 'm':		/* map identifier to type */
123dab5e017Scgd 			add_mapping(NULL, optarg);
124dab5e017Scgd 			break;
125dab5e017Scgd 		case 'n':		/* OBSOLETE: set new tty driver */
126dab5e017Scgd 			break;
127dab5e017Scgd 		case 'p':		/* OBSOLETE: map identifier to type */
128dab5e017Scgd 			add_mapping("plugboard", optarg);
129dab5e017Scgd 			break;
1308d582663Scgd 		case 'Q':		/* don't output control key settings */
131dab5e017Scgd 			quiet = 1;
132dab5e017Scgd 			break;
13398eb8895Sroy 		case 'S':		/* -S does not make sense for terminfo
13498eb8895Sroy 					   should this be noisy? */
1358d582663Scgd 			break;
136dab5e017Scgd 		case 'r':		/* display term on stderr */
137dab5e017Scgd 			showterm = 1;
138dab5e017Scgd 			break;
13998eb8895Sroy 		case 's':		/* output TERM string */
1408d582663Scgd 			sflag = 1;
141dab5e017Scgd 			break;
142dab5e017Scgd 		case '?':
143dab5e017Scgd 		default:
144dab5e017Scgd 			usage();
145dab5e017Scgd 		}
146dab5e017Scgd 	}
147dab5e017Scgd 	argc -= optind;
148dab5e017Scgd 	argv += optind;
149dab5e017Scgd 
150dab5e017Scgd 	if (argc > 1)
151dab5e017Scgd 		usage();
152dab5e017Scgd 
15398eb8895Sroy 	ttype = get_terminfo_entry(*argv);
154dab5e017Scgd 
155dab5e017Scgd 	if (!noset) {
15698eb8895Sroy 		ncolumns = columns;
15798eb8895Sroy 		nlines = lines;
158dab5e017Scgd 
159dab5e017Scgd #ifdef TIOCGWINSZ
160dab5e017Scgd 		/* Set window size */
161dab5e017Scgd 		(void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
162d06abde2Ssimonb 		if (win.ws_row > 0 && win.ws_col > 0) {
16398eb8895Sroy 			nlines = win.ws_row;
16498eb8895Sroy 			ncolumns = win.ws_col;
165d06abde2Ssimonb 		} else if (win.ws_row == 0 && win.ws_col == 0 &&
16698eb8895Sroy 		    nlines > 0 && columns > 0) {
16798eb8895Sroy 			win.ws_row = nlines;
16898eb8895Sroy 			win.ws_col = ncolumns;
169dab5e017Scgd 			(void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
170dab5e017Scgd 		}
171dab5e017Scgd #endif
172dc8f6bbdSchs 		set_control_chars(erasechar, intrchar, killchar);
173dab5e017Scgd 		set_conversions(usingupper);
174dab5e017Scgd 
175dab5e017Scgd 		if (!noinit)
176dab5e017Scgd 			set_init();
177dab5e017Scgd 
178dab5e017Scgd 		/* Set the modes if they've changed. */
179dab5e017Scgd 		if (memcmp(&mode, &oldmode, sizeof(mode)))
180dab5e017Scgd 			tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
181dab5e017Scgd 	}
182dab5e017Scgd 
183dab5e017Scgd 	if (noset)
184dab5e017Scgd 		(void)printf("%s\n", ttype);
185dab5e017Scgd 	else {
186dab5e017Scgd 		if (showterm)
187dab5e017Scgd 			(void)fprintf(stderr, "Terminal type is %s.\n", ttype);
188dab5e017Scgd 		/*
189dab5e017Scgd 		 * If erase, kill and interrupt characters could have been
190dab5e017Scgd 		 * modified and not -Q, display the changes.
191dab5e017Scgd 		 */
192dab5e017Scgd 		if (!quiet) {
193dab5e017Scgd 			report("Erase", VERASE, CERASE);
194dab5e017Scgd 			report("Kill", VKILL, CKILL);
195dab5e017Scgd 			report("Interrupt", VINTR, CINTR);
196dab5e017Scgd 		}
197dab5e017Scgd 	}
198dab5e017Scgd 
1998d582663Scgd 	if (sflag) {
2008d582663Scgd 		/*
2018d582663Scgd 		 * Figure out what shell we're using.  A hack, we look for an
2028d582663Scgd 		 * environmental variable SHELL ending in "csh".
2038d582663Scgd 		 */
2048d582663Scgd 		if ((p = getenv("SHELL")) &&
2058d582663Scgd 		    !strcmp(p + strlen(p) - 3, "csh")) {
206910d6761Slukem 			k1 = "set noglob;\nsetenv TERM ";
20798eb8895Sroy 			k2 = ";\nunset noglob;\n";
2088d582663Scgd 		} else {
209910d6761Slukem 			k1 = "TERM=";
21098eb8895Sroy 			k2 = ";\nexport TERM;\n";
2118d582663Scgd 		}
212910d6761Slukem 		(void)printf("%s%s%s", k1, ttype, k2);
2138d582663Scgd 	}
2148d582663Scgd 
215dab5e017Scgd 	exit(0);
216dab5e017Scgd }
217dab5e017Scgd 
218dab5e017Scgd /*
219dab5e017Scgd  * Tell the user if a control key has been changed from the default value.
220dab5e017Scgd  */
221*be0c033dSjoerg static void
report(const char * name,int which,u_int def)222*be0c033dSjoerg report(const char *name, int which, u_int def)
223dab5e017Scgd {
224dab5e017Scgd 	u_int old, new;
225dab5e017Scgd 
226dab5e017Scgd 	new = mode.c_cc[which];
227dab5e017Scgd 	old = oldmode.c_cc[which];
228dab5e017Scgd 
229dab5e017Scgd 	if (old == new && old == def)
230dab5e017Scgd 		return;
231dab5e017Scgd 
232dab5e017Scgd 	(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
233dab5e017Scgd 
23498eb8895Sroy 	if (key_backspace != NULL &&
23598eb8895Sroy 	    new == (unsigned int)key_backspace[0] &&
23698eb8895Sroy 	    key_backspace[1] == '\0')
237dab5e017Scgd 		(void)fprintf(stderr, "backspace.\n");
238dab5e017Scgd 	else if (new == 0177)
239dab5e017Scgd 		(void)fprintf(stderr, "delete.\n");
240dab5e017Scgd 	else if (new < 040) {
241dab5e017Scgd 		new ^= 0100;
242dab5e017Scgd 		(void)fprintf(stderr, "control-%c (^%c).\n", new, new);
243ece19a52Skleink 	} else if (new == _POSIX_VDISABLE)
244ece19a52Skleink 		(void)fprintf(stderr, "<undef>.\n");
245ece19a52Skleink 	else
246dab5e017Scgd 		(void)fprintf(stderr, "%c.\n", new);
247dab5e017Scgd }
248dab5e017Scgd 
249dab5e017Scgd /*
250dab5e017Scgd  * Convert the obsolete argument form into something that getopt can handle.
251dab5e017Scgd  * This means that -e, -i and -k get default arguments supplied for them.
252dab5e017Scgd  */
253dab5e017Scgd void
obsolete(char * argv[])254*be0c033dSjoerg obsolete(char *argv[])
255dab5e017Scgd {
256910d6761Slukem 	static char earg[5] = { '-', 'e', '^', 'H', '\0' };
257910d6761Slukem 	static char iarg[5] = { '-', 'i', '^', 'C', '\0' };
258910d6761Slukem 	static char karg[5] = { '-', 'k', '^', 'U', '\0' };
259910d6761Slukem 
260dab5e017Scgd 	for (; *argv; ++argv) {
2612aa5d6b7Slukem 		if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') ||
2622aa5d6b7Slukem 		    (argv[0][1] != 'e' && argv[0][1] != 'i' &&
2632aa5d6b7Slukem 		     argv[0][1] != 'k') || argv[0][2] != '\0')
264dab5e017Scgd 			continue;
265dab5e017Scgd 		switch(argv[0][1]) {
266dab5e017Scgd 		case 'e':
267910d6761Slukem 			argv[0] = earg;
268dab5e017Scgd 			break;
269dab5e017Scgd 		case 'i':
270910d6761Slukem 			argv[0] = iarg;
271dab5e017Scgd 			break;
272dab5e017Scgd 		case 'k':
273910d6761Slukem 			argv[0] = karg;
274dab5e017Scgd 			break;
275dab5e017Scgd 		}
276dab5e017Scgd 	}
277dab5e017Scgd }
278dab5e017Scgd 
279*be0c033dSjoerg static void
usage(void)280*be0c033dSjoerg usage(void)
281dab5e017Scgd {
282dab5e017Scgd 	(void)fprintf(stderr,
28373045ab3Swiz "usage: %s [-EIQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n",
28473045ab3Swiz 	getprogname());
285dab5e017Scgd 	exit(1);
286dab5e017Scgd }
287