Initial import from FreeBSD RELENG_4:
[games.git] / games / hack / hack.tty.c
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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)hack.tty.c  8.1 (Berkeley) 5/31/93";
37 #endif
38 static const char rcsid[] =
39  "$FreeBSD: src/games/hack/hack.tty.c,v 1.6.2.1 2000/07/20 10:35:07 kris Exp $";
40 #endif /* not lint */
41
42 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
43 /* hack.tty.c - version 1.0.3 */
44 /* With thanks to the people who sent code for SYSV - hpscdi!jon,
45    arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */
46
47 #include        "hack.h"
48 #include        <stdio.h>
49
50 /*
51  * The distinctions here are not BSD - rest but rather USG - rest, as
52  * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
53  */
54 #ifdef BSD
55 #define V7
56 #else
57 #define USG
58 #endif BSD
59
60 /*
61  * Some systems may have getchar() return EOF for various reasons, and
62  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
63  */
64 #ifndef BSD
65 #define NR_OF_EOFS      20
66 #endif BSD
67
68
69 #ifdef USG
70
71 #include        <termio.h>
72 #define termstruct      termio
73 #define kill_sym        c_cc[VKILL]
74 #define erase_sym       c_cc[VERASE]
75 #define EXTABS          TAB3
76 #define tabflgs         c_oflag
77 #define echoflgs        c_lflag
78 #define cbrkflgs        c_lflag
79 #define CBRKMASK        ICANON
80 #define CBRKON          ! /* reverse condition */
81 #define OSPEED(x)       ((x).c_cflag & CBAUD)
82 #define GTTY(x)         (ioctl(0, TCGETA, x))
83 #define STTY(x)         (ioctl(0, TCSETA, x))   /* TCSETAF? TCSETAW? */
84
85 #else   /* V7 */
86
87 #include        <sgtty.h>
88 #define termstruct      sgttyb
89 #define kill_sym        sg_kill
90 #define erase_sym       sg_erase
91 #define EXTABS          XTABS
92 #define tabflgs         sg_flags
93 #define echoflgs        sg_flags
94 #define cbrkflgs        sg_flags
95 #define CBRKMASK        CBREAK
96 #define CBRKON          /* empty */
97 #define OSPEED(x)       (x).sg_ospeed
98 #define GTTY(x)         (gtty(0, x))
99 #define STTY(x)         (stty(0, x))
100
101 #endif USG
102
103 #if 0
104 extern short ospeed;
105 #endif
106 static char erase_char, kill_char;
107 static boolean settty_needed = FALSE;
108 struct termstruct inittyb, curttyb;
109
110 /*
111  * Get initial state of terminal, set ospeed (for termcap routines)
112  * and switch off tab expansion if necessary.
113  * Called by startup() in termcap.c and after returning from ! or ^Z
114  */
115 gettty(){
116         if(GTTY(&inittyb) < 0)
117                 perror("Hack (gettty)");
118         curttyb = inittyb;
119 #if 0
120         ospeed = OSPEED(inittyb);
121 #endif
122         erase_char = inittyb.erase_sym;
123         kill_char = inittyb.kill_sym;
124         getioctls();
125
126         /* do not expand tabs - they might be needed inside a cm sequence */
127         if(curttyb.tabflgs & EXTABS) {
128                 curttyb.tabflgs &= ~EXTABS;
129                 setctty();
130         }
131         settty_needed = TRUE;
132 }
133
134 /* reset terminal to original state */
135 settty(s) char *s; {
136         clear_screen();
137         end_screen();
138         if(s) printf("%s", s);
139         (void) fflush(stdout);
140         if(STTY(&inittyb) < 0)
141                 perror("Hack (settty)");
142         flags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
143         flags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
144         setioctls();
145 }
146
147 setctty(){
148         if(STTY(&curttyb) < 0)
149                 perror("Hack (setctty)");
150 }
151
152
153 setftty(){
154 int ef = 0;                     /* desired value of flags & ECHO */
155 int cf = CBRKON(CBRKMASK);      /* desired value of flags & CBREAK */
156 int change = 0;
157         flags.cbreak = ON;
158         flags.echo = OFF;
159         /* Should use (ECHO|CRMOD) here instead of ECHO */
160         if((curttyb.echoflgs & ECHO) != ef){
161                 curttyb.echoflgs &= ~ECHO;
162 /*              curttyb.echoflgs |= ef;                                 */
163                 change++;
164         }
165         if((curttyb.cbrkflgs & CBRKMASK) != cf){
166                 curttyb.cbrkflgs &= ~CBRKMASK;
167                 curttyb.cbrkflgs |= cf;
168 #ifdef USG
169                 /* be satisfied with one character; no timeout */
170                 curttyb.c_cc[VMIN] = 1;         /* was VEOF */
171                 curttyb.c_cc[VTIME] = 0;        /* was VEOL */
172 #endif USG
173                 change++;
174         }
175         if(change){
176                 setctty();
177         }
178         start_screen();
179 }
180
181
182 /* fatal error */
183 /*VARARGS1*/
184 error(s,x,y) char *s; {
185         if(settty_needed)
186                 settty((char *) 0);
187         printf(s,x,y);
188         putchar('\n');
189         exit(1);
190 }
191
192 /*
193  * Read a line closed with '\n' into the array char bufp[BUFSZ].
194  * (The '\n' is not stored. The string is closed with a '\0'.)
195  * Reading can be interrupted by an escape ('\033') - now the
196  * resulting string is "\033".
197  */
198 getlin(bufp)
199 char *bufp;
200 {
201         char *obufp = bufp;
202         int c;
203
204         flags.toplin = 2;               /* nonempty, no --More-- required */
205         for(;;) {
206                 (void) fflush(stdout);
207                 if((c = getchar()) == EOF) {
208                         *bufp = 0;
209                         return;
210                 }
211                 if(c == '\033') {
212                         *obufp = c;
213                         obufp[1] = 0;
214                         return;
215                 }
216                 if(c == erase_char || c == '\b') {
217                         if(bufp != obufp) {
218                                 bufp--;
219                                 putstr("\b \b"); /* putsym converts \b */
220                         } else  bell();
221                 } else if(c == '\n') {
222                         *bufp = 0;
223                         return;
224                 } else if(' ' <= c && c < '\177') {
225                                 /* avoid isprint() - some people don't have it
226                                    ' ' is not always a printing char */
227                         *bufp = c;
228                         bufp[1] = 0;
229                         putstr(bufp);
230                         if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
231                                 bufp++;
232                 } else if(c == kill_char || c == '\177') { /* Robert Viduya */
233                                 /* this test last - @ might be the kill_char */
234                         while(bufp != obufp) {
235                                 bufp--;
236                                 putstr("\b \b");
237                         }
238                 } else
239                         bell();
240         }
241 }
242
243 getret() {
244         cgetret("");
245 }
246
247 cgetret(s)
248 char *s;
249 {
250         putsym('\n');
251         if(flags.standout)
252                 standoutbeg();
253         putstr("Hit ");
254         putstr(flags.cbreak ? "space" : "return");
255         putstr(" to continue: ");
256         if(flags.standout)
257                 standoutend();
258         xwaitforspace(s);
259 }
260
261 char morc;      /* tell the outside world what char he used */
262
263 xwaitforspace(s)
264 char *s;        /* chars allowed besides space or return */
265 {
266 int c;
267
268         morc = 0;
269
270         while((c = readchar()) != '\n') {
271             if(flags.cbreak) {
272                 if(c == ' ') break;
273                 if(s && index(s,c)) {
274                         morc = c;
275                         break;
276                 }
277                 bell();
278             }
279         }
280 }
281
282 char *
283 parse()
284 {
285         static char inputline[COLNO];
286         int foo;
287
288         flags.move = 1;
289         if(!Invisible) curs_on_u(); else home();
290         while((foo = readchar()) >= '0' && foo <= '9')
291                 multi = 10*multi+foo-'0';
292         if(multi) {
293                 multi--;
294                 save_cm = inputline;
295         }
296         inputline[0] = foo;
297         inputline[1] = 0;
298         if(foo == 'f' || foo == 'F'){
299                 inputline[1] = getchar();
300 #ifdef QUEST
301                 if(inputline[1] == foo) inputline[2] = getchar(); else
302 #endif QUEST
303                 inputline[2] = 0;
304         }
305         if(foo == 'm' || foo == 'M'){
306                 inputline[1] = getchar();
307                 inputline[2] = 0;
308         }
309         clrlin();
310         return(inputline);
311 }
312
313 char
314 readchar() {
315         int sym;
316
317         (void) fflush(stdout);
318         if((sym = getchar()) == EOF)
319 #ifdef NR_OF_EOFS
320         { /*
321            * Some SYSV systems seem to return EOFs for various reasons
322            * (?like when one hits break or for interrupted systemcalls?),
323            * and we must see several before we quit.
324            */
325                 int cnt = NR_OF_EOFS;
326                 while (cnt--) {
327                     clearerr(stdin);    /* omit if clearerr is undefined */
328                     if((sym = getchar()) != EOF) goto noteof;
329                 }
330                 end_of_input();
331              noteof:    ;
332         }
333 #else
334                 end_of_input();
335 #endif NR_OF_EOFS
336         if(flags.toplin == 1)
337                 flags.toplin = 2;
338         return((char) sym);
339 }
340
341 end_of_input()
342 {
343         settty("End of input?\n");
344         clearlocks();
345         exit(0);
346 }