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