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