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