148761Sbostic /*-
2*62368Sbostic  * Copyright (c) 1988, 1993
3*62368Sbostic  *	The Regents of the University of California.  All rights reserved.
430043Sminshall  *
548761Sbostic  * %sccs.include.redist.c%
630043Sminshall  */
730043Sminshall 
830043Sminshall #ifndef lint
9*62368Sbostic static char sccsid[] = "@(#)termout.c	8.1 (Berkeley) 06/06/93";
1033810Sbostic #endif /* not lint */
1130043Sminshall 
1230043Sminshall #if defined(unix)
1330043Sminshall #include <signal.h>
1430043Sminshall #include <sgtty.h>
1530043Sminshall #endif
1630043Sminshall #include <stdio.h>
1730043Sminshall #include <curses.h>
1834307Sminshall #if	defined(ultrix)
1934307Sminshall /* Some version of this OS has a bad definition for nonl() */
2034307Sminshall #undef	nl
2134307Sminshall #undef	nonl
2230043Sminshall 
2334307Sminshall #define nl()	 (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
2434307Sminshall #define nonl()	 (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
2534307Sminshall #endif	/* defined(ultrix) */
2634307Sminshall 
2731179Sminshall #include "../general/general.h"
2831071Sminshall 
2930043Sminshall #include "terminal.h"
3030043Sminshall 
3131873Sminshall #include "../api/disp_asc.h"
3231224Sminshall 
3330043Sminshall #include "../ctlr/hostctlr.h"
3435423Sminshall #include "../ctlr/externs.h"
3535423Sminshall #include "../ctlr/declare.h"
3631127Sminshall #include "../ctlr/oia.h"
3730043Sminshall #include "../ctlr/screen.h"
3836243Sminshall #include "../ctlr/scrnctlr.h"
3930043Sminshall 
4031179Sminshall #include "../general/globals.h"
4130043Sminshall 
4259891Sbostic #include "telextrn.h"
4330043Sminshall 
4430043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
4531839Sminshall 		CursorAddress:UnLocked? CursorAddress: HighestScreen())
4630043Sminshall 
4730043Sminshall 
4830328Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
4930328Sminshall static int screenInitd; 		/* the screen has been initialized */
5030328Sminshall static int screenStopped;		/* the screen has been stopped */
5130043Sminshall static int max_changes_before_poll;	/* how many characters before looking */
5230043Sminshall 					/* at terminal and net again */
5330043Sminshall 
5430328Sminshall static int needToRing;			/* need to ring terinal bell */
5530043Sminshall static char *bellSequence = "\07";	/* bell sequence (may be replaced by
5630043Sminshall 					 * VB during initialization)
5730043Sminshall 					 */
5830328Sminshall static WINDOW *bellwin = 0;		/* The window the bell message is in */
5930043Sminshall int	bellwinup = 0;			/* Are we up with it or not */
6030043Sminshall 
6130043Sminshall #if	defined(unix)
6234315Sminshall static char *myKS, *myKE;
6330043Sminshall #endif	/* defined(unix) */
6430043Sminshall 
6530074Sminshall 
6630074Sminshall static int inHighlightMode = 0;
6731071Sminshall ScreenImage Terminal[MAXSCREENSIZE];
6830074Sminshall 
6930074Sminshall /* Variables for transparent mode */
7030043Sminshall #if	defined(unix)
7130043Sminshall static int tcflag = -1;			/* transparent mode command flag */
7230043Sminshall static int savefd[2];			/* for storing fds during transcom */
7330074Sminshall extern int	tin, tout;		/* file descriptors */
7430043Sminshall #endif	/* defined(unix) */
7530043Sminshall 
7630730Sminshall 
7730730Sminshall /*
7830730Sminshall  * init_screen()
7930730Sminshall  *
8030730Sminshall  * Initialize variables used by screen.
8130730Sminshall  */
8230730Sminshall 
8330730Sminshall void
init_screen()8430730Sminshall init_screen()
8530730Sminshall {
8630730Sminshall     bellwinup = 0;
8730730Sminshall     inHighlightMode = 0;
8831071Sminshall     ClearArray(Terminal);
8930730Sminshall }
9030730Sminshall 
9130730Sminshall 
9230043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
9330043Sminshall 
9430043Sminshall static void
OurExitString(string,value)9535423Sminshall OurExitString(string, value)
9630043Sminshall char	*string;
9730043Sminshall int	value;
9830043Sminshall {
9930043Sminshall     static int recursion = 0;
10030043Sminshall 
10130043Sminshall     if (!recursion) {
10230043Sminshall 	recursion = 1;
10335423Sminshall 	ExitString(string, value);
10430043Sminshall     }
10530043Sminshall }
10630043Sminshall 
10730043Sminshall 
10830043Sminshall /* DoARefresh */
10930043Sminshall 
11030043Sminshall static void
DoARefresh()11130043Sminshall DoARefresh()
11230043Sminshall {
11330043Sminshall     if (ERR == refresh()) {
11435423Sminshall 	OurExitString("ERR from refresh\n", 1);
11530043Sminshall     }
11630043Sminshall }
11730043Sminshall 
11830043Sminshall static void
GoAway(from,where)11930043Sminshall GoAway(from, where)
12030043Sminshall char *from;		/* routine that gave error */
12130043Sminshall int	where;		/* cursor address */
12230043Sminshall {
12330043Sminshall 	char foo[100];
12430043Sminshall 
12530043Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
12630043Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
12735423Sminshall 	OurExitString(foo, 1);
12830043Sminshall 	/* NOTREACHED */
12930043Sminshall }
13030043Sminshall 
13130043Sminshall /* What is the screen address of the attribute byte for the terminal */
13230043Sminshall 
13330043Sminshall static int
WhereTermAttrByte(p)13430043Sminshall WhereTermAttrByte(p)
13530043Sminshall register int	p;
13630043Sminshall {
13730043Sminshall     register int i;
13830043Sminshall 
13930043Sminshall     i = p;
14030043Sminshall 
14130043Sminshall     do {
14230043Sminshall 	if (TermIsStartField(i)) {
14330043Sminshall 	    return(i);
14430043Sminshall 	}
14530043Sminshall 	i = ScreenDec(i);
14630043Sminshall     } while (i != p);
14730043Sminshall 
14830043Sminshall     return(LowestScreen());	/* unformatted screen... */
14930043Sminshall }
15030043Sminshall 
15130043Sminshall /*
15230043Sminshall  *	There are two algorithms for updating the screen.
15330043Sminshall  *  The first, SlowScreen() optimizes the line between the
15430043Sminshall  *  computer and the screen (say a 9600 baud line).  To do
15530043Sminshall  *  this, we break out of the loop every so often to look
15630043Sminshall  *  at any pending input from the network (so that successive
15730043Sminshall  *  screens will only partially print until the final screen,
15830043Sminshall  *  the one the user possibly wants to see, is displayed
15930043Sminshall  *  in its entirety).
16030043Sminshall  *
16130043Sminshall  *	The second algorithm tries to optimize CPU time (by
16230043Sminshall  *  being simpler) at the cost of the bandwidth to the
16330043Sminshall  *  screen.
16430043Sminshall  *
16530043Sminshall  *	Of course, curses(3X) gets in here also.
16630043Sminshall  */
16730043Sminshall 
16830043Sminshall 
16930043Sminshall #if	defined(NOT43)
17030043Sminshall static int
17130043Sminshall #else	/* defined(NOT43) */
17230043Sminshall static void
17330043Sminshall #endif	/* defined(NOT43) */
SlowScreen()17430043Sminshall SlowScreen()
17530043Sminshall {
17636243Sminshall     register int is, shouldbe, isattr, shouldattr;
17730043Sminshall     register int pointer;
17836243Sminshall     register int fieldattr, termattr;
17930043Sminshall     register int columnsleft;
18030043Sminshall 
18138206Sminshall #define	NORMAL		0
18236243Sminshall #define	HIGHLIGHT	1		/* Mask bits */
18336243Sminshall #define	NONDISPLAY	4		/* Mask bits */
18438206Sminshall #define	UNDETERMINED	8		/* Mask bits */
18536243Sminshall 
18636243Sminshall #define	DoAttributes(x) \
18736243Sminshall 	    switch (x&ATTR_DSPD_MASK) { \
18836243Sminshall 	    case ATTR_DSPD_NONDISPLAY: \
18936243Sminshall 		x = NONDISPLAY; \
19036243Sminshall 		break; \
19136243Sminshall 	    case ATTR_DSPD_HIGH: \
19236243Sminshall 		x = HIGHLIGHT; \
19336243Sminshall 		break; \
19436243Sminshall 	    default: \
19536243Sminshall 		x = 0; \
19636243Sminshall 		break; \
19736243Sminshall 	    }
19836243Sminshall 
19936243Sminshall #   define  SetHighlightMode(x) \
20036243Sminshall 	    { \
20136243Sminshall 		if ((x)&HIGHLIGHT) { \
20230043Sminshall 		    if (!inHighlightMode) { \
20336243Sminshall 			inHighlightMode = HIGHLIGHT; \
20430043Sminshall 			standout(); \
20530043Sminshall 		    } \
20630043Sminshall 		} else { \
20730043Sminshall 		    if (inHighlightMode) { \
20830043Sminshall 			inHighlightMode = 0; \
20930043Sminshall 			standend(); \
21030043Sminshall 		    } \
21130043Sminshall 		} \
21230043Sminshall 	    }
21330043Sminshall 
21430043Sminshall #   define  DoCharacterAt(c,p) { \
21530043Sminshall 		if (p != HighestScreen()) { \
21636243Sminshall 		    c = disp_asc[c&0xff]; \
21730043Sminshall 		    if (terminalCursorAddress != p) { \
21830043Sminshall 			if (ERR == mvaddch(ScreenLine(p), \
21930043Sminshall 						ScreenLineOffset(p), c)) {\
22030043Sminshall 			    GoAway("mvaddch", p); \
22130043Sminshall 			} \
22230043Sminshall 		    } else { \
22330043Sminshall 			if (ERR == addch(c)) {\
22430043Sminshall 			    GoAway("addch", p); \
22530043Sminshall 			} \
22630043Sminshall 		    } \
22730043Sminshall 		    terminalCursorAddress = ScreenInc(p); \
22830043Sminshall 		} \
22930043Sminshall 	    }
23030043Sminshall 
23130043Sminshall 
23230043Sminshall     /* run through screen, printing out non-null lines */
23330043Sminshall 
23430043Sminshall     /* There are two separate reasons for wanting to terminate this
23530043Sminshall      * loop early.  One is to respond to new input (either from
23630043Sminshall      * the terminal or from the network [host]).  For this reason,
23730043Sminshall      * we expect to see 'HaveInput' come true when new input comes in.
23830043Sminshall      *
23930043Sminshall      * The second reason is a bit more difficult (for me) to understand.
24030043Sminshall      * Basically, we don't want to get too far ahead of the characters that
24130043Sminshall      * appear on the screen.  Ideally, we would type out a few characters,
24230043Sminshall      * wait until they appeared on the screen, then type out a few more.
24330043Sminshall      * The reason for this is that the user, on seeing some characters
24430043Sminshall      * appear on the screen may then start to type something.  We would
24530043Sminshall      * like to look at what the user types at about the same 'time'
24630043Sminshall      * (measured by characters being sent to the terminal) that the
24730043Sminshall      * user types them.  For this reason, what we would like to do
24830043Sminshall      * is update a bit, then call curses to do a refresh, flush the
24930043Sminshall      * output to the terminal, then wait until the terminal data
25030043Sminshall      * has been sent.
25130043Sminshall      *
25230043Sminshall      * Note that curses is useful for, among other things, deciding whether
25330043Sminshall      * or not to send :ce: (clear to end of line), so we should call curses
25430043Sminshall      * at end of lines (beginning of next lines).
25530043Sminshall      *
25630043Sminshall      * The problems here are the following:  If we do lots of write(2)s,
25730043Sminshall      * we will be doing lots of context switches, thus lots of overhead
25830043Sminshall      * (which we have already).  Second, if we do a select to wait for
25930043Sminshall      * the output to drain, we have to contend with the fact that NOW
26030043Sminshall      * we are scheduled to run, but who knows what the scheduler will
26130043Sminshall      * decide when the output has caught up.
26230043Sminshall      */
26330043Sminshall 
26433923Sminshall     if (Highest >= HighestScreen()) {	/* Could be > if screen shrunk... */
26530043Sminshall 	Highest = ScreenDec(Highest);	/* else, while loop will never end */
26630043Sminshall     }
26730043Sminshall     if (Lowest < LowestScreen()) {
26830043Sminshall 	Lowest = LowestScreen();	/* could be -1 in some cases with
26930043Sminshall 					 * unformatted screens.
27030043Sminshall 					 */
27130043Sminshall     }
27230043Sminshall     if (Highest >= (pointer = Lowest)) {
27330043Sminshall 		/* if there is anything to do, do it.  We won't terminate
27430043Sminshall 		 * the loop until we've gone at least to Highest.
27530043Sminshall 		 */
27630043Sminshall 	while ((pointer <= Highest) && !HaveInput) {
27730043Sminshall 
27830043Sminshall 		/* point at the next place of disagreement */
27930043Sminshall 	    pointer += (bunequal(Host+pointer, Terminal+pointer,
28030043Sminshall 			(Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
28130043Sminshall 
28236243Sminshall 		/*
28336243Sminshall 		 * How many characters to change until the end of the
28430043Sminshall 		 * current line
28530043Sminshall 		 */
28630043Sminshall 	    columnsleft = NumberColumns - ScreenLineOffset(pointer);
28730043Sminshall 		/*
28830043Sminshall 		 * Make sure we are where we think we are.
28930043Sminshall 		 */
29030043Sminshall 	    move(ScreenLine(pointer), ScreenLineOffset(pointer));
29130043Sminshall 
29230043Sminshall 		/* what is the field attribute of the current position */
29338206Sminshall 	    if (FormattedScreen()) {
29438206Sminshall 		fieldattr = FieldAttributes(pointer);
29538206Sminshall 		DoAttributes(fieldattr);
29638206Sminshall 	    } else {
29738206Sminshall 		fieldattr = NORMAL;
29838206Sminshall 	    }
29938206Sminshall 	    if (TerminalFormattedScreen()) {
30038206Sminshall 		termattr = TermAttributes(pointer);
30138206Sminshall 		DoAttributes(termattr);
30238206Sminshall 	    } else {
30338206Sminshall 		termattr = NORMAL;
30438206Sminshall 	    }
30530043Sminshall 
30636243Sminshall 	    SetHighlightMode(fieldattr);
30736243Sminshall 	    /*
30836243Sminshall 	     * The following will terminate at least when we get back
30936243Sminshall 	     * to the original 'pointer' location (since we force
31036243Sminshall 	     * things to be equal).
31136243Sminshall 	     */
31236243Sminshall 	    for (;;) {
31336243Sminshall 		if (IsStartField(pointer)) {
31436243Sminshall 		    shouldbe = DISP_BLANK;
31536243Sminshall 		    shouldattr = 0;
31636243Sminshall 		    fieldattr = GetHost(pointer);
31736243Sminshall 		    DoAttributes(fieldattr);
31836243Sminshall 		} else {
31936243Sminshall 		    if (fieldattr&NONDISPLAY) {
32036243Sminshall 			shouldbe = DISP_BLANK;
32136243Sminshall 		    } else {
32236243Sminshall 			shouldbe = GetHost(pointer);
32336243Sminshall 		    }
32436243Sminshall 		    shouldattr = fieldattr;
32536243Sminshall 		}
32636243Sminshall 		if (TermIsStartField(pointer)) {
32736243Sminshall 		    is = DISP_BLANK;
32836243Sminshall 		    isattr = 0;
32938206Sminshall 		    termattr = UNDETERMINED; /* Need to find out AFTER update */
33036243Sminshall 		} else {
33136243Sminshall 		    if (termattr&NONDISPLAY) {
33236243Sminshall 			is = DISP_BLANK;
33336243Sminshall 		    } else {
33436243Sminshall 			is = GetTerminal(pointer);
33536243Sminshall 		    }
33636243Sminshall 		    isattr = termattr;
33736243Sminshall 		}
33836243Sminshall 		if ((shouldbe == is) && (shouldattr == isattr)
33936243Sminshall 			&& (GetHost(pointer) == GetTerminal(pointer))
34036243Sminshall 			&& (GetHost(ScreenInc(pointer))
34136243Sminshall 					== GetTerminal(ScreenInc(pointer)))) {
34236243Sminshall 		    break;
34336243Sminshall 		}
34430043Sminshall 
34536243Sminshall 		if (shouldattr^inHighlightMode) {
34636243Sminshall 		    SetHighlightMode(shouldattr);
34736243Sminshall 		}
34830043Sminshall 
34936243Sminshall 		DoCharacterAt(shouldbe, pointer);
35030043Sminshall 		if (IsStartField(pointer)) {
35136243Sminshall 		    TermNewField(pointer, FieldAttributes(pointer));
35238206Sminshall 		    termattr = GetTerminal(pointer);
35338206Sminshall 		    DoAttributes(termattr);
35430043Sminshall 		} else {
35536243Sminshall 		    SetTerminal(pointer, GetHost(pointer));
35638206Sminshall 		    /*
35738206Sminshall 		     * If this USED to be a start field location,
35838206Sminshall 		     * recompute the terminal attributes.
35938206Sminshall 		     */
36038206Sminshall 		    if (termattr == UNDETERMINED) {
36138206Sminshall 			termattr = WhereTermAttrByte(pointer);
36238206Sminshall 			if ((termattr != 0) || TermIsStartField(0)) {
36338206Sminshall 			    termattr = GetTerminal(termattr);
36438206Sminshall 			    DoAttributes(termattr);
36538206Sminshall 			} else {	/* Unformatted screen */
36638206Sminshall 			    termattr = NORMAL;
36738206Sminshall 			}
36838206Sminshall 		    }
36930043Sminshall 		}
37036243Sminshall 		pointer = ScreenInc(pointer);
37136243Sminshall 		if (!(--columnsleft)) {
37236243Sminshall 		    DoARefresh();
37336243Sminshall 		    EmptyTerminal();
37436243Sminshall 		    if (HaveInput) {	/* if input came in, take it */
37536243Sminshall 			int c, j;
37630043Sminshall 
37736243Sminshall 			/*
37836243Sminshall 			 * We need to start a new terminal field
37936243Sminshall 			 * at this location iff the terminal attributes
38036243Sminshall 			 * of this location are not what we have had
38136243Sminshall 			 * them as (ie: we've overwritten the terminal
38236243Sminshall 			 * start field, a the previous field had different
38336243Sminshall 			 * display characteristics).
38436243Sminshall 			 */
38530043Sminshall 
38636243Sminshall 			isattr = TermAttributes(pointer);
38736243Sminshall 			DoAttributes(isattr);
38836243Sminshall 			if ((!TermIsStartField(pointer)) &&
38936243Sminshall 					(isattr != termattr)) {
39030043Sminshall 			    /*
39136243Sminshall 			     * Since we are going to leave a new field
39236243Sminshall 			     * at this terminal position, we
39336243Sminshall 			     * need to make sure that we get an actual
39436243Sminshall 			     * non-highlighted blank on the screen.
39530043Sminshall 			     */
39636243Sminshall 			    if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) {
39736243Sminshall 				SetHighlightMode(0);	/* Turn off highlight */
39836243Sminshall 				c = ScreenInc(pointer);
39936243Sminshall 				j = DISP_BLANK;
40036243Sminshall 				DoCharacterAt(j, c);
40136243Sminshall 			    }
40236243Sminshall 			    if (termattr&HIGHLIGHT) {
40336243Sminshall 				termattr = ATTR_DSPD_HIGH;
40436243Sminshall 			    } else if (termattr&NONDISPLAY) {
40536243Sminshall 				termattr = ATTR_DSPD_NONDISPLAY;
40636243Sminshall 			    } else {
40736243Sminshall 				termattr = 0;
40836243Sminshall 			    }
40936243Sminshall 			    TermNewField(pointer, termattr);
41036243Sminshall 			}
41130043Sminshall 			break;
41230043Sminshall 		    }
41336243Sminshall 		    move(ScreenLine(pointer), 0);
41436243Sminshall 		    columnsleft = NumberColumns;
41530043Sminshall 		}
41636243Sminshall 	    }	/* end of for (;;) */
41736243Sminshall 	} /* end of while (...) */
41830043Sminshall     }
41930043Sminshall     DoARefresh();
42030043Sminshall     Lowest = pointer;
42130043Sminshall     if (Lowest > Highest) {		/* if we finished input... */
42230043Sminshall 	Lowest = HighestScreen()+1;
42330043Sminshall 	Highest = LowestScreen()-1;
42430043Sminshall 	terminalCursorAddress = CorrectTerminalCursor();
42530043Sminshall 	if (ERR == move(ScreenLine(terminalCursorAddress),
42630043Sminshall 			ScreenLineOffset(terminalCursorAddress))) {
42730043Sminshall 	    GoAway("move", terminalCursorAddress);
42830043Sminshall 	}
42930043Sminshall 	DoARefresh();
43030043Sminshall 	if (needToRing) {
43130043Sminshall 	    StringToTerminal(bellSequence);
43230043Sminshall 	    needToRing = 0;
43330043Sminshall 	}
43430043Sminshall     }
43530043Sminshall     EmptyTerminal();			/* move data along */
43630043Sminshall     return;
43730043Sminshall }
43830043Sminshall 
43930043Sminshall #if	defined(NOT43)
44030043Sminshall static int
44130043Sminshall #else	/* defined(NOT43) */
44230043Sminshall static void
44330043Sminshall #endif	/* defined(NOT43) */
FastScreen()44430043Sminshall FastScreen()
44530043Sminshall {
44631101Sminshall #if	defined(MSDOS)
44730043Sminshall #define	SaveCorner	0
44831101Sminshall #else	/* defined(MSDOS) */
44930043Sminshall #define	SaveCorner	1
45031101Sminshall #endif	/* defined(MSDOS) */
45130043Sminshall 
45230043Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
45330043Sminshall 				standout(); \
45430043Sminshall 			    } else { \
45530043Sminshall 				standend(); \
45630043Sminshall 			    } \
45730043Sminshall 			    if (IsNonDisplayAttr(a)) { \
45830043Sminshall 				a = 0; 	/* zero == don't display */ \
45930043Sminshall 			    } \
46030043Sminshall 			    if (!FormattedScreen()) { \
46130043Sminshall 				a = 1;	/* one ==> do display on unformatted */\
46230043Sminshall 			    }
46330043Sminshall     ScreenImage *p, *upper;
46430043Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
46530043Sminshall 
46630043Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
46730043Sminshall  * only need to go from Lowest to Highest.  However, if we find a
46830043Sminshall  * field in the middle, we do the whole screen.
46930043Sminshall  *
47030043Sminshall  * In particular, we separate out the two cases from the beginning.
47130043Sminshall  */
47230043Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
47330043Sminshall 	register int columnsleft;
47430043Sminshall 
47530043Sminshall 	move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
47630043Sminshall 	p = &Host[Lowest];
47731101Sminshall #if	!defined(MSDOS)
47830043Sminshall 	if (Highest == HighestScreen()) {
47930043Sminshall 	    Highest = ScreenDec(Highest);
48030043Sminshall 	}
48131101Sminshall #endif	/* !defined(MSDOS) */
48230043Sminshall 	upper = &Host[Highest];
48330043Sminshall 	fieldattr = FieldAttributes(Lowest);
48430043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
48530043Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
48630043Sminshall 
48730043Sminshall 	while (p <= upper) {
48830054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
48930043Sminshall 		Highest = HighestScreen();
49030043Sminshall 		Lowest = LowestScreen();
49130043Sminshall 		FastScreen();		/* Recurse */
49230043Sminshall 		return;
49330043Sminshall 	    } else if (fieldattr) {	/* Should we display? */
49431148Sminshall 			    /* Display translated data */
49535423Sminshall 		addch((char)disp_asc[GetTerminalPointer(p)]);
49630043Sminshall 	    } else {
49730043Sminshall 		addch(' ');			/* Display a blank */
49830043Sminshall 	    }
49930043Sminshall 			/* If the physical screen is larger than what we
50030043Sminshall 			 * are using, we need to make sure that each line
50130043Sminshall 			 * starts at the beginning of the line.  Otherwise,
50230043Sminshall 			 * we will just string all the lines together.
50330043Sminshall 			 */
50430043Sminshall 	    p++;
50530043Sminshall 	    if (--columnsleft == 0) {
50630043Sminshall 		int i = p-Host;
50730043Sminshall 
50830043Sminshall 		move(ScreenLine(i), 0);
50930043Sminshall 		columnsleft = NumberColumns;
51030043Sminshall 	    }
51130043Sminshall 	}
51230043Sminshall     } else {		/* Going from Lowest to Highest */
51330043Sminshall 	unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
51430043Sminshall 	ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
51530043Sminshall 	register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
51630043Sminshall 
51730043Sminshall 	*tmpend = 0;		/* terminate from the beginning */
51830043Sminshall 	move(0,0);
51930043Sminshall 	p = Host;
52030043Sminshall 	fieldattr = FieldAttributes(LowestScreen());
52130043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
52230043Sminshall 
52330043Sminshall 	while (p <= End) {
52430054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
52530043Sminshall 		if (tmp != tmpbuf) {
52630043Sminshall 		    *tmp++ = 0;			/* close out */
52735423Sminshall 		    addstr((char *)tmpbuf);
52830043Sminshall 		    tmp = tmpbuf;
52936244Sminshall 		    tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1;
53030043Sminshall 		}
53136244Sminshall 		standend();
53236244Sminshall 		addch(' ');
53330054Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
53430043Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
53530043Sminshall 	    } else {
53630043Sminshall 		if (fieldattr) {	/* Should we display? */
53730043Sminshall 				/* Display translated data */
53831148Sminshall 		    *tmp++ = disp_asc[GetTerminalPointer(p)];
53930043Sminshall 		} else {
54030043Sminshall 		    *tmp++ = ' ';
54130043Sminshall 		}
54230043Sminshall 	    }
54330043Sminshall 			/* If the physical screen is larger than what we
54430043Sminshall 			 * are using, we need to make sure that each line
54530043Sminshall 			 * starts at the beginning of the line.  Otherwise,
54630043Sminshall 			 * we will just string all the lines together.
54730043Sminshall 			 */
54830043Sminshall 	    p++;
54930043Sminshall 	    if (tmp == tmpend) {
55030043Sminshall 		int i = p-Host;		/* Be sure the "p++" happened first! */
55130043Sminshall 
55230043Sminshall 		*tmp++ = 0;
55335423Sminshall 		addstr((char *)tmpbuf);
55430043Sminshall 		tmp = tmpbuf;
55530043Sminshall 		move(ScreenLine(i), 0);
55630043Sminshall 		tmpend = tmpbuf + NumberColumns;
55730043Sminshall 	    }
55830043Sminshall 	}
55930043Sminshall 	if (tmp != tmpbuf) {
56030043Sminshall 	    *tmp++ = 0;
56135423Sminshall 	    addstr((char *)tmpbuf);
56230043Sminshall 	    tmp = tmpbuf;
56330043Sminshall 	}
56430043Sminshall     }
56530043Sminshall     Lowest = HighestScreen()+1;
56630043Sminshall     Highest = LowestScreen()-1;
56730043Sminshall     terminalCursorAddress = CorrectTerminalCursor();
56830043Sminshall     if (ERR == move(ScreenLine(terminalCursorAddress),
56930043Sminshall 		    ScreenLineOffset(terminalCursorAddress))) {
57030043Sminshall 	GoAway("move", terminalCursorAddress);
57130043Sminshall     }
57230043Sminshall     DoARefresh();
57330043Sminshall     if (needToRing) {
57430043Sminshall 	StringToTerminal(bellSequence);
57530043Sminshall 	needToRing = 0;
57630043Sminshall     }
57730043Sminshall     EmptyTerminal();			/* move data along */
57830043Sminshall     return;
57930043Sminshall }
58030043Sminshall 
58130043Sminshall 
58230043Sminshall /* TryToSend - send data out to user's terminal */
58330043Sminshall 
58430043Sminshall #if	defined(NOT43)
58530043Sminshall int
58630043Sminshall #else	/* defined(NOT43) */
58730043Sminshall void
58830043Sminshall #endif	/* defined(NOT43) */
58930043Sminshall 	(*TryToSend)() = FastScreen;
59030043Sminshall 
59135423Sminshall /*ARGSUSED*/
59231127Sminshall void
ScreenOIA(oia)59331127Sminshall ScreenOIA(oia)
59431127Sminshall OIA *oia;
59531127Sminshall {
59631127Sminshall }
59731127Sminshall 
59831127Sminshall 
59930328Sminshall /* InitTerminal - called to initialize the screen, etc. */
60030043Sminshall 
60130043Sminshall void
InitTerminal()60230328Sminshall InitTerminal()
60330043Sminshall {
60430043Sminshall #if defined(unix)
60530043Sminshall     struct sgttyb ourttyb;
60630043Sminshall     static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
60730043Sminshall 		2400, 4800, 9600 };
60830043Sminshall #endif
60935423Sminshall     extern void InitMapping();
61030043Sminshall 
61130328Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
61230043Sminshall     if (!screenInitd) { 	/* not initialized */
61330043Sminshall #if	defined(unix)
61430043Sminshall 	char KSEbuffer[2050];
61530043Sminshall 	char *lotsofspace = KSEbuffer;
61659897Sbostic 	extern void abort();
61730043Sminshall 	extern char *tgetstr();
61830043Sminshall #endif	/* defined(unix) */
61930043Sminshall 
62034294Sminshall 	if (initscr() == ERR) {	/* Initialize curses to get line size */
62134294Sminshall 	    ExitString("InitTerminal:  Error initializing curses", 1);
62234294Sminshall 	    /*NOTREACHED*/
62334294Sminshall 	}
62434294Sminshall 	MaxNumberLines = LINES;
62534294Sminshall 	MaxNumberColumns = COLS;
62631101Sminshall 	ClearArray(Terminal);
62730328Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
62830043Sminshall #if defined(unix)
62930043Sminshall 	signal(SIGHUP, abort);
63030043Sminshall #endif
63130043Sminshall 
63230043Sminshall 	TryToSend = FastScreen;
63331559Sminshall #if defined(unix)
63430043Sminshall 	ioctl(1, TIOCGETP, (char *) &ourttyb);
63530043Sminshall 	if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
63630043Sminshall 	    max_changes_before_poll = 1920;
63730043Sminshall 	} else {
63830043Sminshall 	    max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
63930043Sminshall 	    if (max_changes_before_poll < 40) {
64030043Sminshall 		max_changes_before_poll = 40;
64130043Sminshall 	    }
64230043Sminshall 	    TryToSend = SlowScreen;
64330043Sminshall 	    HaveInput = 1;		/* get signals going */
64430043Sminshall 	}
64531559Sminshall #endif	/* defined(unix) */
64630043Sminshall 	setcommandmode();
64730043Sminshall 	/*
64830043Sminshall 	 * By now, initscr() (in curses) has been called (from telnet.c),
64930043Sminshall 	 * and the screen has been initialized.
65030043Sminshall 	 */
65130043Sminshall #if defined(unix)
65230043Sminshall 	nonl();
65330043Sminshall 			/* the problem is that curses catches SIGTSTP to
65430043Sminshall 			 * be nice, but it messes us up.
65530043Sminshall 			 */
65630043Sminshall 	signal(SIGTSTP, SIG_DFL);
65734315Sminshall 	if ((myKS = tgetstr("ks", &lotsofspace)) != 0) {
65834315Sminshall 	    myKS = strsave(myKS);
65934315Sminshall 	    StringToTerminal(myKS);
66030043Sminshall 	}
66134315Sminshall 	if ((myKE = tgetstr("ke", &lotsofspace)) != 0) {
66234315Sminshall 	    myKE = strsave(myKE);
66330043Sminshall 	}
66430043Sminshall 	if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
66530043Sminshall 	   SO = strsave(tgetstr("md", &lotsofspace));
66630043Sminshall 	   SE = strsave(tgetstr("me", &lotsofspace));
66730043Sminshall 	}
66830043Sminshall #endif
66930043Sminshall 	DoARefresh();
67030043Sminshall 	setconnmode();
67130043Sminshall 	if (VB && *VB) {
67230043Sminshall 	    bellSequence = VB;		/* use visual bell */
67330043Sminshall 	}
67430043Sminshall 	screenInitd = 1;
67530043Sminshall 	screenStopped = 0;		/* Not stopped */
67630043Sminshall     }
67730043Sminshall }
67830043Sminshall 
67930043Sminshall 
68030043Sminshall /* StopScreen - called when we are going away... */
68130043Sminshall 
68230043Sminshall void
StopScreen(doNewLine)68330043Sminshall StopScreen(doNewLine)
68430043Sminshall int doNewLine;
68530043Sminshall {
68630043Sminshall     if (screenInitd && !screenStopped) {
68730043Sminshall 	move(NumberLines-1, 1);
68830043Sminshall 	standend();
68930043Sminshall 	inHighlightMode = 0;
69030043Sminshall 	DoARefresh();
69130043Sminshall 	setcommandmode();
69230043Sminshall 	endwin();
69330043Sminshall 	setconnmode();
69430043Sminshall #if	defined(unix)
69534315Sminshall 	if (myKE) {
69634315Sminshall 	    StringToTerminal(myKE);
69730043Sminshall 	}
69830043Sminshall #endif	/* defined(unix) */
69930043Sminshall 	if (doNewLine) {
70030043Sminshall 	    StringToTerminal("\r\n");
70130043Sminshall 	}
70230043Sminshall 	EmptyTerminal();
70330043Sminshall 	screenStopped = 1;		/* This is stopped */
70430043Sminshall     }
70530043Sminshall }
70630043Sminshall 
70730043Sminshall 
70830043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
70930043Sminshall 
71030043Sminshall void
RefreshScreen()71130043Sminshall RefreshScreen()
71230043Sminshall {
71330043Sminshall     clearok(curscr, TRUE);
71430043Sminshall     (*TryToSend)();
71530043Sminshall }
71630043Sminshall 
71730043Sminshall 
71830043Sminshall /* ConnectScreen - called to reconnect to the screen */
71930043Sminshall 
72030043Sminshall void
ConnectScreen()72130043Sminshall ConnectScreen()
72230043Sminshall {
72330043Sminshall     if (screenInitd) {
72430043Sminshall #if	defined(unix)
72534315Sminshall 	if (myKS) {
72634315Sminshall 	    StringToTerminal(myKS);
72730043Sminshall 	}
72830043Sminshall #endif	/* defined(unix) */
72930043Sminshall 	RefreshScreen();
73030043Sminshall 	(*TryToSend)();
73130043Sminshall 	screenStopped = 0;
73230043Sminshall     }
73330043Sminshall }
73430043Sminshall 
73530043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
73630043Sminshall 
73730043Sminshall void
LocalClearScreen()73830043Sminshall LocalClearScreen()
73930043Sminshall {
74035423Sminshall     extern void Clear3270();
74135423Sminshall 
74230043Sminshall     outputPurge();		/* flush all data to terminal */
74330043Sminshall     clear();			/* clear in curses */
74431101Sminshall     ClearArray(Terminal);
74530043Sminshall     Clear3270();
74630043Sminshall     Lowest = HighestScreen()+1; /* everything in sync... */
74730043Sminshall     Highest = LowestScreen()+1;
74830043Sminshall }
74930043Sminshall 
75030043Sminshall 
75130043Sminshall void
BellOff()75230043Sminshall BellOff()
75330043Sminshall {
75430043Sminshall     if (bellwinup) {
75530043Sminshall 	delwin(bellwin);
75630043Sminshall 	bellwin = 0;
75730043Sminshall 	bellwinup = 0;
75830043Sminshall 	touchwin(stdscr);
75930043Sminshall 	DoARefresh();
76030043Sminshall     }
76130043Sminshall }
76230043Sminshall 
76330043Sminshall 
76430043Sminshall void
RingBell(s)76530043Sminshall RingBell(s)
76630043Sminshall char *s;
76730043Sminshall {
76830043Sminshall     needToRing = 1;
76930043Sminshall     if (s) {
77030043Sminshall 	int len = strlen(s);
77130043Sminshall 
77230043Sminshall 	if (len > COLS-2) {
77330043Sminshall 	    len = COLS-2;
77430043Sminshall 	}
77530043Sminshall 	if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
77635423Sminshall 	    OurExitString("Error from newwin in RingBell", 1);
77730043Sminshall 	}
77830043Sminshall 	werase(bellwin);
77930043Sminshall 	wstandout(bellwin);
78030043Sminshall 	box(bellwin, '|', '-');
78130043Sminshall 	if (wmove(bellwin, 1, 1) == ERR) {
78235423Sminshall 	    OurExitString("Error from wmove in RingBell", 1);
78330043Sminshall 	}
78430043Sminshall 	while (len--) {
78530043Sminshall 	    if (waddch(bellwin, *s++) == ERR) {
78635423Sminshall 		OurExitString("Error from waddch in RingBell", 1);
78730043Sminshall 	    }
78830043Sminshall 	}
78930043Sminshall 	wstandend(bellwin);
79030043Sminshall 	if (wrefresh(bellwin) == ERR) {
79135423Sminshall 	    OurExitString("Error from wrefresh in RingBell", 1);
79230043Sminshall 	}
79330043Sminshall 	bellwinup = 1;
79430043Sminshall     }
79530043Sminshall }
79630043Sminshall 
79730043Sminshall 
79830043Sminshall /* returns a 1 if no more output available (so, go ahead and block),
79930043Sminshall     or a 0 if there is more output available (so, just poll the other
80030043Sminshall     sources/destinations, don't block).
80130043Sminshall  */
80230043Sminshall 
80330043Sminshall int
DoTerminalOutput()80430043Sminshall DoTerminalOutput()
80530043Sminshall {
80630043Sminshall 	/* called just before a select to conserve IO to terminal */
80731462Sminshall     if (!(screenInitd||screenStopped)) {
80830369Sminshall 	return 1;		/* No output if not initialized */
80930369Sminshall     }
81030369Sminshall     if ((Lowest <= Highest) || needToRing ||
81130369Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
81230043Sminshall 	(*TryToSend)();
81330043Sminshall     }
81430043Sminshall     if (Lowest > Highest) {
81530369Sminshall 	return 1;		/* no more output now */
81630043Sminshall     } else {
81730369Sminshall 	return 0;		/* more output for future */
81830043Sminshall     }
81930043Sminshall }
82030074Sminshall 
82130074Sminshall /*
82230074Sminshall  * The following are defined to handle transparent data.
82330074Sminshall  */
82430074Sminshall 
82530074Sminshall void
TransStop()82630074Sminshall TransStop()
82730074Sminshall {
82830074Sminshall #if	defined(unix)
82930074Sminshall     if (tcflag == 0) {
83030074Sminshall        tcflag = -1;
83130074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
83230074Sminshall     } else if (tcflag > 0) {
83330074Sminshall        setcommandmode();
83430074Sminshall        (void) close(tin);
83530074Sminshall        (void) close(tout);
83630074Sminshall        tin = savefd[0];
83730074Sminshall        tout = savefd[1];
83830074Sminshall        setconnmode();
83930074Sminshall        tcflag = -1;
84030074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
84130074Sminshall     }
84230074Sminshall #endif	/* defined(unix) */
84330074Sminshall     RefreshScreen();
84430074Sminshall }
84530074Sminshall 
84630074Sminshall void
TransOut(buffer,count,kind,control)84731863Sminshall TransOut(buffer, count, kind, control)
84830074Sminshall unsigned char	*buffer;
84930074Sminshall int		count;
85031863Sminshall int		kind;		/* 0 or 5 */
85131863Sminshall int		control;	/* To see if we are done */
85230074Sminshall {
85330074Sminshall #if	defined(unix)
85430074Sminshall     extern char *transcom;
85535423Sminshall     int inpipefd[2], outpipefd[2];
85659897Sbostic     static void aborttc();
85730074Sminshall #endif	/* defined(unix) */
85830074Sminshall 
85930074Sminshall     while (DoTerminalOutput() == 0) {
86030074Sminshall #if defined(unix)
86130074Sminshall 	HaveInput = 0;
86230074Sminshall #endif /* defined(unix) */
86330074Sminshall     }
86430074Sminshall #if	defined(unix)
86530074Sminshall     if (transcom && tcflag == -1) {
86630074Sminshall        while (1) {			  /* go thru once */
86730074Sminshall 	     if (pipe(outpipefd) < 0) {
86830074Sminshall 		break;
86930074Sminshall 	     }
87030074Sminshall 	     if (pipe(inpipefd) < 0) {
87130074Sminshall 		break;
87230074Sminshall 	     }
87330074Sminshall 	     if ((tcflag = fork()) == 0) {
87430074Sminshall 		(void) close(outpipefd[1]);
87530074Sminshall 		(void) close(0);
87630074Sminshall 		if (dup(outpipefd[0]) < 0) {
87730074Sminshall 		   exit(1);
87830074Sminshall 		}
87930074Sminshall 		(void) close(outpipefd[0]);
88030074Sminshall 		(void) close(inpipefd[0]);
88130074Sminshall 		(void) close(1);
88230074Sminshall 		if (dup(inpipefd[1]) < 0) {
88330074Sminshall 		   exit(1);
88430074Sminshall 		}
88530074Sminshall 		(void) close(inpipefd[1]);
88630074Sminshall 		if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
88730074Sminshall 		    exit(1);
88830074Sminshall 		}
88930074Sminshall 	     }
89030074Sminshall 	     (void) close(inpipefd[1]);
89130074Sminshall 	     (void) close(outpipefd[0]);
89230074Sminshall 	     savefd[0] = tin;
89330074Sminshall 	     savefd[1] = tout;
89430074Sminshall 	     setcommandmode();
89530074Sminshall 	     tin = inpipefd[0];
89630074Sminshall 	     tout = outpipefd[1];
89759897Sbostic 	     (void) signal(SIGCHLD, aborttc);
89830074Sminshall 	     setconnmode();
89930074Sminshall 	     tcflag = 1;
90030074Sminshall 	     break;
90130074Sminshall        }
90230074Sminshall        if (tcflag < 1) {
90330074Sminshall 	  tcflag = 0;
90430074Sminshall        }
90530074Sminshall     }
90630074Sminshall #endif	/* defined(unix) */
90735423Sminshall     (void) DataToTerminal((char *)buffer, count);
90831863Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
90931863Sminshall 	SendToIBM();
91031863Sminshall     } else {
91135423Sminshall 	extern void TransInput();
91235423Sminshall 
91331863Sminshall 	TransInput(1, kind);			/* Go get some data */
91431863Sminshall     }
91530074Sminshall }
91630074Sminshall 
91730074Sminshall 
91830074Sminshall #if	defined(unix)
91930074Sminshall static void
aborttc(signo)92059897Sbostic aborttc(signo)
92159897Sbostic 	int signo;
92230074Sminshall {
92330074Sminshall 	setcommandmode();
92430074Sminshall 	(void) close(tin);
92530074Sminshall 	(void) close(tout);
92630074Sminshall 	tin = savefd[0];
92730074Sminshall 	tout = savefd[1];
92830074Sminshall 	setconnmode();
92930074Sminshall 	tcflag = 0;
93030074Sminshall }
93130074Sminshall #endif	/* defined(unix) */
932