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 * 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
3587701Smarkmstatic const char sccsid[] = "@(#)set.c	8.2 (Berkeley) 2/28/94";
3628370Scharnier#endif
371590Srgrimes
3887701Smarkm#include <stdio.h>
39200419Sdelphij#include <termcap.h>
401590Srgrimes#include <termios.h>
411590Srgrimes#include <unistd.h>
4287701Smarkm
431590Srgrimes#include "extern.h"
441590Srgrimes
451590Srgrimes#define	CHK(val, dft)	(val <= 0 ? dft : val)
461590Srgrimes
4792922Simpint	set_tabs(void);
481590Srgrimes
491590Srgrimes/*
501590Srgrimes * Reset the terminal mode bits to a sensible state.  Very useful after
511590Srgrimes * a child program dies in raw mode.
521590Srgrimes */
531590Srgrimesvoid
54200419Sdelphijreset_mode(void)
551590Srgrimes{
561590Srgrimes	tcgetattr(STDERR_FILENO, &mode);
571590Srgrimes
581590Srgrimes#if defined(VDISCARD) && defined(CDISCARD)
591590Srgrimes	mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
601590Srgrimes#endif
611590Srgrimes	mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
621590Srgrimes	mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
631590Srgrimes#if defined(VFLUSH) && defined(CFLUSH)
641590Srgrimes	mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
651590Srgrimes#endif
661590Srgrimes	mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
671590Srgrimes	mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
681590Srgrimes#if defined(VLNEXT) && defined(CLNEXT)
691590Srgrimes	mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
701590Srgrimes#endif
711590Srgrimes	mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
721590Srgrimes#if defined(VREPRINT) && defined(CRPRNT)
731590Srgrimes	mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
741590Srgrimes#endif
751590Srgrimes	mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
761590Srgrimes	mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
771590Srgrimes	mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
781590Srgrimes#if defined(VWERASE) && defined(CWERASE)
791590Srgrimes	mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
801590Srgrimes#endif
811590Srgrimes
821590Srgrimes	mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
831590Srgrimes#ifdef IUCLC
841590Srgrimes			  | IUCLC
851590Srgrimes#endif
861590Srgrimes#ifdef IXANY
871590Srgrimes			  | IXANY
881590Srgrimes#endif
891590Srgrimes			  | IXOFF);
901590Srgrimes
911590Srgrimes	mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
921590Srgrimes#ifdef IMAXBEL
931590Srgrimes			 | IMAXBEL
941590Srgrimes#endif
951590Srgrimes			 );
961590Srgrimes
971590Srgrimes	mode.c_oflag &= ~(0
981590Srgrimes#ifdef OLCUC
991590Srgrimes			  | OLCUC
1001590Srgrimes#endif
1011590Srgrimes#ifdef OCRNL
1021590Srgrimes			  | OCRNL
1031590Srgrimes#endif
1041590Srgrimes#ifdef ONOCR
1051590Srgrimes			  | ONOCR
1061590Srgrimes#endif
1071590Srgrimes#ifdef ONLRET
1081590Srgrimes			  | ONLRET
1091590Srgrimes#endif
1101590Srgrimes#ifdef OFILL
1111590Srgrimes			  | OFILL
1121590Srgrimes#endif
1131590Srgrimes#ifdef OFDEL
1141590Srgrimes			  | OFDEL
1151590Srgrimes#endif
1161590Srgrimes#ifdef NLDLY
1171590Srgrimes			  | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
1181590Srgrimes#endif
1191590Srgrimes			  );
1201590Srgrimes
1211590Srgrimes	mode.c_oflag |= (OPOST
1221590Srgrimes#ifdef ONLCR
1231590Srgrimes			 | ONLCR
1241590Srgrimes#endif
1251590Srgrimes			 );
1261590Srgrimes
1271590Srgrimes	mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL);
1281590Srgrimes	mode.c_cflag |= (CS8 | CREAD);
1291590Srgrimes	mode.c_lflag &= ~(ECHONL | NOFLSH | TOSTOP
1301590Srgrimes#ifdef ECHOPTR
1311590Srgrimes			  | ECHOPRT
1321590Srgrimes#endif
1331590Srgrimes#ifdef XCASE
1341590Srgrimes			  | XCASE
1351590Srgrimes#endif
1361590Srgrimes			  );
1371590Srgrimes
1381590Srgrimes	mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
1391590Srgrimes#ifdef ECHOCTL
1401590Srgrimes			 | ECHOCTL
1411590Srgrimes#endif
1421590Srgrimes#ifdef ECHOKE
1431590Srgrimes			 | ECHOKE
1441590Srgrimes#endif
1451590Srgrimes 			 );
1461590Srgrimes
1471590Srgrimes	tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
1481590Srgrimes}
1491590Srgrimes
1501590Srgrimes/*
1511590Srgrimes * Determine the erase, interrupt, and kill characters from the termcap
1521590Srgrimes * entry and command line and update their values in 'mode'.
1531590Srgrimes */
1541590Srgrimesvoid
155200419Sdelphijset_control_chars(void)
1561590Srgrimes{
1571590Srgrimes	char *bp, *p, bs_char, buf[1024];
1581590Srgrimes
1591590Srgrimes	bp = buf;
1601590Srgrimes	p = tgetstr("kb", &bp);
1611590Srgrimes	if (p == NULL || p[1] != '\0')
1621590Srgrimes		p = tgetstr("bc", &bp);
1631590Srgrimes	if (p != NULL && p[1] == '\0')
1641590Srgrimes		bs_char = p[0];
1651590Srgrimes	else if (tgetflag("bs"))
1661590Srgrimes		bs_char = CTRL('h');
1671590Srgrimes	else
1681590Srgrimes		bs_char = 0;
1691590Srgrimes
17068617Sdg	if (erasech == 0 && bs_char != 0 && !tgetflag("os"))
17168617Sdg		erasech = -1;
17268617Sdg	if (erasech < 0)
17368617Sdg		erasech = (bs_char != 0) ? bs_char : CTRL('h');
1741590Srgrimes
17568617Sdg	if (mode.c_cc[VERASE] == 0 || erasech != 0)
17668617Sdg		mode.c_cc[VERASE] = erasech ? erasech : CERASE;
1771590Srgrimes
1781590Srgrimes	if (mode.c_cc[VINTR] == 0 || intrchar != 0)
1791590Srgrimes		 mode.c_cc[VINTR] = intrchar ? intrchar : CINTR;
1801590Srgrimes
18168617Sdg	if (mode.c_cc[VKILL] == 0 || killch != 0)
18268617Sdg		mode.c_cc[VKILL] = killch ? killch : CKILL;
1831590Srgrimes}
1841590Srgrimes
1851590Srgrimes/*
1861590Srgrimes * Set up various conversions in 'mode', including parity, tabs, returns,
1871590Srgrimes * echo, and case, according to the termcap entry.  If the program we're
1881590Srgrimes * running was named with a leading upper-case character, map external
1891590Srgrimes * uppercase to internal lowercase.
1901590Srgrimes */
1911590Srgrimesvoid
192200419Sdelphijset_conversions(int usingupper)
1931590Srgrimes{
1941590Srgrimes	if (tgetflag("UC") || usingupper) {
1951590Srgrimes#ifdef IUCLC
1961590Srgrimes		mode.c_iflag |= IUCLC;
1971590Srgrimes		mode.c_oflag |= OLCUC;
1981590Srgrimes#endif
1991590Srgrimes	} else if (tgetflag("LC")) {
2001590Srgrimes#ifdef IUCLC
2011590Srgrimes		mode.c_iflag &= ~IUCLC;
2021590Srgrimes		mode.c_oflag &= ~OLCUC;
2031590Srgrimes#endif
2041590Srgrimes	}
2051590Srgrimes	mode.c_iflag &= ~(PARMRK | INPCK);
2061590Srgrimes	mode.c_lflag |= ICANON;
2071590Srgrimes	if (tgetflag("EP")) {
2081590Srgrimes		mode.c_cflag |= PARENB;
2091590Srgrimes		mode.c_cflag &= ~PARODD;
2101590Srgrimes	}
2111590Srgrimes	if (tgetflag("OP")) {
2121590Srgrimes		mode.c_cflag |= PARENB;
2131590Srgrimes		mode.c_cflag |= PARODD;
2141590Srgrimes	}
2151590Srgrimes
2161590Srgrimes#ifdef ONLCR
2171590Srgrimes	mode.c_oflag |= ONLCR;
2181590Srgrimes#endif
2191590Srgrimes	mode.c_iflag |= ICRNL;
2201590Srgrimes	mode.c_lflag |= ECHO;
2211590Srgrimes	mode.c_oflag |= OXTABS;
2221590Srgrimes	if (tgetflag("NL")) {			/* Newline, not linefeed. */
2231590Srgrimes#ifdef ONLCR
2241590Srgrimes		mode.c_oflag &= ~ONLCR;
2251590Srgrimes#endif
2261590Srgrimes		mode.c_iflag &= ~ICRNL;
2271590Srgrimes	}
2281590Srgrimes	if (tgetflag("HD"))			/* Half duplex. */
2291590Srgrimes		mode.c_lflag &= ~ECHO;
2301590Srgrimes	if (tgetflag("pt"))			/* Print tabs. */
2311590Srgrimes		mode.c_oflag &= ~OXTABS;
2321590Srgrimes	mode.c_lflag |= (ECHOE | ECHOK);
2331590Srgrimes}
2341590Srgrimes
2351590Srgrimes/* Output startup string. */
2361590Srgrimesvoid
237200419Sdelphijset_init(void)
2381590Srgrimes{
2391590Srgrimes	char *bp, buf[1024];
2401590Srgrimes	int settle;
2411590Srgrimes
2421590Srgrimes	bp = buf;
2431590Srgrimes	if (tgetstr("pc", &bp) != 0)		/* Get/set pad character. */
2441590Srgrimes		PC = buf[0];
2453397Sache
2461590Srgrimes#ifdef TAB3
2471590Srgrimes	if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
2481590Srgrimes		oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
2491590Srgrimes		tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
2501590Srgrimes	}
2511590Srgrimes#endif
2521590Srgrimes	settle = set_tabs();
2531590Srgrimes
2541590Srgrimes	if (isreset) {
2551590Srgrimes		bp = buf;
2561590Srgrimes		if (tgetstr("rs", &bp) != 0 || tgetstr("is", &bp) != 0) {
2571590Srgrimes			tputs(buf, 0, outc);
2581590Srgrimes			settle = 1;
2591590Srgrimes		}
2601590Srgrimes		bp = buf;
2611590Srgrimes		if (tgetstr("rf", &bp) != 0 || tgetstr("if", &bp) != 0) {
2621590Srgrimes			cat(buf);
2631590Srgrimes			settle = 1;
2641590Srgrimes		}
2651590Srgrimes	}
2661590Srgrimes
2671590Srgrimes	if (settle) {
2681590Srgrimes		(void)putc('\r', stderr);
2691590Srgrimes		(void)fflush(stderr);
2701590Srgrimes		(void)sleep(1);			/* Settle the terminal. */
2711590Srgrimes	}
2721590Srgrimes}
2731590Srgrimes
2741590Srgrimes/*
2751590Srgrimes * Set the hardware tabs on the terminal, using the ct (clear all tabs),
2761590Srgrimes * st (set one tab) and ch (horizontal cursor addressing) capabilities.
2771590Srgrimes * This is done before if and is, so they can patch in case we blow this.
2781590Srgrimes * Return nonzero if we set any tab stops, zero if not.
2791590Srgrimes */
2801590Srgrimesint
281200419Sdelphijset_tabs(void)
2821590Srgrimes{
2831590Srgrimes	int c;
2841590Srgrimes	char *capsp, *clear_tabs;
28587701Smarkm	char *set_column, *set_pos, *Set_tab;
2861590Srgrimes	char caps[1024];
28787701Smarkm	const char *tg_out;
2881590Srgrimes
2891590Srgrimes	capsp = caps;
29050638Speter	Set_tab = tgetstr("st", &capsp);
2911590Srgrimes
29250638Speter	if (Set_tab && (clear_tabs = tgetstr("ct", &capsp))) {
2931590Srgrimes		(void)putc('\r', stderr);	/* Force to left margin. */
2941590Srgrimes		tputs(clear_tabs, 0, outc);
2951590Srgrimes	}
2961590Srgrimes
2971590Srgrimes	set_column = tgetstr("ch", &capsp);
2981590Srgrimes	set_pos = set_column ? NULL : tgetstr("cm", &capsp);
2991590Srgrimes
30050638Speter	if (Set_tab) {
30150638Speter		for (c = 8; c < Columns; c += 8) {
3021590Srgrimes			/*
3031590Srgrimes			 * Get to the right column.  "OOPS" is returned by
3041590Srgrimes			 * tgoto() if it can't do the job.  (*snarl*)
3051590Srgrimes			 */
3061590Srgrimes			tg_out = "OOPS";
3071590Srgrimes			if (set_column)
3081590Srgrimes				tg_out = tgoto(set_column, 0, c);
3091590Srgrimes			if (*tg_out == 'O' && set_pos)
31050638Speter				tg_out = tgoto(set_pos, c, Lines - 1);
3111590Srgrimes			if (*tg_out != 'O')
3121590Srgrimes				tputs(tg_out, 1, outc);
3131590Srgrimes			else
3141590Srgrimes				(void)fprintf(stderr, "%s", "        ");
3151590Srgrimes			/* Set the tab. */
31650638Speter			tputs(Set_tab, 0, outc);
3171590Srgrimes		}
3181590Srgrimes		putc('\r', stderr);
3191590Srgrimes		return (1);
3201590Srgrimes	}
3211590Srgrimes	return (0);
3221590Srgrimes}
323