11590Srgrimes/*-
21590Srgrimes * Copyright (c) 1980, 1991, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 4. Neither the name of the University nor the names of its contributors
141590Srgrimes *    may be used to endorse or promote products derived from this software
151590Srgrimes *    without specific prior written permission.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes */
291590Srgrimes
3087701Smarkm#include <sys/cdefs.h>
3187701Smarkm
3287701Smarkm__FBSDID("$FreeBSD$");
3387701Smarkm
341590Srgrimes#ifndef lint
3528370Scharnierstatic const char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1980, 1991, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
3887701Smarkm#endif
391590Srgrimes
401590Srgrimes#ifndef lint
4187701Smarkmstatic const char sccsid[] = "@(#)tset.c	8.1 (Berkeley) 6/9/93";
4228370Scharnier#endif
431590Srgrimes
441590Srgrimes#include <sys/types.h>
451590Srgrimes#include <sys/ioctl.h>
4687701Smarkm
4728370Scharnier#include <ctype.h>
4828370Scharnier#include <err.h>
4928370Scharnier#include <stdio.h>
501590Srgrimes#include <stdlib.h>
511590Srgrimes#include <string.h>
52200419Sdelphij#include <termcap.h>
5387701Smarkm#include <termios.h>
5428370Scharnier#include <unistd.h>
5587701Smarkm
561590Srgrimes#include "extern.h"
571590Srgrimes
5892922Simpvoid	obsolete(char *[]);
5992922Simpvoid	report(const char *, int, u_int);
6092922Simpvoid	usage(void);
611590Srgrimes
621590Srgrimesstruct termios mode, oldmode;
631590Srgrimes
6468617Sdgint	erasech;		/* new erase character */
651590Srgrimesint	intrchar;		/* new interrupt character */
661590Srgrimesint	isreset;		/* invoked as reset */
6768617Sdgint	killch;			/* new kill character */
6850638Speterint	Lines, Columns;		/* window size */
692599Sachespeed_t	Ospeed;
701590Srgrimes
711590Srgrimesint
72102944Sdwmalonemain(int argc, char *argv[])
731590Srgrimes{
741590Srgrimes#ifdef TIOCGWINSZ
751590Srgrimes	struct winsize win;
761590Srgrimes#endif
771590Srgrimes	int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper;
7887701Smarkm	char *p, *tcapbuf;
7987701Smarkm	const char *ttype;
801590Srgrimes
811590Srgrimes	if (tcgetattr(STDERR_FILENO, &mode) < 0)
8228370Scharnier		err(1, "standard error");
831590Srgrimes
841590Srgrimes	oldmode = mode;
852599Sache	Ospeed = cfgetospeed(&mode);
863397Sache
8728370Scharnier	if ((p = strrchr(*argv, '/')))
881590Srgrimes		++p;
891590Srgrimes	else
901590Srgrimes		p = *argv;
911590Srgrimes	usingupper = isupper(*p);
921590Srgrimes	if (!strcasecmp(p, "reset")) {
931590Srgrimes		isreset = 1;
941590Srgrimes		reset_mode();
951590Srgrimes	}
961590Srgrimes
971590Srgrimes	obsolete(argv);
981590Srgrimes	noinit = noset = quiet = Sflag = sflag = showterm = 0;
9924360Simp	while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != -1) {
1001590Srgrimes		switch (ch) {
1011590Srgrimes		case '-':		/* display term only */
1021590Srgrimes			noset = 1;
1031590Srgrimes			break;
1041590Srgrimes		case 'a':		/* OBSOLETE: map identifier to type */
1051590Srgrimes			add_mapping("arpanet", optarg);
1061590Srgrimes			break;
1071590Srgrimes		case 'd':		/* OBSOLETE: map identifier to type */
1081590Srgrimes			add_mapping("dialup", optarg);
1091590Srgrimes			break;
1101590Srgrimes		case 'e':		/* erase character */
11168617Sdg			erasech = optarg[0] == '^' && optarg[1] != '\0' ?
1121590Srgrimes			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
1131590Srgrimes			    optarg[0];
1141590Srgrimes			break;
1151590Srgrimes		case 'I':		/* no initialization strings */
1161590Srgrimes			noinit = 1;
1171590Srgrimes			break;
1181590Srgrimes		case 'i':		/* interrupt character */
1191590Srgrimes			intrchar = optarg[0] == '^' && optarg[1] != '\0' ?
1201590Srgrimes			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
1211590Srgrimes			    optarg[0];
1221590Srgrimes			break;
1231590Srgrimes		case 'k':		/* kill character */
12468617Sdg			killch = optarg[0] == '^' && optarg[1] != '\0' ?
1251590Srgrimes			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
1261590Srgrimes			    optarg[0];
1271590Srgrimes			break;
1281590Srgrimes		case 'm':		/* map identifier to type */
1291590Srgrimes			add_mapping(NULL, optarg);
1301590Srgrimes			break;
1311590Srgrimes		case 'n':		/* OBSOLETE: set new tty driver */
1321590Srgrimes			break;
1331590Srgrimes		case 'p':		/* OBSOLETE: map identifier to type */
1341590Srgrimes			add_mapping("plugboard", optarg);
1351590Srgrimes			break;
1361590Srgrimes		case 'Q':		/* don't output control key settings */
1371590Srgrimes			quiet = 1;
1381590Srgrimes			break;
1391590Srgrimes		case 'S':		/* output TERM/TERMCAP strings */
1401590Srgrimes			Sflag = 1;
1411590Srgrimes			break;
1421590Srgrimes		case 'r':		/* display term on stderr */
1431590Srgrimes			showterm = 1;
1441590Srgrimes			break;
1451590Srgrimes		case 's':		/* output TERM/TERMCAP strings */
1461590Srgrimes			sflag = 1;
1471590Srgrimes			break;
1481590Srgrimes		case '?':
1491590Srgrimes		default:
1501590Srgrimes			usage();
1511590Srgrimes		}
1521590Srgrimes	}
1531590Srgrimes	argc -= optind;
1541590Srgrimes	argv += optind;
1551590Srgrimes
1561590Srgrimes	if (argc > 1)
1571590Srgrimes		usage();
1581590Srgrimes
1591590Srgrimes	ttype = get_termcap_entry(*argv, &tcapbuf);
1601590Srgrimes
1611590Srgrimes	if (!noset) {
16250638Speter		Columns = tgetnum("co");
16350638Speter		Lines = tgetnum("li");
1641590Srgrimes
1651590Srgrimes#ifdef TIOCGWINSZ
1661590Srgrimes		/* Set window size */
1671590Srgrimes		(void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
1681590Srgrimes		if (win.ws_row == 0 && win.ws_col == 0 &&
16950638Speter		    Lines > 0 && Columns > 0) {
17050638Speter			win.ws_row = Lines;
17150638Speter			win.ws_col = Columns;
1721590Srgrimes			(void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
1731590Srgrimes		}
1741590Srgrimes#endif
1751590Srgrimes		set_control_chars();
1761590Srgrimes		set_conversions(usingupper);
1771590Srgrimes
1781590Srgrimes		if (!noinit)
1791590Srgrimes			set_init();
1801590Srgrimes
1811590Srgrimes		/* Set the modes if they've changed. */
1821590Srgrimes		if (memcmp(&mode, &oldmode, sizeof(mode)))
1831590Srgrimes			tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1841590Srgrimes	}
1851590Srgrimes
1861590Srgrimes	if (noset)
1871590Srgrimes		(void)printf("%s\n", ttype);
1881590Srgrimes	else {
1891590Srgrimes		if (showterm)
1901590Srgrimes			(void)fprintf(stderr, "Terminal type is %s.\n", ttype);
1911590Srgrimes		/*
1921590Srgrimes		 * If erase, kill and interrupt characters could have been
1931590Srgrimes		 * modified and not -Q, display the changes.
1941590Srgrimes		 */
1951590Srgrimes		if (!quiet) {
1961590Srgrimes			report("Erase", VERASE, CERASE);
1971590Srgrimes			report("Kill", VKILL, CKILL);
1981590Srgrimes			report("Interrupt", VINTR, CINTR);
1991590Srgrimes		}
2001590Srgrimes	}
2011590Srgrimes
2021590Srgrimes	if (Sflag) {
2031590Srgrimes		(void)printf("%s ", ttype);
20450638Speter		if (strlen(tcapbuf) > 0)
20550638Speter			wrtermcap(tcapbuf);
2061590Srgrimes	}
2071590Srgrimes
2081590Srgrimes	if (sflag) {
2091590Srgrimes		/*
2101590Srgrimes		 * Figure out what shell we're using.  A hack, we look for an
2111590Srgrimes		 * environmental variable SHELL ending in "csh".
2121590Srgrimes		 */
2131590Srgrimes		if ((p = getenv("SHELL")) &&
2141590Srgrimes		    !strcmp(p + strlen(p) - 3, "csh")) {
21550638Speter			printf("set noglob;\nsetenv TERM %s;\n", ttype);
21650638Speter			if (strlen(tcapbuf) > 0) {
21750638Speter				printf("setenv TERMCAP '");
21850638Speter				wrtermcap(tcapbuf);
21950638Speter				printf("';\n");
22050638Speter			}
22150638Speter			printf("unset noglob;\n");
2221590Srgrimes		} else {
22350638Speter			printf("TERM=%s;\n", ttype);
22450638Speter			if (strlen(tcapbuf) > 0) {
22550638Speter				printf("TERMCAP='");
22650638Speter				wrtermcap(tcapbuf);
22750638Speter				printf("';\nexport TERMCAP;\n");
22850638Speter			}
22950638Speter			printf("export TERM;\n");
2301590Srgrimes		}
2311590Srgrimes	}
2321590Srgrimes
2331590Srgrimes	exit(0);
2341590Srgrimes}
2351590Srgrimes
2361590Srgrimes/*
2371590Srgrimes * Tell the user if a control key has been changed from the default value.
2381590Srgrimes */
2391590Srgrimesvoid
240102944Sdwmalonereport(const char *name, int which, u_int def)
2411590Srgrimes{
2421590Srgrimes	u_int old, new;
2431590Srgrimes
2441590Srgrimes	new = mode.c_cc[which];
2451590Srgrimes	old = oldmode.c_cc[which];
2461590Srgrimes
2471590Srgrimes	if (old == new && old == def)
2481590Srgrimes		return;
2491590Srgrimes
2501590Srgrimes	(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
2511590Srgrimes
2528524Sache	if (new == 010)
2531590Srgrimes		(void)fprintf(stderr, "backspace.\n");
2541590Srgrimes	else if (new == 0177)
2551590Srgrimes		(void)fprintf(stderr, "delete.\n");
2561590Srgrimes	else if (new < 040) {
2571590Srgrimes		new ^= 0100;
2581590Srgrimes		(void)fprintf(stderr, "control-%c (^%c).\n", new, new);
2591590Srgrimes	} else
2601590Srgrimes		(void)fprintf(stderr, "%c.\n", new);
2611590Srgrimes}
2621590Srgrimes
2631590Srgrimes/*
2641590Srgrimes * Convert the obsolete argument form into something that getopt can handle.
2651590Srgrimes * This means that -e, -i and -k get default arguments supplied for them.
2661590Srgrimes */
2671590Srgrimesvoid
268102944Sdwmaloneobsolete(char *argv[])
2691590Srgrimes{
2701590Srgrimes	for (; *argv; ++argv) {
27128370Scharnier		if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') ||
27228370Scharnier		    (argv[0][1] != 'e' && argv[0][1] != 'i' && argv[0][1] != 'k') ||
27328370Scharnier			argv[0][2] != '\0')
2741590Srgrimes			continue;
2751590Srgrimes		switch(argv[0][1]) {
2761590Srgrimes		case 'e':
27787701Smarkm			argv[0] = strdup("-e^H");
2781590Srgrimes			break;
2791590Srgrimes		case 'i':
28087701Smarkm			argv[0] = strdup("-i^C");
2811590Srgrimes			break;
2821590Srgrimes		case 'k':
28387701Smarkm			argv[0] = strdup("-k^U");
2841590Srgrimes			break;
2851590Srgrimes		}
2861590Srgrimes	}
2871590Srgrimes}
2881590Srgrimes
2891590Srgrimesvoid
290102944Sdwmaloneusage(void)
2911590Srgrimes{
29228370Scharnier	(void)fprintf(stderr, "%s\n%s\n",
29328370Scharnier"usage: tset  [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]",
29428370Scharnier"       reset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]");
2951590Srgrimes	exit(1);
2961590Srgrimes}
29728370Scharnier
298