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