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