nrelease - fix/improve livecd
[dragonfly.git] / games / hack / hack.tty.c
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
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
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
160 setctty(void)
161 {
162         if (tcsetattr(0, TCSADRAIN, &curttyb) < 0)
163                 perror("Hack (setctty)");
164 }
165
166
167 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
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
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
263 getret(void)
264 {
265         cgetret("");
266 }
267
268 void
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
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           *
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
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
373 end_of_input(void)
374 {
375         settty("End of input?\n");
376         clearlocks();
377         exit(0);
378 }