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