1 /* $NetBSD: hack.tty.c,v 1.15 2010/02/03 15:34:39 roy 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.15 2010/02/03 15:34:39 roy 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 static struct termios inittyb, curttyb; 124 125 static void setctty(void); 126 127 /* 128 * Get initial state of terminal, set ospeed (for termcap routines) 129 * and switch off tab expansion if necessary. 130 * Called by startup() in termcap.c and after returning from ! or ^Z 131 */ 132 void 133 gettty(void) 134 { 135 if (tcgetattr(0, &inittyb) < 0) 136 perror("Hack (gettty)"); 137 curttyb = inittyb; 138 ospeed = cfgetospeed(&inittyb); 139 erase_char = inittyb.c_cc[VERASE]; 140 kill_char = inittyb.c_cc[VKILL]; 141 getioctls(); 142 143 /* do not expand tabs - they might be needed inside a cm sequence */ 144 if (curttyb.c_oflag & OXTABS) { 145 curttyb.c_oflag &= ~OXTABS; 146 setctty(); 147 } 148 settty_needed = TRUE; 149 } 150 151 /* reset terminal to original state */ 152 void 153 settty(const char *s) 154 { 155 clearscreen(); 156 endscreen(); 157 if (s) 158 printf("%s", s); 159 (void) fflush(stdout); 160 if (tcsetattr(0, TCSADRAIN, &inittyb) < 0) 161 perror("Hack (settty)"); 162 flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF; 163 flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON; 164 setioctls(); 165 } 166 167 static void 168 setctty(void) 169 { 170 if (tcsetattr(0, TCSADRAIN, &curttyb) < 0) 171 perror("Hack (setctty)"); 172 } 173 174 175 void 176 setftty(void) 177 { 178 int change = 0; 179 flags.cbreak = ON; 180 flags.echo = OFF; 181 /* Should use (ECHO|CRMOD) here instead of ECHO */ 182 if (curttyb.c_lflag & ECHO) { 183 curttyb.c_lflag &= ~ECHO; 184 change++; 185 } 186 if (curttyb.c_lflag & ICANON) { 187 curttyb.c_lflag &= ~ICANON; 188 /* be satisfied with one character; no timeout */ 189 curttyb.c_cc[VMIN] = 1; 190 curttyb.c_cc[VTIME] = 0; 191 change++; 192 } 193 if (change) { 194 setctty(); 195 } 196 startscreen(); 197 } 198 199 200 /* fatal error */ 201 /* VARARGS1 */ 202 void 203 error(const char *fmt, ...) 204 { 205 va_list ap; 206 207 va_start(ap, fmt); 208 if (settty_needed) 209 settty((char *) 0); 210 vprintf(fmt, ap); 211 va_end(ap); 212 putchar('\n'); 213 exit(1); 214 } 215 216 /* 217 * Read a line closed with '\n' into the array char bufp[BUFSZ]. 218 * (The '\n' is not stored. The string is closed with a '\0'.) 219 * Reading can be interrupted by an escape ('\033') - now the 220 * resulting string is "\033". 221 */ 222 void 223 getlin(char *bufp) 224 { 225 char *obufp = bufp; 226 int c; 227 228 flags.toplin = 2; /* nonempty, no --More-- required */ 229 for (;;) { 230 (void) fflush(stdout); 231 if ((c = getchar()) == EOF) { 232 *bufp = 0; 233 return; 234 } 235 if (c == '\033') { 236 *obufp = c; 237 obufp[1] = 0; 238 return; 239 } 240 if (c == erase_char || c == '\b') { 241 if (bufp != obufp) { 242 bufp--; 243 putstr("\b \b"); /* putsym converts \b */ 244 } else 245 sound_bell(); 246 } else if (c == '\n') { 247 *bufp = 0; 248 return; 249 } else if (' ' <= c && c < '\177') { 250 /* 251 * avoid isprint() - some people don't have it ' ' is 252 * not always a printing char 253 */ 254 *bufp = c; 255 bufp[1] = 0; 256 putstr(bufp); 257 if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO) 258 bufp++; 259 } else if (c == kill_char || c == '\177') { /* Robert Viduya */ 260 /* this test last - @ might be the kill_char */ 261 while (bufp != obufp) { 262 bufp--; 263 putstr("\b \b"); 264 } 265 } else 266 sound_bell(); 267 } 268 } 269 270 void 271 getret(void) 272 { 273 cgetret(""); 274 } 275 276 void 277 cgetret(const char *s) 278 { 279 putsym('\n'); 280 if (flags.standout) 281 standoutbeg(); 282 putstr("Hit "); 283 putstr(flags.cbreak ? "space" : "return"); 284 putstr(" to continue: "); 285 if (flags.standout) 286 standoutend(); 287 xwaitforspace(s); 288 } 289 290 char morc; /* tell the outside world what char he used */ 291 292 /* s = chars allowed besides space or return */ 293 void 294 xwaitforspace(const char *s) 295 { 296 int c; 297 298 morc = 0; 299 300 while ((c = readchar()) != '\n') { 301 if (flags.cbreak) { 302 if (c == ' ') 303 break; 304 if (s && strchr(s, c)) { 305 morc = c; 306 break; 307 } 308 sound_bell(); 309 } 310 } 311 } 312 313 char * 314 parse(void) 315 { 316 static char inputline[COLNO]; 317 int foo; 318 319 flags.move = 1; 320 if (!Invisible) 321 curs_on_u(); 322 else 323 home(); 324 while ((foo = readchar()) >= '0' && foo <= '9') 325 multi = 10 * multi + foo - '0'; 326 if (multi) { 327 multi--; 328 save_cm = inputline; 329 } 330 inputline[0] = foo; 331 inputline[1] = 0; 332 if (foo == 'f' || foo == 'F') { 333 inputline[1] = getchar(); 334 #ifdef QUEST 335 if (inputline[1] == foo) 336 inputline[2] = getchar(); 337 else 338 #endif /* QUEST */ 339 inputline[2] = 0; 340 } 341 if (foo == 'm' || foo == 'M') { 342 inputline[1] = getchar(); 343 inputline[2] = 0; 344 } 345 clrlin(); 346 return (inputline); 347 } 348 349 char 350 readchar(void) 351 { 352 int sym; 353 354 (void) fflush(stdout); 355 if ((sym = getchar()) == EOF) 356 #ifdef NR_OF_EOFS 357 { /* 358 * Some SYSV systems seem to return EOFs for various reasons 359 * (?like when one hits break or for interrupted systemcalls?), 360 * and we must see several before we quit. 361 */ 362 int cnt = NR_OF_EOFS; 363 while (cnt--) { 364 clearerr(stdin); /* omit if clearerr is 365 * undefined */ 366 if ((sym = getchar()) != EOF) 367 goto noteof; 368 } 369 end_of_input(); 370 noteof: ; 371 } 372 #else 373 end_of_input(); 374 #endif /* NR_OF_EOFS */ 375 if (flags.toplin == 1) 376 flags.toplin = 2; 377 return ((char) sym); 378 } 379 380 void 381 end_of_input(void) 382 { 383 settty("End of input?\n"); 384 clearlocks(); 385 exit(0); 386 } 387