1 /*- 2 * Copyright (c) 1988, 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 * @(#)hack.tty.c 8.1 (Berkeley) 5/31/93 30 * $FreeBSD: src/games/hack/hack.tty.c,v 1.6.2.1 2000/07/20 10:35:07 kris Exp $ 31 * $DragonFly: src/games/hack/hack.tty.c,v 1.4 2006/08/21 19:45:32 pavalos Exp $ 32 */ 33 34 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 35 /* hack.tty.c - version 1.0.3 */ 36 /* 37 * With thanks to the people who sent code for SYSV - hpscdi!jon, 38 * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. 39 */ 40 41 #include <termios.h> 42 #include "hack.h" 43 44 /* 45 * Some systems may have getchar() return EOF for various reasons, and 46 * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. 47 * FIXME: is this still valid nowadays? 48 */ 49 #define NR_OF_EOFS 20 50 51 static char erase_char, kill_char; 52 static boolean settty_needed = FALSE; 53 struct termios inittyb, curttyb; 54 55 static void setctty(void); 56 57 /* 58 * Get initial state of terminal, set ospeed (for termcap routines) 59 * and switch off tab expansion if necessary. 60 * Called by startup() in termcap.c and after returning from ! or ^Z 61 */ 62 void 63 gettty(void) 64 { 65 if (tcgetattr(fileno(stdin), &inittyb) < 0) 66 perror("Hack (gettty)"); 67 curttyb = inittyb; 68 erase_char = inittyb.c_cc[VERASE]; 69 kill_char = inittyb.c_cc[VKILL]; 70 getioctls(); 71 72 /* do not expand tabs - they might be needed inside a cm sequence */ 73 if (curttyb.c_oflag & OXTABS) { 74 curttyb.c_oflag &= ~OXTABS; 75 setctty(); 76 } 77 settty_needed = TRUE; 78 } 79 80 /* reset terminal to original state */ 81 void 82 settty(const char *s) 83 { 84 clear_screen(); 85 end_screen(); 86 if (s) 87 printf("%s", s); 88 fflush(stdout); 89 if (tcsetattr(fileno(stdin), TCSANOW, &inittyb) < 0) 90 perror("Hack (settty)"); 91 flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF; 92 flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON; 93 setioctls(); 94 } 95 96 static void 97 setctty(void) 98 { 99 if (tcsetattr(fileno(stdin), TCSANOW, &curttyb) < 0) 100 perror("Hack (setctty)"); 101 } 102 103 void 104 setftty(void) 105 { 106 u_long ef = 0; /* desired value of flags & ECHO */ 107 u_long cf = !(ICANON); /* desired value of flags & CBREAK */ 108 int change = 0; 109 110 flags.cbreak = ON; 111 flags.echo = OFF; 112 /* Should use (ECHO|CRMOD) here instead of ECHO */ 113 if ((curttyb.c_lflag & ECHO) != ef) { 114 curttyb.c_lflag &= ~ECHO; 115 change++; 116 } 117 if ((curttyb.c_lflag & ICANON) != cf) { 118 curttyb.c_lflag &= ~ICANON; 119 curttyb.c_lflag |= cf; 120 /* be satisfied with one character; no timeout */ 121 curttyb.c_cc[VMIN] = 1; /* was VEOF */ 122 curttyb.c_cc[VTIME] = 0; /* was VEOL */ 123 change++; 124 } 125 if (change) 126 setctty(); 127 start_screen(); 128 } 129 130 /* fatal error */ 131 /* VARARGS1 */ 132 void 133 error(const char *s, ...) 134 { 135 va_list ap; 136 137 if (settty_needed) 138 settty(NULL); 139 va_start(ap, s); 140 vprintf(s, ap); 141 va_end(ap); 142 putchar('\n'); 143 exit(1); 144 } 145 146 /* 147 * Read a line closed with '\n' into the array char bufp[BUFSZ]. 148 * (The '\n' is not stored. The string is closed with a '\0'.) 149 * Reading can be interrupted by an escape ('\033') - now the 150 * resulting string is "\033". 151 */ 152 void 153 getlin(char *bufp) 154 { 155 char *obufp = bufp; 156 int c; 157 158 flags.toplin = 2; /* nonempty, no --More-- required */ 159 for (;;) { 160 fflush(stdout); 161 if ((c = getchar()) == EOF) { 162 *bufp = 0; 163 return; 164 } 165 if (c == '\033') { 166 *obufp = c; 167 obufp[1] = 0; 168 return; 169 } 170 if (c == erase_char || c == '\b') { 171 if (bufp != obufp) { 172 bufp--; 173 putstr("\b \b"); /* putsym converts \b */ 174 } else 175 bell(); 176 } else if (c == '\n') { 177 *bufp = 0; 178 return; 179 } else if (' ' <= c && c < '\177') { 180 /* 181 * avoid isprint() - some people don't have it ' ' is 182 * not always a printing char 183 */ 184 *bufp = c; 185 bufp[1] = 0; 186 putstr(bufp); 187 if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO) 188 bufp++; 189 } else if (c == kill_char || c == '\177') { /* Robert Viduya */ 190 /* this test last - @ might be the kill_char */ 191 while (bufp != obufp) { 192 bufp--; 193 putstr("\b \b"); 194 } 195 } else 196 bell(); 197 } 198 } 199 200 void 201 getret(void) 202 { 203 cgetret(""); 204 } 205 206 void 207 cgetret(const char *s) 208 { 209 putsym('\n'); 210 if (flags.standout) 211 standoutbeg(); 212 putstr("Hit "); 213 putstr(flags.cbreak ? "space" : "return"); 214 putstr(" to continue: "); 215 if (flags.standout) 216 standoutend(); 217 xwaitforspace(s); 218 } 219 220 char morc; /* tell the outside world what char he used */ 221 222 void 223 xwaitforspace(const char *s) /* chars allowed besides space or return */ 224 { 225 int c; 226 227 morc = 0; 228 while ((c = readchar()) != '\n') { 229 if (flags.cbreak) { 230 if (c == ' ') 231 break; 232 if (s && strchr(s, c)) { 233 morc = c; 234 break; 235 } 236 bell(); 237 } 238 } 239 } 240 241 char * 242 parse(void) 243 { 244 static char inputline[COLNO]; 245 int foo; 246 247 flags.move = 1; 248 if (!Invisible) 249 curs_on_u(); 250 else 251 home(); 252 while ((foo = readchar()) >= '0' && foo <= '9') 253 multi = 10 * multi + foo - '0'; 254 if (multi) { 255 multi--; 256 save_cm = inputline; 257 } 258 inputline[0] = foo; 259 inputline[1] = 0; 260 if (foo == 'f' || foo == 'F') { 261 inputline[1] = getchar(); 262 #ifdef QUEST 263 if (inputline[1] == foo) 264 inputline[2] = getchar(); 265 else 266 #endif /* QUEST */ 267 inputline[2] = 0; 268 } 269 if (foo == 'm' || foo == 'M') { 270 inputline[1] = getchar(); 271 inputline[2] = 0; 272 } 273 clrlin(); 274 return (inputline); 275 } 276 277 char 278 readchar(void) 279 { 280 int sym; 281 282 fflush(stdout); 283 if ((sym = getchar()) == EOF) 284 #ifdef NR_OF_EOFS 285 { /* 286 * Some SYSV systems seem to return EOFs for various reasons 287 * (?like when one hits break or for interrupted systemcalls?), 288 * and we must see several before we quit. 289 */ 290 int cnt = NR_OF_EOFS; 291 while (cnt--) { 292 clearerr(stdin); /* omit if clearerr is undefined */ 293 if ((sym = getchar()) != EOF) 294 goto noteof; 295 } 296 end_of_input(); 297 noteof:; 298 } 299 #else 300 end_of_input(); 301 #endif /* NR_OF_EOFS */ 302 if (flags.toplin == 1) 303 flags.toplin = 2; 304 return ((char)sym); 305 } 306 307 void 308 end_of_input(void) 309 { 310 settty("End of input?\n"); 311 clearlocks(); 312 exit(0); 313 } 314