148757Sbostic /*-
2*62343Sbostic  * Copyright (c) 1988, 1993
3*62343Sbostic  *	The Regents of the University of California.  All rights reserved.
431105Sminshall  *
548757Sbostic  * %sccs.include.redist.c%
631105Sminshall  */
731105Sminshall 
831105Sminshall #ifndef lint
9*62343Sbostic static char sccsid[] = "@(#)termout.c	8.1 (Berkeley) 06/06/93";
1033814Sbostic #endif /* not lint */
1131105Sminshall 
1231105Sminshall #include <stdio.h>
1331120Sminshall #include <dos.h>
1431185Sminshall #include "../general/general.h"
1531105Sminshall 
1631105Sminshall #include "../telnet.ext"
1731105Sminshall 
1831881Sminshall #include "../api/disp_asc.h"
1931225Sminshall #include "../ascii/map3270.ext"
2031225Sminshall 
2131105Sminshall #include "../ctlr/hostctlr.h"
2235424Sminshall #include "../ctlr/externs.h"
2335424Sminshall #include "../ctlr/declare.h"
2431117Sminshall #include "../ctlr/oia.h"
2531105Sminshall #include "../ctlr/screen.h"
2631105Sminshall 
2731185Sminshall #include "../general/globals.h"
2831105Sminshall 
2931120Sminshall #include "video.h"
3031120Sminshall 
3131105Sminshall extern void EmptyTerminal();
3231105Sminshall 
3331105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
3431105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
3531105Sminshall 
3631105Sminshall 
3731105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
3831105Sminshall static int screenInitd; 		/* the screen has been initialized */
3931105Sminshall static int screenStopped;		/* the screen has been stopped */
4031105Sminshall 
4131105Sminshall static int needToRing;			/* need to ring terinal bell */
4231105Sminshall 
4331117Sminshall typedef struct {
4431117Sminshall     char
4531117Sminshall 	data,		/* The data for this position */
4631117Sminshall 	attr;		/* The attributes for this position */
4731117Sminshall } ScreenBuffer;
4831105Sminshall 
4931117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
5031120Sminshall ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
5131105Sminshall 
5231105Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
5331105Sminshall 
5431105Sminshall static void
OurExitString(file,string,value)5531105Sminshall OurExitString(file, string, value)
5631105Sminshall FILE	*file;
5731105Sminshall char	*string;
5831105Sminshall int	value;
5931105Sminshall {
6031105Sminshall     static int recursion = 0;
6131105Sminshall 
6231105Sminshall     if (!recursion) {
6331105Sminshall 	recursion = 1;
6431105Sminshall 	ExitString(file, string, value);
6531105Sminshall     }
6631105Sminshall }
6731105Sminshall 
6831105Sminshall 
6931105Sminshall static void
GoAway(from,where)7031105Sminshall GoAway(from, where)
7131105Sminshall char *from;		/* routine that gave error */
7231105Sminshall int	where;		/* cursor address */
7331105Sminshall {
7431105Sminshall 	char foo[100];
7531105Sminshall 
7631105Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
7731105Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
7831105Sminshall 	OurExitString(stderr, foo, 1);
7931105Sminshall 	/* NOTREACHED */
8031105Sminshall }
8131105Sminshall 
8231120Sminshall /*
8331120Sminshall  * Routines to deal with the screen.  These routines are lifted
8431120Sminshall  * from mskermit.
8531120Sminshall  */
8631120Sminshall 
8731120Sminshall #define	CRT_STATUS	0x3da		/* Color card */
8831120Sminshall #define	DISPLAY_ENABLE	0x08		/* Enable */
8931120Sminshall #define	scrseg()	((crt_mode == 7)? 0xb000 : 0xb800)
9031120Sminshall #define	scrwait()	if (crt_mode != 7) { \
9131120Sminshall 			    while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
9231120Sminshall 				; \
9331120Sminshall 			    } \
9431120Sminshall 			}
9531120Sminshall static int
9631120Sminshall     		crt_mode,
9731120Sminshall 		crt_cols,
9831120Sminshall 		crt_lins,
9931120Sminshall 		curpage;
10031120Sminshall 
10131120Sminshall /*
10231120Sminshall  * Set the cursor position to where it belongs.
10331120Sminshall  */
10431120Sminshall 
10531105Sminshall static void
setcursor(row,column,page)10631120Sminshall setcursor(row, column, page)
10731120Sminshall int
10831120Sminshall     row,
10931120Sminshall     column,
11031120Sminshall     page;
11131120Sminshall {
11231120Sminshall     union REGS inregs, outregs;
11331120Sminshall 
11431120Sminshall     inregs.h.dh = row;
11531120Sminshall     inregs.h.dl = column;
11631120Sminshall     inregs.h.bh = page;
11731120Sminshall     inregs.h.ah = SetCursorPosition;
11831120Sminshall 
11931120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
12031120Sminshall }
12131120Sminshall /*
12231120Sminshall  * Read the state of the video system.  Put the cursor somewhere
12331120Sminshall  * reasonable.
12431120Sminshall  */
12531120Sminshall 
12631120Sminshall static void
scrini()12731120Sminshall scrini()
12831120Sminshall {
12931120Sminshall     union REGS inregs, outregs;
13031120Sminshall 
13131120Sminshall     inregs.h.ah = CurrentVideoState;
13231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
13331120Sminshall 
13431120Sminshall     crt_mode = outregs.h.al;
13531120Sminshall     crt_cols = outregs.h.ah;
13631120Sminshall     crt_lins = 25;
13731120Sminshall     curpage = outregs.h.bh;
13831120Sminshall 
13931120Sminshall     inregs.h.ah = ReadCursorPosition;
14031120Sminshall     inregs.h.bh = curpage;
14131120Sminshall 
14231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
14331120Sminshall 
14431120Sminshall     if (outregs.h.dh > crt_lins) {
14531120Sminshall 	outregs.h.dh = crt_lins;
14631120Sminshall     }
14731120Sminshall     if (outregs.h.dl > crt_cols) {
14831120Sminshall 	outregs.h.dl = crt_cols;
14931120Sminshall     }
15031120Sminshall     inregs.h.dh = outregs.h.dh;
15131120Sminshall     inregs.h.dl = outregs.h.dl;
15231120Sminshall     inregs.h.bh = curpage;
15331120Sminshall 
15431120Sminshall     inregs.h.ah = SetCursorPosition;
15531120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
15631120Sminshall }
15731120Sminshall 
15831120Sminshall 
15931120Sminshall static void
scrwrite(source,length,offset)16031120Sminshall scrwrite(source, length, offset)
16131120Sminshall ScreenBuffer *source;
16231120Sminshall int
16331120Sminshall 	length,
16431120Sminshall 	offset;
16531120Sminshall {
16631120Sminshall     struct SREGS segregs;
16731120Sminshall 
16831120Sminshall     segread(&segregs);		/* read the current segment register */
16931120Sminshall 
17031120Sminshall     scrwait();
17131154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
17231154Sminshall 						sizeof *source*length);
17331120Sminshall }
17431120Sminshall 
17531120Sminshall static void
scrsave(buffer)17631120Sminshall scrsave(buffer)
17731120Sminshall ScreenBuffer *buffer;
17831120Sminshall {
17931120Sminshall     struct SREGS segregs;
18031120Sminshall 
18131120Sminshall     segread(&segregs);		/* read the current segment register */
18231120Sminshall 
18331120Sminshall     scrwait();
18431154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
18531120Sminshall }
18631120Sminshall 
18731120Sminshall static void
scrrest(buffer)18831120Sminshall scrrest(buffer)
18931120Sminshall ScreenBuffer *buffer;
19031120Sminshall {
19131154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
19231120Sminshall }
19331120Sminshall 
19431120Sminshall static void
TryToSend()19531117Sminshall TryToSend()
19631105Sminshall {
19731154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
19831117Sminshall #define	NORMAL		0x02	/* Normal mode */
19931154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
20031105Sminshall 
20131154Sminshall #define	DoAttribute(a) 	    \
20231154Sminshall 			    if (screenIsFormatted) { \
20331154Sminshall 				if (IsNonDisplayAttr(a)) { \
20431154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
20531154Sminshall 				} else if (IsHighlightedAttr(a)) { \
20631154Sminshall 				    a = STANDOUT; \
20731154Sminshall 				} else { \
20831154Sminshall 				    a = NORMAL; \
20931154Sminshall 				} \
21031154Sminshall 			    } else  { \
21131154Sminshall 				a = NORMAL;	/* do display on unformatted */\
21231105Sminshall 			    }
21331105Sminshall     ScreenImage *p, *upper;
21431117Sminshall     ScreenBuffer *sp;
21531105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
21631154Sminshall     int screenIsFormatted = FormattedScreen();
21731105Sminshall 
21831105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
21931105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
22031105Sminshall  * field in the middle, we do the whole screen.
22131105Sminshall  *
22231105Sminshall  * In particular, we separate out the two cases from the beginning.
22331105Sminshall  */
22431105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
22531117Sminshall 	sp = &Screen[Lowest];
22631105Sminshall 	p = &Host[Lowest];
22731105Sminshall 	upper = &Host[Highest];
22831105Sminshall 	fieldattr = FieldAttributes(Lowest);
22931105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
23031105Sminshall 
23131105Sminshall 	while (p <= upper) {
23231105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
23331105Sminshall 		Highest = HighestScreen();
23431105Sminshall 		Lowest = LowestScreen();
23531117Sminshall 		TryToSend();		/* Recurse */
23631105Sminshall 		return;
23731105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
23831154Sminshall 				/* Display translated data */
23931154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
24031105Sminshall 	    } else {
24131117Sminshall 		sp->data = ' ';
24231105Sminshall 	    }
24331154Sminshall 	    sp->attr = fieldattr;
24431105Sminshall 	    p++;
24531117Sminshall 	    sp++;
24631105Sminshall 	}
24731105Sminshall     } else {		/* Going from Lowest to Highest */
24831117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
24931105Sminshall 
25031117Sminshall 	sp = Screen;
25131105Sminshall 	p = Host;
25231105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
25331105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
25431105Sminshall 
25531105Sminshall 	while (p <= End) {
25631105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
25731105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
25831105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
25931154Sminshall 	    }
26031154Sminshall 	    if (fieldattr) {	/* Should we display? */
26131154Sminshall 			    /* Display translated data */
26231154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
26331105Sminshall 	    } else {
26431154Sminshall 		sp->data = ' ';
26531105Sminshall 	    }
26631154Sminshall 	    sp->attr = fieldattr;
26731105Sminshall 	    p++;
26831117Sminshall 	    sp++;
26931105Sminshall 	}
27031105Sminshall     }
27131117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
27231154Sminshall     /*
27331154Sminshall      * We might be here just to update the cursor address.
27431154Sminshall      */
27531154Sminshall     if (Highest >= Lowest) {
27631154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
27731154Sminshall     }
27831120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
27931117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
28031105Sminshall     Lowest = HighestScreen()+1;
28131105Sminshall     Highest = LowestScreen()-1;
28231105Sminshall     if (needToRing) {
28331117Sminshall 	DataToTerminal("\7", 1);
28431105Sminshall 	needToRing = 0;
28531105Sminshall     }
28631105Sminshall     return;
28731105Sminshall }
28831105Sminshall 
28931105Sminshall /* InitTerminal - called to initialize the screen, etc. */
29031105Sminshall 
29131105Sminshall void
InitTerminal()29231105Sminshall InitTerminal()
29331105Sminshall {
29431105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
29531105Sminshall     if (!screenInitd) { 	/* not initialized */
29631129Sminshall 	MaxNumberLines = 24;	/* XXX */
29731129Sminshall 	MaxNumberColumns = 80;	/* XXX */
29831117Sminshall 	scrini();
29931120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
30031117Sminshall 	ClearArray(Screen);
30131105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
30231105Sminshall 	screenInitd = 1;
30331105Sminshall 	screenStopped = 0;		/* Not stopped */
30431105Sminshall     }
30531105Sminshall }
30631105Sminshall 
30731105Sminshall 
30831105Sminshall /* StopScreen - called when we are going away... */
30931105Sminshall 
31031105Sminshall void
StopScreen(doNewLine)31131105Sminshall StopScreen(doNewLine)
31231105Sminshall int doNewLine;
31331105Sminshall {
31431105Sminshall     if (screenInitd && !screenStopped) {
31531120Sminshall 	scrrest(saveScreen);
31631208Sminshall 	setcursor(NumberLines-1, 1, 0);
31731208Sminshall 	if (doNewLine) {
31831208Sminshall 	    StringToTerminal("\r\n");
31931208Sminshall 	}
32031208Sminshall 	EmptyTerminal();
32131208Sminshall 	screenStopped = 1;
32231105Sminshall     }
32331105Sminshall }
32431105Sminshall 
32531105Sminshall 
32631105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
32731105Sminshall 
32831105Sminshall void
RefreshScreen()32931105Sminshall RefreshScreen()
33031105Sminshall {
33131117Sminshall     Highest = HighestScreen();
33231117Sminshall     Lowest = LowestScreen();
33331117Sminshall     TryToSend();
33431105Sminshall }
33531105Sminshall 
33631105Sminshall 
33731105Sminshall /* ConnectScreen - called to reconnect to the screen */
33831105Sminshall 
33931105Sminshall void
ConnectScreen()34031105Sminshall ConnectScreen()
34131105Sminshall {
34231105Sminshall     if (screenInitd) {
34331105Sminshall 	RefreshScreen();
34431105Sminshall 	screenStopped = 0;
34531105Sminshall     }
34631105Sminshall }
34731105Sminshall 
34831105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
34931105Sminshall 
35031105Sminshall void
LocalClearScreen()35131105Sminshall LocalClearScreen()
35231105Sminshall {
35331105Sminshall     Clear3270();
35431117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
35531117Sminshall     Highest = HighestScreen();
35631117Sminshall     TryToSend();
35731105Sminshall }
35831117Sminshall 
35931117Sminshall /*
36031117Sminshall  * Implement the bell/error message function.
36131117Sminshall  */
36231105Sminshall 
36331117Sminshall int
36431117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
36531117Sminshall static int
36631883Sminshall 	bell_len = 0;		/* Length of error message */
36731105Sminshall 
36831117Sminshall 
36931105Sminshall void
BellOff()37031105Sminshall BellOff()
37131105Sminshall {
37231883Sminshall     ScreenBuffer a[100];
37331883Sminshall     int i;
37431883Sminshall 
37531105Sminshall     if (bellwinup) {
37631883Sminshall 	unsigned char blank = ' ';
37731883Sminshall 
37831883Sminshall 	for (i = 0; i < bell_len; i++) {
37931883Sminshall 	    a[i].attr = NORMAL;
38031883Sminshall 	    a[i].data = ' ';
38131883Sminshall 	}
38231105Sminshall     }
38331883Sminshall     scrwrite(a, bell_len, 24*80);		/* XXX */
38431105Sminshall }
38531105Sminshall 
38631105Sminshall 
38731105Sminshall void
RingBell(s)38831105Sminshall RingBell(s)
38931105Sminshall char *s;
39031105Sminshall {
39131105Sminshall     needToRing = 1;
39231105Sminshall     if (s) {
39331883Sminshall 	int i;
39431883Sminshall 	ScreenBuffer bellstring[100];
39531105Sminshall 
39631883Sminshall 	bell_len = strlen(s);
39731883Sminshall 	bellwinup = 1;
39831883Sminshall 	if (bell_len > sizeof bellstring-1) {
39931117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
40031105Sminshall 	}
40131883Sminshall 	for (i = 0; i < bell_len; i++) {
40231883Sminshall 	    bellstring[i].attr = STANDOUT;
40331883Sminshall 	    bellstring[i].data = s[i];
40431883Sminshall 	}
40531883Sminshall 	scrwrite(bellstring, bell_len, 24*80);		/* XXX */
40631105Sminshall     }
40731105Sminshall }
40831105Sminshall 
40931117Sminshall /*
41031117Sminshall  * Update the OIA area.
41131117Sminshall  */
41231105Sminshall 
41331117Sminshall void
ScreenOIA(oia)41431117Sminshall ScreenOIA(oia)
41531117Sminshall OIA *oia;
41631117Sminshall {
41731117Sminshall }
41831117Sminshall 
41931117Sminshall 
42031105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
42131105Sminshall     or a 0 if there is more output available (so, just poll the other
42231105Sminshall     sources/destinations, don't block).
42331105Sminshall  */
42431105Sminshall 
42531105Sminshall int
DoTerminalOutput()42631105Sminshall DoTerminalOutput()
42731105Sminshall {
42831105Sminshall 	/* called just before a select to conserve IO to terminal */
42931490Sminshall     if (!(screenInitd||screenStopped)) {
43031105Sminshall 	return 1;		/* No output if not initialized */
43131105Sminshall     }
43231105Sminshall     if ((Lowest <= Highest) || needToRing ||
43331105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
43431117Sminshall 	TryToSend();
43531105Sminshall     }
43631105Sminshall     if (Lowest > Highest) {
43731105Sminshall 	return 1;		/* no more output now */
43831105Sminshall     } else {
43931105Sminshall 	return 0;		/* more output for future */
44031105Sminshall     }
44131105Sminshall }
44231105Sminshall 
44331105Sminshall /*
44431105Sminshall  * The following are defined to handle transparent data.
44531105Sminshall  */
44631105Sminshall 
44731105Sminshall void
TransStop()44831105Sminshall TransStop()
44931105Sminshall {
45031105Sminshall     RefreshScreen();
45131105Sminshall }
45231105Sminshall 
45331105Sminshall void
TransOut(buffer,count,kind,control)45431885Sminshall TransOut(buffer, count, kind, control)
45531105Sminshall unsigned char	*buffer;
45631105Sminshall int		count;
45731885Sminshall int		kind;		/* 0 or 5 */
45831885Sminshall int		control;	/* To see if we are done */
45931105Sminshall {
46031885Sminshall     char *ptr;
46131105Sminshall 
46231105Sminshall     while (DoTerminalOutput() == 0) {
46331117Sminshall 	;
46431105Sminshall     }
46531885Sminshall     for (ptr = buffer; ptr < buffer+count; ptr++) {
46631885Sminshall 	*ptr &= 0x7f;		/* Turn off parity bit */
46731885Sminshall     }
46831105Sminshall     (void) DataToTerminal(buffer, count);
46931885Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
47031885Sminshall 	SendToIBM();
47131885Sminshall     } else {
47231885Sminshall 	TransInput(1, kind);			/* Go get some data */
47331885Sminshall     }
47431105Sminshall }
47531117Sminshall 
47631117Sminshall /*
47731117Sminshall  * init_screen()
47831117Sminshall  *
47931117Sminshall  * Initialize variables used by screen.
48031117Sminshall  */
48131105Sminshall 
48231117Sminshall void
init_screen()48331117Sminshall init_screen()
48431105Sminshall {
48531117Sminshall     bellwinup = 0;
48631117Sminshall }
48731105Sminshall 
48831117Sminshall 
489