xref: /dragonfly/games/hack/hack.tty.c (revision 4318c66eac379e15105fe145d406dfef81b795f6)
1 /*        @(#)hack.tty.c      8.1 (Berkeley) 5/31/93                                      */
2 /*        $NetBSD: hack.tty.c,v 1.16 2011/08/06 20:42:43 dholland Exp $         */
3 
4 /*-
5  * Copyright (c) 1988, 1993
6  *        The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
35  * Amsterdam
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions are
40  * met:
41  *
42  * - Redistributions of source code must retain the above copyright notice,
43  * this list of conditions and the following disclaimer.
44  *
45  * - Redistributions in binary form must reproduce the above copyright
46  * notice, this list of conditions and the following disclaimer in the
47  * documentation and/or other materials provided with the distribution.
48  *
49  * - Neither the name of the Stichting Centrum voor Wiskunde en
50  * Informatica, nor the names of its contributors may be used to endorse or
51  * promote products derived from this software without specific prior
52  * written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
55  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
57  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
58  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
61  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
62  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
63  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  */
66 
67 /*
68  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
69  * All rights reserved.
70  *
71  * Redistribution and use in source and binary forms, with or without
72  * modification, are permitted provided that the following conditions
73  * are met:
74  * 1. Redistributions of source code must retain the above copyright
75  *    notice, this list of conditions and the following disclaimer.
76  * 2. Redistributions in binary form must reproduce the above copyright
77  *    notice, this list of conditions and the following disclaimer in the
78  *    documentation and/or other materials provided with the distribution.
79  * 3. The name of the author may not be used to endorse or promote products
80  *    derived from this software without specific prior written permission.
81  *
82  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
83  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
84  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
85  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
86  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
87  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
88  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
89  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
90  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
91  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
92  */
93 
94 /* hack.tty.c - version 1.0.3 */
95 /*
96  * With thanks to the people who sent code for SYSV - hpscdi!jon,
97  * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others.
98  */
99 
100 #include <termios.h>
101 #include <termcap.h>
102 #include "hack.h"
103 #include "extern.h"
104 
105 /*
106  * Some systems may have getchar() return EOF for various reasons, and
107  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
108  */
109 #ifndef BSD
110 #define   NR_OF_EOFS          20
111 #endif    /* BSD */
112 
113 static char     erase_char, kill_char;
114 static boolean  settty_needed = FALSE;
115 static struct termios  inittyb, curttyb;
116 
117 static void setctty(void);
118 
119 /*
120  * Get initial state of terminal, set ospeed (for termcap routines)
121  * and switch off tab expansion if necessary.
122  * Called by startup() in termcap.c and after returning from ! or ^Z
123  */
124 void
gettty(void)125 gettty(void)
126 {
127           if (tcgetattr(0, &inittyb) < 0)
128                     perror("Hack (gettty)");
129           curttyb = inittyb;
130           ospeed = cfgetospeed(&inittyb);
131           erase_char = inittyb.c_cc[VERASE];
132           kill_char = inittyb.c_cc[VKILL];
133           getioctls();
134 
135           /* do not expand tabs - they might be needed inside a cm sequence */
136           if (curttyb.c_oflag & OXTABS) {
137                     curttyb.c_oflag &= ~OXTABS;
138                     setctty();
139           }
140           settty_needed = TRUE;
141 }
142 
143 /* reset terminal to original state */
144 void
settty(const char * s)145 settty(const char *s)
146 {
147           clearscreen();
148           endscreen();
149           if (s)
150                     printf("%s", s);
151           (void) fflush(stdout);
152           if (tcsetattr(0, TCSADRAIN, &inittyb) < 0)
153                     perror("Hack (settty)");
154           flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
155           flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
156           setioctls();
157 }
158 
159 static void
setctty(void)160 setctty(void)
161 {
162           if (tcsetattr(0, TCSADRAIN, &curttyb) < 0)
163                     perror("Hack (setctty)");
164 }
165 
166 
167 void
setftty(void)168 setftty(void)
169 {
170           int             change = 0;
171           flags.cbreak = ON;
172           flags.echo = OFF;
173           /* Should use (ECHO|CRMOD) here instead of ECHO */
174           if (curttyb.c_lflag & ECHO) {
175                     curttyb.c_lflag &= ~ECHO;
176                     change++;
177           }
178           if (curttyb.c_lflag & ICANON) {
179                     curttyb.c_lflag &= ~ICANON;
180                     /* be satisfied with one character; no timeout */
181                     curttyb.c_cc[VMIN] = 1;
182                     curttyb.c_cc[VTIME] = 0;
183                     change++;
184           }
185           if (change) {
186                     setctty();
187           }
188           startscreen();
189 }
190 
191 
192 /* fatal error */
193 /* VARARGS1 */
194 void
error(const char * fmt,...)195 error(const char *fmt, ...)
196 {
197           va_list ap;
198 
199           va_start(ap, fmt);
200           if (settty_needed)
201                     settty(NULL);
202           vprintf(fmt, ap);
203           va_end(ap);
204           putchar('\n');
205           exit(1);
206 }
207 
208 /*
209  * Read a line closed with '\n' into the array char bufp[BUFSZ].
210  * (The '\n' is not stored. The string is closed with a '\0'.)
211  * Reading can be interrupted by an escape ('\033') - now the
212  * resulting string is "\033".
213  */
214 void
getlin(char * bufp)215 getlin(char *bufp)
216 {
217           char           *obufp = bufp;
218           int             c;
219 
220           flags.toplin = 2;   /* nonempty, no --More-- required */
221           for (;;) {
222                     (void) fflush(stdout);
223                     if ((c = getchar()) == EOF) {
224                               *bufp = 0;
225                               return;
226                     }
227                     if (c == '\033') {
228                               *obufp = c;
229                               obufp[1] = 0;
230                               return;
231                     }
232                     if (c == erase_char || c == '\b') {
233                               if (bufp != obufp) {
234                                         bufp--;
235                                         putstr("\b \b");    /* putsym converts \b */
236                               } else
237                                         sound_bell();
238                     } else if (c == '\n') {
239                               *bufp = 0;
240                               return;
241                     } else if (' ' <= c && c < '\177') {
242                               /*
243                                * avoid isprint() - some people don't have it ' ' is
244                                * not always a printing char
245                                */
246                               *bufp = c;
247                               bufp[1] = 0;
248                               putstr(bufp);
249                               if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)
250                                         bufp++;
251                     } else if (c == kill_char || c == '\177') {       /* Robert Viduya */
252                               /* this test last - @ might be the kill_char */
253                               while (bufp != obufp) {
254                                         bufp--;
255                                         putstr("\b \b");
256                               }
257                     } else
258                               sound_bell();
259           }
260 }
261 
262 void
getret(void)263 getret(void)
264 {
265           cgetret("");
266 }
267 
268 void
cgetret(const char * s)269 cgetret(const char *s)
270 {
271           putsym('\n');
272           if (flags.standout)
273                     standoutbeg();
274           putstr("Hit ");
275           putstr(flags.cbreak ? "space" : "return");
276           putstr(" to continue: ");
277           if (flags.standout)
278                     standoutend();
279           xwaitforspace(s);
280 }
281 
282 char            morc;                   /* tell the outside world what char he used */
283 
284 /* s = chars allowed besides space or return */
285 void
xwaitforspace(const char * s)286 xwaitforspace(const char *s)
287 {
288           int             c;
289 
290           morc = 0;
291 
292           while ((c = readchar()) != '\n') {
293                     if (flags.cbreak) {
294                               if (c == ' ')
295                                         break;
296                               if (s && strchr(s, c)) {
297                                         morc = c;
298                                         break;
299                               }
300                               sound_bell();
301                     }
302           }
303 }
304 
305 char           *
parse(void)306 parse(void)
307 {
308           static char     inputline[COLNO];
309           int                 foo;
310 
311           flags.move = 1;
312           if (!Invisible)
313                     curs_on_u();
314           else
315                     home();
316           while ((foo = readchar()) >= '0' && foo <= '9')
317                     multi = 10 * multi + foo - '0';
318           if (multi) {
319                     multi--;
320                     save_cm = inputline;
321           }
322           inputline[0] = foo;
323           inputline[1] = 0;
324           if (foo == 'f' || foo == 'F') {
325                     inputline[1] = getchar();
326 #ifdef QUEST
327                     if (inputline[1] == foo)
328                               inputline[2] = getchar();
329                     else
330 #endif    /* QUEST */
331                               inputline[2] = 0;
332           }
333           if (foo == 'm' || foo == 'M') {
334                     inputline[1] = getchar();
335                     inputline[2] = 0;
336           }
337           clrlin();
338           return (inputline);
339 }
340 
341 char
readchar(void)342 readchar(void)
343 {
344           int             sym;
345 
346           (void) fflush(stdout);
347           if ((sym = getchar()) == EOF)
348 #ifdef NR_OF_EOFS
349           {                             /*
350                                        * Some SYSV systems seem to return EOFs for various reasons
351                                        * (?like when one hits break or for interrupted systemcalls?),
352                                        * and we must see several before we quit.
353                                        */
354                     int             cnt = NR_OF_EOFS;
355                     while (cnt--) {
356                               clearerr(stdin);    /* omit if clearerr is
357                                                              * undefined */
358                               if ((sym = getchar()) != EOF)
359                                         goto noteof;
360                     }
361                     end_of_input();
362 noteof:   ;
363           }
364 #else
365                     end_of_input();
366 #endif    /* NR_OF_EOFS */
367           if (flags.toplin == 1)
368                     flags.toplin = 2;
369           return ((char) sym);
370 }
371 
372 void
end_of_input(void)373 end_of_input(void)
374 {
375           settty("End of input?\n");
376           clearlocks();
377           exit(0);
378 }
379