1/*	$NetBSD: set.c,v 1.15 2011/09/06 18:34:12 joerg Exp $	*/
2
3/*-
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: set.c,v 1.15 2011/09/06 18:34:12 joerg Exp $");
34
35#include <err.h>
36#include <stdio.h>
37#include <term.h>
38#include <termios.h>
39#include <unistd.h>
40#include "extern.h"
41
42#define	CHK(val, dft)	(val <= 0 ? dft : val)
43
44static int	set_tabs(void);
45
46/*
47 * Reset the terminal mode bits to a sensible state.  Very useful after
48 * a child program dies in raw mode.
49 */
50void
51reset_mode(void)
52{
53	tcgetattr(STDERR_FILENO, &mode);
54
55#if defined(VDISCARD) && defined(CDISCARD)
56	mode.c_cc[VDISCARD] = CHK(mode.c_cc[VDISCARD], CDISCARD);
57#endif
58	mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
59	mode.c_cc[VERASE] = CHK(mode.c_cc[VERASE], CERASE);
60#if defined(VFLUSH) && defined(CFLUSH)
61	mode.c_cc[VFLUSH] = CHK(mode.c_cc[VFLUSH], CFLUSH);
62#endif
63	mode.c_cc[VINTR] = CHK(mode.c_cc[VINTR], CINTR);
64	mode.c_cc[VKILL] = CHK(mode.c_cc[VKILL], CKILL);
65#if defined(VLNEXT) && defined(CLNEXT)
66	mode.c_cc[VLNEXT] = CHK(mode.c_cc[VLNEXT], CLNEXT);
67#endif
68	mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
69#if defined(VREPRINT) && defined(CRPRNT)
70	mode.c_cc[VREPRINT] = CHK(mode.c_cc[VREPRINT], CRPRNT);
71#endif
72	mode.c_cc[VSTART] = CHK(mode.c_cc[VSTART], CSTART);
73	mode.c_cc[VSTOP] = CHK(mode.c_cc[VSTOP], CSTOP);
74	mode.c_cc[VSUSP] = CHK(mode.c_cc[VSUSP], CSUSP);
75#if defined(VWERASE) && defined(CWERASE)
76	mode.c_cc[VWERASE] = CHK(mode.c_cc[VWERASE], CWERASE);
77#endif
78
79	mode.c_iflag &= ~(IGNBRK | PARMRK | INPCK | ISTRIP | INLCR | IGNCR
80#ifdef IUCLC
81			  | IUCLC
82#endif
83#ifdef IXANY
84			  | IXANY
85#endif
86			  | IXOFF);
87
88	mode.c_iflag |= (BRKINT | IGNPAR | ICRNL | IXON
89#ifdef IMAXBEL
90			 | IMAXBEL
91#endif
92			 );
93
94	mode.c_oflag &= ~(0
95#ifdef OLCUC
96			  | OLCUC
97#endif
98#ifdef OCRNL
99			  | OCRNL
100#endif
101#ifdef ONOCR
102			  | ONOCR
103#endif
104#ifdef ONLRET
105			  | ONLRET
106#endif
107#ifdef OFILL
108			  | OFILL
109#endif
110#ifdef OFDEL
111			  | OFDEL
112#endif
113#ifdef NLDLY
114			  | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY
115#endif
116			  );
117
118	mode.c_oflag |= (OPOST
119#ifdef ONLCR
120			 | ONLCR
121#endif
122			 );
123
124	mode.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
125	mode.c_cflag |= (CS8 | CREAD);
126	mode.c_lflag &= ~(ECHONL | NOFLSH | TOSTOP
127#ifdef ECHOPTR
128			  | ECHOPRT
129#endif
130#ifdef XCASE
131			  | XCASE
132#endif
133			  );
134
135	mode.c_lflag |= (ISIG | ICANON | ECHO | ECHOE | ECHOK
136#ifdef ECHOCTL
137			 | ECHOCTL
138#endif
139#ifdef ECHOKE
140			 | ECHOKE
141#endif
142 			 );
143
144	tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
145}
146
147/*
148 * Determine the erase, interrupt, and kill characters from the termcap
149 * entry and command line and update their values in 'mode'.
150 */
151void
152set_control_chars(int erasechar, int intrchar, int killchar)
153{
154
155	if (mode.c_cc[VERASE] == 0 || erasechar != 0) {
156		if (erasechar == 0) {
157			if (over_strike &&
158			    key_backspace != NULL &&
159			    key_backspace[1] == '\0')
160				mode.c_cc[VERASE] = key_backspace[1];
161			else
162				mode.c_cc[VERASE] = CERASE;
163		} else
164			mode.c_cc[VERASE] = erasechar;
165	}
166
167	if (mode.c_cc[VINTR] == 0 || intrchar != 0)
168		 mode.c_cc[VINTR] = intrchar ? intrchar : CINTR;
169
170	if (mode.c_cc[VKILL] == 0 || killchar != 0)
171		mode.c_cc[VKILL] = killchar ? killchar : CKILL;
172}
173
174/*
175 * Set up various conversions in 'mode', including parity, tabs, returns,
176 * echo, and case, according to the termcap entry.  If the program we're
177 * running was named with a leading upper-case character, map external
178 * uppercase to internal lowercase.
179 */
180void
181set_conversions(int usingupper)
182{
183
184#ifdef ONLCR
185	mode.c_oflag |= ONLCR;
186#endif
187	mode.c_iflag |= ICRNL;
188	mode.c_lflag |= ECHO;
189	mode.c_oflag |= OXTABS;
190	if (newline != NULL && newline[0] == '\n' && !newline[1]) {			/* Newline, not linefeed. */
191#ifdef ONLCR
192		mode.c_oflag &= ~ONLCR;
193#endif
194		mode.c_iflag &= ~ICRNL;
195	}
196	if (tab)	/* Print tabs. */
197		mode.c_oflag &= ~OXTABS;
198	mode.c_lflag |= (ECHOE | ECHOK);
199}
200
201/* Output startup string. */
202void
203set_init(void)
204{
205	const char *bp;
206	int settle;
207
208#ifdef TAB3
209	if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
210		oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
211		tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
212	}
213#endif
214	settle = set_tabs();
215
216	if (isreset) {
217		if (reset_1string) {
218			tputs(reset_1string, 0, outc);
219			settle = 1;
220		}
221		if (reset_2string) {
222			tputs(reset_2string, 0, outc);
223			settle = 1;
224		}
225		if ((bp = reset_file) || (bp = init_file)) {
226			tset_cat(bp);
227			settle = 1;
228		}
229	}
230
231	if (settle) {
232		(void)putc('\r', stderr);
233		(void)fflush(stderr);
234		(void)sleep(1);			/* Settle the terminal. */
235	}
236}
237
238/*
239 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
240 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
241 * This is done before if and is, so they can patch in case we blow this.
242 * Return nonzero if we set any tab stops, zero if not.
243 */
244static int
245set_tabs(void)
246{
247	int c;
248	char *out;
249
250	if (set_tab) {
251		if (clear_all_tabs) {
252			(void)putc('\r', stderr);   /* Force to left margin. */
253			tputs(clear_all_tabs, 0, outc);
254		}
255
256		for (c = 8; c < ncolumns; c += 8) {
257			if (column_address)
258				out = tiparm(column_address, c);
259			else
260				out = NULL;
261			if (out)
262				tputs(out, 1, outc);
263			else
264				(void)fprintf(stderr, "%s", "        ");
265			/* Set the tab. */
266			tputs(set_tab, 0, outc);
267		}
268		putc('\r', stderr);
269		return (1);
270	}
271	return (0);
272}
273