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