148761Sbostic /*- 248761Sbostic * Copyright (c) 1988 The Regents of the University of California. 333810Sbostic * All rights reserved. 430043Sminshall * 548761Sbostic * %sccs.include.redist.c% 630043Sminshall */ 730043Sminshall 830043Sminshall #ifndef lint 9*59897Sbostic static char sccsid[] = "@(#)termout.c 4.5 (Berkeley) 05/11/93"; 1033810Sbostic #endif /* not lint */ 1130043Sminshall 1230043Sminshall #if defined(unix) 1330043Sminshall #include <signal.h> 1430043Sminshall #include <sgtty.h> 1530043Sminshall #endif 1630043Sminshall #include <stdio.h> 1730043Sminshall #include <curses.h> 1834307Sminshall #if defined(ultrix) 1934307Sminshall /* Some version of this OS has a bad definition for nonl() */ 2034307Sminshall #undef nl 2134307Sminshall #undef nonl 2230043Sminshall 2334307Sminshall #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) 2434307Sminshall #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) 2534307Sminshall #endif /* defined(ultrix) */ 2634307Sminshall 2731179Sminshall #include "../general/general.h" 2831071Sminshall 2930043Sminshall #include "terminal.h" 3030043Sminshall 3131873Sminshall #include "../api/disp_asc.h" 3231224Sminshall 3330043Sminshall #include "../ctlr/hostctlr.h" 3435423Sminshall #include "../ctlr/externs.h" 3535423Sminshall #include "../ctlr/declare.h" 3631127Sminshall #include "../ctlr/oia.h" 3730043Sminshall #include "../ctlr/screen.h" 3836243Sminshall #include "../ctlr/scrnctlr.h" 3930043Sminshall 4031179Sminshall #include "../general/globals.h" 4130043Sminshall 4259891Sbostic #include "telextrn.h" 4330043Sminshall 4430043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 4531839Sminshall CursorAddress:UnLocked? CursorAddress: HighestScreen()) 4630043Sminshall 4730043Sminshall 4830328Sminshall static int terminalCursorAddress; /* where the cursor is on term */ 4930328Sminshall static int screenInitd; /* the screen has been initialized */ 5030328Sminshall static int screenStopped; /* the screen has been stopped */ 5130043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 5230043Sminshall /* at terminal and net again */ 5330043Sminshall 5430328Sminshall static int needToRing; /* need to ring terinal bell */ 5530043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 5630043Sminshall * VB during initialization) 5730043Sminshall */ 5830328Sminshall static WINDOW *bellwin = 0; /* The window the bell message is in */ 5930043Sminshall int bellwinup = 0; /* Are we up with it or not */ 6030043Sminshall 6130043Sminshall #if defined(unix) 6234315Sminshall static char *myKS, *myKE; 6330043Sminshall #endif /* defined(unix) */ 6430043Sminshall 6530074Sminshall 6630074Sminshall static int inHighlightMode = 0; 6731071Sminshall ScreenImage Terminal[MAXSCREENSIZE]; 6830074Sminshall 6930074Sminshall /* Variables for transparent mode */ 7030043Sminshall #if defined(unix) 7130043Sminshall static int tcflag = -1; /* transparent mode command flag */ 7230043Sminshall static int savefd[2]; /* for storing fds during transcom */ 7330074Sminshall extern int tin, tout; /* file descriptors */ 7430043Sminshall #endif /* defined(unix) */ 7530043Sminshall 7630730Sminshall 7730730Sminshall /* 7830730Sminshall * init_screen() 7930730Sminshall * 8030730Sminshall * Initialize variables used by screen. 8130730Sminshall */ 8230730Sminshall 8330730Sminshall void 8430730Sminshall init_screen() 8530730Sminshall { 8630730Sminshall bellwinup = 0; 8730730Sminshall inHighlightMode = 0; 8831071Sminshall ClearArray(Terminal); 8930730Sminshall } 9030730Sminshall 9130730Sminshall 9230043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 9330043Sminshall 9430043Sminshall static void 9535423Sminshall OurExitString(string, value) 9630043Sminshall char *string; 9730043Sminshall int value; 9830043Sminshall { 9930043Sminshall static int recursion = 0; 10030043Sminshall 10130043Sminshall if (!recursion) { 10230043Sminshall recursion = 1; 10335423Sminshall ExitString(string, value); 10430043Sminshall } 10530043Sminshall } 10630043Sminshall 10730043Sminshall 10830043Sminshall /* DoARefresh */ 10930043Sminshall 11030043Sminshall static void 11130043Sminshall DoARefresh() 11230043Sminshall { 11330043Sminshall if (ERR == refresh()) { 11435423Sminshall OurExitString("ERR from refresh\n", 1); 11530043Sminshall } 11630043Sminshall } 11730043Sminshall 11830043Sminshall static void 11930043Sminshall GoAway(from, where) 12030043Sminshall char *from; /* routine that gave error */ 12130043Sminshall int where; /* cursor address */ 12230043Sminshall { 12330043Sminshall char foo[100]; 12430043Sminshall 12530043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 12630043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 12735423Sminshall OurExitString(foo, 1); 12830043Sminshall /* NOTREACHED */ 12930043Sminshall } 13030043Sminshall 13130043Sminshall /* What is the screen address of the attribute byte for the terminal */ 13230043Sminshall 13330043Sminshall static int 13430043Sminshall WhereTermAttrByte(p) 13530043Sminshall register int p; 13630043Sminshall { 13730043Sminshall register int i; 13830043Sminshall 13930043Sminshall i = p; 14030043Sminshall 14130043Sminshall do { 14230043Sminshall if (TermIsStartField(i)) { 14330043Sminshall return(i); 14430043Sminshall } 14530043Sminshall i = ScreenDec(i); 14630043Sminshall } while (i != p); 14730043Sminshall 14830043Sminshall return(LowestScreen()); /* unformatted screen... */ 14930043Sminshall } 15030043Sminshall 15130043Sminshall /* 15230043Sminshall * There are two algorithms for updating the screen. 15330043Sminshall * The first, SlowScreen() optimizes the line between the 15430043Sminshall * computer and the screen (say a 9600 baud line). To do 15530043Sminshall * this, we break out of the loop every so often to look 15630043Sminshall * at any pending input from the network (so that successive 15730043Sminshall * screens will only partially print until the final screen, 15830043Sminshall * the one the user possibly wants to see, is displayed 15930043Sminshall * in its entirety). 16030043Sminshall * 16130043Sminshall * The second algorithm tries to optimize CPU time (by 16230043Sminshall * being simpler) at the cost of the bandwidth to the 16330043Sminshall * screen. 16430043Sminshall * 16530043Sminshall * Of course, curses(3X) gets in here also. 16630043Sminshall */ 16730043Sminshall 16830043Sminshall 16930043Sminshall #if defined(NOT43) 17030043Sminshall static int 17130043Sminshall #else /* defined(NOT43) */ 17230043Sminshall static void 17330043Sminshall #endif /* defined(NOT43) */ 17430043Sminshall SlowScreen() 17530043Sminshall { 17636243Sminshall register int is, shouldbe, isattr, shouldattr; 17730043Sminshall register int pointer; 17836243Sminshall register int fieldattr, termattr; 17930043Sminshall register int columnsleft; 18030043Sminshall 18138206Sminshall #define NORMAL 0 18236243Sminshall #define HIGHLIGHT 1 /* Mask bits */ 18336243Sminshall #define NONDISPLAY 4 /* Mask bits */ 18438206Sminshall #define UNDETERMINED 8 /* Mask bits */ 18536243Sminshall 18636243Sminshall #define DoAttributes(x) \ 18736243Sminshall switch (x&ATTR_DSPD_MASK) { \ 18836243Sminshall case ATTR_DSPD_NONDISPLAY: \ 18936243Sminshall x = NONDISPLAY; \ 19036243Sminshall break; \ 19136243Sminshall case ATTR_DSPD_HIGH: \ 19236243Sminshall x = HIGHLIGHT; \ 19336243Sminshall break; \ 19436243Sminshall default: \ 19536243Sminshall x = 0; \ 19636243Sminshall break; \ 19736243Sminshall } 19836243Sminshall 19936243Sminshall # define SetHighlightMode(x) \ 20036243Sminshall { \ 20136243Sminshall if ((x)&HIGHLIGHT) { \ 20230043Sminshall if (!inHighlightMode) { \ 20336243Sminshall inHighlightMode = HIGHLIGHT; \ 20430043Sminshall standout(); \ 20530043Sminshall } \ 20630043Sminshall } else { \ 20730043Sminshall if (inHighlightMode) { \ 20830043Sminshall inHighlightMode = 0; \ 20930043Sminshall standend(); \ 21030043Sminshall } \ 21130043Sminshall } \ 21230043Sminshall } 21330043Sminshall 21430043Sminshall # define DoCharacterAt(c,p) { \ 21530043Sminshall if (p != HighestScreen()) { \ 21636243Sminshall c = disp_asc[c&0xff]; \ 21730043Sminshall if (terminalCursorAddress != p) { \ 21830043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 21930043Sminshall ScreenLineOffset(p), c)) {\ 22030043Sminshall GoAway("mvaddch", p); \ 22130043Sminshall } \ 22230043Sminshall } else { \ 22330043Sminshall if (ERR == addch(c)) {\ 22430043Sminshall GoAway("addch", p); \ 22530043Sminshall } \ 22630043Sminshall } \ 22730043Sminshall terminalCursorAddress = ScreenInc(p); \ 22830043Sminshall } \ 22930043Sminshall } 23030043Sminshall 23130043Sminshall 23230043Sminshall /* run through screen, printing out non-null lines */ 23330043Sminshall 23430043Sminshall /* There are two separate reasons for wanting to terminate this 23530043Sminshall * loop early. One is to respond to new input (either from 23630043Sminshall * the terminal or from the network [host]). For this reason, 23730043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 23830043Sminshall * 23930043Sminshall * The second reason is a bit more difficult (for me) to understand. 24030043Sminshall * Basically, we don't want to get too far ahead of the characters that 24130043Sminshall * appear on the screen. Ideally, we would type out a few characters, 24230043Sminshall * wait until they appeared on the screen, then type out a few more. 24330043Sminshall * The reason for this is that the user, on seeing some characters 24430043Sminshall * appear on the screen may then start to type something. We would 24530043Sminshall * like to look at what the user types at about the same 'time' 24630043Sminshall * (measured by characters being sent to the terminal) that the 24730043Sminshall * user types them. For this reason, what we would like to do 24830043Sminshall * is update a bit, then call curses to do a refresh, flush the 24930043Sminshall * output to the terminal, then wait until the terminal data 25030043Sminshall * has been sent. 25130043Sminshall * 25230043Sminshall * Note that curses is useful for, among other things, deciding whether 25330043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 25430043Sminshall * at end of lines (beginning of next lines). 25530043Sminshall * 25630043Sminshall * The problems here are the following: If we do lots of write(2)s, 25730043Sminshall * we will be doing lots of context switches, thus lots of overhead 25830043Sminshall * (which we have already). Second, if we do a select to wait for 25930043Sminshall * the output to drain, we have to contend with the fact that NOW 26030043Sminshall * we are scheduled to run, but who knows what the scheduler will 26130043Sminshall * decide when the output has caught up. 26230043Sminshall */ 26330043Sminshall 26433923Sminshall if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ 26530043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 26630043Sminshall } 26730043Sminshall if (Lowest < LowestScreen()) { 26830043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 26930043Sminshall * unformatted screens. 27030043Sminshall */ 27130043Sminshall } 27230043Sminshall if (Highest >= (pointer = Lowest)) { 27330043Sminshall /* if there is anything to do, do it. We won't terminate 27430043Sminshall * the loop until we've gone at least to Highest. 27530043Sminshall */ 27630043Sminshall while ((pointer <= Highest) && !HaveInput) { 27730043Sminshall 27830043Sminshall /* point at the next place of disagreement */ 27930043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 28030043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 28130043Sminshall 28236243Sminshall /* 28336243Sminshall * How many characters to change until the end of the 28430043Sminshall * current line 28530043Sminshall */ 28630043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 28730043Sminshall /* 28830043Sminshall * Make sure we are where we think we are. 28930043Sminshall */ 29030043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 29130043Sminshall 29230043Sminshall /* what is the field attribute of the current position */ 29338206Sminshall if (FormattedScreen()) { 29438206Sminshall fieldattr = FieldAttributes(pointer); 29538206Sminshall DoAttributes(fieldattr); 29638206Sminshall } else { 29738206Sminshall fieldattr = NORMAL; 29838206Sminshall } 29938206Sminshall if (TerminalFormattedScreen()) { 30038206Sminshall termattr = TermAttributes(pointer); 30138206Sminshall DoAttributes(termattr); 30238206Sminshall } else { 30338206Sminshall termattr = NORMAL; 30438206Sminshall } 30530043Sminshall 30636243Sminshall SetHighlightMode(fieldattr); 30736243Sminshall /* 30836243Sminshall * The following will terminate at least when we get back 30936243Sminshall * to the original 'pointer' location (since we force 31036243Sminshall * things to be equal). 31136243Sminshall */ 31236243Sminshall for (;;) { 31336243Sminshall if (IsStartField(pointer)) { 31436243Sminshall shouldbe = DISP_BLANK; 31536243Sminshall shouldattr = 0; 31636243Sminshall fieldattr = GetHost(pointer); 31736243Sminshall DoAttributes(fieldattr); 31836243Sminshall } else { 31936243Sminshall if (fieldattr&NONDISPLAY) { 32036243Sminshall shouldbe = DISP_BLANK; 32136243Sminshall } else { 32236243Sminshall shouldbe = GetHost(pointer); 32336243Sminshall } 32436243Sminshall shouldattr = fieldattr; 32536243Sminshall } 32636243Sminshall if (TermIsStartField(pointer)) { 32736243Sminshall is = DISP_BLANK; 32836243Sminshall isattr = 0; 32938206Sminshall termattr = UNDETERMINED; /* Need to find out AFTER update */ 33036243Sminshall } else { 33136243Sminshall if (termattr&NONDISPLAY) { 33236243Sminshall is = DISP_BLANK; 33336243Sminshall } else { 33436243Sminshall is = GetTerminal(pointer); 33536243Sminshall } 33636243Sminshall isattr = termattr; 33736243Sminshall } 33836243Sminshall if ((shouldbe == is) && (shouldattr == isattr) 33936243Sminshall && (GetHost(pointer) == GetTerminal(pointer)) 34036243Sminshall && (GetHost(ScreenInc(pointer)) 34136243Sminshall == GetTerminal(ScreenInc(pointer)))) { 34236243Sminshall break; 34336243Sminshall } 34430043Sminshall 34536243Sminshall if (shouldattr^inHighlightMode) { 34636243Sminshall SetHighlightMode(shouldattr); 34736243Sminshall } 34830043Sminshall 34936243Sminshall DoCharacterAt(shouldbe, pointer); 35030043Sminshall if (IsStartField(pointer)) { 35136243Sminshall TermNewField(pointer, FieldAttributes(pointer)); 35238206Sminshall termattr = GetTerminal(pointer); 35338206Sminshall DoAttributes(termattr); 35430043Sminshall } else { 35536243Sminshall SetTerminal(pointer, GetHost(pointer)); 35638206Sminshall /* 35738206Sminshall * If this USED to be a start field location, 35838206Sminshall * recompute the terminal attributes. 35938206Sminshall */ 36038206Sminshall if (termattr == UNDETERMINED) { 36138206Sminshall termattr = WhereTermAttrByte(pointer); 36238206Sminshall if ((termattr != 0) || TermIsStartField(0)) { 36338206Sminshall termattr = GetTerminal(termattr); 36438206Sminshall DoAttributes(termattr); 36538206Sminshall } else { /* Unformatted screen */ 36638206Sminshall termattr = NORMAL; 36738206Sminshall } 36838206Sminshall } 36930043Sminshall } 37036243Sminshall pointer = ScreenInc(pointer); 37136243Sminshall if (!(--columnsleft)) { 37236243Sminshall DoARefresh(); 37336243Sminshall EmptyTerminal(); 37436243Sminshall if (HaveInput) { /* if input came in, take it */ 37536243Sminshall int c, j; 37630043Sminshall 37736243Sminshall /* 37836243Sminshall * We need to start a new terminal field 37936243Sminshall * at this location iff the terminal attributes 38036243Sminshall * of this location are not what we have had 38136243Sminshall * them as (ie: we've overwritten the terminal 38236243Sminshall * start field, a the previous field had different 38336243Sminshall * display characteristics). 38436243Sminshall */ 38530043Sminshall 38636243Sminshall isattr = TermAttributes(pointer); 38736243Sminshall DoAttributes(isattr); 38836243Sminshall if ((!TermIsStartField(pointer)) && 38936243Sminshall (isattr != termattr)) { 39030043Sminshall /* 39136243Sminshall * Since we are going to leave a new field 39236243Sminshall * at this terminal position, we 39336243Sminshall * need to make sure that we get an actual 39436243Sminshall * non-highlighted blank on the screen. 39530043Sminshall */ 39636243Sminshall if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { 39736243Sminshall SetHighlightMode(0); /* Turn off highlight */ 39836243Sminshall c = ScreenInc(pointer); 39936243Sminshall j = DISP_BLANK; 40036243Sminshall DoCharacterAt(j, c); 40136243Sminshall } 40236243Sminshall if (termattr&HIGHLIGHT) { 40336243Sminshall termattr = ATTR_DSPD_HIGH; 40436243Sminshall } else if (termattr&NONDISPLAY) { 40536243Sminshall termattr = ATTR_DSPD_NONDISPLAY; 40636243Sminshall } else { 40736243Sminshall termattr = 0; 40836243Sminshall } 40936243Sminshall TermNewField(pointer, termattr); 41036243Sminshall } 41130043Sminshall break; 41230043Sminshall } 41336243Sminshall move(ScreenLine(pointer), 0); 41436243Sminshall columnsleft = NumberColumns; 41530043Sminshall } 41636243Sminshall } /* end of for (;;) */ 41736243Sminshall } /* end of while (...) */ 41830043Sminshall } 41930043Sminshall DoARefresh(); 42030043Sminshall Lowest = pointer; 42130043Sminshall if (Lowest > Highest) { /* if we finished input... */ 42230043Sminshall Lowest = HighestScreen()+1; 42330043Sminshall Highest = LowestScreen()-1; 42430043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 42530043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 42630043Sminshall ScreenLineOffset(terminalCursorAddress))) { 42730043Sminshall GoAway("move", terminalCursorAddress); 42830043Sminshall } 42930043Sminshall DoARefresh(); 43030043Sminshall if (needToRing) { 43130043Sminshall StringToTerminal(bellSequence); 43230043Sminshall needToRing = 0; 43330043Sminshall } 43430043Sminshall } 43530043Sminshall EmptyTerminal(); /* move data along */ 43630043Sminshall return; 43730043Sminshall } 43830043Sminshall 43930043Sminshall #if defined(NOT43) 44030043Sminshall static int 44130043Sminshall #else /* defined(NOT43) */ 44230043Sminshall static void 44330043Sminshall #endif /* defined(NOT43) */ 44430043Sminshall FastScreen() 44530043Sminshall { 44631101Sminshall #if defined(MSDOS) 44730043Sminshall #define SaveCorner 0 44831101Sminshall #else /* defined(MSDOS) */ 44930043Sminshall #define SaveCorner 1 45031101Sminshall #endif /* defined(MSDOS) */ 45130043Sminshall 45230043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 45330043Sminshall standout(); \ 45430043Sminshall } else { \ 45530043Sminshall standend(); \ 45630043Sminshall } \ 45730043Sminshall if (IsNonDisplayAttr(a)) { \ 45830043Sminshall a = 0; /* zero == don't display */ \ 45930043Sminshall } \ 46030043Sminshall if (!FormattedScreen()) { \ 46130043Sminshall a = 1; /* one ==> do display on unformatted */\ 46230043Sminshall } 46330043Sminshall ScreenImage *p, *upper; 46430043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 46530043Sminshall 46630043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 46730043Sminshall * only need to go from Lowest to Highest. However, if we find a 46830043Sminshall * field in the middle, we do the whole screen. 46930043Sminshall * 47030043Sminshall * In particular, we separate out the two cases from the beginning. 47130043Sminshall */ 47230043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 47330043Sminshall register int columnsleft; 47430043Sminshall 47530043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 47630043Sminshall p = &Host[Lowest]; 47731101Sminshall #if !defined(MSDOS) 47830043Sminshall if (Highest == HighestScreen()) { 47930043Sminshall Highest = ScreenDec(Highest); 48030043Sminshall } 48131101Sminshall #endif /* !defined(MSDOS) */ 48230043Sminshall upper = &Host[Highest]; 48330043Sminshall fieldattr = FieldAttributes(Lowest); 48430043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 48530043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 48630043Sminshall 48730043Sminshall while (p <= upper) { 48830054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 48930043Sminshall Highest = HighestScreen(); 49030043Sminshall Lowest = LowestScreen(); 49130043Sminshall FastScreen(); /* Recurse */ 49230043Sminshall return; 49330043Sminshall } else if (fieldattr) { /* Should we display? */ 49431148Sminshall /* Display translated data */ 49535423Sminshall addch((char)disp_asc[GetTerminalPointer(p)]); 49630043Sminshall } else { 49730043Sminshall addch(' '); /* Display a blank */ 49830043Sminshall } 49930043Sminshall /* If the physical screen is larger than what we 50030043Sminshall * are using, we need to make sure that each line 50130043Sminshall * starts at the beginning of the line. Otherwise, 50230043Sminshall * we will just string all the lines together. 50330043Sminshall */ 50430043Sminshall p++; 50530043Sminshall if (--columnsleft == 0) { 50630043Sminshall int i = p-Host; 50730043Sminshall 50830043Sminshall move(ScreenLine(i), 0); 50930043Sminshall columnsleft = NumberColumns; 51030043Sminshall } 51130043Sminshall } 51230043Sminshall } else { /* Going from Lowest to Highest */ 51330043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 51430043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 51530043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 51630043Sminshall 51730043Sminshall *tmpend = 0; /* terminate from the beginning */ 51830043Sminshall move(0,0); 51930043Sminshall p = Host; 52030043Sminshall fieldattr = FieldAttributes(LowestScreen()); 52130043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 52230043Sminshall 52330043Sminshall while (p <= End) { 52430054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 52530043Sminshall if (tmp != tmpbuf) { 52630043Sminshall *tmp++ = 0; /* close out */ 52735423Sminshall addstr((char *)tmpbuf); 52830043Sminshall tmp = tmpbuf; 52936244Sminshall tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1; 53030043Sminshall } 53136244Sminshall standend(); 53236244Sminshall addch(' '); 53330054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 53430043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 53530043Sminshall } else { 53630043Sminshall if (fieldattr) { /* Should we display? */ 53730043Sminshall /* Display translated data */ 53831148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 53930043Sminshall } else { 54030043Sminshall *tmp++ = ' '; 54130043Sminshall } 54230043Sminshall } 54330043Sminshall /* If the physical screen is larger than what we 54430043Sminshall * are using, we need to make sure that each line 54530043Sminshall * starts at the beginning of the line. Otherwise, 54630043Sminshall * we will just string all the lines together. 54730043Sminshall */ 54830043Sminshall p++; 54930043Sminshall if (tmp == tmpend) { 55030043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 55130043Sminshall 55230043Sminshall *tmp++ = 0; 55335423Sminshall addstr((char *)tmpbuf); 55430043Sminshall tmp = tmpbuf; 55530043Sminshall move(ScreenLine(i), 0); 55630043Sminshall tmpend = tmpbuf + NumberColumns; 55730043Sminshall } 55830043Sminshall } 55930043Sminshall if (tmp != tmpbuf) { 56030043Sminshall *tmp++ = 0; 56135423Sminshall addstr((char *)tmpbuf); 56230043Sminshall tmp = tmpbuf; 56330043Sminshall } 56430043Sminshall } 56530043Sminshall Lowest = HighestScreen()+1; 56630043Sminshall Highest = LowestScreen()-1; 56730043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 56830043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 56930043Sminshall ScreenLineOffset(terminalCursorAddress))) { 57030043Sminshall GoAway("move", terminalCursorAddress); 57130043Sminshall } 57230043Sminshall DoARefresh(); 57330043Sminshall if (needToRing) { 57430043Sminshall StringToTerminal(bellSequence); 57530043Sminshall needToRing = 0; 57630043Sminshall } 57730043Sminshall EmptyTerminal(); /* move data along */ 57830043Sminshall return; 57930043Sminshall } 58030043Sminshall 58130043Sminshall 58230043Sminshall /* TryToSend - send data out to user's terminal */ 58330043Sminshall 58430043Sminshall #if defined(NOT43) 58530043Sminshall int 58630043Sminshall #else /* defined(NOT43) */ 58730043Sminshall void 58830043Sminshall #endif /* defined(NOT43) */ 58930043Sminshall (*TryToSend)() = FastScreen; 59030043Sminshall 59135423Sminshall /*ARGSUSED*/ 59231127Sminshall void 59331127Sminshall ScreenOIA(oia) 59431127Sminshall OIA *oia; 59531127Sminshall { 59631127Sminshall } 59731127Sminshall 59831127Sminshall 59930328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 60030043Sminshall 60130043Sminshall void 60230328Sminshall InitTerminal() 60330043Sminshall { 60430043Sminshall #if defined(unix) 60530043Sminshall struct sgttyb ourttyb; 60630043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 60730043Sminshall 2400, 4800, 9600 }; 60830043Sminshall #endif 60935423Sminshall extern void InitMapping(); 61030043Sminshall 61130328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 61230043Sminshall if (!screenInitd) { /* not initialized */ 61330043Sminshall #if defined(unix) 61430043Sminshall char KSEbuffer[2050]; 61530043Sminshall char *lotsofspace = KSEbuffer; 616*59897Sbostic extern void abort(); 61730043Sminshall extern char *tgetstr(); 61830043Sminshall #endif /* defined(unix) */ 61930043Sminshall 62034294Sminshall if (initscr() == ERR) { /* Initialize curses to get line size */ 62134294Sminshall ExitString("InitTerminal: Error initializing curses", 1); 62234294Sminshall /*NOTREACHED*/ 62334294Sminshall } 62434294Sminshall MaxNumberLines = LINES; 62534294Sminshall MaxNumberColumns = COLS; 62631101Sminshall ClearArray(Terminal); 62730328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 62830043Sminshall #if defined(unix) 62930043Sminshall signal(SIGHUP, abort); 63030043Sminshall #endif 63130043Sminshall 63230043Sminshall TryToSend = FastScreen; 63331559Sminshall #if defined(unix) 63430043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 63530043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 63630043Sminshall max_changes_before_poll = 1920; 63730043Sminshall } else { 63830043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 63930043Sminshall if (max_changes_before_poll < 40) { 64030043Sminshall max_changes_before_poll = 40; 64130043Sminshall } 64230043Sminshall TryToSend = SlowScreen; 64330043Sminshall HaveInput = 1; /* get signals going */ 64430043Sminshall } 64531559Sminshall #endif /* defined(unix) */ 64630043Sminshall setcommandmode(); 64730043Sminshall /* 64830043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 64930043Sminshall * and the screen has been initialized. 65030043Sminshall */ 65130043Sminshall #if defined(unix) 65230043Sminshall nonl(); 65330043Sminshall /* the problem is that curses catches SIGTSTP to 65430043Sminshall * be nice, but it messes us up. 65530043Sminshall */ 65630043Sminshall signal(SIGTSTP, SIG_DFL); 65734315Sminshall if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 65834315Sminshall myKS = strsave(myKS); 65934315Sminshall StringToTerminal(myKS); 66030043Sminshall } 66134315Sminshall if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 66234315Sminshall myKE = strsave(myKE); 66330043Sminshall } 66430043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 66530043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 66630043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 66730043Sminshall } 66830043Sminshall #endif 66930043Sminshall DoARefresh(); 67030043Sminshall setconnmode(); 67130043Sminshall if (VB && *VB) { 67230043Sminshall bellSequence = VB; /* use visual bell */ 67330043Sminshall } 67430043Sminshall screenInitd = 1; 67530043Sminshall screenStopped = 0; /* Not stopped */ 67630043Sminshall } 67730043Sminshall } 67830043Sminshall 67930043Sminshall 68030043Sminshall /* StopScreen - called when we are going away... */ 68130043Sminshall 68230043Sminshall void 68330043Sminshall StopScreen(doNewLine) 68430043Sminshall int doNewLine; 68530043Sminshall { 68630043Sminshall if (screenInitd && !screenStopped) { 68730043Sminshall move(NumberLines-1, 1); 68830043Sminshall standend(); 68930043Sminshall inHighlightMode = 0; 69030043Sminshall DoARefresh(); 69130043Sminshall setcommandmode(); 69230043Sminshall endwin(); 69330043Sminshall setconnmode(); 69430043Sminshall #if defined(unix) 69534315Sminshall if (myKE) { 69634315Sminshall StringToTerminal(myKE); 69730043Sminshall } 69830043Sminshall #endif /* defined(unix) */ 69930043Sminshall if (doNewLine) { 70030043Sminshall StringToTerminal("\r\n"); 70130043Sminshall } 70230043Sminshall EmptyTerminal(); 70330043Sminshall screenStopped = 1; /* This is stopped */ 70430043Sminshall } 70530043Sminshall } 70630043Sminshall 70730043Sminshall 70830043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 70930043Sminshall 71030043Sminshall void 71130043Sminshall RefreshScreen() 71230043Sminshall { 71330043Sminshall clearok(curscr, TRUE); 71430043Sminshall (*TryToSend)(); 71530043Sminshall } 71630043Sminshall 71730043Sminshall 71830043Sminshall /* ConnectScreen - called to reconnect to the screen */ 71930043Sminshall 72030043Sminshall void 72130043Sminshall ConnectScreen() 72230043Sminshall { 72330043Sminshall if (screenInitd) { 72430043Sminshall #if defined(unix) 72534315Sminshall if (myKS) { 72634315Sminshall StringToTerminal(myKS); 72730043Sminshall } 72830043Sminshall #endif /* defined(unix) */ 72930043Sminshall RefreshScreen(); 73030043Sminshall (*TryToSend)(); 73130043Sminshall screenStopped = 0; 73230043Sminshall } 73330043Sminshall } 73430043Sminshall 73530043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 73630043Sminshall 73730043Sminshall void 73830043Sminshall LocalClearScreen() 73930043Sminshall { 74035423Sminshall extern void Clear3270(); 74135423Sminshall 74230043Sminshall outputPurge(); /* flush all data to terminal */ 74330043Sminshall clear(); /* clear in curses */ 74431101Sminshall ClearArray(Terminal); 74530043Sminshall Clear3270(); 74630043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 74730043Sminshall Highest = LowestScreen()+1; 74830043Sminshall } 74930043Sminshall 75030043Sminshall 75130043Sminshall void 75230043Sminshall BellOff() 75330043Sminshall { 75430043Sminshall if (bellwinup) { 75530043Sminshall delwin(bellwin); 75630043Sminshall bellwin = 0; 75730043Sminshall bellwinup = 0; 75830043Sminshall touchwin(stdscr); 75930043Sminshall DoARefresh(); 76030043Sminshall } 76130043Sminshall } 76230043Sminshall 76330043Sminshall 76430043Sminshall void 76530043Sminshall RingBell(s) 76630043Sminshall char *s; 76730043Sminshall { 76830043Sminshall needToRing = 1; 76930043Sminshall if (s) { 77030043Sminshall int len = strlen(s); 77130043Sminshall 77230043Sminshall if (len > COLS-2) { 77330043Sminshall len = COLS-2; 77430043Sminshall } 77530043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 77635423Sminshall OurExitString("Error from newwin in RingBell", 1); 77730043Sminshall } 77830043Sminshall werase(bellwin); 77930043Sminshall wstandout(bellwin); 78030043Sminshall box(bellwin, '|', '-'); 78130043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 78235423Sminshall OurExitString("Error from wmove in RingBell", 1); 78330043Sminshall } 78430043Sminshall while (len--) { 78530043Sminshall if (waddch(bellwin, *s++) == ERR) { 78635423Sminshall OurExitString("Error from waddch in RingBell", 1); 78730043Sminshall } 78830043Sminshall } 78930043Sminshall wstandend(bellwin); 79030043Sminshall if (wrefresh(bellwin) == ERR) { 79135423Sminshall OurExitString("Error from wrefresh in RingBell", 1); 79230043Sminshall } 79330043Sminshall bellwinup = 1; 79430043Sminshall } 79530043Sminshall } 79630043Sminshall 79730043Sminshall 79830043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 79930043Sminshall or a 0 if there is more output available (so, just poll the other 80030043Sminshall sources/destinations, don't block). 80130043Sminshall */ 80230043Sminshall 80330043Sminshall int 80430043Sminshall DoTerminalOutput() 80530043Sminshall { 80630043Sminshall /* called just before a select to conserve IO to terminal */ 80731462Sminshall if (!(screenInitd||screenStopped)) { 80830369Sminshall return 1; /* No output if not initialized */ 80930369Sminshall } 81030369Sminshall if ((Lowest <= Highest) || needToRing || 81130369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 81230043Sminshall (*TryToSend)(); 81330043Sminshall } 81430043Sminshall if (Lowest > Highest) { 81530369Sminshall return 1; /* no more output now */ 81630043Sminshall } else { 81730369Sminshall return 0; /* more output for future */ 81830043Sminshall } 81930043Sminshall } 82030074Sminshall 82130074Sminshall /* 82230074Sminshall * The following are defined to handle transparent data. 82330074Sminshall */ 82430074Sminshall 82530074Sminshall void 82630074Sminshall TransStop() 82730074Sminshall { 82830074Sminshall #if defined(unix) 82930074Sminshall if (tcflag == 0) { 83030074Sminshall tcflag = -1; 83130074Sminshall (void) signal(SIGCHLD, SIG_DFL); 83230074Sminshall } else if (tcflag > 0) { 83330074Sminshall setcommandmode(); 83430074Sminshall (void) close(tin); 83530074Sminshall (void) close(tout); 83630074Sminshall tin = savefd[0]; 83730074Sminshall tout = savefd[1]; 83830074Sminshall setconnmode(); 83930074Sminshall tcflag = -1; 84030074Sminshall (void) signal(SIGCHLD, SIG_DFL); 84130074Sminshall } 84230074Sminshall #endif /* defined(unix) */ 84330074Sminshall RefreshScreen(); 84430074Sminshall } 84530074Sminshall 84630074Sminshall void 84731863Sminshall TransOut(buffer, count, kind, control) 84830074Sminshall unsigned char *buffer; 84930074Sminshall int count; 85031863Sminshall int kind; /* 0 or 5 */ 85131863Sminshall int control; /* To see if we are done */ 85230074Sminshall { 85330074Sminshall #if defined(unix) 85430074Sminshall extern char *transcom; 85535423Sminshall int inpipefd[2], outpipefd[2]; 856*59897Sbostic static void aborttc(); 85730074Sminshall #endif /* defined(unix) */ 85830074Sminshall 85930074Sminshall while (DoTerminalOutput() == 0) { 86030074Sminshall #if defined(unix) 86130074Sminshall HaveInput = 0; 86230074Sminshall #endif /* defined(unix) */ 86330074Sminshall } 86430074Sminshall #if defined(unix) 86530074Sminshall if (transcom && tcflag == -1) { 86630074Sminshall while (1) { /* go thru once */ 86730074Sminshall if (pipe(outpipefd) < 0) { 86830074Sminshall break; 86930074Sminshall } 87030074Sminshall if (pipe(inpipefd) < 0) { 87130074Sminshall break; 87230074Sminshall } 87330074Sminshall if ((tcflag = fork()) == 0) { 87430074Sminshall (void) close(outpipefd[1]); 87530074Sminshall (void) close(0); 87630074Sminshall if (dup(outpipefd[0]) < 0) { 87730074Sminshall exit(1); 87830074Sminshall } 87930074Sminshall (void) close(outpipefd[0]); 88030074Sminshall (void) close(inpipefd[0]); 88130074Sminshall (void) close(1); 88230074Sminshall if (dup(inpipefd[1]) < 0) { 88330074Sminshall exit(1); 88430074Sminshall } 88530074Sminshall (void) close(inpipefd[1]); 88630074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 88730074Sminshall exit(1); 88830074Sminshall } 88930074Sminshall } 89030074Sminshall (void) close(inpipefd[1]); 89130074Sminshall (void) close(outpipefd[0]); 89230074Sminshall savefd[0] = tin; 89330074Sminshall savefd[1] = tout; 89430074Sminshall setcommandmode(); 89530074Sminshall tin = inpipefd[0]; 89630074Sminshall tout = outpipefd[1]; 897*59897Sbostic (void) signal(SIGCHLD, aborttc); 89830074Sminshall setconnmode(); 89930074Sminshall tcflag = 1; 90030074Sminshall break; 90130074Sminshall } 90230074Sminshall if (tcflag < 1) { 90330074Sminshall tcflag = 0; 90430074Sminshall } 90530074Sminshall } 90630074Sminshall #endif /* defined(unix) */ 90735423Sminshall (void) DataToTerminal((char *)buffer, count); 90831863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 90931863Sminshall SendToIBM(); 91031863Sminshall } else { 91135423Sminshall extern void TransInput(); 91235423Sminshall 91331863Sminshall TransInput(1, kind); /* Go get some data */ 91431863Sminshall } 91530074Sminshall } 91630074Sminshall 91730074Sminshall 91830074Sminshall #if defined(unix) 91930074Sminshall static void 920*59897Sbostic aborttc(signo) 921*59897Sbostic int signo; 92230074Sminshall { 92330074Sminshall setcommandmode(); 92430074Sminshall (void) close(tin); 92530074Sminshall (void) close(tout); 92630074Sminshall tin = savefd[0]; 92730074Sminshall tout = savefd[1]; 92830074Sminshall setconnmode(); 92930074Sminshall tcflag = 0; 93030074Sminshall } 93130074Sminshall #endif /* defined(unix) */ 932