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