home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tn3270 / sys_curses / termout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-26  |  24.1 KB  |  957 lines

  1. /*-
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * 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    4.3 (Berkeley) 4/26/91";
  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.  
  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.  
  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.  
  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.  
  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.  
  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 int 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.  
  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.  
  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.     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, (int (*)())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()
  947. {
  948.     setcommandmode();
  949.     (void) close(tin);
  950.     (void) close(tout);
  951.     tin = savefd[0];
  952.     tout = savefd[1];
  953.     setconnmode();
  954.     tcflag = 0;
  955. }
  956. #endif    /* defined(unix) */
  957.