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