xref: /original-bsd/usr.bin/tset/tset.c (revision be7e82b8)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)tset.c	5.20 (Berkeley) 12/28/91";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <termios.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include "extern.h"
27 
28 void	obsolete __P((char *[]));
29 void	report __P((char *, int, u_int));
30 void	usage __P((void));
31 
32 struct termios mode, oldmode;
33 
34 int	erasechar;		/* new erase character */
35 int	intrchar;		/* new interrupt character */
36 int	isreset;		/* invoked as reset */
37 int	killchar;		/* new kill character */
38 int	lines, columns;		/* window size */
39 
40 int
41 main(argc, argv)
42 	int argc;
43 	char *argv[];
44 {
45 #ifdef TIOCGWINSZ
46 	struct winsize win;
47 #endif
48 	int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper;
49 	char savech, *p, *t, *tcapbuf, *ttype;
50 
51 	if (tcgetattr(STDERR_FILENO, &mode) < 0)
52 		err("standard error: %s", strerror(errno));
53 
54 	oldmode = mode;
55 	ospeed = cfgetospeed(&mode);
56 
57 	if (p = strrchr(*argv, '/'))
58 		++p;
59 	else
60 		p = *argv;
61 	usingupper = isupper(*p);
62 	if (!strcasecmp(p, "reset")) {
63 		isreset = 1;
64 		reset_mode();
65 	}
66 
67 	obsolete(argv);
68 	noinit = noset = quiet = Sflag = sflag = showterm = 0;
69 	while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != EOF) {
70 		switch (ch) {
71 		case '-':		/* display term only */
72 			noset = 1;
73 			break;
74 		case 'a':		/* OBSOLETE: map identifier to type */
75 			add_mapping("arpanet", optarg);
76 			break;
77 		case 'd':		/* OBSOLETE: map identifier to type */
78 			add_mapping("dialup", optarg);
79 			break;
80 		case 'e':		/* erase character */
81 			erasechar = optarg[0] == '^' && optarg[1] != '\0' ?
82 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
83 			    optarg[0];
84 			break;
85 		case 'I':		/* no initialization strings */
86 			noinit = 1;
87 			break;
88 		case 'i':		/* interrupt character */
89 			intrchar = optarg[0] == '^' && optarg[1] != '\0' ?
90 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
91 			    optarg[0];
92 			break;
93 		case 'k':		/* kill character */
94 			killchar = optarg[0] == '^' && optarg[1] != '\0' ?
95 			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
96 			    optarg[0];
97 			break;
98 		case 'm':		/* map identifier to type */
99 			add_mapping(NULL, optarg);
100 			break;
101 		case 'n':		/* OBSOLETE: set new tty driver */
102 			break;
103 		case 'p':		/* OBSOLETE: map identifier to type */
104 			add_mapping("plugboard", optarg);
105 			break;
106 		case 'Q':		/* don't output control key settings */
107 			quiet = 1;
108 			break;
109 		case 'S':		/* output TERM/TERMCAP strings */
110 			Sflag = 1;
111 			break;
112 		case 'r':		/* display term on stderr */
113 			showterm = 1;
114 			break;
115 		case 's':		/* output TERM/TERMCAP strings */
116 			sflag = 1;
117 			break;
118 		case '?':
119 		default:
120 			usage();
121 		}
122 	}
123 	argc -= optind;
124 	argv += optind;
125 
126 	if (argc > 1)
127 		usage();
128 
129 	ttype = get_termcap_entry(*argv, &tcapbuf);
130 
131 	if (!noset) {
132 		columns = tgetnum("co");
133 		lines = tgetnum("li");
134 
135 #ifdef TIOCGWINSZ
136 		/* Set window size */
137 		(void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
138 		if (win.ws_row == 0 && win.ws_col == 0 &&
139 		    lines > 0 && columns > 0) {
140 			win.ws_row = lines;
141 			win.ws_col = columns;
142 			(void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
143 		}
144 #endif
145 		set_control_chars();
146 		set_conversions(usingupper);
147 
148 		if (!noinit)
149 			set_init();
150 
151 		/* Set the modes if they've changed. */
152 		if (memcmp(&mode, &oldmode, sizeof(mode)))
153 			tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
154 	}
155 
156 	/*
157 	 * The termcap file generally has a two-character name first in each
158 	 * entry followed by more descriptive names.  If we ended up with the
159 	 * first one, we switch to the second one for setting or reporting
160 	 * information.
161 	 */
162 	p = strpbrk(tcapbuf, "|:");
163 	if (p && *p != ':' && !strncmp(ttype, tcapbuf, p - tcapbuf)) {
164 		t = ++p;
165 		if (p = strpbrk(p, "|:")) {
166 			savech = *p;
167 			*p = '\0';
168 			if ((ttype = strdup(t)) == NULL)
169 				err("%s", strerror(errno));
170 			*p = savech;
171 		}
172 	}
173 
174 	if (noset)
175 		(void)printf("%s\n", ttype);
176 	else {
177 		if (showterm)
178 			(void)fprintf(stderr, "Terminal type is %s.\n", ttype);
179 		/*
180 		 * If erase, kill and interrupt characters could have been
181 		 * modified and not -Q, display the changes.
182 		 */
183 		if (!quiet) {
184 			report("Erase", VERASE, CERASE);
185 			report("Kill", VKILL, CKILL);
186 			report("Interrupt", VINTR, CINTR);
187 		}
188 	}
189 
190 	if (Sflag) {
191 		(void)printf("%s ", ttype);
192 		wrtermcap(tcapbuf);
193 	}
194 
195 	if (sflag) {
196 		/*
197 		 * Figure out what shell we're using.  A hack, we look for an
198 		 * environmental variable SHELL ending in "csh".
199 		 */
200 		if ((p = getenv("SHELL")) &&
201 		    !strcmp(p + strlen(p) - 3, "csh")) {
202 			p = "set noglob;\nsetenv TERM %s;\nsetenv TERMCAP '";
203 			t = "';\nunset noglob;\n";
204 		} else {
205 			p = "TERM=%s;\nTERMCAP='";
206 			t = "';\nexport TERMCAP TERM;\n";
207 		}
208 		(void)printf(p, ttype);
209 		wrtermcap(tcapbuf);
210 		(void)printf(t);
211 	}
212 
213 	exit(0);
214 }
215 
216 /*
217  * Tell the user if a control key has been changed from the default value.
218  */
219 void
220 report(name, which, def)
221 	char *name;
222 	int which;
223 	u_int def;
224 {
225 	u_int old, new;
226 	char *bp, buf[1024];
227 
228 	new = mode.c_cc[which];
229 	old = oldmode.c_cc[which];
230 
231 	if (old == new && old == def)
232 		return;
233 
234 	(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
235 
236 	bp = buf;
237 	if (tgetstr("kb", &bp) && new == buf[0] && buf[1] == '\0')
238 		(void)fprintf(stderr, "backspace.\n");
239 	else if (new == 0177)
240 		(void)fprintf(stderr, "delete.\n");
241 	else if (new < 040) {
242 		new ^= 0100;
243 		(void)fprintf(stderr, "control-%c (^%c).\n", new, new);
244 	} else
245 		(void)fprintf(stderr, "%c.\n", new);
246 }
247 
248 /*
249  * Convert the obsolete argument form into something that getopt can handle.
250  * This means that -e, -i and -k get default arguments supplied for them.
251  */
252 void
253 obsolete(argv)
254 	char *argv[];
255 {
256 	for (; *argv; ++argv) {
257 		if (argv[0][0] != '-' || argv[1] && argv[1][0] != '-' ||
258 		    argv[0][1] != 'e' && argv[0][1] != 'i' &&
259 		    argv[0][1] != 'k' || argv[0][2] != '\0')
260 			continue;
261 		switch(argv[0][1]) {
262 		case 'e':
263 			argv[0] = "-e^H";
264 			break;
265 		case 'i':
266 			argv[0] = "-i^C";
267 			break;
268 		case 'k':
269 			argv[0] = "-k^U";
270 			break;
271 		}
272 	}
273 }
274 
275 void
276 usage()
277 {
278 	(void)fprintf(stderr,
279 "usage: tset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]\n");
280 	exit(1);
281 }
282