131105Sminshall /*
233814Sbostic  * Copyright (c) 1988 Regents of the University of California.
333814Sbostic  * All rights reserved.
431105Sminshall  *
533814Sbostic  * Redistribution and use in source and binary forms are permitted
634889Sbostic  * provided that the above copyright notice and this paragraph are
734889Sbostic  * duplicated in all such forms and that any documentation,
834889Sbostic  * advertising materials, and other materials related to such
934889Sbostic  * distribution and use acknowledge that the software was developed
1034889Sbostic  * by the University of California, Berkeley.  The name of the
1134889Sbostic  * University may not be used to endorse or promote products derived
1234889Sbostic  * from this software without specific prior written permission.
1334889Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434889Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534889Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1631105Sminshall  */
1731105Sminshall 
1831105Sminshall #ifndef lint
19*35424Sminshall static char sccsid[] = "@(#)termout.c	3.4 (Berkeley) 08/28/88";
2033814Sbostic #endif /* not lint */
2131105Sminshall 
2231105Sminshall #include <stdio.h>
2331120Sminshall #include <dos.h>
2431185Sminshall #include "../general/general.h"
2531105Sminshall 
2631105Sminshall #include "../telnet.ext"
2731105Sminshall 
2831881Sminshall #include "../api/disp_asc.h"
2931225Sminshall #include "../ascii/map3270.ext"
3031225Sminshall 
3131105Sminshall #include "../ctlr/hostctlr.h"
32*35424Sminshall #include "../ctlr/externs.h"
33*35424Sminshall #include "../ctlr/declare.h"
3431117Sminshall #include "../ctlr/oia.h"
3531105Sminshall #include "../ctlr/screen.h"
3631105Sminshall 
3731185Sminshall #include "../general/globals.h"
3831105Sminshall 
3931120Sminshall #include "video.h"
4031120Sminshall 
4131105Sminshall extern void EmptyTerminal();
4231105Sminshall 
4331105Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
4431105Sminshall 		terminalCursorAddress:UnLocked? CursorAddress: HighestScreen())
4531105Sminshall 
4631105Sminshall 
4731105Sminshall static int terminalCursorAddress;	/* where the cursor is on term */
4831105Sminshall static int screenInitd; 		/* the screen has been initialized */
4931105Sminshall static int screenStopped;		/* the screen has been stopped */
5031105Sminshall 
5131105Sminshall static int needToRing;			/* need to ring terinal bell */
5231105Sminshall 
5331117Sminshall typedef struct {
5431117Sminshall     char
5531117Sminshall 	data,		/* The data for this position */
5631117Sminshall 	attr;		/* The attributes for this position */
5731117Sminshall } ScreenBuffer;
5831105Sminshall 
5931117Sminshall ScreenBuffer Screen[MAXNUMBERLINES*MAXNUMBERCOLUMNS];
6031120Sminshall ScreenBuffer saveScreen[sizeof Screen/sizeof Screen[0]];
6131105Sminshall 
6231105Sminshall /* OurExitString - designed to keep us from going through infinite recursion */
6331105Sminshall 
6431105Sminshall static void
6531105Sminshall OurExitString(file, string, value)
6631105Sminshall FILE	*file;
6731105Sminshall char	*string;
6831105Sminshall int	value;
6931105Sminshall {
7031105Sminshall     static int recursion = 0;
7131105Sminshall 
7231105Sminshall     if (!recursion) {
7331105Sminshall 	recursion = 1;
7431105Sminshall 	ExitString(file, string, value);
7531105Sminshall     }
7631105Sminshall }
7731105Sminshall 
7831105Sminshall 
7931105Sminshall static void
8031105Sminshall GoAway(from, where)
8131105Sminshall char *from;		/* routine that gave error */
8231105Sminshall int	where;		/* cursor address */
8331105Sminshall {
8431105Sminshall 	char foo[100];
8531105Sminshall 
8631105Sminshall 	sprintf(foo, "ERR from %s at %d (%d, %d)\n",
8731105Sminshall 		from, where, ScreenLine(where), ScreenLineOffset(where));
8831105Sminshall 	OurExitString(stderr, foo, 1);
8931105Sminshall 	/* NOTREACHED */
9031105Sminshall }
9131105Sminshall 
9231120Sminshall /*
9331120Sminshall  * Routines to deal with the screen.  These routines are lifted
9431120Sminshall  * from mskermit.
9531120Sminshall  */
9631120Sminshall 
9731120Sminshall #define	CRT_STATUS	0x3da		/* Color card */
9831120Sminshall #define	DISPLAY_ENABLE	0x08		/* Enable */
9931120Sminshall #define	scrseg()	((crt_mode == 7)? 0xb000 : 0xb800)
10031120Sminshall #define	scrwait()	if (crt_mode != 7) { \
10131120Sminshall 			    while ((inp(CRT_STATUS)&DISPLAY_ENABLE) == 0) { \
10231120Sminshall 				; \
10331120Sminshall 			    } \
10431120Sminshall 			}
10531120Sminshall static int
10631120Sminshall     		crt_mode,
10731120Sminshall 		crt_cols,
10831120Sminshall 		crt_lins,
10931120Sminshall 		curpage;
11031120Sminshall 
11131120Sminshall /*
11231120Sminshall  * Set the cursor position to where it belongs.
11331120Sminshall  */
11431120Sminshall 
11531105Sminshall static void
11631120Sminshall setcursor(row, column, page)
11731120Sminshall int
11831120Sminshall     row,
11931120Sminshall     column,
12031120Sminshall     page;
12131120Sminshall {
12231120Sminshall     union REGS inregs, outregs;
12331120Sminshall 
12431120Sminshall     inregs.h.dh = row;
12531120Sminshall     inregs.h.dl = column;
12631120Sminshall     inregs.h.bh = page;
12731120Sminshall     inregs.h.ah = SetCursorPosition;
12831120Sminshall 
12931120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
13031120Sminshall }
13131120Sminshall /*
13231120Sminshall  * Read the state of the video system.  Put the cursor somewhere
13331120Sminshall  * reasonable.
13431120Sminshall  */
13531120Sminshall 
13631120Sminshall static void
13731120Sminshall scrini()
13831120Sminshall {
13931120Sminshall     union REGS inregs, outregs;
14031120Sminshall 
14131120Sminshall     inregs.h.ah = CurrentVideoState;
14231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
14331120Sminshall 
14431120Sminshall     crt_mode = outregs.h.al;
14531120Sminshall     crt_cols = outregs.h.ah;
14631120Sminshall     crt_lins = 25;
14731120Sminshall     curpage = outregs.h.bh;
14831120Sminshall 
14931120Sminshall     inregs.h.ah = ReadCursorPosition;
15031120Sminshall     inregs.h.bh = curpage;
15131120Sminshall 
15231120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
15331120Sminshall 
15431120Sminshall     if (outregs.h.dh > crt_lins) {
15531120Sminshall 	outregs.h.dh = crt_lins;
15631120Sminshall     }
15731120Sminshall     if (outregs.h.dl > crt_cols) {
15831120Sminshall 	outregs.h.dl = crt_cols;
15931120Sminshall     }
16031120Sminshall     inregs.h.dh = outregs.h.dh;
16131120Sminshall     inregs.h.dl = outregs.h.dl;
16231120Sminshall     inregs.h.bh = curpage;
16331120Sminshall 
16431120Sminshall     inregs.h.ah = SetCursorPosition;
16531120Sminshall     int86(BIOS_VIDEO, &inregs, &outregs);
16631120Sminshall }
16731120Sminshall 
16831120Sminshall 
16931120Sminshall static void
17031120Sminshall scrwrite(source, length, offset)
17131120Sminshall ScreenBuffer *source;
17231120Sminshall int
17331120Sminshall 	length,
17431120Sminshall 	offset;
17531120Sminshall {
17631120Sminshall     struct SREGS segregs;
17731120Sminshall 
17831120Sminshall     segread(&segregs);		/* read the current segment register */
17931120Sminshall 
18031120Sminshall     scrwait();
18131154Sminshall     movedata(segregs.ds, source, scrseg(), sizeof *source*offset,
18231154Sminshall 						sizeof *source*length);
18331120Sminshall }
18431120Sminshall 
18531120Sminshall static void
18631120Sminshall scrsave(buffer)
18731120Sminshall ScreenBuffer *buffer;
18831120Sminshall {
18931120Sminshall     struct SREGS segregs;
19031120Sminshall 
19131120Sminshall     segread(&segregs);		/* read the current segment register */
19231120Sminshall 
19331120Sminshall     scrwait();
19431154Sminshall     movedata(scrseg(), 0, segregs.ds, buffer, crt_cols*crt_lins*2);
19531120Sminshall }
19631120Sminshall 
19731120Sminshall static void
19831120Sminshall scrrest(buffer)
19931120Sminshall ScreenBuffer *buffer;
20031120Sminshall {
20131154Sminshall     scrwrite(buffer, crt_cols*crt_lins, 0);
20231120Sminshall }
20331120Sminshall 
20431120Sminshall static void
20531117Sminshall TryToSend()
20631105Sminshall {
20731154Sminshall #define	STANDOUT	0x0a	/* Highlighted mode */
20831117Sminshall #define	NORMAL		0x02	/* Normal mode */
20931154Sminshall #define	NONDISPLAY	0x00	/* Don't display */
21031105Sminshall 
21131154Sminshall #define	DoAttribute(a) 	    \
21231154Sminshall 			    if (screenIsFormatted) { \
21331154Sminshall 				if (IsNonDisplayAttr(a)) { \
21431154Sminshall 				    a = NONDISPLAY; 	/* don't display */ \
21531154Sminshall 				} else if (IsHighlightedAttr(a)) { \
21631154Sminshall 				    a = STANDOUT; \
21731154Sminshall 				} else { \
21831154Sminshall 				    a = NORMAL; \
21931154Sminshall 				} \
22031154Sminshall 			    } else  { \
22131154Sminshall 				a = NORMAL;	/* do display on unformatted */\
22231105Sminshall 			    }
22331105Sminshall     ScreenImage *p, *upper;
22431117Sminshall     ScreenBuffer *sp;
22531105Sminshall     int fieldattr;		/* spends most of its time == 0 or 1 */
22631154Sminshall     int screenIsFormatted = FormattedScreen();
22731105Sminshall 
22831105Sminshall /* OK.  We want to do this a quickly as possible.  So, we assume we
22931105Sminshall  * only need to go from Lowest to Highest.  However, if we find a
23031105Sminshall  * field in the middle, we do the whole screen.
23131105Sminshall  *
23231105Sminshall  * In particular, we separate out the two cases from the beginning.
23331105Sminshall  */
23431105Sminshall     if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
23531117Sminshall 	sp = &Screen[Lowest];
23631105Sminshall 	p = &Host[Lowest];
23731105Sminshall 	upper = &Host[Highest];
23831105Sminshall 	fieldattr = FieldAttributes(Lowest);
23931105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
24031105Sminshall 
24131105Sminshall 	while (p <= upper) {
24231105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
24331105Sminshall 		Highest = HighestScreen();
24431105Sminshall 		Lowest = LowestScreen();
24531117Sminshall 		TryToSend();		/* Recurse */
24631105Sminshall 		return;
24731105Sminshall 	    } else if (fieldattr) {	/* Should we display? */
24831154Sminshall 				/* Display translated data */
24931154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
25031105Sminshall 	    } else {
25131117Sminshall 		sp->data = ' ';
25231105Sminshall 	    }
25331154Sminshall 	    sp->attr = fieldattr;
25431105Sminshall 	    p++;
25531117Sminshall 	    sp++;
25631105Sminshall 	}
25731105Sminshall     } else {		/* Going from Lowest to Highest */
25831117Sminshall 	ScreenImage *End = &Host[ScreenSize]-1;
25931105Sminshall 
26031117Sminshall 	sp = Screen;
26131105Sminshall 	p = Host;
26231105Sminshall 	fieldattr = FieldAttributes(LowestScreen());
26331105Sminshall 	DoAttribute(fieldattr);	/* Set standout, non-display status */
26431105Sminshall 
26531105Sminshall 	while (p <= End) {
26631105Sminshall 	    if (IsStartFieldPointer(p)) {	/* New field? */
26731105Sminshall 		fieldattr = FieldAttributesPointer(p);	/* Get attributes */
26831105Sminshall 		DoAttribute(fieldattr);	/* Set standout, non-display */
26931154Sminshall 	    }
27031154Sminshall 	    if (fieldattr) {	/* Should we display? */
27131154Sminshall 			    /* Display translated data */
27231154Sminshall 		sp->data = disp_asc[GetHostPointer(p)];
27331105Sminshall 	    } else {
27431154Sminshall 		sp->data = ' ';
27531105Sminshall 	    }
27631154Sminshall 	    sp->attr = fieldattr;
27731105Sminshall 	    p++;
27831117Sminshall 	    sp++;
27931105Sminshall 	}
28031105Sminshall     }
28131117Sminshall     terminalCursorAddress = CorrectTerminalCursor();
28231154Sminshall     /*
28331154Sminshall      * We might be here just to update the cursor address.
28431154Sminshall      */
28531154Sminshall     if (Highest >= Lowest) {
28631154Sminshall 	scrwrite(Screen+Lowest, (1+Highest-Lowest), Lowest);
28731154Sminshall     }
28831120Sminshall     setcursor(ScreenLine(terminalCursorAddress),
28931117Sminshall 		    ScreenLineOffset(terminalCursorAddress), 0);
29031105Sminshall     Lowest = HighestScreen()+1;
29131105Sminshall     Highest = LowestScreen()-1;
29231105Sminshall     if (needToRing) {
29331117Sminshall 	DataToTerminal("\7", 1);
29431105Sminshall 	needToRing = 0;
29531105Sminshall     }
29631105Sminshall     return;
29731105Sminshall }
29831105Sminshall 
29931105Sminshall /* InitTerminal - called to initialize the screen, etc. */
30031105Sminshall 
30131105Sminshall void
30231105Sminshall InitTerminal()
30331105Sminshall {
30431105Sminshall     InitMapping();		/* Go do mapping file (MAP3270) first */
30531105Sminshall     if (!screenInitd) { 	/* not initialized */
30631129Sminshall 	MaxNumberLines = 24;	/* XXX */
30731129Sminshall 	MaxNumberColumns = 80;	/* XXX */
30831117Sminshall 	scrini();
30931120Sminshall 	scrsave(saveScreen);	/* Save the screen buffer away */
31031117Sminshall 	ClearArray(Screen);
31131105Sminshall 	terminalCursorAddress = SetBufferAddress(0,0);
31231105Sminshall 	screenInitd = 1;
31331105Sminshall 	screenStopped = 0;		/* Not stopped */
31431105Sminshall     }
31531105Sminshall }
31631105Sminshall 
31731105Sminshall 
31831105Sminshall /* StopScreen - called when we are going away... */
31931105Sminshall 
32031105Sminshall void
32131105Sminshall StopScreen(doNewLine)
32231105Sminshall int doNewLine;
32331105Sminshall {
32431105Sminshall     if (screenInitd && !screenStopped) {
32531120Sminshall 	scrrest(saveScreen);
32631208Sminshall 	setcursor(NumberLines-1, 1, 0);
32731208Sminshall 	if (doNewLine) {
32831208Sminshall 	    StringToTerminal("\r\n");
32931208Sminshall 	}
33031208Sminshall 	EmptyTerminal();
33131208Sminshall 	screenStopped = 1;
33231105Sminshall     }
33331105Sminshall }
33431105Sminshall 
33531105Sminshall 
33631105Sminshall /* RefreshScreen - called to cause the screen to be refreshed */
33731105Sminshall 
33831105Sminshall void
33931105Sminshall RefreshScreen()
34031105Sminshall {
34131117Sminshall     Highest = HighestScreen();
34231117Sminshall     Lowest = LowestScreen();
34331117Sminshall     TryToSend();
34431105Sminshall }
34531105Sminshall 
34631105Sminshall 
34731105Sminshall /* ConnectScreen - called to reconnect to the screen */
34831105Sminshall 
34931105Sminshall void
35031105Sminshall ConnectScreen()
35131105Sminshall {
35231105Sminshall     if (screenInitd) {
35331105Sminshall 	RefreshScreen();
35431105Sminshall 	screenStopped = 0;
35531105Sminshall     }
35631105Sminshall }
35731105Sminshall 
35831105Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */
35931105Sminshall 
36031105Sminshall void
36131105Sminshall LocalClearScreen()
36231105Sminshall {
36331105Sminshall     Clear3270();
36431117Sminshall     Lowest = LowestScreen(); /* everything in sync... */
36531117Sminshall     Highest = HighestScreen();
36631117Sminshall     TryToSend();
36731105Sminshall }
36831117Sminshall 
36931117Sminshall /*
37031117Sminshall  * Implement the bell/error message function.
37131117Sminshall  */
37231105Sminshall 
37331117Sminshall int
37431117Sminshall 	bellwinup = 0;		/* If != 0, length of bell message */
37531117Sminshall static int
37631883Sminshall 	bell_len = 0;		/* Length of error message */
37731105Sminshall 
37831117Sminshall 
37931105Sminshall void
38031105Sminshall BellOff()
38131105Sminshall {
38231883Sminshall     ScreenBuffer a[100];
38331883Sminshall     int i;
38431883Sminshall 
38531105Sminshall     if (bellwinup) {
38631883Sminshall 	unsigned char blank = ' ';
38731883Sminshall 
38831883Sminshall 	for (i = 0; i < bell_len; i++) {
38931883Sminshall 	    a[i].attr = NORMAL;
39031883Sminshall 	    a[i].data = ' ';
39131883Sminshall 	}
39231105Sminshall     }
39331883Sminshall     scrwrite(a, bell_len, 24*80);		/* XXX */
39431105Sminshall }
39531105Sminshall 
39631105Sminshall 
39731105Sminshall void
39831105Sminshall RingBell(s)
39931105Sminshall char *s;
40031105Sminshall {
40131105Sminshall     needToRing = 1;
40231105Sminshall     if (s) {
40331883Sminshall 	int i;
40431883Sminshall 	ScreenBuffer bellstring[100];
40531105Sminshall 
40631883Sminshall 	bell_len = strlen(s);
40731883Sminshall 	bellwinup = 1;
40831883Sminshall 	if (bell_len > sizeof bellstring-1) {
40931117Sminshall 	    OurExitString(stderr, "Bell string too long.", 1);
41031105Sminshall 	}
41131883Sminshall 	for (i = 0; i < bell_len; i++) {
41231883Sminshall 	    bellstring[i].attr = STANDOUT;
41331883Sminshall 	    bellstring[i].data = s[i];
41431883Sminshall 	}
41531883Sminshall 	scrwrite(bellstring, bell_len, 24*80);		/* XXX */
41631105Sminshall     }
41731105Sminshall }
41831105Sminshall 
41931117Sminshall /*
42031117Sminshall  * Update the OIA area.
42131117Sminshall  */
42231105Sminshall 
42331117Sminshall void
42431117Sminshall ScreenOIA(oia)
42531117Sminshall OIA *oia;
42631117Sminshall {
42731117Sminshall }
42831117Sminshall 
42931117Sminshall 
43031105Sminshall /* returns a 1 if no more output available (so, go ahead and block),
43131105Sminshall     or a 0 if there is more output available (so, just poll the other
43231105Sminshall     sources/destinations, don't block).
43331105Sminshall  */
43431105Sminshall 
43531105Sminshall int
43631105Sminshall DoTerminalOutput()
43731105Sminshall {
43831105Sminshall 	/* called just before a select to conserve IO to terminal */
43931490Sminshall     if (!(screenInitd||screenStopped)) {
44031105Sminshall 	return 1;		/* No output if not initialized */
44131105Sminshall     }
44231105Sminshall     if ((Lowest <= Highest) || needToRing ||
44331105Sminshall 			(terminalCursorAddress != CorrectTerminalCursor())) {
44431117Sminshall 	TryToSend();
44531105Sminshall     }
44631105Sminshall     if (Lowest > Highest) {
44731105Sminshall 	return 1;		/* no more output now */
44831105Sminshall     } else {
44931105Sminshall 	return 0;		/* more output for future */
45031105Sminshall     }
45131105Sminshall }
45231105Sminshall 
45331105Sminshall /*
45431105Sminshall  * The following are defined to handle transparent data.
45531105Sminshall  */
45631105Sminshall 
45731105Sminshall void
45831105Sminshall TransStop()
45931105Sminshall {
46031105Sminshall     RefreshScreen();
46131105Sminshall }
46231105Sminshall 
46331105Sminshall void
46431885Sminshall TransOut(buffer, count, kind, control)
46531105Sminshall unsigned char	*buffer;
46631105Sminshall int		count;
46731885Sminshall int		kind;		/* 0 or 5 */
46831885Sminshall int		control;	/* To see if we are done */
46931105Sminshall {
47031885Sminshall     char *ptr;
47131105Sminshall 
47231105Sminshall     while (DoTerminalOutput() == 0) {
47331117Sminshall 	;
47431105Sminshall     }
47531885Sminshall     for (ptr = buffer; ptr < buffer+count; ptr++) {
47631885Sminshall 	*ptr &= 0x7f;		/* Turn off parity bit */
47731885Sminshall     }
47831105Sminshall     (void) DataToTerminal(buffer, count);
47931885Sminshall     if (control && (kind == 0)) {		/* Send in AID byte */
48031885Sminshall 	SendToIBM();
48131885Sminshall     } else {
48231885Sminshall 	TransInput(1, kind);			/* Go get some data */
48331885Sminshall     }
48431105Sminshall }
48531117Sminshall 
48631117Sminshall /*
48731117Sminshall  * init_screen()
48831117Sminshall  *
48931117Sminshall  * Initialize variables used by screen.
49031117Sminshall  */
49131105Sminshall 
49231117Sminshall void
49331117Sminshall init_screen()
49431105Sminshall {
49531117Sminshall     bellwinup = 0;
49631117Sminshall }
49731105Sminshall 
49831117Sminshall 
499