1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)hack.tty.c 8.1 (Berkeley) 05/31/93";
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 */
gettty()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 */
settty(s)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
setctty()113 setctty(){
114 if(STTY(&curttyb) < 0)
115 perror("Hack (setctty)");
116 }
117
118
setftty()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*/
error(s,x,y)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 */
getlin(bufp)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
getret()209 getret() {
210 cgetret("");
211 }
212
cgetret(s)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
xwaitforspace(s)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 *
parse()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
readchar()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
end_of_input()307 end_of_input()
308 {
309 settty("End of input?\n");
310 clearlocks();
311 exit(0);
312 }
313