1 /************************************************************************
2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is *
3 * provided to you without charge, and with no warranty. You may give *
4 * away copies of JOVE, including sources, provided that this notice is *
5 * included in all the files. *
6 ************************************************************************/
7
8 #include <errno.h>
9
10 #include "jove.h"
11
12 #ifdef UNIX /* the body is the rest of the file */
13
14 #include "fp.h"
15
16 #ifdef BIFF
17 # include <sys/stat.h>
18 #endif
19
20 #include "chars.h"
21 #include "term.h" /* ospeed */
22 #include "ttystate.h"
23 #include "util.h"
24
25
26 #ifdef SGTTY
27 struct sgttyb sg[2];
28 #endif
29
30 #ifdef TERMIO
31 struct termio sg[2];
32 #endif
33
34 #ifdef TERMIOS
35 struct termios sg[2];
36 #endif
37
38 #ifdef USE_TIOCSLTC
39 struct ltchars ls[2];
40 #endif /* USE_TIOCSLTC */
41
42 #ifdef SGTTY
43
44 # ifdef TIOCGETC
45 struct tchars tc[2];
46 # endif
47
48 # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */
49 int lmword[2]; /* local mode word */
50 # endif
51
52 #endif /* SGTTY */
53
54
55 /* Set tty to original (if !n) or JOVE (if n) modes.
56 * This is designed to be idempotent: it can be called
57 * several times with the same argument without damage.
58 */
59
60 bool OKXonXoff = NO; /* VAR: XON/XOFF can be used as ordinary chars */
61 ZXchar IntChar = CTL(']'); /* VAR: ttysetattr sets this to generate SIGINT */
62
63 #ifdef BIFF
64 bool DisBiff = NO; /* VAR: turn off/on biff with entering/exiting jove */
65 #endif /* BIFF */
66
67 void
ttysetattr(n)68 ttysetattr(n)
69 bool n; /* also used as subscript! */
70 {
71 static bool prev_n = NO;
72
73 if (!prev_n) {
74 /* Previously, the tty was not in JOVE mode.
75 * Find out the current settings:
76 * do the ioctls or whatever to fill in NO half
77 * of each appropriate tty state pair.
78 * NOTE: the nested tangle of ifdefs is intended to follow
79 * the structure of the definitions in ttystate.c.
80 */
81 #ifdef SGTTY
82 (void) gtty(0, &sg[NO]);
83 #endif
84
85 #ifdef TERMIO
86 (void) ioctl(0, TCGETA, (UnivPtr) &sg[NO]);
87 #endif
88
89 #ifdef TERMIOS
90 (void) tcgetattr(0, &sg[NO]);
91 #endif
92
93 #ifdef USE_TIOCSLTC
94 (void) ioctl(0, TIOCGLTC, (UnivPtr) &ls[NO]);
95 #endif /* USE_TIOCSLTC */
96
97 #ifdef SGTTY
98
99 # ifdef TIOCGETC
100 (void) ioctl(0, TIOCGETC, (UnivPtr) &tc[NO]);
101 # endif
102
103 # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */
104 (void) ioctl(0, TIOCLGET, (UnivPtr) &lmword[NO]);
105 # endif
106
107 #endif /* SGTTY */
108
109 /* extract some info from results */
110
111 #if defined(TERMIO) || defined(TERMIOS)
112 # ifdef TAB3
113 TABS = (sg[NO].c_oflag & TABDLY) != TAB3;
114 # endif
115 # ifdef TERMIOS
116 ospeed = cfgetospeed(&sg[NO]);
117 # else /* ! TERMIOS */
118 # ifdef CBAUD
119 ospeed = sg[NO].c_cflag & CBAUD;
120 # else /* ! CBAUD */
121 ospeed = B9600; /* XXX */
122 # endif /* CBAUD */
123 # endif /* TERMIOS */
124 #endif /* defined(TERMIO) || defined(TERMIOS) */
125
126 #ifdef SGTTY
127 TABS = !(sg[NO].sg_flags & XTABS);
128 ospeed = sg[NO].sg_ospeed;
129 #endif /* SGTTY */
130 }
131
132 /* Fill in YES half of each appropriate tty state pair.
133 * They are filled in as late as possible so that each will
134 * reflect the latest settings of controling variables.
135 * NOTE: the nested tangle of ifdefs is intended to follow
136 * the structure of the definitions in ttystate.c.
137 */
138
139 sg[YES] = sg[NO];
140
141 #ifdef SGTTY
142 sg[YES].sg_flags &= ~(XTABS|ECHO|CRMOD);
143 # ifdef LPASS8
144 sg[YES].sg_flags |= CBREAK;
145 # else
146 sg[YES].sg_flags |= (MetaKey ? RAW : CBREAK);
147 # endif
148 #endif
149
150 #if defined(TERMIO) || defined(TERMIOS)
151 if (OKXonXoff)
152 sg[YES].c_iflag &= ~(IXON | IXOFF);
153 sg[YES].c_iflag &= ~(INLCR|ICRNL|IGNCR | (MetaKey? ISTRIP : 0));
154 sg[YES].c_lflag &= ~(ICANON|ECHO);
155 sg[YES].c_oflag &= ~(OPOST);
156
157 /* Set all those c_cc elements that we must.
158 * For peculiar systems, one might wish to predefine JVDISABLE
159 * in the configuration. For example, on some unnamed
160 * versions of the Convex OS, it would be good to
161 * define it as (sg[YES].c_cc[VDISABLE]), saving a system call.
162 * Note that the only uses of JDISABLE are in this block,
163 * so the macro may safely refer to things in this context.
164 */
165 {
166 # ifndef JVDISABLE
167 # ifdef _POSIX_VDISABLE
168 # define JVDISABLE _POSIX_VDISABLE
169 # else /* !_POSIX_VDISABLE */
170 # ifdef _PC_VDISABLE
171 /* Cache the result of fpathconf to reduce the number of syscalls.
172 * We don't handle the error return (-1) because there isn't
173 * anything better to do with it.
174 */
175 cc_t jvd = fpathconf(0, _PC_VDISABLE);
176 # define JVDISABLE jvd
177 # else /* !_PC_VDISABLE */
178 # define JVDISABLE 0
179 # endif /* !_PC_VDISABLE */
180 # endif /* !_POSIX_VDISABLE */
181 # endif /* JVDISABLE */
182
183 sg[YES].c_cc[VINTR] = IntChar;
184
185 # ifdef VQUIT
186 sg[YES].c_cc[VQUIT] = JVDISABLE;
187 # endif
188 /* VERASE, VKILL, VEOL2 irrelevant */
189 /* Beware aliasing! VMIN is VEOF and VTIME is VEOL */
190 # ifdef VSWTCH
191 sg[YES].c_cc[VSWTCH] = JVDISABLE;
192 # endif
193
194 /* Under at least one system (SunOS 4.0), <termio.h>
195 * mistakenly defines the extra V symbols of <termios.h>
196 * without extending the c_cc array in struct termio
197 * to hold them! This is why the following goo is doubly
198 * ifdefed. It turns out that we don't use <termio.h>
199 * on SunOS 4.0, so the problem may be moot.
200 */
201
202 # ifdef TERMIOS
203 # ifdef VSUSP
204 sg[YES].c_cc[VSUSP] = JVDISABLE;
205 # endif
206 # ifdef VDSUSP
207 sg[YES].c_cc[VDSUSP] = JVDISABLE;
208 # endif
209 # ifdef VDISCARD
210 /* ??? Under Solaris 2.1 needs VDISCARD disabled, or it will
211 * be processed by the tty driver, but not under SysVR4!
212 */
213 sg[YES].c_cc[VDISCARD] = JVDISABLE; /* flush output */
214 # endif
215 # ifdef VLNEXT
216 sg[YES].c_cc[VLNEXT] = JVDISABLE; /* literal next char */
217 # endif
218 # endif /* TERMIOS */
219
220 sg[YES].c_cc[VMIN] = 1;
221 sg[YES].c_cc[VTIME] = 1;
222 }
223 #endif /* defined(TERMIO) || defined(TERMIOS) */
224
225 #ifdef USE_TIOCSLTC
226 ls[YES] = ls[NO];
227 ls[YES].t_suspc = (char) -1;
228 ls[YES].t_dsuspc = (char) -1;
229 ls[YES].t_flushc = (char) -1;
230 ls[YES].t_lnextc = (char) -1;
231 #endif /* USE_TIOCSLTC */
232
233 #ifdef SGTTY
234
235 # ifdef TIOCGETC
236 tc[YES] = tc[NO];
237 tc[YES].t_intrc = IntChar;
238 tc[YES].t_quitc = (char) -1;
239 if (OKXonXoff) {
240 tc[YES].t_stopc = (char) -1;
241 tc[YES].t_startc = (char) -1;
242 }
243 # endif
244
245 # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */
246 lmword[YES] = lmword[NO];
247
248 if (MetaKey)
249 lmword[YES] |= LPASS8;
250
251 # ifdef LLITOUT
252 /* ??? under what conditions should we turn on LLITOUT flag? */
253 # endif /* LLITOUT */
254
255 # ifdef LTILDE
256 if (Hazeltine)
257 lmword[YES] &= ~LTILDE;
258 # endif /* LTILDE */
259
260 # endif /* LPASS8 */
261
262 #endif /* SGTTY */
263
264 /* Set tty state according to appropriate entry of each state pair.
265 * NOTE: the nested tangle of ifdefs is intended to follow
266 * the structure of the definitions in ttystate.c.
267 */
268
269 #ifdef SGTTY
270 # ifdef TIOCSETN
271 (void) ioctl(0, TIOCSETN, (UnivPtr) &sg[n]);
272 # else
273 (void) stty(0, &sg[n]);
274 # endif
275 #endif
276
277 #ifdef TERMIO
278 do ; while (ioctl(0, TCSETAW, (UnivPtr) &sg[n]) < 0 && errno == EINTR);
279 #endif
280
281 #ifdef TERMIOS
282 do ; while (tcsetattr(0, TCSADRAIN, &sg[n]) < 0 && errno == EINTR);
283 #endif
284
285 #ifdef USE_TIOCSLTC
286 (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[n]);
287 #endif /* USE_TIOCSLTC */
288
289 #ifdef SGTTY
290
291 # ifdef TIOCGETC
292 (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[n]);
293 # endif
294
295 # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */
296 (void) ioctl(0, TIOCLSET, (UnivPtr) &lmword[n]); /* local mode word */
297 # endif
298
299 #endif /* SGTTY */
300
301 #ifdef BIFF
302
303 /* biff state is an honorary part of the tty state.
304 * On the other hand, it is different from the rest of the state
305 * since we only want to examine the setting if DisBiff
306 * has been set by the user. For this reason, the code is
307 * somewhat more intricate.
308 */
309 {
310 # define BS_UNEXAMINED 0 /* we don't know if biff is enabled */
311 # define BS_DISABLED 1 /* we have disabled biff */
312 # define BS_UNCHANGED 2 /* we didn't disable biff */
313 static int biff_state = BS_UNEXAMINED;
314
315 static struct stat tt_stat;
316 # if !defined(USE_FSTAT) || !defined(USE_FCHMOD)
317 static char *tt_name = NULL; /* name of the control tty */
318 extern char *ttyname proto((int)); /* for systems w/o fstat */
319 # endif
320
321 if (n && DisBiff) {
322 /* biff supression is our business */
323 if (biff_state == BS_UNEXAMINED) {
324 /* and we haven't looked after it */
325 biff_state = BS_UNCHANGED; /* at least so far */
326 if (
327 # ifdef USE_FSTAT
328 fstat(0, &tt_stat) != -1
329 # else
330 ((tt_name != NULL) || (tt_name = ttyname(0)) != NULL)
331 && stat(tt_name, &tt_stat) != -1
332 # endif
333 && (tt_stat.st_mode & S_IEXEC))
334 {
335 /* so let's suppress it */
336 # ifdef USE_FCHMOD
337 (void) fchmod(0, tt_stat.st_mode & ~S_IEXEC);
338 biff_state = BS_DISABLED;
339 # else
340 if ((tt_name != NULL || (tt_name = ttyname(0)) != NULL)
341 && chmod(tt_name, tt_stat.st_mode & ~S_IEXEC) != -1)
342 {
343 /* Note: only change biff_state if we were able to
344 * get the tt_name -- this prevents the other
345 * chmod from blowing up.
346 */
347 biff_state = BS_DISABLED;
348 }
349 # endif
350 }
351 }
352 } else {
353 /* any biff suppression should be undone */
354 if (biff_state == BS_DISABLED) {
355 /* and we did suppress it, so we enable it */
356 # ifdef USE_FCHMOD
357 (void) fchmod(0, tt_stat.st_mode);
358 # else
359 (void) chmod(tt_name, tt_stat.st_mode);
360 # endif
361 }
362 biff_state = BS_UNEXAMINED; /* it's out of our hands */
363 }
364 # undef BS_UNEXAMINED
365 # undef BS_DISABLED
366 # undef BS_UNCHANGED
367 }
368
369 #endif /* BIFF */
370 prev_n = n;
371 }
372
373 /* Determine the number of characters to buffer at each baud rate. The
374 lower the number, the quicker the response when new input arrives. Of
375 course the lower the number, the more prone the program is to stop in
376 output. Decide what matters most to you. This sets ScrBufSize to the right
377 number or chars, and initializes `jstdout'. */
378
379 void
settout()380 settout()
381 {
382 int speed_chars;
383
384 static const struct {
385 unsigned int bsize;
386 unsigned int brate;
387 } speeds[] = {
388
389 #ifdef B0
390 { 1, B0 },
391 #endif
392 #ifdef B50
393 { 1, B50 },
394 #endif
395 #ifdef B75
396 { 1, B75 },
397 #endif
398 #ifdef B110
399 { 1, B110 },
400 #endif
401 #ifdef B134
402 { 1, B134 },
403 #endif
404 #ifdef B150
405 { 1, B150 },
406 #endif
407 #ifdef B200
408 { 1, B200 },
409 #endif
410 #ifdef B300
411 { 2, B300 },
412 #endif
413 #ifdef B600
414 { 4, B600 },
415 #endif
416 #ifdef B900
417 { 6, B900 },
418 #endif
419 #ifdef B1200
420 { 8, B1200 },
421 #endif
422 #ifdef B1800
423 { 16, B1800 },
424 #endif
425 #ifdef B2400
426 { 32, B2400 },
427 #endif
428 #ifdef B3600
429 { 64, B3600 },
430 #endif
431 #ifdef B4800
432 { 128, B4800 },
433 #endif
434 #ifdef B7200
435 { 256, B7200 },
436 #endif
437 #ifdef B9600
438 { 256, B9600 },
439 #endif
440 #ifdef EXTA
441 { 512, EXTA },
442 #endif
443 #ifdef B19200
444 { 512, B19200 },
445 #endif
446 #ifdef EXTB
447 { 1024, EXTB },
448 #endif
449 #ifdef B38400
450 { 1024, B38400 },
451 #endif
452 #ifdef EXT
453 { 1024, EXT }
454 #endif
455 };
456 int i;
457 for (i = 0; ; i++) {
458 if (i == elemsof(speeds)) {
459 speed_chars = 512;
460 ospeed = B9600; /* XXX */
461 break;
462 }
463 if (speeds[i].brate == (unsigned short) ospeed) {
464 speed_chars = speeds[i].bsize;
465 break;
466 }
467 }
468
469 flushscreen(); /* flush the one character buffer */
470 ScrBufSize = min(MAXTTYBUF, speed_chars * max(LI / 24, 1));
471 #ifndef NO_JSTDOUT
472 jstdout = fd_open("/dev/tty", F_WRITE|F_LOCKED, 1, (char *)NULL, ScrBufSize);
473 #endif
474 }
475
476 void
ttsize()477 ttsize()
478 {
479 /* ??? We really ought to wait until the screen is big enough:
480 * at least three lines high (one line each for buffer, mode,
481 * and message) and at least twelve columns wide (eight for
482 * line number, one for content, two for overflow indicators,
483 * and one blank at end).
484 */
485 #ifdef TIOCGWINSZ
486 struct winsize win;
487
488 if (ioctl(0, TIOCGWINSZ, (UnivPtr) &win) == 0
489 && win.ws_col >= 12
490 && win.ws_row >= 3)
491 {
492 CO = min(win.ws_col, MAXCOLS);
493 LI = win.ws_row;
494 }
495 #else /* !TIOCGWINSZ */
496 # ifdef BTL_BLIT
497 struct jwinsize jwin;
498
499 if (ioctl(0, JWINSIZE, (UnivPtr) &jwin) == 0
500 && jwin.bytesx >= 12
501 && jwin.bytesy >= 3)
502 {
503 CO = min(jwin.bytesx, MAXCOLS);
504 LI = jwin.bytesy;
505 }
506 # endif /* BTL_BLIT */
507 #endif /* !TIOCGWINSZ */
508 ILI = LI - 1;
509 }
510
511 #endif /* UNIX */
512