Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.bin / tn3270 / sys_curses / termout.c
blobfffa0b67c9cd5879a4c7b4f0fd958ca28e1d074f
1 /* $NetBSD: termout.c,v 1.14 2003/08/07 11:16:37 agc Exp $ */
3 /*-
4 * Copyright (c) 1988 The Regents of the University of California.
5 * All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)termout.c 4.3 (Berkeley) 4/26/91";
36 #else
37 __RCSID("$NetBSD: termout.c,v 1.14 2003/08/07 11:16:37 agc Exp $");
38 #endif
39 #endif /* not lint */
41 #if defined(unix)
42 #include <signal.h>
43 #include <termios.h>
44 #include <unistd.h>
45 #ifdef __NetBSD__
46 #include <termcap.h>
47 #else
48 extern char *tgetstr(char *, char **);
49 #endif
50 #endif
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <curses.h>
55 #if defined(ultrix)
56 /* Some version of this OS has a bad definition for nonl() */
57 #undef nl
58 #undef nonl
60 #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
61 #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
62 #endif /* defined(ultrix) */
64 #include "../general/general.h"
66 #include "terminal.h"
68 #include "../api/disp_asc.h"
70 #include "../ctlr/hostctlr.h"
71 #include "../ctlr/declare.h"
72 #include "../ctlr/oia.h"
73 #include "../ctlr/screen.h"
74 #include "../ctlr/scrnctlr.h"
76 #include "../ascii/state.h"
77 #include "../ascii/map3270.h"
79 #include "../general/globals.h"
81 #include "telextrn.h"
82 #include "externs.h"
84 extern int TransparentClock, OutputClock;
86 #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
87 CursorAddress:UnLocked? CursorAddress: HighestScreen())
90 static int terminalCursorAddress; /* where the cursor is on term */
91 static int screenInitd; /* the screen has been initialized */
92 static int screenStopped; /* the screen has been stopped */
93 static int max_changes_before_poll; /* how many characters before looking */
94 /* at terminal and net again */
96 static int needToRing; /* need to ring terinal bell */
97 static char bellSequence[1024]; /* bell sequence */
98 static WINDOW *bellwin = 0; /* The window the bell message is in */
99 int bellwinup = 0; /* Are we up with it or not */
102 static int inHighlightMode = 0;
103 ScreenImage Terminal[MAXSCREENSIZE];
105 /* Variables for transparent mode */
106 #if defined(unix)
107 static int tcflag = -1; /* transparent mode command flag */
108 static int savefd[2]; /* for storing fds during transcom */
109 extern int tin, tout; /* file descriptors */
111 static void aborttc(int);
112 #endif /* defined(unix) */
114 static void OurExitString(char *, int);
115 static void DoARefresh(void);
116 static void GoAway(char *, int);
117 static int WhereTermAttrByte(int);
118 static void SlowScreen(void);
119 static void FastScreen(void);
120 #if 0
121 static void ScreenOIA(OIA *);
122 #endif
126 * init_screen()
128 * Initialize variables used by screen.
131 void
132 init_screen()
134 bellwinup = 0;
135 inHighlightMode = 0;
136 ClearArray(Terminal);
140 /* OurExitString - designed to keep us from going through infinite recursion */
142 static void
143 OurExitString(string, value)
144 char *string;
145 int value;
147 static int recursion = 0;
149 if (!recursion) {
150 recursion = 1;
151 ExitString(string, value);
156 /* DoARefresh */
158 static void
159 DoARefresh()
161 if (ERR == refresh()) {
162 OurExitString("ERR from refresh\n", 1);
166 static void
167 GoAway(from, where)
168 char *from; /* routine that gave error */
169 int where; /* cursor address */
171 char foo[100];
173 sprintf(foo, "ERR from %s at %d (%d, %d)\n",
174 from, where, ScreenLine(where), ScreenLineOffset(where));
175 OurExitString(foo, 1);
176 /* NOTREACHED */
179 /* What is the screen address of the attribute byte for the terminal */
181 static int
182 WhereTermAttrByte(p)
183 int p;
185 int i;
187 i = p;
189 do {
190 if (TermIsStartField(i)) {
191 return(i);
193 i = ScreenDec(i);
194 } while (i != p);
196 return(LowestScreen()); /* unformatted screen... */
200 * There are two algorithms for updating the screen.
201 * The first, SlowScreen() optimizes the line between the
202 * computer and the screen (say a 9600 baud line). To do
203 * this, we break out of the loop every so often to look
204 * at any pending input from the network (so that successive
205 * screens will only partially print until the final screen,
206 * the one the user possibly wants to see, is displayed
207 * in its entirety).
209 * The second algorithm tries to optimize CPU time (by
210 * being simpler) at the cost of the bandwidth to the
211 * screen.
213 * Of course, curses(3X) gets in here also.
217 #if defined(NOT43)
218 static int
219 #else /* defined(NOT43) */
220 static void
221 #endif /* defined(NOT43) */
222 SlowScreen()
224 int is, shouldbe, isattr, shouldattr;
225 int pointer;
226 int fieldattr, termattr;
227 int columnsleft;
229 #define NORMAL 0
230 #define HIGHLIGHT 1 /* Mask bits */
231 #define NONDISPLAY 4 /* Mask bits */
232 #define UNDETERMINED 8 /* Mask bits */
234 #define DoAttributes(x) \
235 switch (x&ATTR_DSPD_MASK) { \
236 case ATTR_DSPD_NONDISPLAY: \
237 x = NONDISPLAY; \
238 break; \
239 case ATTR_DSPD_HIGH: \
240 x = HIGHLIGHT; \
241 break; \
242 default: \
243 x = 0; \
244 break; \
247 # define SetHighlightMode(x) \
249 if ((x)&HIGHLIGHT) { \
250 if (!inHighlightMode) { \
251 inHighlightMode = HIGHLIGHT; \
252 standout(); \
254 } else { \
255 if (inHighlightMode) { \
256 inHighlightMode = 0; \
257 standend(); \
262 # define DoCharacterAt(c,p) { \
263 if (p != HighestScreen()) { \
264 c = disp_asc[c&0xff]; \
265 if (terminalCursorAddress != p) { \
266 if (ERR == mvaddch(ScreenLine(p), \
267 ScreenLineOffset(p), c)) {\
268 GoAway("mvaddch", p); \
270 } else { \
271 if (ERR == addch(c)) {\
272 GoAway("addch", p); \
275 terminalCursorAddress = ScreenInc(p); \
280 /* run through screen, printing out non-null lines */
282 /* There are two separate reasons for wanting to terminate this
283 * loop early. One is to respond to new input (either from
284 * the terminal or from the network [host]). For this reason,
285 * we expect to see 'HaveInput' come true when new input comes in.
287 * The second reason is a bit more difficult (for me) to understand.
288 * Basically, we don't want to get too far ahead of the characters that
289 * appear on the screen. Ideally, we would type out a few characters,
290 * wait until they appeared on the screen, then type out a few more.
291 * The reason for this is that the user, on seeing some characters
292 * appear on the screen may then start to type something. We would
293 * like to look at what the user types at about the same 'time'
294 * (measured by characters being sent to the terminal) that the
295 * user types them. For this reason, what we would like to do
296 * is update a bit, then call curses to do a refresh, flush the
297 * output to the terminal, then wait until the terminal data
298 * has been sent.
300 * Note that curses is useful for, among other things, deciding whether
301 * or not to send :ce: (clear to end of line), so we should call curses
302 * at end of lines (beginning of next lines).
304 * The problems here are the following: If we do lots of write(2)s,
305 * we will be doing lots of context switches, thus lots of overhead
306 * (which we have already). Second, if we do a select to wait for
307 * the output to drain, we have to contend with the fact that NOW
308 * we are scheduled to run, but who knows what the scheduler will
309 * decide when the output has caught up.
312 if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */
313 Highest = ScreenDec(Highest); /* else, while loop will never end */
315 if (Lowest < LowestScreen()) {
316 Lowest = LowestScreen(); /* could be -1 in some cases with
317 * unformatted screens.
320 if (Highest >= (pointer = Lowest)) {
321 /* if there is anything to do, do it. We won't terminate
322 * the loop until we've gone at least to Highest.
324 while ((pointer <= Highest) && !HaveInput) {
326 /* point at the next place of disagreement */
327 pointer += (bunequal(Host+pointer, Terminal+pointer,
328 (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
331 * How many characters to change until the end of the
332 * current line
334 columnsleft = NumberColumns - ScreenLineOffset(pointer);
336 * Make sure we are where we think we are.
338 move(ScreenLine(pointer), ScreenLineOffset(pointer));
340 /* what is the field attribute of the current position */
341 if (FormattedScreen()) {
342 fieldattr = FieldAttributes(pointer);
343 DoAttributes(fieldattr);
344 } else {
345 fieldattr = NORMAL;
347 if (TerminalFormattedScreen()) {
348 termattr = TermAttributes(pointer);
349 DoAttributes(termattr);
350 } else {
351 termattr = NORMAL;
354 SetHighlightMode(fieldattr);
356 * The following will terminate at least when we get back
357 * to the original 'pointer' location (since we force
358 * things to be equal).
360 for (;;) {
361 if (IsStartField(pointer)) {
362 shouldbe = DISP_BLANK;
363 shouldattr = 0;
364 fieldattr = GetHost(pointer);
365 DoAttributes(fieldattr);
366 } else {
367 if (fieldattr&NONDISPLAY) {
368 shouldbe = DISP_BLANK;
369 } else {
370 shouldbe = GetHost(pointer);
372 shouldattr = fieldattr;
374 if (TermIsStartField(pointer)) {
375 is = DISP_BLANK;
376 isattr = 0;
377 termattr = UNDETERMINED; /* Need to find out AFTER update */
378 } else {
379 if (termattr&NONDISPLAY) {
380 is = DISP_BLANK;
381 } else {
382 is = GetTerminal(pointer);
384 isattr = termattr;
386 if ((shouldbe == is) && (shouldattr == isattr)
387 && (GetHost(pointer) == GetTerminal(pointer))
388 && (GetHost(ScreenInc(pointer))
389 == GetTerminal(ScreenInc(pointer)))) {
390 break;
393 if (shouldattr^inHighlightMode) {
394 SetHighlightMode(shouldattr);
397 DoCharacterAt(shouldbe, pointer);
398 if (IsStartField(pointer)) {
399 TermNewField(pointer, FieldAttributes(pointer));
400 termattr = GetTerminal(pointer);
401 DoAttributes(termattr);
402 } else {
403 SetTerminal(pointer, GetHost(pointer));
405 * If this USED to be a start field location,
406 * recompute the terminal attributes.
408 if (termattr == UNDETERMINED) {
409 termattr = WhereTermAttrByte(pointer);
410 if ((termattr != 0) || TermIsStartField(0)) {
411 termattr = GetTerminal(termattr);
412 DoAttributes(termattr);
413 } else { /* Unformatted screen */
414 termattr = NORMAL;
418 pointer = ScreenInc(pointer);
419 if (!(--columnsleft)) {
420 DoARefresh();
421 EmptyTerminal();
422 if (HaveInput) { /* if input came in, take it */
423 int c, j;
426 * We need to start a new terminal field
427 * at this location iff the terminal attributes
428 * of this location are not what we have had
429 * them as (ie: we've overwritten the terminal
430 * start field, a the previous field had different
431 * display characteristics).
434 isattr = TermAttributes(pointer);
435 DoAttributes(isattr);
436 if ((!TermIsStartField(pointer)) &&
437 (isattr != termattr)) {
439 * Since we are going to leave a new field
440 * at this terminal position, we
441 * need to make sure that we get an actual
442 * non-highlighted blank on the screen.
444 if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) {
445 SetHighlightMode(0); /* Turn off highlight */
446 c = ScreenInc(pointer);
447 j = DISP_BLANK;
448 DoCharacterAt(j, c);
450 if (termattr&HIGHLIGHT) {
451 termattr = ATTR_DSPD_HIGH;
452 } else if (termattr&NONDISPLAY) {
453 termattr = ATTR_DSPD_NONDISPLAY;
454 } else {
455 termattr = 0;
457 TermNewField(pointer, termattr);
459 break;
461 move(ScreenLine(pointer), 0);
462 columnsleft = NumberColumns;
464 } /* end of for (;;) */
465 } /* end of while (...) */
467 DoARefresh();
468 Lowest = pointer;
469 if (Lowest > Highest) { /* if we finished input... */
470 Lowest = HighestScreen()+1;
471 Highest = LowestScreen()-1;
472 terminalCursorAddress = CorrectTerminalCursor();
473 if (ERR == move(ScreenLine(terminalCursorAddress),
474 ScreenLineOffset(terminalCursorAddress))) {
475 GoAway("move", terminalCursorAddress);
477 DoARefresh();
478 if (needToRing) {
479 StringToTerminal(bellSequence);
480 needToRing = 0;
483 EmptyTerminal(); /* move data along */
484 return;
487 #if defined(NOT43)
488 static int
489 #else /* defined(NOT43) */
490 static void
491 #endif /* defined(NOT43) */
492 FastScreen()
494 #if defined(MSDOS)
495 #define SaveCorner 0
496 #else /* defined(MSDOS) */
497 #define SaveCorner 1
498 #endif /* defined(MSDOS) */
500 #define DoAttribute(a) if (IsHighlightedAttr(a)) { \
501 standout(); \
502 } else { \
503 standend(); \
505 if (IsNonDisplayAttr(a)) { \
506 a = 0; /* zero == don't display */ \
508 if (!FormattedScreen()) { \
509 a = 1; /* one ==> do display on unformatted */\
511 ScreenImage *p, *upper;
512 int fieldattr; /* spends most of its time == 0 or 1 */
514 /* OK. We want to do this a quickly as possible. So, we assume we
515 * only need to go from Lowest to Highest. However, if we find a
516 * field in the middle, we do the whole screen.
518 * In particular, we separate out the two cases from the beginning.
520 if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
521 int columnsleft;
523 move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
524 p = &Host[Lowest];
525 #if !defined(MSDOS)
526 if (Highest == HighestScreen()) {
527 Highest = ScreenDec(Highest);
529 #endif /* !defined(MSDOS) */
530 upper = &Host[Highest];
531 fieldattr = FieldAttributes(Lowest);
532 DoAttribute(fieldattr); /* Set standout, non-display status */
533 columnsleft = NumberColumns-ScreenLineOffset(p-Host);
535 while (p <= upper) {
536 if (IsStartFieldPointer(p)) { /* New field? */
537 Highest = HighestScreen();
538 Lowest = LowestScreen();
539 FastScreen(); /* Recurse */
540 return;
541 } else if (fieldattr) { /* Should we display? */
542 /* Display translated data */
543 addch((char)disp_asc[GetTerminalPointer(p)]);
544 } else {
545 addch(' '); /* Display a blank */
547 /* If the physical screen is larger than what we
548 * are using, we need to make sure that each line
549 * starts at the beginning of the line. Otherwise,
550 * we will just string all the lines together.
552 p++;
553 if (--columnsleft == 0) {
554 int i = p-Host;
556 move(ScreenLine(i), 0);
557 columnsleft = NumberColumns;
560 } else { /* Going from Lowest to Highest */
561 unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
562 ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
563 unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
565 *tmpend = 0; /* terminate from the beginning */
566 move(0,0);
567 p = Host;
568 fieldattr = FieldAttributes(LowestScreen());
569 DoAttribute(fieldattr); /* Set standout, non-display status */
571 while (p <= End) {
572 if (IsStartFieldPointer(p)) { /* New field? */
573 if (tmp != tmpbuf) {
574 *tmp++ = 0; /* close out */
575 addstr((char *)tmpbuf);
576 tmp = tmpbuf;
577 tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1;
579 standend();
580 addch(' ');
581 fieldattr = FieldAttributesPointer(p); /* Get attributes */
582 DoAttribute(fieldattr); /* Set standout, non-display */
583 } else {
584 if (fieldattr) { /* Should we display? */
585 /* Display translated data */
586 *tmp++ = disp_asc[GetTerminalPointer(p)];
587 } else {
588 *tmp++ = ' ';
591 /* If the physical screen is larger than what we
592 * are using, we need to make sure that each line
593 * starts at the beginning of the line. Otherwise,
594 * we will just string all the lines together.
596 p++;
597 if (tmp == tmpend) {
598 int i = p-Host; /* Be sure the "p++" happened first! */
600 *tmp++ = 0;
601 addstr((char *)tmpbuf);
602 tmp = tmpbuf;
603 move(ScreenLine(i), 0);
604 tmpend = tmpbuf + NumberColumns;
607 if (tmp != tmpbuf) {
608 *tmp++ = 0;
609 addstr((char *)tmpbuf);
610 tmp = tmpbuf;
613 Lowest = HighestScreen()+1;
614 Highest = LowestScreen()-1;
615 terminalCursorAddress = CorrectTerminalCursor();
616 if (ERR == move(ScreenLine(terminalCursorAddress),
617 ScreenLineOffset(terminalCursorAddress))) {
618 GoAway("move", terminalCursorAddress);
620 DoARefresh();
621 if (needToRing) {
622 StringToTerminal(bellSequence);
623 needToRing = 0;
625 EmptyTerminal(); /* move data along */
626 return;
630 /* TryToSend - send data out to user's terminal */
632 #if defined(NOT43)
634 #else /* defined(NOT43) */
635 void
636 #endif /* defined(NOT43) */
637 (*TryToSend)(void) = FastScreen;
639 #if 0
640 /*ARGSUSED*/
641 static void
642 ScreenOIA(oia)
643 OIA *oia;
646 #endif
649 /* InitTerminal - called to initialize the screen, etc. */
651 void
652 InitTerminal()
654 #if defined(unix)
655 struct termios term;
656 speed_t speed;
657 #endif
658 char termbuf[1024];
659 char *bsp;
661 InitMapping(); /* Go do mapping file (MAP3270) first */
662 if (!screenInitd) { /* not initialized */
663 if (initscr() == NULL) { /* Initialize curses to get line size */
664 ExitString("InitTerminal: Error initializing curses", 1);
665 /*NOTREACHED*/
667 MaxNumberLines = LINES;
668 MaxNumberColumns = COLS;
669 ClearArray(Terminal);
670 terminalCursorAddress = SetBufferAddress(0,0);
671 #if defined(unix)
672 signal(SIGHUP, (void (*)(int))abort);
673 #endif
675 TryToSend = FastScreen;
676 #if defined(unix)
677 tcgetattr(1, &term);
678 speed = cfgetospeed(&term);
679 if ((speed < 0) || (speed > 9600)) {
680 max_changes_before_poll = 1920;
681 } else {
682 max_changes_before_poll = speed/10;
683 if (max_changes_before_poll < 40) {
684 max_changes_before_poll = 40;
686 TryToSend = SlowScreen;
687 HaveInput = 1; /* get signals going */
689 #endif /* defined(unix) */
690 setcommandmode();
691 #if defined(unix)
692 nonl();
693 #endif
694 DoARefresh();
695 setconnmode(0);
696 if (tgetent(termbuf, getenv("TERM")) == 1) {
697 bsp = bellSequence;
698 if ((bsp = tgetstr("vb", &bsp)) == NULL) { /* use visual bell */
699 bsp = bellSequence;
700 if ((bsp = tgetstr("bl", &bsp)) == NULL) {
701 strcpy (bellSequence, "\07");
705 screenInitd = 1;
706 screenStopped = 0; /* Not stopped */
711 /* StopScreen - called when we are going away... */
713 void
714 StopScreen(doNewLine)
715 int doNewLine;
717 if (screenInitd && !screenStopped) {
718 move(NumberLines-1, 1);
719 standend();
720 inHighlightMode = 0;
721 DoARefresh();
722 endwin();
723 setcommandmode();
724 setconnmode(0);
725 if (doNewLine) {
726 StringToTerminal("\r\n");
728 EmptyTerminal();
729 screenStopped = 1; /* This is stopped */
734 /* RefreshScreen - called to cause the screen to be refreshed */
736 void
737 RefreshScreen()
739 clearok(curscr, TRUE);
740 (*TryToSend)();
744 /* ConnectScreen - called to reconnect to the screen */
746 void
747 ConnectScreen()
749 if (screenInitd) {
750 RefreshScreen();
751 (*TryToSend)();
752 screenStopped = 0;
756 /* LocalClearScreen() - clear the whole ball of wax, cheaply */
758 void
759 LocalClearScreen()
761 outputPurge(); /* flush all data to terminal */
762 clear(); /* clear in curses */
763 ClearArray(Terminal);
764 Clear3270();
765 Lowest = HighestScreen()+1; /* everything in sync... */
766 Highest = LowestScreen()+1;
770 void
771 BellOff()
773 if (bellwinup) {
774 delwin(bellwin);
775 bellwin = 0;
776 bellwinup = 0;
777 touchwin(stdscr);
778 DoARefresh();
783 void
784 RingBell(s)
785 char *s;
787 needToRing = 1;
788 if (s) {
789 int len = strlen(s);
791 if (len > COLS-2) {
792 len = COLS-2;
794 if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
795 OurExitString("Error from newwin in RingBell", 1);
797 werase(bellwin);
798 wstandout(bellwin);
799 box(bellwin, '|', '-');
800 if (wmove(bellwin, 1, 1) == ERR) {
801 OurExitString("Error from wmove in RingBell", 1);
803 while (len--) {
804 if (waddch(bellwin, *s++) == ERR) {
805 OurExitString("Error from waddch in RingBell", 1);
808 wstandend(bellwin);
809 if (wrefresh(bellwin) == ERR) {
810 OurExitString("Error from wrefresh in RingBell", 1);
812 bellwinup = 1;
817 /* returns a 1 if no more output available (so, go ahead and block),
818 or a 0 if there is more output available (so, just poll the other
819 sources/destinations, don't block).
823 DoTerminalOutput()
825 /* called just before a select to conserve IO to terminal */
826 if (!(screenInitd||screenStopped)) {
827 return 1; /* No output if not initialized */
829 if ((Lowest <= Highest) || needToRing ||
830 (terminalCursorAddress != CorrectTerminalCursor())) {
831 (*TryToSend)();
833 if (Lowest > Highest) {
834 return 1; /* no more output now */
835 } else {
836 return 0; /* more output for future */
841 * The following are defined to handle transparent data.
844 void
845 TransStop()
847 #if defined(unix)
848 if (tcflag == 0) {
849 tcflag = -1;
850 (void) signal(SIGCHLD, SIG_DFL);
851 } else if (tcflag > 0) {
852 setcommandmode();
853 (void) close(tin);
854 (void) close(tout);
855 tin = savefd[0];
856 tout = savefd[1];
857 setconnmode(0);
858 tcflag = -1;
859 (void) signal(SIGCHLD, SIG_DFL);
861 #endif /* defined(unix) */
862 RefreshScreen();
865 void
866 TransOut(buffer, count, kind, control)
867 unsigned char *buffer;
868 int count;
869 int kind; /* 0 or 5 */
870 int control; /* To see if we are done */
872 #if defined(unix)
873 extern char *transcom;
874 int inpipefd[2], outpipefd[2];
875 #endif /* defined(unix) */
877 while (DoTerminalOutput() == 0) {
878 #if defined(unix)
879 HaveInput = 0;
880 #endif /* defined(unix) */
882 #if defined(unix)
883 if (transcom && tcflag == -1) {
884 while (1) { /* go thru once */
885 if (pipe(outpipefd) < 0) {
886 break;
888 if (pipe(inpipefd) < 0) {
889 break;
891 if ((tcflag = fork()) == 0) {
892 (void) close(outpipefd[1]);
893 (void) close(0);
894 if (dup(outpipefd[0]) < 0) {
895 exit(1);
897 (void) close(outpipefd[0]);
898 (void) close(inpipefd[0]);
899 (void) close(1);
900 if (dup(inpipefd[1]) < 0) {
901 exit(1);
903 (void) close(inpipefd[1]);
904 if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
905 exit(1);
908 (void) close(inpipefd[1]);
909 (void) close(outpipefd[0]);
910 savefd[0] = tin;
911 savefd[1] = tout;
912 setcommandmode();
913 tin = inpipefd[0];
914 tout = outpipefd[1];
915 (void) signal(SIGCHLD, aborttc);
916 setconnmode(0);
917 tcflag = 1;
918 break;
920 if (tcflag < 1) {
921 tcflag = 0;
924 #endif /* defined(unix) */
925 (void) DataToTerminal((char *)buffer, count);
926 if (control && (kind == 0)) { /* Send in AID byte */
927 SendToIBM();
928 } else {
929 TransInput(1, kind); /* Go get some data */
934 #if defined(unix)
935 static void
936 aborttc(n)
937 int n;
939 setcommandmode();
940 (void) close(tin);
941 (void) close(tout);
942 tin = savefd[0];
943 tout = savefd[1];
944 setconnmode(0);
945 tcflag = 0;
947 #endif /* defined(unix) */