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