130043Sminshall /*
233810Sbostic  * Copyright (c) 1988 Regents of the University of California.
333810Sbostic  * All rights reserved.
430043Sminshall  *
533810Sbostic  * Redistribution and use in source and binary forms are permitted
6*35423Sminshall  * provided that the above copyright notice and this paragraph are
7*35423Sminshall  * duplicated in all such forms and that any documentation,
8*35423Sminshall  * advertising materials, and other materials related to such
9*35423Sminshall  * distribution and use acknowledge that the software was developed
10*35423Sminshall  * by the University of California, Berkeley.  The name of the
11*35423Sminshall  * University may not be used to endorse or promote products derived
12*35423Sminshall  * from this software without specific prior written permission.
13*35423Sminshall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*35423Sminshall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*35423Sminshall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1630043Sminshall  */
1730043Sminshall 
1830043Sminshall #ifndef lint
19*35423Sminshall static char sccsid[] = "@(#)termout.c	3.7 (Berkeley) 08/28/88";
2033810Sbostic #endif /* not lint */
2130043Sminshall 
2230043Sminshall #if defined(unix)
2330043Sminshall #include <signal.h>
2430043Sminshall #include <sgtty.h>
2530043Sminshall #endif
2630043Sminshall #include <stdio.h>
2730043Sminshall #include <curses.h>
2834307Sminshall #if	defined(ultrix)
2934307Sminshall /* Some version of this OS has a bad definition for nonl() */
3034307Sminshall #undef	nl
3134307Sminshall #undef	nonl
3230043Sminshall 
3334307Sminshall #define nl()	 (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))
3434307Sminshall #define nonl()	 (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))
3534307Sminshall #endif	/* defined(ultrix) */
3634307Sminshall 
3731179Sminshall #include "../general/general.h"
3831071Sminshall 
3930043Sminshall #include "terminal.h"
4030043Sminshall 
4131873Sminshall #include "../api/disp_asc.h"
4231224Sminshall 
4330043Sminshall #include "../ctlr/hostctlr.h"
44*35423Sminshall #include "../ctlr/externs.h"
45*35423Sminshall #include "../ctlr/declare.h"
4631127Sminshall #include "../ctlr/oia.h"
4730043Sminshall #include "../ctlr/screen.h"
4830043Sminshall 
4931179Sminshall #include "../general/globals.h"
5030043Sminshall 
51*35423Sminshall #include "../telextrn.h"
5230043Sminshall 
5330043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
5431839Sminshall 		CursorAddress:UnLocked? CursorAddress: HighestScreen())
5530043Sminshall 
5630043Sminshall 
5730328Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
5830328Sminshall static int screenInitd; 		/* the screen has been initialized */
5930328Sminshall static int screenStopped;		/* the screen has been stopped */
6030043Sminshall static int max_changes_before_poll;	/* how many characters before looking */
6130043Sminshall 					/* at terminal and net again */
6230043Sminshall 
6330328Sminshall static int needToRing;			/* need to ring terinal bell */
6430043Sminshall static char *bellSequence = "\07";	/* bell sequence (may be replaced by
6530043Sminshall 					 * VB during initialization)
6630043Sminshall 					 */
6730328Sminshall static WINDOW *bellwin = 0;		/* The window the bell message is in */
6830043Sminshall int	bellwinup = 0;			/* Are we up with it or not */
6930043Sminshall 
7030043Sminshall #if	defined(unix)
7134315Sminshall static char *myKS, *myKE;
7230043Sminshall #endif	/* defined(unix) */
7330043Sminshall 
7430074Sminshall 
7530074Sminshall static int inHighlightMode = 0;
7631071Sminshall ScreenImage Terminal[MAXSCREENSIZE];
7730074Sminshall 
7830074Sminshall /* Variables for transparent mode */
7930043Sminshall #if	defined(unix)
8030043Sminshall static int tcflag = -1;			/* transparent mode command flag */
8130043Sminshall static int savefd[2];			/* for storing fds during transcom */
8230074Sminshall extern int	tin, tout;		/* file descriptors */
8330043Sminshall #endif	/* defined(unix) */
8430043Sminshall 
8530730Sminshall 
8630730Sminshall /*
8730730Sminshall  * init_screen()
8830730Sminshall  *
8930730Sminshall  * Initialize variables used by screen.
9030730Sminshall  */
9130730Sminshall 
9230730Sminshall void
9330730Sminshall init_screen()
9430730Sminshall {
9530730Sminshall     bellwinup = 0;
9630730Sminshall     inHighlightMode = 0;
9731071Sminshall     ClearArray(Terminal);
9830730Sminshall }
9930730Sminshall 
10030730Sminshall 
10130043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
10230043Sminshall 
10330043Sminshall static void
104*35423Sminshall OurExitString(string, value)
10530043Sminshall char	*string;
10630043Sminshall int	value;
10730043Sminshall {
10830043Sminshall     static int recursion = 0;
10930043Sminshall 
11030043Sminshall     if (!recursion) {
11130043Sminshall 	recursion = 1;
112*35423Sminshall 	ExitString(string, value);
11330043Sminshall     }
11430043Sminshall }
11530043Sminshall 
11630043Sminshall 
11730043Sminshall /* DoARefresh */
11830043Sminshall 
11930043Sminshall static void
12030043Sminshall DoARefresh()
12130043Sminshall {
12230043Sminshall     if (ERR == refresh()) {
123*35423Sminshall 	OurExitString("ERR from refresh\n", 1);
12430043Sminshall     }
12530043Sminshall }
12630043Sminshall 
12730043Sminshall static void
12830043Sminshall GoAway(from, where)
12930043Sminshall char *from;		/* routine that gave error */
13030043Sminshall int	where;		/* cursor address */
13130043Sminshall {
13230043Sminshall 	char foo[100];
13330043Sminshall 
13430043Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
13530043Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
136*35423Sminshall 	OurExitString(foo, 1);
13730043Sminshall 	/* NOTREACHED */
13830043Sminshall }
13930043Sminshall 
14030043Sminshall /* What is the screen address of the attribute byte for the terminal */
14130043Sminshall 
14230043Sminshall static int
14330043Sminshall WhereTermAttrByte(p)
14430043Sminshall register int	p;
14530043Sminshall {
14630043Sminshall     register int i;
14730043Sminshall 
14830043Sminshall     i = p;
14930043Sminshall 
15030043Sminshall     do {
15130043Sminshall 	if (TermIsStartField(i)) {
15230043Sminshall 	    return(i);
15330043Sminshall 	}
15430043Sminshall 	i = ScreenDec(i);
15530043Sminshall     } while (i != p);
15630043Sminshall 
15730043Sminshall     return(LowestScreen());	/* unformatted screen... */
15830043Sminshall }
15930043Sminshall 
16030043Sminshall /*
16130043Sminshall  *	There are two algorithms for updating the screen.
16230043Sminshall  *  The first, SlowScreen() optimizes the line between the
16330043Sminshall  *  computer and the screen (say a 9600 baud line).  To do
16430043Sminshall  *  this, we break out of the loop every so often to look
16530043Sminshall  *  at any pending input from the network (so that successive
16630043Sminshall  *  screens will only partially print until the final screen,
16730043Sminshall  *  the one the user possibly wants to see, is displayed
16830043Sminshall  *  in its entirety).
16930043Sminshall  *
17030043Sminshall  *	The second algorithm tries to optimize CPU time (by
17130043Sminshall  *  being simpler) at the cost of the bandwidth to the
17230043Sminshall  *  screen.
17330043Sminshall  *
17430043Sminshall  *	Of course, curses(3X) gets in here also.
17530043Sminshall  */
17630043Sminshall 
17730043Sminshall 
17830043Sminshall #if	defined(NOT43)
17930043Sminshall static int
18030043Sminshall #else	/* defined(NOT43) */
18130043Sminshall static void
18230043Sminshall #endif	/* defined(NOT43) */
18330043Sminshall SlowScreen()
18430043Sminshall {
18530043Sminshall     register int pointer;
18630043Sminshall     register int c;
18730043Sminshall     register int fieldattr;
18830043Sminshall     register int columnsleft;
18930043Sminshall 
19030043Sminshall #   define  SetHighlightMode(p) { \
19130043Sminshall 		if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \
19230043Sminshall 		    if (!inHighlightMode) { \
19330043Sminshall 			inHighlightMode = 1; \
19430043Sminshall 			standout(); \
19530043Sminshall 		    } \
19630043Sminshall 		} else { \
19730043Sminshall 		    if (inHighlightMode) { \
19830043Sminshall 			inHighlightMode = 0; \
19930043Sminshall 			standend(); \
20030043Sminshall 		    } \
20130043Sminshall 		} \
20230043Sminshall 	    }
20330043Sminshall 
20430043Sminshall #   define  DoCharacterAt(c,p) { \
20530043Sminshall 		SetTerminal(p, c); \
20630043Sminshall 		if (p != HighestScreen()) { \
20730043Sminshall 		    c = TerminalCharacterAttr(disp_asc[c&0xff], p, \
20830043Sminshall 								fieldattr); \
20930043Sminshall 		    if (terminalCursorAddress != p) { \
21030043Sminshall 			if (ERR == mvaddch(ScreenLine(p), \
21130043Sminshall 						ScreenLineOffset(p), c)) {\
21230043Sminshall 			    GoAway("mvaddch", p); \
21330043Sminshall 			} \
21430043Sminshall 		    } else { \
21530043Sminshall 			if (ERR == addch(c)) {\
21630043Sminshall 			    GoAway("addch", p); \
21730043Sminshall 			} \
21830043Sminshall 		    } \
21930043Sminshall 		    terminalCursorAddress = ScreenInc(p); \
22030043Sminshall 		} \
22130043Sminshall 	    }
22230043Sminshall 
22330043Sminshall 
22430043Sminshall     /* run through screen, printing out non-null lines */
22530043Sminshall 
22630043Sminshall     /* There are two separate reasons for wanting to terminate this
22730043Sminshall      * loop early.  One is to respond to new input (either from
22830043Sminshall      * the terminal or from the network [host]).  For this reason,
22930043Sminshall      * we expect to see 'HaveInput' come true when new input comes in.
23030043Sminshall      *
23130043Sminshall      * The second reason is a bit more difficult (for me) to understand.
23230043Sminshall      * Basically, we don't want to get too far ahead of the characters that
23330043Sminshall      * appear on the screen.  Ideally, we would type out a few characters,
23430043Sminshall      * wait until they appeared on the screen, then type out a few more.
23530043Sminshall      * The reason for this is that the user, on seeing some characters
23630043Sminshall      * appear on the screen may then start to type something.  We would
23730043Sminshall      * like to look at what the user types at about the same 'time'
23830043Sminshall      * (measured by characters being sent to the terminal) that the
23930043Sminshall      * user types them.  For this reason, what we would like to do
24030043Sminshall      * is update a bit, then call curses to do a refresh, flush the
24130043Sminshall      * output to the terminal, then wait until the terminal data
24230043Sminshall      * has been sent.
24330043Sminshall      *
24430043Sminshall      * Note that curses is useful for, among other things, deciding whether
24530043Sminshall      * or not to send :ce: (clear to end of line), so we should call curses
24630043Sminshall      * at end of lines (beginning of next lines).
24730043Sminshall      *
24830043Sminshall      * The problems here are the following:  If we do lots of write(2)s,
24930043Sminshall      * we will be doing lots of context switches, thus lots of overhead
25030043Sminshall      * (which we have already).  Second, if we do a select to wait for
25130043Sminshall      * the output to drain, we have to contend with the fact that NOW
25230043Sminshall      * we are scheduled to run, but who knows what the scheduler will
25330043Sminshall      * decide when the output has caught up.
25430043Sminshall      */
25530043Sminshall 
25633923Sminshall     if (Highest >= HighestScreen()) {	/* Could be > if screen shrunk... */
25730043Sminshall 	Highest = ScreenDec(Highest);	/* else, while loop will never end */
25830043Sminshall     }
25930043Sminshall     if (Lowest < LowestScreen()) {
26030043Sminshall 	Lowest = LowestScreen();	/* could be -1 in some cases with
26130043Sminshall 					 * unformatted screens.
26230043Sminshall 					 */
26330043Sminshall     }
26430043Sminshall     if (Highest >= (pointer = Lowest)) {
26530043Sminshall 		/* if there is anything to do, do it.  We won't terminate
26630043Sminshall 		 * the loop until we've gone at least to Highest.
26730043Sminshall 		 */
26830043Sminshall 	while ((pointer <= Highest) && !HaveInput) {
26930043Sminshall 
27030043Sminshall 		/* point at the next place of disagreement */
27130043Sminshall 	    pointer += (bunequal(Host+pointer, Terminal+pointer,
27230043Sminshall 			(Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
27330043Sminshall 
27430043Sminshall 		/* how many characters to change until the end of the
27530043Sminshall 		 * current line
27630043Sminshall 		 */
27730043Sminshall 	    columnsleft = NumberColumns - ScreenLineOffset(pointer);
27830043Sminshall 		/*
27930043Sminshall 		 * Make sure we are where we think we are.
28030043Sminshall 		 */
28130043Sminshall 	    move(ScreenLine(pointer), ScreenLineOffset(pointer));
28230043Sminshall 
28330043Sminshall 		/* what is the field attribute of the current position */
28430043Sminshall 	    fieldattr = FieldAttributes(WhereAttrByte(pointer));
28530043Sminshall 
28630043Sminshall 	    if ((IsStartField(pointer) != TermIsStartField(pointer)) ||
28730043Sminshall 		    (IsStartField(pointer) &&
28830043Sminshall 			fieldattr != TermAttributes(pointer))) {
28930043Sminshall 
29030043Sminshall 		int oldterm;
29130043Sminshall 
29230043Sminshall 		oldterm = TermAttributes(pointer);
29330043Sminshall 		if (IsStartField(pointer)) {
29430043Sminshall 		    TermNewField(pointer, fieldattr);
29530043Sminshall 		    SetTerminal(pointer, 0);
29630043Sminshall 		} else {
29730043Sminshall 		    TermDeleteField(pointer);
29830043Sminshall 		}
29930043Sminshall 		    /* We always do the first character in a divergent
30030043Sminshall 		     * field, since otherwise the start of a field in
30130043Sminshall 		     * the Host structure may leave a highlighted blank
30230043Sminshall 		     * on the screen, and the start of a field in the
30330043Sminshall 		     * Terminal structure may leave a non-highlighted
30430043Sminshall 		     * something in the middle of a highlighted field
30530043Sminshall 		     * on the screen.
30630043Sminshall 		     */
30730043Sminshall 		SetHighlightMode(pointer);
30830043Sminshall 		c = GetHost(pointer);
30930043Sminshall 		DoCharacterAt(c,pointer);		/* MACRO */
31030043Sminshall 
31130043Sminshall 		if (NotVisuallyCompatibleAttributes
31230043Sminshall 				(pointer, fieldattr, oldterm)) {
31330043Sminshall 		    int j;
31430043Sminshall 
31530043Sminshall 		    j = pointer;
31630043Sminshall 
31730043Sminshall 		    pointer = ScreenInc(pointer);
31830043Sminshall 		    if (!(--columnsleft)) {
31930043Sminshall 			DoARefresh();
32030043Sminshall 			EmptyTerminal();
32130043Sminshall 			move(ScreenLine(pointer), 0);
32230043Sminshall 			columnsleft = NumberColumns;
32330043Sminshall 		    }
32430043Sminshall 		    SetHighlightMode(pointer);	/* Turn on highlighting */
32531452Sminshall 		    while ((!IsStartField(pointer)) &&
32631452Sminshall 				(!TermIsStartField(pointer))) {
32730043Sminshall 			c = GetHost(pointer);
32830043Sminshall 			DoCharacterAt(c,pointer);	/* MACRO */
32930043Sminshall 			pointer = ScreenInc(pointer);
33030043Sminshall 			if (!(--columnsleft)) {
33130043Sminshall 			    DoARefresh();
33230043Sminshall 			    EmptyTerminal();
33330043Sminshall 			    move(ScreenLine(pointer), 0);
33430043Sminshall 			    columnsleft = NumberColumns;
33530043Sminshall 				/* We don't look at HaveInput here, since
33630043Sminshall 				 * if we leave this loop before the end of
33730043Sminshall 				 * the 3270 field, we could have pointer
33830043Sminshall 				 * higher than Highest.  This would cause
33930043Sminshall 				 * us to end the highest "while" loop,
34030043Sminshall 				 * but we may, in fact, need to go around the
34130043Sminshall 				 * screen once again.
34230043Sminshall 				 */
34330043Sminshall 			}
34430043Sminshall 			/*		The loop needs to be protected
34530043Sminshall 			 *	from the situation where there had been only
34630043Sminshall 			 *	one field on the Terminal, and none on the Host.
34730043Sminshall 			 *	In this case, we have just deleted our last
34830043Sminshall 			 *	field.	Hence, the break.
34930043Sminshall 			 */
35030043Sminshall 			if (j == pointer) {
35130043Sminshall 			    break;
35230043Sminshall 			}
35330043Sminshall 		    }
35430043Sminshall 		    if (IsStartField(pointer) && !TermIsStartField(pointer)) {
35530043Sminshall 			    /* Remember what the terminal looked like */
35630043Sminshall 			TermNewField(pointer, oldterm);
35730043Sminshall 			    /*
35830043Sminshall 			     * The danger here is that the current position may
35930043Sminshall 			     * be the start of a Host field.  If so, and the
36030043Sminshall 			     * field is highlighted, and our terminal was
36130043Sminshall 			     * highlighted, then we will leave a highlighted
36230043Sminshall 			     * blank at this position.
36330043Sminshall 			     */
36430043Sminshall 			SetHighlightMode(pointer);
36530043Sminshall 			c = GetHost(pointer);
36630043Sminshall 			DoCharacterAt(c,pointer);
36730043Sminshall 		    }
36830043Sminshall 			/* We could be in the situation of needing to exit.
36930043Sminshall 			 * This could happen if the current field wrapped around
37030043Sminshall 			 * the end of the screen.
37130043Sminshall 			 */
37230043Sminshall 		    if (j > pointer) {
37331452Sminshall 			/*
37431452Sminshall 			 * pointer is guaranteed to be higher than Highest...
37531452Sminshall 			 */
37631452Sminshall 			pointer = Highest+1;	/* We did the highest thing */
37730043Sminshall 			break;
37830043Sminshall 		    }
37930043Sminshall 		} else {
38030043Sminshall 		    c = GetHost(pointer);
38130043Sminshall 			/* We always do the first character in a divergent
38230043Sminshall 			 * field, since otherwise the start of a field in
38330043Sminshall 			 * the Host structure may leave a highlighted blank
38430043Sminshall 			 * on the screen, and the start of a field in the
38530043Sminshall 			 * Terminal structure may leave a non-highlighted
38630043Sminshall 			 * something in the middle of a highlighted field
38730043Sminshall 			 * on the screen.
38830043Sminshall 			 */
38930043Sminshall 		    SetHighlightMode(pointer);
39030043Sminshall 		    DoCharacterAt(c,pointer);
39130043Sminshall 		}
39230043Sminshall 	    } else {
39330043Sminshall 		SetHighlightMode(pointer);
39430054Sminshall 		/*
39530054Sminshall 		 * The following will terminate at least when we get back
39630043Sminshall 		 * to the original 'pointer' location (since we force
39730043Sminshall 		 * things to be equal).
39830043Sminshall 		 */
39930043Sminshall 		while (((c = GetHost(pointer)) != GetTerminal(pointer)) &&
40030043Sminshall 			!IsStartField(pointer) && !TermIsStartField(pointer)) {
40130043Sminshall 		    DoCharacterAt(c, pointer);
40230043Sminshall 		    pointer = ScreenInc(pointer);
40330043Sminshall 		    if (!(--columnsleft)) {
40430043Sminshall 			DoARefresh();
40530043Sminshall 			EmptyTerminal();
40630043Sminshall 			if (HaveInput) {	/* if input came in, take it */
40730043Sminshall 			    break;
40830043Sminshall 			}
40930043Sminshall 			move(ScreenLine(pointer), 0);
41030043Sminshall 			columnsleft = NumberColumns;
41130043Sminshall 		    }
41230043Sminshall 		}
41330043Sminshall 	    }
41430043Sminshall 	}
41530043Sminshall     }
41630043Sminshall     DoARefresh();
41730043Sminshall     Lowest = pointer;
41830043Sminshall     if (Lowest > Highest) {		/* if we finished input... */
41930043Sminshall 	Lowest = HighestScreen()+1;
42030043Sminshall 	Highest = LowestScreen()-1;
42130043Sminshall 	terminalCursorAddress = CorrectTerminalCursor();
42230043Sminshall 	if (ERR == move(ScreenLine(terminalCursorAddress),
42330043Sminshall 			ScreenLineOffset(terminalCursorAddress))) {
42430043Sminshall 	    GoAway("move", terminalCursorAddress);
42530043Sminshall 	}
42630043Sminshall 	DoARefresh();
42730043Sminshall 	if (needToRing) {
42830043Sminshall 	    StringToTerminal(bellSequence);
42930043Sminshall 	    needToRing = 0;
43030043Sminshall 	}
43130043Sminshall     }
43230043Sminshall     EmptyTerminal();			/* move data along */
43330043Sminshall     return;
43430043Sminshall }
43530043Sminshall 
43630043Sminshall #if	defined(NOT43)
43730043Sminshall static int
43830043Sminshall #else	/* defined(NOT43) */
43930043Sminshall static void
44030043Sminshall #endif	/* defined(NOT43) */
44130043Sminshall FastScreen()
44230043Sminshall {
44331101Sminshall #if	defined(MSDOS)
44430043Sminshall #define	SaveCorner	0
44531101Sminshall #else	/* defined(MSDOS) */
44630043Sminshall #define	SaveCorner	1
44731101Sminshall #endif	/* defined(MSDOS) */
44830043Sminshall 
44930043Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
45030043Sminshall 				standout(); \
45130043Sminshall 			    } else { \
45230043Sminshall 				standend(); \
45330043Sminshall 			    } \
45430043Sminshall 			    if (IsNonDisplayAttr(a)) { \
45530043Sminshall 				a = 0; 	/* zero == don't display */ \
45630043Sminshall 			    } \
45730043Sminshall 			    if (!FormattedScreen()) { \
45830043Sminshall 				a = 1;	/* one ==> do display on unformatted */\
45930043Sminshall 			    }
46030043Sminshall     ScreenImage *p, *upper;
46130043Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
46230043Sminshall 
46330043Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
46430043Sminshall  * only need to go from Lowest to Highest.  However, if we find a
46530043Sminshall  * field in the middle, we do the whole screen.
46630043Sminshall  *
46730043Sminshall  * In particular, we separate out the two cases from the beginning.
46830043Sminshall  */
46930043Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
47030043Sminshall 	register int columnsleft;
47130043Sminshall 
47230043Sminshall 	move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
47330043Sminshall 	p = &Host[Lowest];
47431101Sminshall #if	!defined(MSDOS)
47530043Sminshall 	if (Highest == HighestScreen()) {
47630043Sminshall 	    Highest = ScreenDec(Highest);
47730043Sminshall 	}
47831101Sminshall #endif	/* !defined(MSDOS) */
47930043Sminshall 	upper = &Host[Highest];
48030043Sminshall 	fieldattr = FieldAttributes(Lowest);
48130043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
48230043Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
48330043Sminshall 
48430043Sminshall 	while (p <= upper) {
48530054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
48630043Sminshall 		Highest = HighestScreen();
48730043Sminshall 		Lowest = LowestScreen();
48830043Sminshall 		FastScreen();		/* Recurse */
48930043Sminshall 		return;
49030043Sminshall 	    } else if (fieldattr) {	/* Should we display? */
49131148Sminshall 			    /* Display translated data */
492*35423Sminshall 		addch((char)disp_asc[GetTerminalPointer(p)]);
49330043Sminshall 	    } else {
49430043Sminshall 		addch(' ');			/* Display a blank */
49530043Sminshall 	    }
49630043Sminshall 			/* If the physical screen is larger than what we
49730043Sminshall 			 * are using, we need to make sure that each line
49830043Sminshall 			 * starts at the beginning of the line.  Otherwise,
49930043Sminshall 			 * we will just string all the lines together.
50030043Sminshall 			 */
50130043Sminshall 	    p++;
50230043Sminshall 	    if (--columnsleft == 0) {
50330043Sminshall 		int i = p-Host;
50430043Sminshall 
50530043Sminshall 		move(ScreenLine(i), 0);
50630043Sminshall 		columnsleft = NumberColumns;
50730043Sminshall 	    }
50830043Sminshall 	}
50930043Sminshall     } else {		/* Going from Lowest to Highest */
51030043Sminshall 	unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
51130043Sminshall 	ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
51230043Sminshall 	register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
51330043Sminshall 
51430043Sminshall 	*tmpend = 0;		/* terminate from the beginning */
51530043Sminshall 	move(0,0);
51630043Sminshall 	p = Host;
51730043Sminshall 	fieldattr = FieldAttributes(LowestScreen());
51830043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
51930043Sminshall 
52030043Sminshall 	while (p <= End) {
52130054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
52230043Sminshall 		if (tmp != tmpbuf) {
52330043Sminshall 		    *tmp++ = 0;			/* close out */
524*35423Sminshall 		    addstr((char *)tmpbuf);
52530043Sminshall 		    tmp = tmpbuf;
52630043Sminshall 		    tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host);
52730043Sminshall 		}
52830054Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
52930043Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
53030043Sminshall 		*tmp++ = ' ';
53130043Sminshall 	    } else {
53230043Sminshall 		if (fieldattr) {	/* Should we display? */
53330043Sminshall 				/* Display translated data */
53431148Sminshall 		    *tmp++ = disp_asc[GetTerminalPointer(p)];
53530043Sminshall 		} else {
53630043Sminshall 		    *tmp++ = ' ';
53730043Sminshall 		}
53830043Sminshall 	    }
53930043Sminshall 			/* If the physical screen is larger than what we
54030043Sminshall 			 * are using, we need to make sure that each line
54130043Sminshall 			 * starts at the beginning of the line.  Otherwise,
54230043Sminshall 			 * we will just string all the lines together.
54330043Sminshall 			 */
54430043Sminshall 	    p++;
54530043Sminshall 	    if (tmp == tmpend) {
54630043Sminshall 		int i = p-Host;		/* Be sure the "p++" happened first! */
54730043Sminshall 
54830043Sminshall 		*tmp++ = 0;
549*35423Sminshall 		addstr((char *)tmpbuf);
55030043Sminshall 		tmp = tmpbuf;
55130043Sminshall 		move(ScreenLine(i), 0);
55230043Sminshall 		tmpend = tmpbuf + NumberColumns;
55330043Sminshall 	    }
55430043Sminshall 	}
55530043Sminshall 	if (tmp != tmpbuf) {
55630043Sminshall 	    *tmp++ = 0;
557*35423Sminshall 	    addstr((char *)tmpbuf);
55830043Sminshall 	    tmp = tmpbuf;
55930043Sminshall 	}
56030043Sminshall     }
56130043Sminshall     Lowest = HighestScreen()+1;
56230043Sminshall     Highest = LowestScreen()-1;
56330043Sminshall     terminalCursorAddress = CorrectTerminalCursor();
56430043Sminshall     if (ERR == move(ScreenLine(terminalCursorAddress),
56530043Sminshall 		    ScreenLineOffset(terminalCursorAddress))) {
56630043Sminshall 	GoAway("move", terminalCursorAddress);
56730043Sminshall     }
56830043Sminshall     DoARefresh();
56930043Sminshall     if (needToRing) {
57030043Sminshall 	StringToTerminal(bellSequence);
57130043Sminshall 	needToRing = 0;
57230043Sminshall     }
57330043Sminshall     EmptyTerminal();			/* move data along */
57430043Sminshall     return;
57530043Sminshall }
57630043Sminshall 
57730043Sminshall 
57830043Sminshall /* TryToSend - send data out to user's terminal */
57930043Sminshall 
58030043Sminshall #if	defined(NOT43)
58130043Sminshall int
58230043Sminshall #else	/* defined(NOT43) */
58330043Sminshall void
58430043Sminshall #endif	/* defined(NOT43) */
58530043Sminshall 	(*TryToSend)() = FastScreen;
58630043Sminshall 
587*35423Sminshall /*ARGSUSED*/
58831127Sminshall void
58931127Sminshall ScreenOIA(oia)
59031127Sminshall OIA *oia;
59131127Sminshall {
59231127Sminshall }
59331127Sminshall 
59431127Sminshall 
59530328Sminshall /* InitTerminal - called to initialize the screen, etc. */
59630043Sminshall 
59730043Sminshall void
59830328Sminshall InitTerminal()
59930043Sminshall {
60030043Sminshall #if defined(unix)
60130043Sminshall     struct sgttyb ourttyb;
60230043Sminshall     static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
60330043Sminshall 		2400, 4800, 9600 };
60430043Sminshall #endif
605*35423Sminshall     extern void InitMapping();
60630043Sminshall 
60730328Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
60830043Sminshall     if (!screenInitd) { 	/* not initialized */
60930043Sminshall #if	defined(unix)
61030043Sminshall 	char KSEbuffer[2050];
61130043Sminshall 	char *lotsofspace = KSEbuffer;
61230043Sminshall 	extern int abort();
61330043Sminshall 	extern char *tgetstr();
61430043Sminshall #endif	/* defined(unix) */
61530043Sminshall 
61634294Sminshall 	if (initscr() == ERR) {	/* Initialize curses to get line size */
61734294Sminshall 	    ExitString("InitTerminal:  Error initializing curses", 1);
61834294Sminshall 	    /*NOTREACHED*/
61934294Sminshall 	}
62034294Sminshall 	MaxNumberLines = LINES;
62134294Sminshall 	MaxNumberColumns = COLS;
62231101Sminshall 	ClearArray(Terminal);
62330328Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
62430043Sminshall #if defined(unix)
62530043Sminshall 	signal(SIGHUP, abort);
62630043Sminshall #endif
62730043Sminshall 
62830043Sminshall 	TryToSend = FastScreen;
62931559Sminshall #if defined(unix)
63030043Sminshall 	ioctl(1, TIOCGETP, (char *) &ourttyb);
63130043Sminshall 	if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
63230043Sminshall 	    max_changes_before_poll = 1920;
63330043Sminshall 	} else {
63430043Sminshall 	    max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
63530043Sminshall 	    if (max_changes_before_poll < 40) {
63630043Sminshall 		max_changes_before_poll = 40;
63730043Sminshall 	    }
63830043Sminshall 	    TryToSend = SlowScreen;
63930043Sminshall 	    HaveInput = 1;		/* get signals going */
64030043Sminshall 	}
64131559Sminshall #endif	/* defined(unix) */
64230043Sminshall 	setcommandmode();
64330043Sminshall 	/*
64430043Sminshall 	 * By now, initscr() (in curses) has been called (from telnet.c),
64530043Sminshall 	 * and the screen has been initialized.
64630043Sminshall 	 */
64730043Sminshall #if defined(unix)
64830043Sminshall 	nonl();
64930043Sminshall 			/* the problem is that curses catches SIGTSTP to
65030043Sminshall 			 * be nice, but it messes us up.
65130043Sminshall 			 */
65230043Sminshall 	signal(SIGTSTP, SIG_DFL);
65334315Sminshall 	if ((myKS = tgetstr("ks", &lotsofspace)) != 0) {
65434315Sminshall 	    myKS = strsave(myKS);
65534315Sminshall 	    StringToTerminal(myKS);
65630043Sminshall 	}
65734315Sminshall 	if ((myKE = tgetstr("ke", &lotsofspace)) != 0) {
65834315Sminshall 	    myKE = strsave(myKE);
65930043Sminshall 	}
66030043Sminshall 	if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
66130043Sminshall 	   SO = strsave(tgetstr("md", &lotsofspace));
66230043Sminshall 	   SE = strsave(tgetstr("me", &lotsofspace));
66330043Sminshall 	}
66430043Sminshall #endif
66530043Sminshall 	DoARefresh();
66630043Sminshall 	setconnmode();
66730043Sminshall 	if (VB && *VB) {
66830043Sminshall 	    bellSequence = VB;		/* use visual bell */
66930043Sminshall 	}
67030043Sminshall 	screenInitd = 1;
67130043Sminshall 	screenStopped = 0;		/* Not stopped */
67230043Sminshall     }
67330043Sminshall }
67430043Sminshall 
67530043Sminshall 
67630043Sminshall /* StopScreen - called when we are going away... */
67730043Sminshall 
67830043Sminshall void
67930043Sminshall StopScreen(doNewLine)
68030043Sminshall int doNewLine;
68130043Sminshall {
68230043Sminshall     if (screenInitd && !screenStopped) {
68330043Sminshall 	move(NumberLines-1, 1);
68430043Sminshall 	standend();
68530043Sminshall 	inHighlightMode = 0;
68630043Sminshall 	DoARefresh();
68730043Sminshall 	setcommandmode();
68830043Sminshall 	endwin();
68930043Sminshall 	setconnmode();
69030043Sminshall #if	defined(unix)
69134315Sminshall 	if (myKE) {
69234315Sminshall 	    StringToTerminal(myKE);
69330043Sminshall 	}
69430043Sminshall #endif	/* defined(unix) */
69530043Sminshall 	if (doNewLine) {
69630043Sminshall 	    StringToTerminal("\r\n");
69730043Sminshall 	}
69830043Sminshall 	EmptyTerminal();
69930043Sminshall 	screenStopped = 1;		/* This is stopped */
70030043Sminshall     }
70130043Sminshall }
70230043Sminshall 
70330043Sminshall 
70430043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
70530043Sminshall 
70630043Sminshall void
70730043Sminshall RefreshScreen()
70830043Sminshall {
70930043Sminshall     clearok(curscr, TRUE);
71030043Sminshall     (*TryToSend)();
71130043Sminshall }
71230043Sminshall 
71330043Sminshall 
71430043Sminshall /* ConnectScreen - called to reconnect to the screen */
71530043Sminshall 
71630043Sminshall void
71730043Sminshall ConnectScreen()
71830043Sminshall {
71930043Sminshall     if (screenInitd) {
72030043Sminshall #if	defined(unix)
72134315Sminshall 	if (myKS) {
72234315Sminshall 	    StringToTerminal(myKS);
72330043Sminshall 	}
72430043Sminshall #endif	/* defined(unix) */
72530043Sminshall 	RefreshScreen();
72630043Sminshall 	(*TryToSend)();
72730043Sminshall 	screenStopped = 0;
72830043Sminshall     }
72930043Sminshall }
73030043Sminshall 
73130043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
73230043Sminshall 
73330043Sminshall void
73430043Sminshall LocalClearScreen()
73530043Sminshall {
736*35423Sminshall     extern void Clear3270();
737*35423Sminshall 
73830043Sminshall     outputPurge();		/* flush all data to terminal */
73930043Sminshall     clear();			/* clear in curses */
74031101Sminshall     ClearArray(Terminal);
74130043Sminshall     Clear3270();
74230043Sminshall     Lowest = HighestScreen()+1; /* everything in sync... */
74330043Sminshall     Highest = LowestScreen()+1;
74430043Sminshall }
74530043Sminshall 
74630043Sminshall 
74730043Sminshall void
74830043Sminshall BellOff()
74930043Sminshall {
75030043Sminshall     if (bellwinup) {
75130043Sminshall 	delwin(bellwin);
75230043Sminshall 	bellwin = 0;
75330043Sminshall 	bellwinup = 0;
75430043Sminshall 	touchwin(stdscr);
75530043Sminshall 	DoARefresh();
75630043Sminshall     }
75730043Sminshall }
75830043Sminshall 
75930043Sminshall 
76030043Sminshall void
76130043Sminshall RingBell(s)
76230043Sminshall char *s;
76330043Sminshall {
76430043Sminshall     needToRing = 1;
76530043Sminshall     if (s) {
76630043Sminshall 	int len = strlen(s);
76730043Sminshall 
76830043Sminshall 	if (len > COLS-2) {
76930043Sminshall 	    len = COLS-2;
77030043Sminshall 	}
77130043Sminshall 	if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
772*35423Sminshall 	    OurExitString("Error from newwin in RingBell", 1);
77330043Sminshall 	}
77430043Sminshall 	werase(bellwin);
77530043Sminshall 	wstandout(bellwin);
77630043Sminshall 	box(bellwin, '|', '-');
77730043Sminshall 	if (wmove(bellwin, 1, 1) == ERR) {
778*35423Sminshall 	    OurExitString("Error from wmove in RingBell", 1);
77930043Sminshall 	}
78030043Sminshall 	while (len--) {
78130043Sminshall 	    if (waddch(bellwin, *s++) == ERR) {
782*35423Sminshall 		OurExitString("Error from waddch in RingBell", 1);
78330043Sminshall 	    }
78430043Sminshall 	}
78530043Sminshall 	wstandend(bellwin);
78630043Sminshall 	if (wrefresh(bellwin) == ERR) {
787*35423Sminshall 	    OurExitString("Error from wrefresh in RingBell", 1);
78830043Sminshall 	}
78930043Sminshall 	bellwinup = 1;
79030043Sminshall     }
79130043Sminshall }
79230043Sminshall 
79330043Sminshall 
79430043Sminshall /* returns a 1 if no more output available (so, go ahead and block),
79530043Sminshall     or a 0 if there is more output available (so, just poll the other
79630043Sminshall     sources/destinations, don't block).
79730043Sminshall  */
79830043Sminshall 
79930043Sminshall int
80030043Sminshall DoTerminalOutput()
80130043Sminshall {
80230043Sminshall 	/* called just before a select to conserve IO to terminal */
80331462Sminshall     if (!(screenInitd||screenStopped)) {
80430369Sminshall 	return 1;		/* No output if not initialized */
80530369Sminshall     }
80630369Sminshall     if ((Lowest <= Highest) || needToRing ||
80730369Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
80830043Sminshall 	(*TryToSend)();
80930043Sminshall     }
81030043Sminshall     if (Lowest > Highest) {
81130369Sminshall 	return 1;		/* no more output now */
81230043Sminshall     } else {
81330369Sminshall 	return 0;		/* more output for future */
81430043Sminshall     }
81530043Sminshall }
81630074Sminshall 
81730074Sminshall /*
81830074Sminshall  * The following are defined to handle transparent data.
81930074Sminshall  */
82030074Sminshall 
82130074Sminshall void
82230074Sminshall TransStop()
82330074Sminshall {
82430074Sminshall #if	defined(unix)
82530074Sminshall     if (tcflag == 0) {
82630074Sminshall        tcflag = -1;
82730074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
82830074Sminshall     } else if (tcflag > 0) {
82930074Sminshall        setcommandmode();
83030074Sminshall        (void) close(tin);
83130074Sminshall        (void) close(tout);
83230074Sminshall        tin = savefd[0];
83330074Sminshall        tout = savefd[1];
83430074Sminshall        setconnmode();
83530074Sminshall        tcflag = -1;
83630074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
83730074Sminshall     }
83830074Sminshall #endif	/* defined(unix) */
83930074Sminshall     RefreshScreen();
84030074Sminshall }
84130074Sminshall 
84230074Sminshall void
84331863Sminshall TransOut(buffer, count, kind, control)
84430074Sminshall unsigned char	*buffer;
84530074Sminshall int		count;
84631863Sminshall int		kind;		/* 0 or 5 */
84731863Sminshall int		control;	/* To see if we are done */
84830074Sminshall {
84930074Sminshall #if	defined(unix)
85030074Sminshall     extern char *transcom;
851*35423Sminshall     int inpipefd[2], outpipefd[2];
85230074Sminshall     void aborttc();
85330074Sminshall #endif	/* defined(unix) */
85430074Sminshall 
85530074Sminshall     while (DoTerminalOutput() == 0) {
85630074Sminshall #if defined(unix)
85730074Sminshall 	HaveInput = 0;
85830074Sminshall #endif /* defined(unix) */
85930074Sminshall     }
86030074Sminshall #if	defined(unix)
86130074Sminshall     if (transcom && tcflag == -1) {
86230074Sminshall        while (1) {			  /* go thru once */
86330074Sminshall 	     if (pipe(outpipefd) < 0) {
86430074Sminshall 		break;
86530074Sminshall 	     }
86630074Sminshall 	     if (pipe(inpipefd) < 0) {
86730074Sminshall 		break;
86830074Sminshall 	     }
86930074Sminshall 	     if ((tcflag = fork()) == 0) {
87030074Sminshall 		(void) close(outpipefd[1]);
87130074Sminshall 		(void) close(0);
87230074Sminshall 		if (dup(outpipefd[0]) < 0) {
87330074Sminshall 		   exit(1);
87430074Sminshall 		}
87530074Sminshall 		(void) close(outpipefd[0]);
87630074Sminshall 		(void) close(inpipefd[0]);
87730074Sminshall 		(void) close(1);
87830074Sminshall 		if (dup(inpipefd[1]) < 0) {
87930074Sminshall 		   exit(1);
88030074Sminshall 		}
88130074Sminshall 		(void) close(inpipefd[1]);
88230074Sminshall 		if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
88330074Sminshall 		    exit(1);
88430074Sminshall 		}
88530074Sminshall 	     }
88630074Sminshall 	     (void) close(inpipefd[1]);
88730074Sminshall 	     (void) close(outpipefd[0]);
88830074Sminshall 	     savefd[0] = tin;
88930074Sminshall 	     savefd[1] = tout;
89030074Sminshall 	     setcommandmode();
89130074Sminshall 	     tin = inpipefd[0];
89230074Sminshall 	     tout = outpipefd[1];
893*35423Sminshall 	     (void) signal(SIGCHLD, (int (*)())aborttc);
89430074Sminshall 	     setconnmode();
89530074Sminshall 	     tcflag = 1;
89630074Sminshall 	     break;
89730074Sminshall        }
89830074Sminshall        if (tcflag < 1) {
89930074Sminshall 	  tcflag = 0;
90030074Sminshall        }
90130074Sminshall     }
90230074Sminshall #endif	/* defined(unix) */
903*35423Sminshall     (void) DataToTerminal((char *)buffer, count);
90431863Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
90531863Sminshall 	SendToIBM();
90631863Sminshall     } else {
907*35423Sminshall 	extern void TransInput();
908*35423Sminshall 
90931863Sminshall 	TransInput(1, kind);			/* Go get some data */
91031863Sminshall     }
91130074Sminshall }
91230074Sminshall 
91330074Sminshall 
91430074Sminshall #if	defined(unix)
91530074Sminshall static void
91630074Sminshall aborttc()
91730074Sminshall {
91830074Sminshall 	setcommandmode();
91930074Sminshall 	(void) close(tin);
92030074Sminshall 	(void) close(tout);
92130074Sminshall 	tin = savefd[0];
92230074Sminshall 	tout = savefd[1];
92330074Sminshall 	setconnmode();
92430074Sminshall 	tcflag = 0;
92530074Sminshall }
92630074Sminshall #endif	/* defined(unix) */
927