1 /*        $NetBSD: set.c,v 1.18 2015/06/21 08:23:22 mlelstv 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.18 2015/06/21 08:23:22 mlelstv 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 
44 static 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  */
50 void
reset_mode(void)51 reset_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 terminfo
149  * entry and command line and update their values in 'mode'.
150  */
151 void
set_control_chars(int erasechar,int intrchar,int killchar)152 set_control_chars(int erasechar, int intrchar, int killchar)
153 {
154           int bs_char;
155 
156           if (key_backspace != NULL && key_backspace[1] == '\0')
157                     bs_char = key_backspace[0];
158           else
159                     bs_char = 0;
160 
161           if (erasechar == 0 && bs_char != 0 && !over_strike)
162                     erasechar = -1;
163           if (erasechar < 0)
164                     erasechar = (bs_char != 0) ? bs_char : CTRL('h');
165 
166           if (mode.c_cc[VERASE] == 0 || erasechar != 0)
167                      mode.c_cc[VERASE] = erasechar ? erasechar : CERASE;
168 
169           if (mode.c_cc[VINTR] == 0 || intrchar != 0)
170                      mode.c_cc[VINTR] = intrchar ? intrchar : CINTR;
171 
172           if (mode.c_cc[VKILL] == 0 || killchar != 0)
173                     mode.c_cc[VKILL] = killchar ? killchar : CKILL;
174 }
175 
176 /*
177  * Set up various conversions in 'mode', including parity, tabs, returns,
178  * echo, and case, according to the terminfo entry.  If the program we're
179  * running was named with a leading upper-case character, map external
180  * uppercase to internal lowercase.
181  */
182 void
set_conversions(int usingupper)183 set_conversions(int usingupper)
184 {
185 
186 #ifdef ONLCR
187           mode.c_oflag |= ONLCR;
188 #endif
189           mode.c_iflag |= ICRNL;
190           mode.c_lflag |= ECHO;
191           mode.c_oflag |= OXTABS;
192           if (newline != NULL && newline[0] == '\n' && !newline[1]) {                     /* Newline, not linefeed. */
193 #ifdef ONLCR
194                     mode.c_oflag &= ~ONLCR;
195 #endif
196                     mode.c_iflag &= ~ICRNL;
197           }
198           if (tab)  /* Print tabs. */
199                     mode.c_oflag &= ~OXTABS;
200           mode.c_lflag |= (ECHOE | ECHOK);
201 }
202 
203 /* Output startup string. */
204 void
set_init(void)205 set_init(void)
206 {
207           const char *bp;
208           int settle;
209 
210 #ifdef TAB3
211           if (oldmode.c_oflag & (TAB3 | ONLCR | OCRNL | ONLRET)) {
212                     oldmode.c_oflag &= (TAB3 | ONLCR | OCRNL | ONLRET);
213                     tcsetattr(STDERR_FILENO, TCSADRAIN, &oldmode);
214           }
215 #endif
216           settle = set_tabs();
217 
218           if (isreset) {
219                     if (reset_1string) {
220                               tputs(reset_1string, 0, outc);
221                               settle = 1;
222                     }
223                     if (reset_2string) {
224                               tputs(reset_2string, 0, outc);
225                               settle = 1;
226                     }
227                     if ((bp = reset_file) || (bp = init_file)) {
228                               tset_cat(bp);
229                               settle = 1;
230                     }
231           }
232 
233           if (settle) {
234                     (void)putc('\r', stderr);
235                     (void)fflush(stderr);
236                     (void)sleep(1);                         /* Settle the terminal. */
237           }
238 }
239 
240 /*
241  * Set the hardware tabs on the terminal, using the ct (clear all tabs),
242  * st (set one tab) and ch (horizontal cursor addressing) capabilities.
243  * This is done before if and is, so they can patch in case we blow this.
244  * Return nonzero if we set any tab stops, zero if not.
245  */
246 static int
set_tabs(void)247 set_tabs(void)
248 {
249           int c;
250           char *out;
251 
252           if (set_tab) {
253                     if (clear_all_tabs) {
254                               (void)putc('\r', stderr);   /* Force to left margin. */
255                               tputs(clear_all_tabs, 0, outc);
256                     }
257 
258                     for (c = 8; c < ncolumns; c += 8) {
259                               if (column_address)
260                                         out = tiparm(column_address, c);
261                               else
262                                         out = NULL;
263                               if (out)
264                                         tputs(out, 1, outc);
265                               else
266                                         (void)fprintf(stderr, "%s", "        ");
267                               /* Set the tab. */
268                               tputs(set_tab, 0, outc);
269                     }
270                     putc('\r', stderr);
271                     return (1);
272           }
273           return (0);
274 }
275