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
635423Sminshall  * provided that the above copyright notice and this paragraph are
735423Sminshall  * duplicated in all such forms and that any documentation,
835423Sminshall  * advertising materials, and other materials related to such
935423Sminshall  * distribution and use acknowledge that the software was developed
1035423Sminshall  * by the University of California, Berkeley.  The name of the
1135423Sminshall  * University may not be used to endorse or promote products derived
1235423Sminshall  * from this software without specific prior written permission.
1335423Sminshall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435423Sminshall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535423Sminshall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1630043Sminshall  */
1730043Sminshall 
1830043Sminshall #ifndef lint
19*36243Sminshall static char sccsid[] = "@(#)termout.c	3.8 (Berkeley) 11/18/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"
4435423Sminshall #include "../ctlr/externs.h"
4535423Sminshall #include "../ctlr/declare.h"
4631127Sminshall #include "../ctlr/oia.h"
4730043Sminshall #include "../ctlr/screen.h"
48*36243Sminshall #include "../ctlr/scrnctlr.h"
4930043Sminshall 
5031179Sminshall #include "../general/globals.h"
5130043Sminshall 
5235423Sminshall #include "../telextrn.h"
5330043Sminshall 
5430043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
5531839Sminshall 		CursorAddress:UnLocked? CursorAddress: HighestScreen())
5630043Sminshall 
5730043Sminshall 
5830328Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
5930328Sminshall static int screenInitd; 		/* the screen has been initialized */
6030328Sminshall static int screenStopped;		/* the screen has been stopped */
6130043Sminshall static int max_changes_before_poll;	/* how many characters before looking */
6230043Sminshall 					/* at terminal and net again */
6330043Sminshall 
6430328Sminshall static int needToRing;			/* need to ring terinal bell */
6530043Sminshall static char *bellSequence = "\07";	/* bell sequence (may be replaced by
6630043Sminshall 					 * VB during initialization)
6730043Sminshall 					 */
6830328Sminshall static WINDOW *bellwin = 0;		/* The window the bell message is in */
6930043Sminshall int	bellwinup = 0;			/* Are we up with it or not */
7030043Sminshall 
7130043Sminshall #if	defined(unix)
7234315Sminshall static char *myKS, *myKE;
7330043Sminshall #endif	/* defined(unix) */
7430043Sminshall 
7530074Sminshall 
7630074Sminshall static int inHighlightMode = 0;
7731071Sminshall ScreenImage Terminal[MAXSCREENSIZE];
7830074Sminshall 
7930074Sminshall /* Variables for transparent mode */
8030043Sminshall #if	defined(unix)
8130043Sminshall static int tcflag = -1;			/* transparent mode command flag */
8230043Sminshall static int savefd[2];			/* for storing fds during transcom */
8330074Sminshall extern int	tin, tout;		/* file descriptors */
8430043Sminshall #endif	/* defined(unix) */
8530043Sminshall 
8630730Sminshall 
8730730Sminshall /*
8830730Sminshall  * init_screen()
8930730Sminshall  *
9030730Sminshall  * Initialize variables used by screen.
9130730Sminshall  */
9230730Sminshall 
9330730Sminshall void
9430730Sminshall init_screen()
9530730Sminshall {
9630730Sminshall     bellwinup = 0;
9730730Sminshall     inHighlightMode = 0;
9831071Sminshall     ClearArray(Terminal);
9930730Sminshall }
10030730Sminshall 
10130730Sminshall 
10230043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
10330043Sminshall 
10430043Sminshall static void
10535423Sminshall OurExitString(string, value)
10630043Sminshall char	*string;
10730043Sminshall int	value;
10830043Sminshall {
10930043Sminshall     static int recursion = 0;
11030043Sminshall 
11130043Sminshall     if (!recursion) {
11230043Sminshall 	recursion = 1;
11335423Sminshall 	ExitString(string, value);
11430043Sminshall     }
11530043Sminshall }
11630043Sminshall 
11730043Sminshall 
11830043Sminshall /* DoARefresh */
11930043Sminshall 
12030043Sminshall static void
12130043Sminshall DoARefresh()
12230043Sminshall {
12330043Sminshall     if (ERR == refresh()) {
12435423Sminshall 	OurExitString("ERR from refresh\n", 1);
12530043Sminshall     }
12630043Sminshall }
12730043Sminshall 
12830043Sminshall static void
12930043Sminshall GoAway(from, where)
13030043Sminshall char *from;		/* routine that gave error */
13130043Sminshall int	where;		/* cursor address */
13230043Sminshall {
13330043Sminshall 	char foo[100];
13430043Sminshall 
13530043Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
13630043Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
13735423Sminshall 	OurExitString(foo, 1);
13830043Sminshall 	/* NOTREACHED */
13930043Sminshall }
14030043Sminshall 
14130043Sminshall /* What is the screen address of the attribute byte for the terminal */
14230043Sminshall 
14330043Sminshall static int
14430043Sminshall WhereTermAttrByte(p)
14530043Sminshall register int	p;
14630043Sminshall {
14730043Sminshall     register int i;
14830043Sminshall 
14930043Sminshall     i = p;
15030043Sminshall 
15130043Sminshall     do {
15230043Sminshall 	if (TermIsStartField(i)) {
15330043Sminshall 	    return(i);
15430043Sminshall 	}
15530043Sminshall 	i = ScreenDec(i);
15630043Sminshall     } while (i != p);
15730043Sminshall 
15830043Sminshall     return(LowestScreen());	/* unformatted screen... */
15930043Sminshall }
16030043Sminshall 
16130043Sminshall /*
16230043Sminshall  *	There are two algorithms for updating the screen.
16330043Sminshall  *  The first, SlowScreen() optimizes the line between the
16430043Sminshall  *  computer and the screen (say a 9600 baud line).  To do
16530043Sminshall  *  this, we break out of the loop every so often to look
16630043Sminshall  *  at any pending input from the network (so that successive
16730043Sminshall  *  screens will only partially print until the final screen,
16830043Sminshall  *  the one the user possibly wants to see, is displayed
16930043Sminshall  *  in its entirety).
17030043Sminshall  *
17130043Sminshall  *	The second algorithm tries to optimize CPU time (by
17230043Sminshall  *  being simpler) at the cost of the bandwidth to the
17330043Sminshall  *  screen.
17430043Sminshall  *
17530043Sminshall  *	Of course, curses(3X) gets in here also.
17630043Sminshall  */
17730043Sminshall 
17830043Sminshall 
17930043Sminshall #if	defined(NOT43)
18030043Sminshall static int
18130043Sminshall #else	/* defined(NOT43) */
18230043Sminshall static void
18330043Sminshall #endif	/* defined(NOT43) */
18430043Sminshall SlowScreen()
18530043Sminshall {
186*36243Sminshall     register int is, shouldbe, isattr, shouldattr;
18730043Sminshall     register int pointer;
188*36243Sminshall     register int fieldattr, termattr;
18930043Sminshall     register int columnsleft;
19030043Sminshall 
191*36243Sminshall #define	HIGHLIGHT	1		/* Mask bits */
192*36243Sminshall #define	NONDISPLAY	4		/* Mask bits */
193*36243Sminshall 
194*36243Sminshall #define	DoAttributes(x) \
195*36243Sminshall 	    switch (x&ATTR_DSPD_MASK) { \
196*36243Sminshall 	    case ATTR_DSPD_NONDISPLAY: \
197*36243Sminshall 		x = NONDISPLAY; \
198*36243Sminshall 		break; \
199*36243Sminshall 	    case ATTR_DSPD_HIGH: \
200*36243Sminshall 		x = HIGHLIGHT; \
201*36243Sminshall 		break; \
202*36243Sminshall 	    default: \
203*36243Sminshall 		x = 0; \
204*36243Sminshall 		break; \
205*36243Sminshall 	    }
206*36243Sminshall 
207*36243Sminshall #   define  SetHighlightMode(x) \
208*36243Sminshall 	    { \
209*36243Sminshall 		if ((x)&HIGHLIGHT) { \
21030043Sminshall 		    if (!inHighlightMode) { \
211*36243Sminshall 			inHighlightMode = HIGHLIGHT; \
21230043Sminshall 			standout(); \
21330043Sminshall 		    } \
21430043Sminshall 		} else { \
21530043Sminshall 		    if (inHighlightMode) { \
21630043Sminshall 			inHighlightMode = 0; \
21730043Sminshall 			standend(); \
21830043Sminshall 		    } \
21930043Sminshall 		} \
22030043Sminshall 	    }
22130043Sminshall 
22230043Sminshall #   define  DoCharacterAt(c,p) { \
22330043Sminshall 		if (p != HighestScreen()) { \
224*36243Sminshall 		    c = disp_asc[c&0xff]; \
22530043Sminshall 		    if (terminalCursorAddress != p) { \
22630043Sminshall 			if (ERR == mvaddch(ScreenLine(p), \
22730043Sminshall 						ScreenLineOffset(p), c)) {\
22830043Sminshall 			    GoAway("mvaddch", p); \
22930043Sminshall 			} \
23030043Sminshall 		    } else { \
23130043Sminshall 			if (ERR == addch(c)) {\
23230043Sminshall 			    GoAway("addch", p); \
23330043Sminshall 			} \
23430043Sminshall 		    } \
23530043Sminshall 		    terminalCursorAddress = ScreenInc(p); \
23630043Sminshall 		} \
23730043Sminshall 	    }
23830043Sminshall 
23930043Sminshall 
24030043Sminshall     /* run through screen, printing out non-null lines */
24130043Sminshall 
24230043Sminshall     /* There are two separate reasons for wanting to terminate this
24330043Sminshall      * loop early.  One is to respond to new input (either from
24430043Sminshall      * the terminal or from the network [host]).  For this reason,
24530043Sminshall      * we expect to see 'HaveInput' come true when new input comes in.
24630043Sminshall      *
24730043Sminshall      * The second reason is a bit more difficult (for me) to understand.
24830043Sminshall      * Basically, we don't want to get too far ahead of the characters that
24930043Sminshall      * appear on the screen.  Ideally, we would type out a few characters,
25030043Sminshall      * wait until they appeared on the screen, then type out a few more.
25130043Sminshall      * The reason for this is that the user, on seeing some characters
25230043Sminshall      * appear on the screen may then start to type something.  We would
25330043Sminshall      * like to look at what the user types at about the same 'time'
25430043Sminshall      * (measured by characters being sent to the terminal) that the
25530043Sminshall      * user types them.  For this reason, what we would like to do
25630043Sminshall      * is update a bit, then call curses to do a refresh, flush the
25730043Sminshall      * output to the terminal, then wait until the terminal data
25830043Sminshall      * has been sent.
25930043Sminshall      *
26030043Sminshall      * Note that curses is useful for, among other things, deciding whether
26130043Sminshall      * or not to send :ce: (clear to end of line), so we should call curses
26230043Sminshall      * at end of lines (beginning of next lines).
26330043Sminshall      *
26430043Sminshall      * The problems here are the following:  If we do lots of write(2)s,
26530043Sminshall      * we will be doing lots of context switches, thus lots of overhead
26630043Sminshall      * (which we have already).  Second, if we do a select to wait for
26730043Sminshall      * the output to drain, we have to contend with the fact that NOW
26830043Sminshall      * we are scheduled to run, but who knows what the scheduler will
26930043Sminshall      * decide when the output has caught up.
27030043Sminshall      */
27130043Sminshall 
27233923Sminshall     if (Highest >= HighestScreen()) {	/* Could be > if screen shrunk... */
27330043Sminshall 	Highest = ScreenDec(Highest);	/* else, while loop will never end */
27430043Sminshall     }
27530043Sminshall     if (Lowest < LowestScreen()) {
27630043Sminshall 	Lowest = LowestScreen();	/* could be -1 in some cases with
27730043Sminshall 					 * unformatted screens.
27830043Sminshall 					 */
27930043Sminshall     }
28030043Sminshall     if (Highest >= (pointer = Lowest)) {
28130043Sminshall 		/* if there is anything to do, do it.  We won't terminate
28230043Sminshall 		 * the loop until we've gone at least to Highest.
28330043Sminshall 		 */
28430043Sminshall 	while ((pointer <= Highest) && !HaveInput) {
28530043Sminshall 
28630043Sminshall 		/* point at the next place of disagreement */
28730043Sminshall 	    pointer += (bunequal(Host+pointer, Terminal+pointer,
28830043Sminshall 			(Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
28930043Sminshall 
290*36243Sminshall 		/*
291*36243Sminshall 		 * How many characters to change until the end of the
29230043Sminshall 		 * current line
29330043Sminshall 		 */
29430043Sminshall 	    columnsleft = NumberColumns - ScreenLineOffset(pointer);
29530043Sminshall 		/*
29630043Sminshall 		 * Make sure we are where we think we are.
29730043Sminshall 		 */
29830043Sminshall 	    move(ScreenLine(pointer), ScreenLineOffset(pointer));
29930043Sminshall 
30030043Sminshall 		/* what is the field attribute of the current position */
301*36243Sminshall 	    fieldattr = FieldAttributes(pointer);
302*36243Sminshall 	    DoAttributes(fieldattr);
303*36243Sminshall 	    termattr = TermAttributes(pointer);
304*36243Sminshall 	    DoAttributes(termattr);
30530043Sminshall 
306*36243Sminshall 	    SetHighlightMode(fieldattr);
307*36243Sminshall 	    /*
308*36243Sminshall 	     * The following will terminate at least when we get back
309*36243Sminshall 	     * to the original 'pointer' location (since we force
310*36243Sminshall 	     * things to be equal).
311*36243Sminshall 	     */
312*36243Sminshall 	    for (;;) {
313*36243Sminshall 		if (IsStartField(pointer)) {
314*36243Sminshall 		    shouldbe = DISP_BLANK;
315*36243Sminshall 		    shouldattr = 0;
316*36243Sminshall 		    fieldattr = GetHost(pointer);
317*36243Sminshall 		    DoAttributes(fieldattr);
318*36243Sminshall 		} else {
319*36243Sminshall 		    if (fieldattr&NONDISPLAY) {
320*36243Sminshall 			shouldbe = DISP_BLANK;
321*36243Sminshall 		    } else {
322*36243Sminshall 			shouldbe = GetHost(pointer);
323*36243Sminshall 		    }
324*36243Sminshall 		    shouldattr = fieldattr;
325*36243Sminshall 		}
326*36243Sminshall 		if (TermIsStartField(pointer)) {
327*36243Sminshall 		    is = DISP_BLANK;
328*36243Sminshall 		    isattr = 0;
329*36243Sminshall 		    termattr = GetTerminal(pointer);
330*36243Sminshall 		    DoAttributes(termattr);
331*36243Sminshall 		} else {
332*36243Sminshall 		    if (termattr&NONDISPLAY) {
333*36243Sminshall 			is = DISP_BLANK;
334*36243Sminshall 		    } else {
335*36243Sminshall 			is = GetTerminal(pointer);
336*36243Sminshall 		    }
337*36243Sminshall 		    isattr = termattr;
338*36243Sminshall 		}
339*36243Sminshall 		if ((shouldbe == is) && (shouldattr == isattr)
340*36243Sminshall 			&& (GetHost(pointer) == GetTerminal(pointer))
341*36243Sminshall 			&& (GetHost(ScreenInc(pointer))
342*36243Sminshall 					== GetTerminal(ScreenInc(pointer)))) {
343*36243Sminshall 		    break;
344*36243Sminshall 		}
34530043Sminshall 
346*36243Sminshall 		if (shouldattr^inHighlightMode) {
347*36243Sminshall 		    SetHighlightMode(shouldattr);
348*36243Sminshall 		}
34930043Sminshall 
350*36243Sminshall 		DoCharacterAt(shouldbe, pointer);
35130043Sminshall 		if (IsStartField(pointer)) {
352*36243Sminshall 		    TermNewField(pointer, FieldAttributes(pointer));
35330043Sminshall 		} else {
354*36243Sminshall 		    SetTerminal(pointer, GetHost(pointer));
35530043Sminshall 		}
356*36243Sminshall 		pointer = ScreenInc(pointer);
357*36243Sminshall 		if (!(--columnsleft)) {
358*36243Sminshall 		    DoARefresh();
359*36243Sminshall 		    EmptyTerminal();
360*36243Sminshall 		    if (HaveInput) {	/* if input came in, take it */
361*36243Sminshall 			int c, j;
36230043Sminshall 
363*36243Sminshall 			/*
364*36243Sminshall 			 * We need to start a new terminal field
365*36243Sminshall 			 * at this location iff the terminal attributes
366*36243Sminshall 			 * of this location are not what we have had
367*36243Sminshall 			 * them as (ie: we've overwritten the terminal
368*36243Sminshall 			 * start field, a the previous field had different
369*36243Sminshall 			 * display characteristics).
370*36243Sminshall 			 */
37130043Sminshall 
372*36243Sminshall 			isattr = TermAttributes(pointer);
373*36243Sminshall 			DoAttributes(isattr);
374*36243Sminshall 			if ((!TermIsStartField(pointer)) &&
375*36243Sminshall 					(isattr != termattr)) {
37630043Sminshall 			    /*
377*36243Sminshall 			     * Since we are going to leave a new field
378*36243Sminshall 			     * at this terminal position, we
379*36243Sminshall 			     * need to make sure that we get an actual
380*36243Sminshall 			     * non-highlighted blank on the screen.
38130043Sminshall 			     */
382*36243Sminshall 			    if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) {
383*36243Sminshall 				SetHighlightMode(0);	/* Turn off highlight */
384*36243Sminshall 				c = ScreenInc(pointer);
385*36243Sminshall 				j = DISP_BLANK;
386*36243Sminshall 				DoCharacterAt(j, c);
387*36243Sminshall 			    }
388*36243Sminshall 			    if (termattr&HIGHLIGHT) {
389*36243Sminshall 				termattr = ATTR_DSPD_HIGH;
390*36243Sminshall 			    } else if (termattr&NONDISPLAY) {
391*36243Sminshall 				termattr = ATTR_DSPD_NONDISPLAY;
392*36243Sminshall 			    } else {
393*36243Sminshall 				termattr = 0;
394*36243Sminshall 			    }
395*36243Sminshall 			    TermNewField(pointer, termattr);
396*36243Sminshall 			}
39730043Sminshall 			break;
39830043Sminshall 		    }
399*36243Sminshall 		    move(ScreenLine(pointer), 0);
400*36243Sminshall 		    columnsleft = NumberColumns;
40130043Sminshall 		}
402*36243Sminshall 	    }	/* end of for (;;) */
403*36243Sminshall 	} /* end of while (...) */
40430043Sminshall     }
40530043Sminshall     DoARefresh();
40630043Sminshall     Lowest = pointer;
40730043Sminshall     if (Lowest > Highest) {		/* if we finished input... */
40830043Sminshall 	Lowest = HighestScreen()+1;
40930043Sminshall 	Highest = LowestScreen()-1;
41030043Sminshall 	terminalCursorAddress = CorrectTerminalCursor();
41130043Sminshall 	if (ERR == move(ScreenLine(terminalCursorAddress),
41230043Sminshall 			ScreenLineOffset(terminalCursorAddress))) {
41330043Sminshall 	    GoAway("move", terminalCursorAddress);
41430043Sminshall 	}
41530043Sminshall 	DoARefresh();
41630043Sminshall 	if (needToRing) {
41730043Sminshall 	    StringToTerminal(bellSequence);
41830043Sminshall 	    needToRing = 0;
41930043Sminshall 	}
42030043Sminshall     }
42130043Sminshall     EmptyTerminal();			/* move data along */
42230043Sminshall     return;
42330043Sminshall }
42430043Sminshall 
42530043Sminshall #if	defined(NOT43)
42630043Sminshall static int
42730043Sminshall #else	/* defined(NOT43) */
42830043Sminshall static void
42930043Sminshall #endif	/* defined(NOT43) */
43030043Sminshall FastScreen()
43130043Sminshall {
43231101Sminshall #if	defined(MSDOS)
43330043Sminshall #define	SaveCorner	0
43431101Sminshall #else	/* defined(MSDOS) */
43530043Sminshall #define	SaveCorner	1
43631101Sminshall #endif	/* defined(MSDOS) */
43730043Sminshall 
43830043Sminshall #define	DoAttribute(a) 	    if (IsHighlightedAttr(a)) { \
43930043Sminshall 				standout(); \
44030043Sminshall 			    } else { \
44130043Sminshall 				standend(); \
44230043Sminshall 			    } \
44330043Sminshall 			    if (IsNonDisplayAttr(a)) { \
44430043Sminshall 				a = 0; 	/* zero == don't display */ \
44530043Sminshall 			    } \
44630043Sminshall 			    if (!FormattedScreen()) { \
44730043Sminshall 				a = 1;	/* one ==> do display on unformatted */\
44830043Sminshall 			    }
44930043Sminshall     ScreenImage *p, *upper;
45030043Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
45130043Sminshall 
45230043Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
45330043Sminshall  * only need to go from Lowest to Highest.  However, if we find a
45430043Sminshall  * field in the middle, we do the whole screen.
45530043Sminshall  *
45630043Sminshall  * In particular, we separate out the two cases from the beginning.
45730043Sminshall  */
45830043Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
45930043Sminshall 	register int columnsleft;
46030043Sminshall 
46130043Sminshall 	move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
46230043Sminshall 	p = &Host[Lowest];
46331101Sminshall #if	!defined(MSDOS)
46430043Sminshall 	if (Highest == HighestScreen()) {
46530043Sminshall 	    Highest = ScreenDec(Highest);
46630043Sminshall 	}
46731101Sminshall #endif	/* !defined(MSDOS) */
46830043Sminshall 	upper = &Host[Highest];
46930043Sminshall 	fieldattr = FieldAttributes(Lowest);
47030043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
47130043Sminshall 	columnsleft = NumberColumns-ScreenLineOffset(p-Host);
47230043Sminshall 
47330043Sminshall 	while (p <= upper) {
47430054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
47530043Sminshall 		Highest = HighestScreen();
47630043Sminshall 		Lowest = LowestScreen();
47730043Sminshall 		FastScreen();		/* Recurse */
47830043Sminshall 		return;
47930043Sminshall 	    } else if (fieldattr) {	/* Should we display? */
48031148Sminshall 			    /* Display translated data */
48135423Sminshall 		addch((char)disp_asc[GetTerminalPointer(p)]);
48230043Sminshall 	    } else {
48330043Sminshall 		addch(' ');			/* Display a blank */
48430043Sminshall 	    }
48530043Sminshall 			/* If the physical screen is larger than what we
48630043Sminshall 			 * are using, we need to make sure that each line
48730043Sminshall 			 * starts at the beginning of the line.  Otherwise,
48830043Sminshall 			 * we will just string all the lines together.
48930043Sminshall 			 */
49030043Sminshall 	    p++;
49130043Sminshall 	    if (--columnsleft == 0) {
49230043Sminshall 		int i = p-Host;
49330043Sminshall 
49430043Sminshall 		move(ScreenLine(i), 0);
49530043Sminshall 		columnsleft = NumberColumns;
49630043Sminshall 	    }
49730043Sminshall 	}
49830043Sminshall     } else {		/* Going from Lowest to Highest */
49930043Sminshall 	unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
50030043Sminshall 	ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
50130043Sminshall 	register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
50230043Sminshall 
50330043Sminshall 	*tmpend = 0;		/* terminate from the beginning */
50430043Sminshall 	move(0,0);
50530043Sminshall 	p = Host;
50630043Sminshall 	fieldattr = FieldAttributes(LowestScreen());
50730043Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
50830043Sminshall 
50930043Sminshall 	while (p <= End) {
51030054Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
51130043Sminshall 		if (tmp != tmpbuf) {
51230043Sminshall 		    *tmp++ = 0;			/* close out */
51335423Sminshall 		    addstr((char *)tmpbuf);
51430043Sminshall 		    tmp = tmpbuf;
51530043Sminshall 		    tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host);
51630043Sminshall 		}
51730054Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
51830043Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
51930043Sminshall 		*tmp++ = ' ';
52030043Sminshall 	    } else {
52130043Sminshall 		if (fieldattr) {	/* Should we display? */
52230043Sminshall 				/* Display translated data */
52331148Sminshall 		    *tmp++ = disp_asc[GetTerminalPointer(p)];
52430043Sminshall 		} else {
52530043Sminshall 		    *tmp++ = ' ';
52630043Sminshall 		}
52730043Sminshall 	    }
52830043Sminshall 			/* If the physical screen is larger than what we
52930043Sminshall 			 * are using, we need to make sure that each line
53030043Sminshall 			 * starts at the beginning of the line.  Otherwise,
53130043Sminshall 			 * we will just string all the lines together.
53230043Sminshall 			 */
53330043Sminshall 	    p++;
53430043Sminshall 	    if (tmp == tmpend) {
53530043Sminshall 		int i = p-Host;		/* Be sure the "p++" happened first! */
53630043Sminshall 
53730043Sminshall 		*tmp++ = 0;
53835423Sminshall 		addstr((char *)tmpbuf);
53930043Sminshall 		tmp = tmpbuf;
54030043Sminshall 		move(ScreenLine(i), 0);
54130043Sminshall 		tmpend = tmpbuf + NumberColumns;
54230043Sminshall 	    }
54330043Sminshall 	}
54430043Sminshall 	if (tmp != tmpbuf) {
54530043Sminshall 	    *tmp++ = 0;
54635423Sminshall 	    addstr((char *)tmpbuf);
54730043Sminshall 	    tmp = tmpbuf;
54830043Sminshall 	}
54930043Sminshall     }
55030043Sminshall     Lowest = HighestScreen()+1;
55130043Sminshall     Highest = LowestScreen()-1;
55230043Sminshall     terminalCursorAddress = CorrectTerminalCursor();
55330043Sminshall     if (ERR == move(ScreenLine(terminalCursorAddress),
55430043Sminshall 		    ScreenLineOffset(terminalCursorAddress))) {
55530043Sminshall 	GoAway("move", terminalCursorAddress);
55630043Sminshall     }
55730043Sminshall     DoARefresh();
55830043Sminshall     if (needToRing) {
55930043Sminshall 	StringToTerminal(bellSequence);
56030043Sminshall 	needToRing = 0;
56130043Sminshall     }
56230043Sminshall     EmptyTerminal();			/* move data along */
56330043Sminshall     return;
56430043Sminshall }
56530043Sminshall 
56630043Sminshall 
56730043Sminshall /* TryToSend - send data out to user's terminal */
56830043Sminshall 
56930043Sminshall #if	defined(NOT43)
57030043Sminshall int
57130043Sminshall #else	/* defined(NOT43) */
57230043Sminshall void
57330043Sminshall #endif	/* defined(NOT43) */
57430043Sminshall 	(*TryToSend)() = FastScreen;
57530043Sminshall 
57635423Sminshall /*ARGSUSED*/
57731127Sminshall void
57831127Sminshall ScreenOIA(oia)
57931127Sminshall OIA *oia;
58031127Sminshall {
58131127Sminshall }
58231127Sminshall 
58331127Sminshall 
58430328Sminshall /* InitTerminal - called to initialize the screen, etc. */
58530043Sminshall 
58630043Sminshall void
58730328Sminshall InitTerminal()
58830043Sminshall {
58930043Sminshall #if defined(unix)
59030043Sminshall     struct sgttyb ourttyb;
59130043Sminshall     static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
59230043Sminshall 		2400, 4800, 9600 };
59330043Sminshall #endif
59435423Sminshall     extern void InitMapping();
59530043Sminshall 
59630328Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
59730043Sminshall     if (!screenInitd) { 	/* not initialized */
59830043Sminshall #if	defined(unix)
59930043Sminshall 	char KSEbuffer[2050];
60030043Sminshall 	char *lotsofspace = KSEbuffer;
60130043Sminshall 	extern int abort();
60230043Sminshall 	extern char *tgetstr();
60330043Sminshall #endif	/* defined(unix) */
60430043Sminshall 
60534294Sminshall 	if (initscr() == ERR) {	/* Initialize curses to get line size */
60634294Sminshall 	    ExitString("InitTerminal:  Error initializing curses", 1);
60734294Sminshall 	    /*NOTREACHED*/
60834294Sminshall 	}
60934294Sminshall 	MaxNumberLines = LINES;
61034294Sminshall 	MaxNumberColumns = COLS;
61131101Sminshall 	ClearArray(Terminal);
61230328Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
61330043Sminshall #if defined(unix)
61430043Sminshall 	signal(SIGHUP, abort);
61530043Sminshall #endif
61630043Sminshall 
61730043Sminshall 	TryToSend = FastScreen;
61831559Sminshall #if defined(unix)
61930043Sminshall 	ioctl(1, TIOCGETP, (char *) &ourttyb);
62030043Sminshall 	if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) {
62130043Sminshall 	    max_changes_before_poll = 1920;
62230043Sminshall 	} else {
62330043Sminshall 	    max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10;
62430043Sminshall 	    if (max_changes_before_poll < 40) {
62530043Sminshall 		max_changes_before_poll = 40;
62630043Sminshall 	    }
62730043Sminshall 	    TryToSend = SlowScreen;
62830043Sminshall 	    HaveInput = 1;		/* get signals going */
62930043Sminshall 	}
63031559Sminshall #endif	/* defined(unix) */
63130043Sminshall 	setcommandmode();
63230043Sminshall 	/*
63330043Sminshall 	 * By now, initscr() (in curses) has been called (from telnet.c),
63430043Sminshall 	 * and the screen has been initialized.
63530043Sminshall 	 */
63630043Sminshall #if defined(unix)
63730043Sminshall 	nonl();
63830043Sminshall 			/* the problem is that curses catches SIGTSTP to
63930043Sminshall 			 * be nice, but it messes us up.
64030043Sminshall 			 */
64130043Sminshall 	signal(SIGTSTP, SIG_DFL);
64234315Sminshall 	if ((myKS = tgetstr("ks", &lotsofspace)) != 0) {
64334315Sminshall 	    myKS = strsave(myKS);
64434315Sminshall 	    StringToTerminal(myKS);
64530043Sminshall 	}
64634315Sminshall 	if ((myKE = tgetstr("ke", &lotsofspace)) != 0) {
64734315Sminshall 	    myKE = strsave(myKE);
64830043Sminshall 	}
64930043Sminshall 	if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
65030043Sminshall 	   SO = strsave(tgetstr("md", &lotsofspace));
65130043Sminshall 	   SE = strsave(tgetstr("me", &lotsofspace));
65230043Sminshall 	}
65330043Sminshall #endif
65430043Sminshall 	DoARefresh();
65530043Sminshall 	setconnmode();
65630043Sminshall 	if (VB && *VB) {
65730043Sminshall 	    bellSequence = VB;		/* use visual bell */
65830043Sminshall 	}
65930043Sminshall 	screenInitd = 1;
66030043Sminshall 	screenStopped = 0;		/* Not stopped */
66130043Sminshall     }
66230043Sminshall }
66330043Sminshall 
66430043Sminshall 
66530043Sminshall /* StopScreen - called when we are going away... */
66630043Sminshall 
66730043Sminshall void
66830043Sminshall StopScreen(doNewLine)
66930043Sminshall int doNewLine;
67030043Sminshall {
67130043Sminshall     if (screenInitd && !screenStopped) {
67230043Sminshall 	move(NumberLines-1, 1);
67330043Sminshall 	standend();
67430043Sminshall 	inHighlightMode = 0;
67530043Sminshall 	DoARefresh();
67630043Sminshall 	setcommandmode();
67730043Sminshall 	endwin();
67830043Sminshall 	setconnmode();
67930043Sminshall #if	defined(unix)
68034315Sminshall 	if (myKE) {
68134315Sminshall 	    StringToTerminal(myKE);
68230043Sminshall 	}
68330043Sminshall #endif	/* defined(unix) */
68430043Sminshall 	if (doNewLine) {
68530043Sminshall 	    StringToTerminal("\r\n");
68630043Sminshall 	}
68730043Sminshall 	EmptyTerminal();
68830043Sminshall 	screenStopped = 1;		/* This is stopped */
68930043Sminshall     }
69030043Sminshall }
69130043Sminshall 
69230043Sminshall 
69330043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
69430043Sminshall 
69530043Sminshall void
69630043Sminshall RefreshScreen()
69730043Sminshall {
69830043Sminshall     clearok(curscr, TRUE);
69930043Sminshall     (*TryToSend)();
70030043Sminshall }
70130043Sminshall 
70230043Sminshall 
70330043Sminshall /* ConnectScreen - called to reconnect to the screen */
70430043Sminshall 
70530043Sminshall void
70630043Sminshall ConnectScreen()
70730043Sminshall {
70830043Sminshall     if (screenInitd) {
70930043Sminshall #if	defined(unix)
71034315Sminshall 	if (myKS) {
71134315Sminshall 	    StringToTerminal(myKS);
71230043Sminshall 	}
71330043Sminshall #endif	/* defined(unix) */
71430043Sminshall 	RefreshScreen();
71530043Sminshall 	(*TryToSend)();
71630043Sminshall 	screenStopped = 0;
71730043Sminshall     }
71830043Sminshall }
71930043Sminshall 
72030043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
72130043Sminshall 
72230043Sminshall void
72330043Sminshall LocalClearScreen()
72430043Sminshall {
72535423Sminshall     extern void Clear3270();
72635423Sminshall 
72730043Sminshall     outputPurge();		/* flush all data to terminal */
72830043Sminshall     clear();			/* clear in curses */
72931101Sminshall     ClearArray(Terminal);
73030043Sminshall     Clear3270();
73130043Sminshall     Lowest = HighestScreen()+1; /* everything in sync... */
73230043Sminshall     Highest = LowestScreen()+1;
73330043Sminshall }
73430043Sminshall 
73530043Sminshall 
73630043Sminshall void
73730043Sminshall BellOff()
73830043Sminshall {
73930043Sminshall     if (bellwinup) {
74030043Sminshall 	delwin(bellwin);
74130043Sminshall 	bellwin = 0;
74230043Sminshall 	bellwinup = 0;
74330043Sminshall 	touchwin(stdscr);
74430043Sminshall 	DoARefresh();
74530043Sminshall     }
74630043Sminshall }
74730043Sminshall 
74830043Sminshall 
74930043Sminshall void
75030043Sminshall RingBell(s)
75130043Sminshall char *s;
75230043Sminshall {
75330043Sminshall     needToRing = 1;
75430043Sminshall     if (s) {
75530043Sminshall 	int len = strlen(s);
75630043Sminshall 
75730043Sminshall 	if (len > COLS-2) {
75830043Sminshall 	    len = COLS-2;
75930043Sminshall 	}
76030043Sminshall 	if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
76135423Sminshall 	    OurExitString("Error from newwin in RingBell", 1);
76230043Sminshall 	}
76330043Sminshall 	werase(bellwin);
76430043Sminshall 	wstandout(bellwin);
76530043Sminshall 	box(bellwin, '|', '-');
76630043Sminshall 	if (wmove(bellwin, 1, 1) == ERR) {
76735423Sminshall 	    OurExitString("Error from wmove in RingBell", 1);
76830043Sminshall 	}
76930043Sminshall 	while (len--) {
77030043Sminshall 	    if (waddch(bellwin, *s++) == ERR) {
77135423Sminshall 		OurExitString("Error from waddch in RingBell", 1);
77230043Sminshall 	    }
77330043Sminshall 	}
77430043Sminshall 	wstandend(bellwin);
77530043Sminshall 	if (wrefresh(bellwin) == ERR) {
77635423Sminshall 	    OurExitString("Error from wrefresh in RingBell", 1);
77730043Sminshall 	}
77830043Sminshall 	bellwinup = 1;
77930043Sminshall     }
78030043Sminshall }
78130043Sminshall 
78230043Sminshall 
78330043Sminshall /* returns a 1 if no more output available (so, go ahead and block),
78430043Sminshall     or a 0 if there is more output available (so, just poll the other
78530043Sminshall     sources/destinations, don't block).
78630043Sminshall  */
78730043Sminshall 
78830043Sminshall int
78930043Sminshall DoTerminalOutput()
79030043Sminshall {
79130043Sminshall 	/* called just before a select to conserve IO to terminal */
79231462Sminshall     if (!(screenInitd||screenStopped)) {
79330369Sminshall 	return 1;		/* No output if not initialized */
79430369Sminshall     }
79530369Sminshall     if ((Lowest <= Highest) || needToRing ||
79630369Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
79730043Sminshall 	(*TryToSend)();
79830043Sminshall     }
79930043Sminshall     if (Lowest > Highest) {
80030369Sminshall 	return 1;		/* no more output now */
80130043Sminshall     } else {
80230369Sminshall 	return 0;		/* more output for future */
80330043Sminshall     }
80430043Sminshall }
80530074Sminshall 
80630074Sminshall /*
80730074Sminshall  * The following are defined to handle transparent data.
80830074Sminshall  */
80930074Sminshall 
81030074Sminshall void
81130074Sminshall TransStop()
81230074Sminshall {
81330074Sminshall #if	defined(unix)
81430074Sminshall     if (tcflag == 0) {
81530074Sminshall        tcflag = -1;
81630074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
81730074Sminshall     } else if (tcflag > 0) {
81830074Sminshall        setcommandmode();
81930074Sminshall        (void) close(tin);
82030074Sminshall        (void) close(tout);
82130074Sminshall        tin = savefd[0];
82230074Sminshall        tout = savefd[1];
82330074Sminshall        setconnmode();
82430074Sminshall        tcflag = -1;
82530074Sminshall        (void) signal(SIGCHLD, SIG_DFL);
82630074Sminshall     }
82730074Sminshall #endif	/* defined(unix) */
82830074Sminshall     RefreshScreen();
82930074Sminshall }
83030074Sminshall 
83130074Sminshall void
83231863Sminshall TransOut(buffer, count, kind, control)
83330074Sminshall unsigned char	*buffer;
83430074Sminshall int		count;
83531863Sminshall int		kind;		/* 0 or 5 */
83631863Sminshall int		control;	/* To see if we are done */
83730074Sminshall {
83830074Sminshall #if	defined(unix)
83930074Sminshall     extern char *transcom;
84035423Sminshall     int inpipefd[2], outpipefd[2];
84130074Sminshall     void aborttc();
84230074Sminshall #endif	/* defined(unix) */
84330074Sminshall 
84430074Sminshall     while (DoTerminalOutput() == 0) {
84530074Sminshall #if defined(unix)
84630074Sminshall 	HaveInput = 0;
84730074Sminshall #endif /* defined(unix) */
84830074Sminshall     }
84930074Sminshall #if	defined(unix)
85030074Sminshall     if (transcom && tcflag == -1) {
85130074Sminshall        while (1) {			  /* go thru once */
85230074Sminshall 	     if (pipe(outpipefd) < 0) {
85330074Sminshall 		break;
85430074Sminshall 	     }
85530074Sminshall 	     if (pipe(inpipefd) < 0) {
85630074Sminshall 		break;
85730074Sminshall 	     }
85830074Sminshall 	     if ((tcflag = fork()) == 0) {
85930074Sminshall 		(void) close(outpipefd[1]);
86030074Sminshall 		(void) close(0);
86130074Sminshall 		if (dup(outpipefd[0]) < 0) {
86230074Sminshall 		   exit(1);
86330074Sminshall 		}
86430074Sminshall 		(void) close(outpipefd[0]);
86530074Sminshall 		(void) close(inpipefd[0]);
86630074Sminshall 		(void) close(1);
86730074Sminshall 		if (dup(inpipefd[1]) < 0) {
86830074Sminshall 		   exit(1);
86930074Sminshall 		}
87030074Sminshall 		(void) close(inpipefd[1]);
87130074Sminshall 		if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
87230074Sminshall 		    exit(1);
87330074Sminshall 		}
87430074Sminshall 	     }
87530074Sminshall 	     (void) close(inpipefd[1]);
87630074Sminshall 	     (void) close(outpipefd[0]);
87730074Sminshall 	     savefd[0] = tin;
87830074Sminshall 	     savefd[1] = tout;
87930074Sminshall 	     setcommandmode();
88030074Sminshall 	     tin = inpipefd[0];
88130074Sminshall 	     tout = outpipefd[1];
88235423Sminshall 	     (void) signal(SIGCHLD, (int (*)())aborttc);
88330074Sminshall 	     setconnmode();
88430074Sminshall 	     tcflag = 1;
88530074Sminshall 	     break;
88630074Sminshall        }
88730074Sminshall        if (tcflag < 1) {
88830074Sminshall 	  tcflag = 0;
88930074Sminshall        }
89030074Sminshall     }
89130074Sminshall #endif	/* defined(unix) */
89235423Sminshall     (void) DataToTerminal((char *)buffer, count);
89331863Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
89431863Sminshall 	SendToIBM();
89531863Sminshall     } else {
89635423Sminshall 	extern void TransInput();
89735423Sminshall 
89831863Sminshall 	TransInput(1, kind);			/* Go get some data */
89931863Sminshall     }
90030074Sminshall }
90130074Sminshall 
90230074Sminshall 
90330074Sminshall #if	defined(unix)
90430074Sminshall static void
90530074Sminshall aborttc()
90630074Sminshall {
90730074Sminshall 	setcommandmode();
90830074Sminshall 	(void) close(tin);
90930074Sminshall 	(void) close(tout);
91030074Sminshall 	tin = savefd[0];
91130074Sminshall 	tout = savefd[1];
91230074Sminshall 	setconnmode();
91330074Sminshall 	tcflag = 0;
91430074Sminshall }
91530074Sminshall #endif	/* defined(unix) */
916