131105Sminshall /*
2*33814Sbostic  * Copyright (c) 1988 Regents of the University of California.
3*33814Sbostic  * All rights reserved.
431105Sminshall  *
5*33814Sbostic  * Redistribution and use in source and binary forms are permitted
6*33814Sbostic  * provided that this notice is preserved and that due credit is given
7*33814Sbostic  * to the University of California at Berkeley. The name of the University
8*33814Sbostic  * may not be used to endorse or promote products derived from this
9*33814Sbostic  * software without specific prior written permission. This software
10*33814Sbostic  * is provided ``as is'' without express or implied warranty.
1131105Sminshall  */
1231105Sminshall 
1331105Sminshall #ifndef lint
14*33814Sbostic static char sccsid[] = "@(#)termout.c	3.2 (Berkeley) 03/28/88";
15*33814Sbostic #endif /* not lint */
1631105Sminshall 
1731105Sminshall #include <stdio.h>
1831120Sminshall #include <dos.h>
1931185Sminshall #include "../general/general.h"
2031105Sminshall 
2131105Sminshall #include "../telnet.ext"
2231105Sminshall 
2331881Sminshall #include "../api/disp_asc.h"
2431225Sminshall #include "../ascii/map3270.ext"
2531225Sminshall 
2631105Sminshall #include "../ctlr/hostctlr.h"
2731105Sminshall #include "../ctlr/inbound.ext"
2831117Sminshall #include "../ctlr/oia.h"
2931105Sminshall #include "../ctlr/options.ext"
3031105Sminshall #include "../ctlr/outbound.ext"
3131105Sminshall #include "../ctlr/screen.h"
3231105Sminshall 
3331185Sminshall #include "../general/globals.h"
3431105Sminshall 
3531120Sminshall #include "video.h"
3631120Sminshall 
3731105Sminshall extern void EmptyTerminal();
3831105Sminshall 
3931105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
4031105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
4131105Sminshall 
4231105Sminshall 
4331105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
4431105Sminshall static int screenInitd; 		/* the screen has been initialized */
4531105Sminshall static int screenStopped;		/* the screen has been stopped */
4631105Sminshall 
4731105Sminshall static int needToRing;			/* need to ring terinal bell */
4831105Sminshall 
4931117Sminshall typedef struct {
5031117Sminshall     char
5131117Sminshall 	data,		/* The data for this position */
5231117Sminshall 	attr;		/* The attributes for this position */
5331117Sminshall } ScreenBuffer;
5431105Sminshall 
5531117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
5631120Sminshall ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
5731105Sminshall 
5831105Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
5931105Sminshall 
6031105Sminshall static void
6131105Sminshall OurExitString(file, string, value)
6231105Sminshall FILE	*file;
6331105Sminshall char	*string;
6431105Sminshall int	value;
6531105Sminshall {
6631105Sminshall     static int recursion = 0;
6731105Sminshall 
6831105Sminshall     if (!recursion) {
6931105Sminshall 	recursion = 1;
7031105Sminshall 	ExitString(file, string, value);
7131105Sminshall     }
7231105Sminshall }
7331105Sminshall 
7431105Sminshall 
7531105Sminshall static void
7631105Sminshall GoAway(from, where)
7731105Sminshall char *from;		/* routine that gave error */
7831105Sminshall int	where;		/* cursor address */
7931105Sminshall {
8031105Sminshall 	char foo[100];
8131105Sminshall 
8231105Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
8331105Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
8431105Sminshall 	OurExitString(stderr, foo, 1);
8531105Sminshall 	/* NOTREACHED */
8631105Sminshall }
8731105Sminshall 
8831120Sminshall /*
8931120Sminshall  * Routines to deal with the screen.  These routines are lifted
9031120Sminshall  * from mskermit.
9131120Sminshall  */
9231120Sminshall 
9331120Sminshall #define	CRT_STATUS	0x3da		/* Color card */
9431120Sminshall #define	DISPLAY_ENABLE	0x08		/* Enable */
9531120Sminshall #define	scrseg()	((crt_mode == 7)? 0xb000 : 0xb800)
9631120Sminshall #define	scrwait()	if (crt_mode != 7) { \
9731120Sminshall 			    while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
9831120Sminshall 				; \
9931120Sminshall 			    } \
10031120Sminshall 			}
10131120Sminshall static int
10231120Sminshall     		crt_mode,
10331120Sminshall 		crt_cols,
10431120Sminshall 		crt_lins,
10531120Sminshall 		curpage;
10631120Sminshall 
10731120Sminshall /*
10831120Sminshall  * Set the cursor position to where it belongs.
10931120Sminshall  */
11031120Sminshall 
11131105Sminshall static void
11231120Sminshall setcursor(row, column, page)
11331120Sminshall int
11431120Sminshall     row,
11531120Sminshall     column,
11631120Sminshall     page;
11731120Sminshall {
11831120Sminshall     union REGS inregs, outregs;
11931120Sminshall 
12031120Sminshall     inregs.h.dh = row;
12131120Sminshall     inregs.h.dl = column;
12231120Sminshall     inregs.h.bh = page;
12331120Sminshall     inregs.h.ah = SetCursorPosition;
12431120Sminshall 
12531120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
12631120Sminshall }
12731120Sminshall /*
12831120Sminshall  * Read the state of the video system.  Put the cursor somewhere
12931120Sminshall  * reasonable.
13031120Sminshall  */
13131120Sminshall 
13231120Sminshall static void
13331120Sminshall scrini()
13431120Sminshall {
13531120Sminshall     union REGS inregs, outregs;
13631120Sminshall 
13731120Sminshall     inregs.h.ah = CurrentVideoState;
13831120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
13931120Sminshall 
14031120Sminshall     crt_mode = outregs.h.al;
14131120Sminshall     crt_cols = outregs.h.ah;
14231120Sminshall     crt_lins = 25;
14331120Sminshall     curpage = outregs.h.bh;
14431120Sminshall 
14531120Sminshall     inregs.h.ah = ReadCursorPosition;
14631120Sminshall     inregs.h.bh = curpage;
14731120Sminshall 
14831120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
14931120Sminshall 
15031120Sminshall     if (outregs.h.dh > crt_lins) {
15131120Sminshall 	outregs.h.dh = crt_lins;
15231120Sminshall     }
15331120Sminshall     if (outregs.h.dl > crt_cols) {
15431120Sminshall 	outregs.h.dl = crt_cols;
15531120Sminshall     }
15631120Sminshall     inregs.h.dh = outregs.h.dh;
15731120Sminshall     inregs.h.dl = outregs.h.dl;
15831120Sminshall     inregs.h.bh = curpage;
15931120Sminshall 
16031120Sminshall     inregs.h.ah = SetCursorPosition;
16131120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
16231120Sminshall }
16331120Sminshall 
16431120Sminshall 
16531120Sminshall static void
16631120Sminshall scrwrite(source, length, offset)
16731120Sminshall ScreenBuffer *source;
16831120Sminshall int
16931120Sminshall 	length,
17031120Sminshall 	offset;
17131120Sminshall {
17231120Sminshall     struct SREGS segregs;
17331120Sminshall 
17431120Sminshall     segread(&segregs);		/* read the current segment register */
17531120Sminshall 
17631120Sminshall     scrwait();
17731154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
17831154Sminshall 						sizeof *source*length);
17931120Sminshall }
18031120Sminshall 
18131120Sminshall static void
18231120Sminshall scrsave(buffer)
18331120Sminshall ScreenBuffer *buffer;
18431120Sminshall {
18531120Sminshall     struct SREGS segregs;
18631120Sminshall 
18731120Sminshall     segread(&segregs);		/* read the current segment register */
18831120Sminshall 
18931120Sminshall     scrwait();
19031154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
19131120Sminshall }
19231120Sminshall 
19331120Sminshall static void
19431120Sminshall scrrest(buffer)
19531120Sminshall ScreenBuffer *buffer;
19631120Sminshall {
19731154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
19831120Sminshall }
19931120Sminshall 
20031120Sminshall static void
20131117Sminshall TryToSend()
20231105Sminshall {
20331154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
20431117Sminshall #define	NORMAL		0x02	/* Normal mode */
20531154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
20631105Sminshall 
20731154Sminshall #define	DoAttribute(a) 	    \
20831154Sminshall 			    if (screenIsFormatted) { \
20931154Sminshall 				if (IsNonDisplayAttr(a)) { \
21031154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
21131154Sminshall 				} else if (IsHighlightedAttr(a)) { \
21231154Sminshall 				    a = STANDOUT; \
21331154Sminshall 				} else { \
21431154Sminshall 				    a = NORMAL; \
21531154Sminshall 				} \
21631154Sminshall 			    } else  { \
21731154Sminshall 				a = NORMAL;	/* do display on unformatted */\
21831105Sminshall 			    }
21931105Sminshall     ScreenImage *p, *upper;
22031117Sminshall     ScreenBuffer *sp;
22131105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
22231154Sminshall     int screenIsFormatted = FormattedScreen();
22331105Sminshall 
22431105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
22531105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
22631105Sminshall  * field in the middle, we do the whole screen.
22731105Sminshall  *
22831105Sminshall  * In particular, we separate out the two cases from the beginning.
22931105Sminshall  */
23031105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
23131117Sminshall 	sp = &Screen[Lowest];
23231105Sminshall 	p = &Host[Lowest];
23331105Sminshall 	upper = &Host[Highest];
23431105Sminshall 	fieldattr = FieldAttributes(Lowest);
23531105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
23631105Sminshall 
23731105Sminshall 	while (p <= upper) {
23831105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
23931105Sminshall 		Highest = HighestScreen();
24031105Sminshall 		Lowest = LowestScreen();
24131117Sminshall 		TryToSend();		/* Recurse */
24231105Sminshall 		return;
24331105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
24431154Sminshall 				/* Display translated data */
24531154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
24631105Sminshall 	    } else {
24731117Sminshall 		sp->data = ' ';
24831105Sminshall 	    }
24931154Sminshall 	    sp->attr = fieldattr;
25031105Sminshall 	    p++;
25131117Sminshall 	    sp++;
25231105Sminshall 	}
25331105Sminshall     } else {		/* Going from Lowest to Highest */
25431117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
25531105Sminshall 
25631117Sminshall 	sp = Screen;
25731105Sminshall 	p = Host;
25831105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
25931105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
26031105Sminshall 
26131105Sminshall 	while (p <= End) {
26231105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
26331105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
26431105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
26531154Sminshall 	    }
26631154Sminshall 	    if (fieldattr) {	/* Should we display? */
26731154Sminshall 			    /* Display translated data */
26831154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
26931105Sminshall 	    } else {
27031154Sminshall 		sp->data = ' ';
27131105Sminshall 	    }
27231154Sminshall 	    sp->attr = fieldattr;
27331105Sminshall 	    p++;
27431117Sminshall 	    sp++;
27531105Sminshall 	}
27631105Sminshall     }
27731117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
27831154Sminshall     /*
27931154Sminshall      * We might be here just to update the cursor address.
28031154Sminshall      */
28131154Sminshall     if (Highest >= Lowest) {
28231154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
28331154Sminshall     }
28431120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
28531117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
28631105Sminshall     Lowest = HighestScreen()+1;
28731105Sminshall     Highest = LowestScreen()-1;
28831105Sminshall     if (needToRing) {
28931117Sminshall 	DataToTerminal("\7", 1);
29031105Sminshall 	needToRing = 0;
29131105Sminshall     }
29231105Sminshall     return;
29331105Sminshall }
29431105Sminshall 
29531105Sminshall /* InitTerminal - called to initialize the screen, etc. */
29631105Sminshall 
29731105Sminshall void
29831105Sminshall InitTerminal()
29931105Sminshall {
30031105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
30131105Sminshall     if (!screenInitd) { 	/* not initialized */
30231129Sminshall 	MaxNumberLines = 24;	/* XXX */
30331129Sminshall 	MaxNumberColumns = 80;	/* XXX */
30431117Sminshall 	scrini();
30531120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
30631117Sminshall 	ClearArray(Screen);
30731105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
30831105Sminshall 	screenInitd = 1;
30931105Sminshall 	screenStopped = 0;		/* Not stopped */
31031105Sminshall     }
31131105Sminshall }
31231105Sminshall 
31331105Sminshall 
31431105Sminshall /* StopScreen - called when we are going away... */
31531105Sminshall 
31631105Sminshall void
31731105Sminshall StopScreen(doNewLine)
31831105Sminshall int doNewLine;
31931105Sminshall {
32031105Sminshall     if (screenInitd && !screenStopped) {
32131120Sminshall 	scrrest(saveScreen);
32231208Sminshall 	setcursor(NumberLines-1, 1, 0);
32331208Sminshall 	if (doNewLine) {
32431208Sminshall 	    StringToTerminal("\r\n");
32531208Sminshall 	}
32631208Sminshall 	EmptyTerminal();
32731208Sminshall 	screenStopped = 1;
32831105Sminshall     }
32931105Sminshall }
33031105Sminshall 
33131105Sminshall 
33231105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
33331105Sminshall 
33431105Sminshall void
33531105Sminshall RefreshScreen()
33631105Sminshall {
33731117Sminshall     Highest = HighestScreen();
33831117Sminshall     Lowest = LowestScreen();
33931117Sminshall     TryToSend();
34031105Sminshall }
34131105Sminshall 
34231105Sminshall 
34331105Sminshall /* ConnectScreen - called to reconnect to the screen */
34431105Sminshall 
34531105Sminshall void
34631105Sminshall ConnectScreen()
34731105Sminshall {
34831105Sminshall     if (screenInitd) {
34931105Sminshall 	RefreshScreen();
35031105Sminshall 	screenStopped = 0;
35131105Sminshall     }
35231105Sminshall }
35331105Sminshall 
35431105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
35531105Sminshall 
35631105Sminshall void
35731105Sminshall LocalClearScreen()
35831105Sminshall {
35931105Sminshall     Clear3270();
36031117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
36131117Sminshall     Highest = HighestScreen();
36231117Sminshall     TryToSend();
36331105Sminshall }
36431117Sminshall 
36531117Sminshall /*
36631117Sminshall  * Implement the bell/error message function.
36731117Sminshall  */
36831105Sminshall 
36931117Sminshall int
37031117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
37131117Sminshall static int
37231883Sminshall 	bell_len = 0;		/* Length of error message */
37331105Sminshall 
37431117Sminshall 
37531105Sminshall void
37631105Sminshall BellOff()
37731105Sminshall {
37831883Sminshall     ScreenBuffer a[100];
37931883Sminshall     int i;
38031883Sminshall 
38131105Sminshall     if (bellwinup) {
38231883Sminshall 	unsigned char blank = ' ';
38331883Sminshall 
38431883Sminshall 	for (i = 0; i < bell_len; i++) {
38531883Sminshall 	    a[i].attr = NORMAL;
38631883Sminshall 	    a[i].data = ' ';
38731883Sminshall 	}
38831105Sminshall     }
38931883Sminshall     scrwrite(a, bell_len, 24*80);		/* XXX */
39031105Sminshall }
39131105Sminshall 
39231105Sminshall 
39331105Sminshall void
39431105Sminshall RingBell(s)
39531105Sminshall char *s;
39631105Sminshall {
39731105Sminshall     needToRing = 1;
39831105Sminshall     if (s) {
39931883Sminshall 	int i;
40031883Sminshall 	ScreenBuffer bellstring[100];
40131105Sminshall 
40231883Sminshall 	bell_len = strlen(s);
40331883Sminshall 	bellwinup = 1;
40431883Sminshall 	if (bell_len > sizeof bellstring-1) {
40531117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
40631105Sminshall 	}
40731883Sminshall 	for (i = 0; i < bell_len; i++) {
40831883Sminshall 	    bellstring[i].attr = STANDOUT;
40931883Sminshall 	    bellstring[i].data = s[i];
41031883Sminshall 	}
41131883Sminshall 	scrwrite(bellstring, bell_len, 24*80);		/* XXX */
41231105Sminshall     }
41331105Sminshall }
41431105Sminshall 
41531117Sminshall /*
41631117Sminshall  * Update the OIA area.
41731117Sminshall  */
41831105Sminshall 
41931117Sminshall void
42031117Sminshall ScreenOIA(oia)
42131117Sminshall OIA *oia;
42231117Sminshall {
42331117Sminshall }
42431117Sminshall 
42531117Sminshall 
42631105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
42731105Sminshall     or a 0 if there is more output available (so, just poll the other
42831105Sminshall     sources/destinations, don't block).
42931105Sminshall  */
43031105Sminshall 
43131105Sminshall int
43231105Sminshall DoTerminalOutput()
43331105Sminshall {
43431105Sminshall 	/* called just before a select to conserve IO to terminal */
43531490Sminshall     if (!(screenInitd||screenStopped)) {
43631105Sminshall 	return 1;		/* No output if not initialized */
43731105Sminshall     }
43831105Sminshall     if ((Lowest <= Highest) || needToRing ||
43931105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
44031117Sminshall 	TryToSend();
44131105Sminshall     }
44231105Sminshall     if (Lowest > Highest) {
44331105Sminshall 	return 1;		/* no more output now */
44431105Sminshall     } else {
44531105Sminshall 	return 0;		/* more output for future */
44631105Sminshall     }
44731105Sminshall }
44831105Sminshall 
44931105Sminshall /*
45031105Sminshall  * The following are defined to handle transparent data.
45131105Sminshall  */
45231105Sminshall 
45331105Sminshall void
45431105Sminshall TransStop()
45531105Sminshall {
45631105Sminshall     RefreshScreen();
45731105Sminshall }
45831105Sminshall 
45931105Sminshall void
46031885Sminshall TransOut(buffer, count, kind, control)
46131105Sminshall unsigned char	*buffer;
46231105Sminshall int		count;
46331885Sminshall int		kind;		/* 0 or 5 */
46431885Sminshall int		control;	/* To see if we are done */
46531105Sminshall {
46631885Sminshall     char *ptr;
46731105Sminshall 
46831105Sminshall     while (DoTerminalOutput() == 0) {
46931117Sminshall 	;
47031105Sminshall     }
47131885Sminshall     for (ptr = buffer; ptr < buffer+count; ptr++) {
47231885Sminshall 	*ptr &= 0x7f;		/* Turn off parity bit */
47331885Sminshall     }
47431105Sminshall     (void) DataToTerminal(buffer, count);
47531885Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
47631885Sminshall 	SendToIBM();
47731885Sminshall     } else {
47831885Sminshall 	TransInput(1, kind);			/* Go get some data */
47931885Sminshall     }
48031105Sminshall }
48131117Sminshall 
48231117Sminshall /*
48331117Sminshall  * init_screen()
48431117Sminshall  *
48531117Sminshall  * Initialize variables used by screen.
48631117Sminshall  */
48731105Sminshall 
48831117Sminshall void
48931117Sminshall init_screen()
49031105Sminshall {
49131117Sminshall     bellwinup = 0;
49231117Sminshall }
49331105Sminshall 
49431117Sminshall 
495