1*48757Sbostic /*- 2*48757Sbostic * Copyright (c) 1988 The Regents of the University of California. 333814Sbostic * All rights reserved. 431105Sminshall * 5*48757Sbostic * %sccs.include.redist.c% 631105Sminshall */ 731105Sminshall 831105Sminshall #ifndef lint 9*48757Sbostic static char sccsid[] = "@(#)termout.c 4.2 (Berkeley) 04/26/91"; 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 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 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 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 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 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 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 18831120Sminshall scrrest(buffer) 18931120Sminshall ScreenBuffer *buffer; 19031120Sminshall { 19131154Sminshall scrwrite(buffer, crt_cols*crt_lins, 0); 19231120Sminshall } 19331120Sminshall 19431120Sminshall static void 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 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 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 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 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 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 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 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 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 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 44831105Sminshall TransStop() 44931105Sminshall { 45031105Sminshall RefreshScreen(); 45131105Sminshall } 45231105Sminshall 45331105Sminshall void 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 48331117Sminshall init_screen() 48431105Sminshall { 48531117Sminshall bellwinup = 0; 48631117Sminshall } 48731105Sminshall 48831117Sminshall 489