1 /* $OpenBSD: hack.tty.c,v 1.11 2009/10/27 23:59:25 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 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 /* 33 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 34 * Amsterdam 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions are 39 * met: 40 * 41 * - Redistributions of source code must retain the above copyright notice, 42 * this list of conditions and the following disclaimer. 43 * 44 * - Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * - Neither the name of the Stichting Centrum voor Wiskunde en 49 * Informatica, nor the names of its contributors may be used to endorse or 50 * promote products derived from this software without specific prior 51 * written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 54 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 55 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 56 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 57 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 58 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 59 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 60 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 61 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 62 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 63 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 64 */ 65 66 /* 67 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 68 * All rights reserved. 69 * 70 * Redistribution and use in source and binary forms, with or without 71 * modification, are permitted provided that the following conditions 72 * are met: 73 * 1. Redistributions of source code must retain the above copyright 74 * notice, this list of conditions and the following disclaimer. 75 * 2. Redistributions in binary form must reproduce the above copyright 76 * notice, this list of conditions and the following disclaimer in the 77 * documentation and/or other materials provided with the distribution. 78 * 3. The name of the author may not be used to endorse or promote products 79 * derived from this software without specific prior written permission. 80 * 81 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 82 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 83 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 84 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 85 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 86 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 87 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 88 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 89 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 90 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 91 */ 92 93 /* hack.tty.c - version 1.0.3 */ 94 /* With thanks to the people who sent code for SYSV - hpscdi!jon, 95 arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */ 96 97 #include "hack.h" 98 #include <stdio.h> 99 #include <stdarg.h> 100 #include <stdlib.h> 101 #include <termios.h> 102 103 /* 104 * Some systems may have getchar() return EOF for various reasons, and 105 * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. 106 */ 107 #ifndef BSD 108 #define NR_OF_EOFS 20 109 #endif /* BSD */ 110 111 static char erase_char, kill_char; 112 static boolean settty_needed = FALSE; 113 struct termios inittyb, curttyb; 114 115 static void setctty(); 116 117 /* 118 * Get initial state of terminal, 119 * and switch off tab expansion if necessary. 120 * Called by startup() in termcap.c and after returning from ! or ^Z 121 */ 122 void 123 gettty() 124 { 125 if(tcgetattr(0, &inittyb) < 0) 126 perror("Hack (gettty)"); 127 curttyb = inittyb; 128 erase_char = inittyb.c_cc[VERASE]; 129 kill_char = inittyb.c_cc[VKILL]; 130 getioctls(); 131 132 /* do not expand tabs - they might be needed inside a cm sequence */ 133 if(curttyb.c_oflag & OXTABS) { 134 curttyb.c_oflag &= ~OXTABS; 135 setctty(); 136 } 137 settty_needed = TRUE; 138 } 139 140 /* reset terminal to original state */ 141 void 142 settty(char *s) 143 { 144 clr_screen(); 145 end_screen(); 146 if(s) printf("%s", s); 147 (void) fflush(stdout); 148 if(tcsetattr(0, TCSADRAIN, &inittyb) < 0) 149 perror("Hack (settty)"); 150 flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF; 151 flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON; 152 setioctls(); 153 } 154 155 static void 156 setctty() 157 { 158 if(tcsetattr(0, TCSADRAIN, &curttyb) < 0) 159 perror("Hack (setctty)"); 160 } 161 162 void 163 setftty() 164 { 165 int change = 0; 166 flags.cbreak = ON; 167 flags.echo = OFF; 168 /* Should use (ECHO|CRMOD) here instead of ECHO */ 169 if(curttyb.c_lflag & ECHO){ 170 curttyb.c_lflag &= ~ECHO; 171 change++; 172 } 173 if(curttyb.c_lflag & ICANON){ 174 curttyb.c_lflag &= ~ICANON; 175 /* be satisfied with one character; no timeout */ 176 curttyb.c_cc[VMIN] = 1; 177 curttyb.c_cc[VTIME] = 0; 178 change++; 179 } 180 if(change){ 181 setctty(); 182 } 183 start_screen(); 184 } 185 186 187 /* fatal error */ 188 void 189 error(char *s, ...) 190 { 191 va_list ap; 192 193 if(settty_needed) 194 settty((char *) 0); 195 va_start(ap, s); 196 vprintf(s, ap); 197 va_end(ap); 198 putchar('\n'); 199 exit(1); 200 } 201 202 /* 203 * Read a line closed with '\n' into the array char bufp[BUFSZ]. 204 * (The '\n' is not stored. The string is closed with a '\0'.) 205 * Reading can be interrupted by an escape ('\033') - now the 206 * resulting string is "\033". 207 */ 208 void 209 getlin(char *bufp) 210 { 211 char *obufp = bufp; 212 int c; 213 214 flags.toplin = 2; /* nonempty, no --More-- required */ 215 for(;;) { 216 (void) fflush(stdout); 217 if((c = getchar()) == EOF) { 218 *bufp = 0; 219 return; 220 } 221 if(c == '\033') { 222 *obufp = c; 223 obufp[1] = 0; 224 return; 225 } 226 if(c == erase_char || c == '\b') { 227 if(bufp != obufp) { 228 bufp--; 229 putstr("\b \b"); /* putsym converts \b */ 230 } else hackbell(); 231 } else if(c == '\n') { 232 *bufp = 0; 233 return; 234 } else if(' ' <= c && c < '\177') { 235 /* avoid isprint() - some people don't have it 236 ' ' is not always a printing char */ 237 *bufp = c; 238 bufp[1] = 0; 239 putstr(bufp); 240 if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO) 241 bufp++; 242 } else if(c == kill_char || c == '\177') { /* Robert Viduya */ 243 /* this test last - @ might be the kill_char */ 244 while(bufp != obufp) { 245 bufp--; 246 putstr("\b \b"); 247 } 248 } else 249 hackbell(); 250 } 251 } 252 253 void 254 getret() 255 { 256 cgetret(""); 257 } 258 259 void 260 cgetret(char *s) 261 { 262 putsym('\n'); 263 if(flags.standout) 264 standoutbeg(); 265 putstr("Hit "); 266 putstr(flags.cbreak ? "space" : "return"); 267 putstr(" to continue: "); 268 if(flags.standout) 269 standoutend(); 270 xwaitforspace(s); 271 } 272 273 char morc; /* tell the outside world what char he used */ 274 275 /* s: chars allowed besides space or return */ 276 void 277 xwaitforspace(char *s) 278 { 279 int c; 280 281 morc = 0; 282 283 while((c = readchar()) != '\n') { 284 if(flags.cbreak) { 285 if(c == ' ') break; 286 if(s && strchr(s,c)) { 287 morc = c; 288 break; 289 } 290 hackbell(); 291 } 292 } 293 } 294 295 char * 296 parse() 297 { 298 static char inputline[COLNO]; 299 int foo; 300 301 flags.move = 1; 302 if(!Invisible) curs_on_u(); else home(); 303 while((foo = readchar()) >= '0' && foo <= '9') 304 multi = 10*multi+foo-'0'; 305 if(multi) { 306 multi--; 307 save_cm = inputline; 308 } 309 inputline[0] = foo; 310 inputline[1] = 0; 311 if(foo == 'f' || foo == 'F'){ 312 inputline[1] = getchar(); 313 #ifdef QUEST 314 if(inputline[1] == foo) inputline[2] = getchar(); else 315 #endif /* QUEST */ 316 inputline[2] = 0; 317 } 318 if(foo == 'm' || foo == 'M'){ 319 inputline[1] = getchar(); 320 inputline[2] = 0; 321 } 322 clrlin(); 323 return(inputline); 324 } 325 326 char 327 readchar() 328 { 329 int sym; 330 331 (void) fflush(stdout); 332 if((sym = getchar()) == EOF) 333 #ifdef NR_OF_EOFS 334 { /* 335 * Some SYSV systems seem to return EOFs for various reasons 336 * (?like when one hits break or for interrupted systemcalls?), 337 * and we must see several before we quit. 338 */ 339 int cnt = NR_OF_EOFS; 340 while (cnt--) { 341 clearerr(stdin); /* omit if clearerr is undefined */ 342 if((sym = getchar()) != EOF) goto noteof; 343 } 344 end_of_input(); 345 noteof: ; 346 } 347 #else 348 end_of_input(); 349 #endif /* NR_OF_EOFS */ 350 if(flags.toplin == 1) 351 flags.toplin = 2; 352 return((char) sym); 353 } 354 355 void 356 end_of_input() 357 { 358 settty("End of input?\n"); 359 clearlocks(); 360 exit(0); 361 } 362