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