set.c revision 200419
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 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 * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
3487701Smarkm#include <sys/cdefs.h>
3587701Smarkm
3687701Smarkm__FBSDID("$FreeBSD: head/usr.bin/tset/set.c 200419 2009-12-11 23:30:22Z delphij $");
3787701Smarkm
381590Srgrimes#ifndef lint
3987701Smarkmstatic const char sccsid[] = "@(#)set.c	8.2 (Berkeley) 2/28/94";
4028370Scharnier#endif
411590Srgrimes
4287701Smarkm#include <stdio.h>
43200419Sdelphij#include <termcap.h>
441590Srgrimes#include <termios.h>
451590Srgrimes#include <unistd.h>
4687701Smarkm
471590Srgrimes#include "extern.h"
481590Srgrimes
491590Srgrimes#define	CHK(val, dft)	(val <= 0 ? dft : val)
501590Srgrimes
5192922Simpint	set_tabs(void);
521590Srgrimes
531590Srgrimes/*
541590Srgrimes * Reset the terminal mode bits to a sensible state.  Very useful after
551590Srgrimes * a child program dies in raw mode.
561590Srgrimes */
571590Srgrimesvoid
58200419Sdelphijreset_mode(void)
591590Srgrimes{
601590Srgrimes	tcgetattr(STDERR_FILENO, &mode);
611590Srgrimes
621590Srgrimes#if defined(VDISCARD) && defined(CDISCARD)
631590Srgrimes	mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
641590Srgrimes#endif
651590Srgrimes	mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
661590Srgrimes	mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
671590Srgrimes#if defined(VFLUSH) && defined(CFLUSH)
681590Srgrimes	mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
691590Srgrimes#endif
701590Srgrimes	mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
711590Srgrimes	mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
721590Srgrimes#if defined(VLNEXT) && defined(CLNEXT)
731590Srgrimes	mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
741590Srgrimes#endif
751590Srgrimes	mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
761590Srgrimes#if defined(VREPRINT) && defined(CRPRNT)
771590Srgrimes	mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
781590Srgrimes#endif
791590Srgrimes	mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
801590Srgrimes	mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
811590Srgrimes	mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
821590Srgrimes#if defined(VWERASE) && defined(CWERASE)
831590Srgrimes	mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
841590Srgrimes#endif
851590Srgrimes
861590Srgrimes	mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
871590Srgrimes#ifdef IUCLC
881590Srgrimes			  | IUCLC
891590Srgrimes#endif
901590Srgrimes#ifdef IXANY
911590Srgrimes			  | IXANY
921590Srgrimes#endif
931590Srgrimes			  | IXOFF);
941590Srgrimes
951590Srgrimes	mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
961590Srgrimes#ifdef IMAXBEL
971590Srgrimes			 | IMAXBEL
981590Srgrimes#endif
991590Srgrimes			 );
1001590Srgrimes
1011590Srgrimes	mode.c_oflag &= ~(0
1021590Srgrimes#ifdef OLCUC
1031590Srgrimes			  | OLCUC
1041590Srgrimes#endif
1051590Srgrimes#ifdef OCRNL
1061590Srgrimes			  | OCRNL
1071590Srgrimes#endif
1081590Srgrimes#ifdef ONOCR
1091590Srgrimes			  | ONOCR
1101590Srgrimes#endif
1111590Srgrimes#ifdef ONLRET
1121590Srgrimes			  | ONLRET
1131590Srgrimes#endif
1141590Srgrimes#ifdef OFILL
1151590Srgrimes			  | OFILL
1161590Srgrimes#endif
1171590Srgrimes#ifdef OFDEL
1181590Srgrimes			  | OFDEL
1191590Srgrimes#endif
1201590Srgrimes#ifdef NLDLY
1211590Srgrimes			  | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
1221590Srgrimes#endif
1231590Srgrimes			  );
1241590Srgrimes
1251590Srgrimes	mode.c_oflag |= (OPOST
1261590Srgrimes#ifdef ONLCR
1271590Srgrimes			 | ONLCR
1281590Srgrimes#endif
1291590Srgrimes			 );
1301590Srgrimes
1311590Srgrimes	mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
1321590Srgrimes	mode.c_cflag |= (CS8 | CREAD);
1331590Srgrimes	mode.c_lflag &= ~(ECHONL | NOFLSH | TOSTOP
1341590Srgrimes#ifdef ECHOPTR
1351590Srgrimes			  | ECHOPRT
1361590Srgrimes#endif
1371590Srgrimes#ifdef XCASE
1381590Srgrimes			  | XCASE
1391590Srgrimes#endif
1401590Srgrimes			  );
1411590Srgrimes
1421590Srgrimes	mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
1431590Srgrimes#ifdef ECHOCTL
1441590Srgrimes			 | ECHOCTL
1451590Srgrimes#endif
1461590Srgrimes#ifdef ECHOKE
1471590Srgrimes			 | ECHOKE
1481590Srgrimes#endif
1491590Srgrimes 			 );
1501590Srgrimes
1511590Srgrimes	tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1521590Srgrimes}
1531590Srgrimes
1541590Srgrimes/*
1551590Srgrimes * Determine the erase, interrupt, and kill characters from the termcap
1561590Srgrimes * entry and command line and update their values in 'mode'.
1571590Srgrimes */
1581590Srgrimesvoid
159200419Sdelphijset_control_chars(void)
1601590Srgrimes{
1611590Srgrimes	char *bp, *p, bs_char, buf[1024];
1621590Srgrimes
1631590Srgrimes	bp = buf;
1641590Srgrimes	p = tgetstr("kb", &bp);
1651590Srgrimes	if (p == NULL || p[1] != '\0')
1661590Srgrimes		p = tgetstr("bc", &bp);
1671590Srgrimes	if (p != NULL && p[1] == '\0')
1681590Srgrimes		bs_char = p[0];
1691590Srgrimes	else if (tgetflag("bs"))
1701590Srgrimes		bs_char = CTRL('h');
1711590Srgrimes	else
1721590Srgrimes		bs_char = 0;
1731590Srgrimes
17468617Sdg	if (erasech == 0 && bs_char != 0 && !tgetflag("os"))
17568617Sdg		erasech = -1;
17668617Sdg	if (erasech < 0)
17768617Sdg		erasech = (bs_char != 0) ? bs_char : CTRL('h');
1781590Srgrimes
17968617Sdg	if (mode.c_cc[VERASE] == 0 || erasech != 0)
18068617Sdg		mode.c_cc[VERASE] = erasech ? erasech : CERASE;
1811590Srgrimes
1821590Srgrimes	if (mode.c_cc[VINTR] == 0 || intrchar != 0)
1831590Srgrimes		 mode.c_cc[VINTR] = intrchar ? intrchar : CINTR;
1841590Srgrimes
18568617Sdg	if (mode.c_cc[VKILL] == 0 || killch != 0)
18668617Sdg		mode.c_cc[VKILL] = killch ? killch : CKILL;
1871590Srgrimes}
1881590Srgrimes
1891590Srgrimes/*
1901590Srgrimes * Set up various conversions in 'mode', including parity, tabs, returns,
1911590Srgrimes * echo, and case, according to the termcap entry.  If the program we're
1921590Srgrimes * running was named with a leading upper-case character, map external
1931590Srgrimes * uppercase to internal lowercase.
1941590Srgrimes */
1951590Srgrimesvoid
196200419Sdelphijset_conversions(int usingupper)
1971590Srgrimes{
1981590Srgrimes	if (tgetflag("UC") || usingupper) {
1991590Srgrimes#ifdef IUCLC
2001590Srgrimes		mode.c_iflag |= IUCLC;
2011590Srgrimes		mode.c_oflag |= OLCUC;
2021590Srgrimes#endif
2031590Srgrimes	} else if (tgetflag("LC")) {
2041590Srgrimes#ifdef IUCLC
2051590Srgrimes		mode.c_iflag &= ~IUCLC;
2061590Srgrimes		mode.c_oflag &= ~OLCUC;
2071590Srgrimes#endif
2081590Srgrimes	}
2091590Srgrimes	mode.c_iflag &= ~(PARMRK | INPCK);
2101590Srgrimes	mode.c_lflag |= ICANON;
2111590Srgrimes	if (tgetflag("EP")) {
2121590Srgrimes		mode.c_cflag |= PARENB;
2131590Srgrimes		mode.c_cflag &= ~PARODD;
2141590Srgrimes	}
2151590Srgrimes	if (tgetflag("OP")) {
2161590Srgrimes		mode.c_cflag |= PARENB;
2171590Srgrimes		mode.c_cflag |= PARODD;
2181590Srgrimes	}
2191590Srgrimes
2201590Srgrimes#ifdef ONLCR
2211590Srgrimes	mode.c_oflag |= ONLCR;
2221590Srgrimes#endif
2231590Srgrimes	mode.c_iflag |= ICRNL;
2241590Srgrimes	mode.c_lflag |= ECHO;
2251590Srgrimes	mode.c_oflag |= OXTABS;
2261590Srgrimes	if (tgetflag("NL")) {			/* Newline, not linefeed. */
2271590Srgrimes#ifdef ONLCR
2281590Srgrimes		mode.c_oflag &= ~ONLCR;
2291590Srgrimes#endif
2301590Srgrimes		mode.c_iflag &= ~ICRNL;
2311590Srgrimes	}
2321590Srgrimes	if (tgetflag("HD"))			/* Half duplex. */
2331590Srgrimes		mode.c_lflag &= ~ECHO;
2341590Srgrimes	if (tgetflag("pt"))			/* Print tabs. */
2351590Srgrimes		mode.c_oflag &= ~OXTABS;
2361590Srgrimes	mode.c_lflag |= (ECHOE | ECHOK);
2371590Srgrimes}
2381590Srgrimes
2391590Srgrimes/* Output startup string. */
2401590Srgrimesvoid
241200419Sdelphijset_init(void)
2421590Srgrimes{
2431590Srgrimes	char *bp, buf[1024];
2441590Srgrimes	int settle;
2451590Srgrimes
2461590Srgrimes	bp = buf;
2471590Srgrimes	if (tgetstr("pc", &bp) != 0)		/* Get/set pad character. */
2481590Srgrimes		PC = buf[0];
2493397Sache
2501590Srgrimes#ifdef TAB3
2511590Srgrimes	if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
2521590Srgrimes		oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
2531590Srgrimes		tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
2541590Srgrimes	}
2551590Srgrimes#endif
2561590Srgrimes	settle = set_tabs();
2571590Srgrimes
2581590Srgrimes	if (isreset) {
2591590Srgrimes		bp = buf;
2601590Srgrimes		if (tgetstr("rs", &bp) != 0 || tgetstr("is", &bp) != 0) {
2611590Srgrimes			tputs(buf, 0, outc);
2621590Srgrimes			settle = 1;
2631590Srgrimes		}
2641590Srgrimes		bp = buf;
2651590Srgrimes		if (tgetstr("rf", &bp) != 0 || tgetstr("if", &bp) != 0) {
2661590Srgrimes			cat(buf);
2671590Srgrimes			settle = 1;
2681590Srgrimes		}
2691590Srgrimes	}
2701590Srgrimes
2711590Srgrimes	if (settle) {
2721590Srgrimes		(void)putc('\r', stderr);
2731590Srgrimes		(void)fflush(stderr);
2741590Srgrimes		(void)sleep(1);			/* Settle the terminal. */
2751590Srgrimes	}
2761590Srgrimes}
2771590Srgrimes
2781590Srgrimes/*
2791590Srgrimes * Set the hardware tabs on the terminal, using the ct (clear all tabs),
2801590Srgrimes * st (set one tab) and ch (horizontal cursor addressing) capabilities.
2811590Srgrimes * This is done before if and is, so they can patch in case we blow this.
2821590Srgrimes * Return nonzero if we set any tab stops, zero if not.
2831590Srgrimes */
2841590Srgrimesint
285200419Sdelphijset_tabs(void)
2861590Srgrimes{
2871590Srgrimes	int c;
2881590Srgrimes	char *capsp, *clear_tabs;
28987701Smarkm	char *set_column, *set_pos, *Set_tab;
2901590Srgrimes	char caps[1024];
29187701Smarkm	const char *tg_out;
2921590Srgrimes
2931590Srgrimes	capsp = caps;
29450638Speter	Set_tab = tgetstr("st", &capsp);
2951590Srgrimes
29650638Speter	if (Set_tab && (clear_tabs = tgetstr("ct", &capsp))) {
2971590Srgrimes		(void)putc('\r', stderr);	/* Force to left margin. */
2981590Srgrimes		tputs(clear_tabs, 0, outc);
2991590Srgrimes	}
3001590Srgrimes
3011590Srgrimes	set_column = tgetstr("ch", &capsp);
3021590Srgrimes	set_pos = set_column ? NULL : tgetstr("cm", &capsp);
3031590Srgrimes
30450638Speter	if (Set_tab) {
30550638Speter		for (c = 8; c < Columns; c += 8) {
3061590Srgrimes			/*
3071590Srgrimes			 * Get to the right column.  "OOPS" is returned by
3081590Srgrimes			 * tgoto() if it can't do the job.  (*snarl*)
3091590Srgrimes			 */
3101590Srgrimes			tg_out = "OOPS";
3111590Srgrimes			if (set_column)
3121590Srgrimes				tg_out = tgoto(set_column, 0, c);
3131590Srgrimes			if (*tg_out == 'O' && set_pos)
31450638Speter				tg_out = tgoto(set_pos, c, Lines - 1);
3151590Srgrimes			if (*tg_out != 'O')
3161590Srgrimes				tputs(tg_out, 1, outc);
3171590Srgrimes			else
3181590Srgrimes				(void)fprintf(stderr, "%s", "        ");
3191590Srgrimes			/* Set the tab. */
32050638Speter			tputs(Set_tab, 0, outc);
3211590Srgrimes		}
3221590Srgrimes		putc('\r', stderr);
3231590Srgrimes		return (1);
3241590Srgrimes	}
3251590Srgrimes	return (0);
3261590Srgrimes}
327