1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)termout.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #if defined(unix)
13 #include <signal.h>
14 #include <sgtty.h>
15 #endif
16 #include <stdio.h>
17 #include <curses.h>
18 #if defined(ultrix)
19 /* Some version of this OS has a bad definition for nonl() */
20 #undef nl
21 #undef nonl
22
23 #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
24 #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
25 #endif /* defined(ultrix) */
26
27 #include "../general/general.h"
28
29 #include "terminal.h"
30
31 #include "../api/disp_asc.h"
32
33 #include "../ctlr/hostctlr.h"
34 #include "../ctlr/externs.h"
35 #include "../ctlr/declare.h"
36 #include "../ctlr/oia.h"
37 #include "../ctlr/screen.h"
38 #include "../ctlr/scrnctlr.h"
39
40 #include "../general/globals.h"
41
42 #include "telextrn.h"
43
44 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
45 CursorAddress:UnLocked? CursorAddress: HighestScreen())
46
47
48 static int terminalCursorAddress; /* where the cursor is on term */
49 static int screenInitd; /* the screen has been initialized */
50 static int screenStopped; /* the screen has been stopped */
51 static int max_changes_before_poll; /* how many characters before looking */
52 /* at terminal and net again */
53
54 static int needToRing; /* need to ring terinal bell */
55 static char *bellSequence = "\07"; /* bell sequence (may be replaced by
56 * VB during initialization)
57 */
58 static WINDOW *bellwin = 0; /* The window the bell message is in */
59 int bellwinup = 0; /* Are we up with it or not */
60
61 #if defined(unix)
62 static char *myKS, *myKE;
63 #endif /* defined(unix) */
64
65
66 static int inHighlightMode = 0;
67 ScreenImage Terminal[MAXSCREENSIZE];
68
69 /* Variables for transparent mode */
70 #if defined(unix)
71 static int tcflag = -1; /* transparent mode command flag */
72 static int savefd[2]; /* for storing fds during transcom */
73 extern int tin, tout; /* file descriptors */
74 #endif /* defined(unix) */
75
76
77 /*
78 * init_screen()
79 *
80 * Initialize variables used by screen.
81 */
82
83 void
init_screen()84 init_screen()
85 {
86 bellwinup = 0;
87 inHighlightMode = 0;
88 ClearArray(Terminal);
89 }
90
91
92 /* OurExitString - designed to keep us from going through infinite recursion */
93
94 static void
OurExitString(string,value)95 OurExitString(string, value)
96 char *string;
97 int value;
98 {
99 static int recursion = 0;
100
101 if (!recursion) {
102 recursion = 1;
103 ExitString(string, value);
104 }
105 }
106
107
108 /* DoARefresh */
109
110 static void
DoARefresh()111 DoARefresh()
112 {
113 if (ERR == refresh()) {
114 OurExitString("ERR from refresh\n", 1);
115 }
116 }
117
118 static void
GoAway(from,where)119 GoAway(from, where)
120 char *from; /* routine that gave error */
121 int where; /* cursor address */
122 {
123 char foo[100];
124
125 sprintf(foo, "ERR from %s at %d (%d, %d)\n",
126 from, where, ScreenLine(where), ScreenLineOffset(where));
127 OurExitString(foo, 1);
128 /* NOTREACHED */
129 }
130
131 /* What is the screen address of the attribute byte for the terminal */
132
133 static int
WhereTermAttrByte(p)134 WhereTermAttrByte(p)
135 register int p;
136 {
137 register int i;
138
139 i = p;
140
141 do {
142 if (TermIsStartField(i)) {
143 return(i);
144 }
145 i = ScreenDec(i);
146 } while (i != p);
147
148 return(LowestScreen()); /* unformatted screen... */
149 }
150
151 /*
152 * There are two algorithms for updating the screen.
153 * The first, SlowScreen() optimizes the line between the
154 * computer and the screen (say a 9600 baud line). To do
155 * this, we break out of the loop every so often to look
156 * at any pending input from the network (so that successive
157 * screens will only partially print until the final screen,
158 * the one the user possibly wants to see, is displayed
159 * in its entirety).
160 *
161 * The second algorithm tries to optimize CPU time (by
162 * being simpler) at the cost of the bandwidth to the
163 * screen.
164 *
165 * Of course, curses(3X) gets in here also.
166 */
167
168
169 #if defined(NOT43)
170 static int
171 #else /* defined(NOT43) */
172 static void
173 #endif /* defined(NOT43) */
SlowScreen()174 SlowScreen()
175 {
176 register int is, shouldbe, isattr, shouldattr;
177 register int pointer;
178 register int fieldattr, termattr;
179 register int columnsleft;
180
181 #define NORMAL 0
182 #define HIGHLIGHT 1 /* Mask bits */
183 #define NONDISPLAY 4 /* Mask bits */
184 #define UNDETERMINED 8 /* Mask bits */
185
186 #define DoAttributes(x) \
187 switch (x&ATTR_DSPD_MASK) { \
188 case ATTR_DSPD_NONDISPLAY: \
189 x = NONDISPLAY; \
190 break; \
191 case ATTR_DSPD_HIGH: \
192 x = HIGHLIGHT; \
193 break; \
194 default: \
195 x = 0; \
196 break; \
197 }
198
199 # define SetHighlightMode(x) \
200 { \
201 if ((x)&HIGHLIGHT) { \
202 if (!inHighlightMode) { \
203 inHighlightMode = HIGHLIGHT; \
204 standout(); \
205 } \
206 } else { \
207 if (inHighlightMode) { \
208 inHighlightMode = 0; \
209 standend(); \
210 } \
211 } \
212 }
213
214 # define DoCharacterAt(c,p) { \
215 if (p != HighestScreen()) { \
216 c = disp_asc[c&0xff]; \
217 if (terminalCursorAddress != p) { \
218 if (ERR == mvaddch(ScreenLine(p), \
219 ScreenLineOffset(p), c)) {\
220 GoAway("mvaddch", p); \
221 } \
222 } else { \
223 if (ERR == addch(c)) {\
224 GoAway("addch", p); \
225 } \
226 } \
227 terminalCursorAddress = ScreenInc(p); \
228 } \
229 }
230
231
232 /* run through screen, printing out non-null lines */
233
234 /* There are two separate reasons for wanting to terminate this
235 * loop early. One is to respond to new input (either from
236 * the terminal or from the network [host]). For this reason,
237 * we expect to see 'HaveInput' come true when new input comes in.
238 *
239 * The second reason is a bit more difficult (for me) to understand.
240 * Basically, we don't want to get too far ahead of the characters that
241 * appear on the screen. Ideally, we would type out a few characters,
242 * wait until they appeared on the screen, then type out a few more.
243 * The reason for this is that the user, on seeing some characters
244 * appear on the screen may then start to type something. We would
245 * like to look at what the user types at about the same 'time'
246 * (measured by characters being sent to the terminal) that the
247 * user types them. For this reason, what we would like to do
248 * is update a bit, then call curses to do a refresh, flush the
249 * output to the terminal, then wait until the terminal data
250 * has been sent.
251 *
252 * Note that curses is useful for, among other things, deciding whether
253 * or not to send :ce: (clear to end of line), so we should call curses
254 * at end of lines (beginning of next lines).
255 *
256 * The problems here are the following: If we do lots of write(2)s,
257 * we will be doing lots of context switches, thus lots of overhead
258 * (which we have already). Second, if we do a select to wait for
259 * the output to drain, we have to contend with the fact that NOW
260 * we are scheduled to run, but who knows what the scheduler will
261 * decide when the output has caught up.
262 */
263
264 if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */
265 Highest = ScreenDec(Highest); /* else, while loop will never end */
266 }
267 if (Lowest < LowestScreen()) {
268 Lowest = LowestScreen(); /* could be -1 in some cases with
269 * unformatted screens.
270 */
271 }
272 if (Highest >= (pointer = Lowest)) {
273 /* if there is anything to do, do it. We won't terminate
274 * the loop until we've gone at least to Highest.
275 */
276 while ((pointer <= Highest) && !HaveInput) {
277
278 /* point at the next place of disagreement */
279 pointer += (bunequal(Host+pointer, Terminal+pointer,
280 (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
281
282 /*
283 * How many characters to change until the end of the
284 * current line
285 */
286 columnsleft = NumberColumns - ScreenLineOffset(pointer);
287 /*
288 * Make sure we are where we think we are.
289 */
290 move(ScreenLine(pointer), ScreenLineOffset(pointer));
291
292 /* what is the field attribute of the current position */
293 if (FormattedScreen()) {
294 fieldattr = FieldAttributes(pointer);
295 DoAttributes(fieldattr);
296 } else {
297 fieldattr = NORMAL;
298 }
299 if (TerminalFormattedScreen()) {
300 termattr = TermAttributes(pointer);
301 DoAttributes(termattr);
302 } else {
303 termattr = NORMAL;
304 }
305
306 SetHighlightMode(fieldattr);
307 /*
308 * The following will terminate at least when we get back
309 * to the original 'pointer' location (since we force
310 * things to be equal).
311 */
312 for (;;) {
313 if (IsStartField(pointer)) {
314 shouldbe = DISP_BLANK;
315 shouldattr = 0;
316 fieldattr = GetHost(pointer);
317 DoAttributes(fieldattr);
318 } else {
319 if (fieldattr&NONDISPLAY) {
320 shouldbe = DISP_BLANK;
321 } else {
322 shouldbe = GetHost(pointer);
323 }
324 shouldattr = fieldattr;
325 }
326 if (TermIsStartField(pointer)) {
327 is = DISP_BLANK;
328 isattr = 0;
329 termattr = UNDETERMINED; /* Need to find out AFTER update */
330 } else {
331 if (termattr&NONDISPLAY) {
332 is = DISP_BLANK;
333 } else {
334 is = GetTerminal(pointer);
335 }
336 isattr = termattr;
337 }
338 if ((shouldbe == is) && (shouldattr == isattr)
339 && (GetHost(pointer) == GetTerminal(pointer))
340 && (GetHost(ScreenInc(pointer))
341 == GetTerminal(ScreenInc(pointer)))) {
342 break;
343 }
344
345 if (shouldattr^inHighlightMode) {
346 SetHighlightMode(shouldattr);
347 }
348
349 DoCharacterAt(shouldbe, pointer);
350 if (IsStartField(pointer)) {
351 TermNewField(pointer, FieldAttributes(pointer));
352 termattr = GetTerminal(pointer);
353 DoAttributes(termattr);
354 } else {
355 SetTerminal(pointer, GetHost(pointer));
356 /*
357 * If this USED to be a start field location,
358 * recompute the terminal attributes.
359 */
360 if (termattr == UNDETERMINED) {
361 termattr = WhereTermAttrByte(pointer);
362 if ((termattr != 0) || TermIsStartField(0)) {
363 termattr = GetTerminal(termattr);
364 DoAttributes(termattr);
365 } else { /* Unformatted screen */
366 termattr = NORMAL;
367 }
368 }
369 }
370 pointer = ScreenInc(pointer);
371 if (!(--columnsleft)) {
372 DoARefresh();
373 EmptyTerminal();
374 if (HaveInput) { /* if input came in, take it */
375 int c, j;
376
377 /*
378 * We need to start a new terminal field
379 * at this location iff the terminal attributes
380 * of this location are not what we have had
381 * them as (ie: we've overwritten the terminal
382 * start field, a the previous field had different
383 * display characteristics).
384 */
385
386 isattr = TermAttributes(pointer);
387 DoAttributes(isattr);
388 if ((!TermIsStartField(pointer)) &&
389 (isattr != termattr)) {
390 /*
391 * Since we are going to leave a new field
392 * at this terminal position, we
393 * need to make sure that we get an actual
394 * non-highlighted blank on the screen.
395 */
396 if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) {
397 SetHighlightMode(0); /* Turn off highlight */
398 c = ScreenInc(pointer);
399 j = DISP_BLANK;
400 DoCharacterAt(j, c);
401 }
402 if (termattr&HIGHLIGHT) {
403 termattr = ATTR_DSPD_HIGH;
404 } else if (termattr&NONDISPLAY) {
405 termattr = ATTR_DSPD_NONDISPLAY;
406 } else {
407 termattr = 0;
408 }
409 TermNewField(pointer, termattr);
410 }
411 break;
412 }
413 move(ScreenLine(pointer), 0);
414 columnsleft = NumberColumns;
415 }
416 } /* end of for (;;) */
417 } /* end of while (...) */
418 }
419 DoARefresh();
420 Lowest = pointer;
421 if (Lowest > Highest) { /* if we finished input... */
422 Lowest = HighestScreen()+1;
423 Highest = LowestScreen()-1;
424 terminalCursorAddress = CorrectTerminalCursor();
425 if (ERR == move(ScreenLine(terminalCursorAddress),
426 ScreenLineOffset(terminalCursorAddress))) {
427 GoAway("move", terminalCursorAddress);
428 }
429 DoARefresh();
430 if (needToRing) {
431 StringToTerminal(bellSequence);
432 needToRing = 0;
433 }
434 }
435 EmptyTerminal(); /* move data along */
436 return;
437 }
438
439 #if defined(NOT43)
440 static int
441 #else /* defined(NOT43) */
442 static void
443 #endif /* defined(NOT43) */
FastScreen()444 FastScreen()
445 {
446 #if defined(MSDOS)
447 #define SaveCorner 0
448 #else /* defined(MSDOS) */
449 #define SaveCorner 1
450 #endif /* defined(MSDOS) */
451
452 #define DoAttribute(a) if (IsHighlightedAttr(a)) { \
453 standout(); \
454 } else { \
455 standend(); \
456 } \
457 if (IsNonDisplayAttr(a)) { \
458 a = 0; /* zero == don't display */ \
459 } \
460 if (!FormattedScreen()) { \
461 a = 1; /* one ==> do display on unformatted */\
462 }
463 ScreenImage *p, *upper;
464 int fieldattr; /* spends most of its time == 0 or 1 */
465
466 /* OK. We want to do this a quickly as possible. So, we assume we
467 * only need to go from Lowest to Highest. However, if we find a
468 * field in the middle, we do the whole screen.
469 *
470 * In particular, we separate out the two cases from the beginning.
471 */
472 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
473 register int columnsleft;
474
475 move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
476 p = &Host[Lowest];
477 #if !defined(MSDOS)
478 if (Highest == HighestScreen()) {
479 Highest = ScreenDec(Highest);
480 }
481 #endif /* !defined(MSDOS) */
482 upper = &Host[Highest];
483 fieldattr = FieldAttributes(Lowest);
484 DoAttribute(fieldattr); /* Set standout, non-display status */
485 columnsleft = NumberColumns-ScreenLineOffset(p-Host);
486
487 while (p <= upper) {
488 if (IsStartFieldPointer(p)) { /* New field? */
489 Highest = HighestScreen();
490 Lowest = LowestScreen();
491 FastScreen(); /* Recurse */
492 return;
493 } else if (fieldattr) { /* Should we display? */
494 /* Display translated data */
495 addch((char)disp_asc[GetTerminalPointer(p)]);
496 } else {
497 addch(' '); /* Display a blank */
498 }
499 /* If the physical screen is larger than what we
500 * are using, we need to make sure that each line
501 * starts at the beginning of the line. Otherwise,
502 * we will just string all the lines together.
503 */
504 p++;
505 if (--columnsleft == 0) {
506 int i = p-Host;
507
508 move(ScreenLine(i), 0);
509 columnsleft = NumberColumns;
510 }
511 }
512 } else { /* Going from Lowest to Highest */
513 unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
514 ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
515 register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
516
517 *tmpend = 0; /* terminate from the beginning */
518 move(0,0);
519 p = Host;
520 fieldattr = FieldAttributes(LowestScreen());
521 DoAttribute(fieldattr); /* Set standout, non-display status */
522
523 while (p <= End) {
524 if (IsStartFieldPointer(p)) { /* New field? */
525 if (tmp != tmpbuf) {
526 *tmp++ = 0; /* close out */
527 addstr((char *)tmpbuf);
528 tmp = tmpbuf;
529 tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1;
530 }
531 standend();
532 addch(' ');
533 fieldattr = FieldAttributesPointer(p); /* Get attributes */
534 DoAttribute(fieldattr); /* Set standout, non-display */
535 } else {
536 if (fieldattr) { /* Should we display? */
537 /* Display translated data */
538 *tmp++ = disp_asc[GetTerminalPointer(p)];
539 } else {
540 *tmp++ = ' ';
541 }
542 }
543 /* If the physical screen is larger than what we
544 * are using, we need to make sure that each line
545 * starts at the beginning of the line. Otherwise,
546 * we will just string all the lines together.
547 */
548 p++;
549 if (tmp == tmpend) {
550 int i = p-Host; /* Be sure the "p++" happened first! */
551
552 *tmp++ = 0;
553 addstr((char *)tmpbuf);
554 tmp = tmpbuf;
555 move(ScreenLine(i), 0);
556 tmpend = tmpbuf + NumberColumns;
557 }
558 }
559 if (tmp != tmpbuf) {
560 *tmp++ = 0;
561 addstr((char *)tmpbuf);
562 tmp = tmpbuf;
563 }
564 }
565 Lowest = HighestScreen()+1;
566 Highest = LowestScreen()-1;
567 terminalCursorAddress = CorrectTerminalCursor();
568 if (ERR == move(ScreenLine(terminalCursorAddress),
569 ScreenLineOffset(terminalCursorAddress))) {
570 GoAway("move", terminalCursorAddress);
571 }
572 DoARefresh();
573 if (needToRing) {
574 StringToTerminal(bellSequence);
575 needToRing = 0;
576 }
577 EmptyTerminal(); /* move data along */
578 return;
579 }
580
581
582 /* TryToSend - send data out to user's terminal */
583
584 #if defined(NOT43)
585 int
586 #else /* defined(NOT43) */
587 void
588 #endif /* defined(NOT43) */
589 (*TryToSend)() = FastScreen;
590
591 /*ARGSUSED*/
592 void
ScreenOIA(oia)593 ScreenOIA(oia)
594 OIA *oia;
595 {
596 }
597
598
599 /* InitTerminal - called to initialize the screen, etc. */
600
601 void
InitTerminal()602 InitTerminal()
603 {
604 #if defined(unix)
605 struct sgttyb ourttyb;
606 static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
607 2400, 4800, 9600 };
608 #endif
609 extern void InitMapping();
610
611 InitMapping(); /* Go do mapping file (MAP3270) first */
612 if (!screenInitd) { /* not initialized */
613 #if defined(unix)
614 char KSEbuffer[2050];
615 char *lotsofspace = KSEbuffer;
616 extern void abort();
617 extern char *tgetstr();
618 #endif /* defined(unix) */
619
620 if (initscr() == ERR) { /* Initialize curses to get line size */
621 ExitString("InitTerminal: Error initializing curses", 1);
622 /*NOTREACHED*/
623 }
624 MaxNumberLines = LINES;
625 MaxNumberColumns = COLS;
626 ClearArray(Terminal);
627 terminalCursorAddress = SetBufferAddress(0,0);
628 #if defined(unix)
629 signal(SIGHUP, abort);
630 #endif
631
632 TryToSend = FastScreen;
633 #if defined(unix)
634 ioctl(1, TIOCGETP, (char *) &ourttyb);
635 if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
636 max_changes_before_poll = 1920;
637 } else {
638 max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
639 if (max_changes_before_poll < 40) {
640 max_changes_before_poll = 40;
641 }
642 TryToSend = SlowScreen;
643 HaveInput = 1; /* get signals going */
644 }
645 #endif /* defined(unix) */
646 setcommandmode();
647 /*
648 * By now, initscr() (in curses) has been called (from telnet.c),
649 * and the screen has been initialized.
650 */
651 #if defined(unix)
652 nonl();
653 /* the problem is that curses catches SIGTSTP to
654 * be nice, but it messes us up.
655 */
656 signal(SIGTSTP, SIG_DFL);
657 if ((myKS = tgetstr("ks", &lotsofspace)) != 0) {
658 myKS = strsave(myKS);
659 StringToTerminal(myKS);
660 }
661 if ((myKE = tgetstr("ke", &lotsofspace)) != 0) {
662 myKE = strsave(myKE);
663 }
664 if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
665 SO = strsave(tgetstr("md", &lotsofspace));
666 SE = strsave(tgetstr("me", &lotsofspace));
667 }
668 #endif
669 DoARefresh();
670 setconnmode();
671 if (VB && *VB) {
672 bellSequence = VB; /* use visual bell */
673 }
674 screenInitd = 1;
675 screenStopped = 0; /* Not stopped */
676 }
677 }
678
679
680 /* StopScreen - called when we are going away... */
681
682 void
StopScreen(doNewLine)683 StopScreen(doNewLine)
684 int doNewLine;
685 {
686 if (screenInitd && !screenStopped) {
687 move(NumberLines-1, 1);
688 standend();
689 inHighlightMode = 0;
690 DoARefresh();
691 setcommandmode();
692 endwin();
693 setconnmode();
694 #if defined(unix)
695 if (myKE) {
696 StringToTerminal(myKE);
697 }
698 #endif /* defined(unix) */
699 if (doNewLine) {
700 StringToTerminal("\r\n");
701 }
702 EmptyTerminal();
703 screenStopped = 1; /* This is stopped */
704 }
705 }
706
707
708 /* RefreshScreen - called to cause the screen to be refreshed */
709
710 void
RefreshScreen()711 RefreshScreen()
712 {
713 clearok(curscr, TRUE);
714 (*TryToSend)();
715 }
716
717
718 /* ConnectScreen - called to reconnect to the screen */
719
720 void
ConnectScreen()721 ConnectScreen()
722 {
723 if (screenInitd) {
724 #if defined(unix)
725 if (myKS) {
726 StringToTerminal(myKS);
727 }
728 #endif /* defined(unix) */
729 RefreshScreen();
730 (*TryToSend)();
731 screenStopped = 0;
732 }
733 }
734
735 /* LocalClearScreen() - clear the whole ball of wax, cheaply */
736
737 void
LocalClearScreen()738 LocalClearScreen()
739 {
740 extern void Clear3270();
741
742 outputPurge(); /* flush all data to terminal */
743 clear(); /* clear in curses */
744 ClearArray(Terminal);
745 Clear3270();
746 Lowest = HighestScreen()+1; /* everything in sync... */
747 Highest = LowestScreen()+1;
748 }
749
750
751 void
BellOff()752 BellOff()
753 {
754 if (bellwinup) {
755 delwin(bellwin);
756 bellwin = 0;
757 bellwinup = 0;
758 touchwin(stdscr);
759 DoARefresh();
760 }
761 }
762
763
764 void
RingBell(s)765 RingBell(s)
766 char *s;
767 {
768 needToRing = 1;
769 if (s) {
770 int len = strlen(s);
771
772 if (len > COLS-2) {
773 len = COLS-2;
774 }
775 if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
776 OurExitString("Error from newwin in RingBell", 1);
777 }
778 werase(bellwin);
779 wstandout(bellwin);
780 box(bellwin, '|', '-');
781 if (wmove(bellwin, 1, 1) == ERR) {
782 OurExitString("Error from wmove in RingBell", 1);
783 }
784 while (len--) {
785 if (waddch(bellwin, *s++) == ERR) {
786 OurExitString("Error from waddch in RingBell", 1);
787 }
788 }
789 wstandend(bellwin);
790 if (wrefresh(bellwin) == ERR) {
791 OurExitString("Error from wrefresh in RingBell", 1);
792 }
793 bellwinup = 1;
794 }
795 }
796
797
798 /* returns a 1 if no more output available (so, go ahead and block),
799 or a 0 if there is more output available (so, just poll the other
800 sources/destinations, don't block).
801 */
802
803 int
DoTerminalOutput()804 DoTerminalOutput()
805 {
806 /* called just before a select to conserve IO to terminal */
807 if (!(screenInitd||screenStopped)) {
808 return 1; /* No output if not initialized */
809 }
810 if ((Lowest <= Highest) || needToRing ||
811 (terminalCursorAddress != CorrectTerminalCursor())) {
812 (*TryToSend)();
813 }
814 if (Lowest > Highest) {
815 return 1; /* no more output now */
816 } else {
817 return 0; /* more output for future */
818 }
819 }
820
821 /*
822 * The following are defined to handle transparent data.
823 */
824
825 void
TransStop()826 TransStop()
827 {
828 #if defined(unix)
829 if (tcflag == 0) {
830 tcflag = -1;
831 (void) signal(SIGCHLD, SIG_DFL);
832 } else if (tcflag > 0) {
833 setcommandmode();
834 (void) close(tin);
835 (void) close(tout);
836 tin = savefd[0];
837 tout = savefd[1];
838 setconnmode();
839 tcflag = -1;
840 (void) signal(SIGCHLD, SIG_DFL);
841 }
842 #endif /* defined(unix) */
843 RefreshScreen();
844 }
845
846 void
TransOut(buffer,count,kind,control)847 TransOut(buffer, count, kind, control)
848 unsigned char *buffer;
849 int count;
850 int kind; /* 0 or 5 */
851 int control; /* To see if we are done */
852 {
853 #if defined(unix)
854 extern char *transcom;
855 int inpipefd[2], outpipefd[2];
856 static void aborttc();
857 #endif /* defined(unix) */
858
859 while (DoTerminalOutput() == 0) {
860 #if defined(unix)
861 HaveInput = 0;
862 #endif /* defined(unix) */
863 }
864 #if defined(unix)
865 if (transcom && tcflag == -1) {
866 while (1) { /* go thru once */
867 if (pipe(outpipefd) < 0) {
868 break;
869 }
870 if (pipe(inpipefd) < 0) {
871 break;
872 }
873 if ((tcflag = fork()) == 0) {
874 (void) close(outpipefd[1]);
875 (void) close(0);
876 if (dup(outpipefd[0]) < 0) {
877 exit(1);
878 }
879 (void) close(outpipefd[0]);
880 (void) close(inpipefd[0]);
881 (void) close(1);
882 if (dup(inpipefd[1]) < 0) {
883 exit(1);
884 }
885 (void) close(inpipefd[1]);
886 if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
887 exit(1);
888 }
889 }
890 (void) close(inpipefd[1]);
891 (void) close(outpipefd[0]);
892 savefd[0] = tin;
893 savefd[1] = tout;
894 setcommandmode();
895 tin = inpipefd[0];
896 tout = outpipefd[1];
897 (void) signal(SIGCHLD, aborttc);
898 setconnmode();
899 tcflag = 1;
900 break;
901 }
902 if (tcflag < 1) {
903 tcflag = 0;
904 }
905 }
906 #endif /* defined(unix) */
907 (void) DataToTerminal((char *)buffer, count);
908 if (control && (kind == 0)) { /* Send in AID byte */
909 SendToIBM();
910 } else {
911 extern void TransInput();
912
913 TransInput(1, kind); /* Go get some data */
914 }
915 }
916
917
918 #if defined(unix)
919 static void
aborttc(signo)920 aborttc(signo)
921 int signo;
922 {
923 setcommandmode();
924 (void) close(tin);
925 (void) close(tout);
926 tin = savefd[0];
927 tout = savefd[1];
928 setconnmode();
929 tcflag = 0;
930 }
931 #endif /* defined(unix) */
932