130043Sminshall /* 233810Sbostic * Copyright (c) 1988 Regents of the University of California. 333810Sbostic * All rights reserved. 430043Sminshall * 533810Sbostic * Redistribution and use in source and binary forms are permitted 635423Sminshall * provided that the above copyright notice and this paragraph are 735423Sminshall * duplicated in all such forms and that any documentation, 835423Sminshall * advertising materials, and other materials related to such 935423Sminshall * distribution and use acknowledge that the software was developed 1035423Sminshall * by the University of California, Berkeley. The name of the 1135423Sminshall * University may not be used to endorse or promote products derived 1235423Sminshall * from this software without specific prior written permission. 1335423Sminshall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435423Sminshall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535423Sminshall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1630043Sminshall */ 1730043Sminshall 1830043Sminshall #ifndef lint 19*38206Sminshall static char sccsid[] = "@(#)termout.c 4.2 (Berkeley) 05/30/89"; 2033810Sbostic #endif /* not lint */ 2130043Sminshall 2230043Sminshall #if defined(unix) 2330043Sminshall #include <signal.h> 2430043Sminshall #include <sgtty.h> 2530043Sminshall #endif 2630043Sminshall #include <stdio.h> 2730043Sminshall #include <curses.h> 2834307Sminshall #if defined(ultrix) 2934307Sminshall /* Some version of this OS has a bad definition for nonl() */ 3034307Sminshall #undef nl 3134307Sminshall #undef nonl 3230043Sminshall 3334307Sminshall #define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty)) 3434307Sminshall #define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty)) 3534307Sminshall #endif /* defined(ultrix) */ 3634307Sminshall 3731179Sminshall #include "../general/general.h" 3831071Sminshall 3930043Sminshall #include "terminal.h" 4030043Sminshall 4131873Sminshall #include "../api/disp_asc.h" 4231224Sminshall 4330043Sminshall #include "../ctlr/hostctlr.h" 4435423Sminshall #include "../ctlr/externs.h" 4535423Sminshall #include "../ctlr/declare.h" 4631127Sminshall #include "../ctlr/oia.h" 4730043Sminshall #include "../ctlr/screen.h" 4836243Sminshall #include "../ctlr/scrnctlr.h" 4930043Sminshall 5031179Sminshall #include "../general/globals.h" 5130043Sminshall 5235423Sminshall #include "../telextrn.h" 5330043Sminshall 5430043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 5531839Sminshall CursorAddress:UnLocked? CursorAddress: HighestScreen()) 5630043Sminshall 5730043Sminshall 5830328Sminshall static int terminalCursorAddress; /* where the cursor is on term */ 5930328Sminshall static int screenInitd; /* the screen has been initialized */ 6030328Sminshall static int screenStopped; /* the screen has been stopped */ 6130043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 6230043Sminshall /* at terminal and net again */ 6330043Sminshall 6430328Sminshall static int needToRing; /* need to ring terinal bell */ 6530043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 6630043Sminshall * VB during initialization) 6730043Sminshall */ 6830328Sminshall static WINDOW *bellwin = 0; /* The window the bell message is in */ 6930043Sminshall int bellwinup = 0; /* Are we up with it or not */ 7030043Sminshall 7130043Sminshall #if defined(unix) 7234315Sminshall static char *myKS, *myKE; 7330043Sminshall #endif /* defined(unix) */ 7430043Sminshall 7530074Sminshall 7630074Sminshall static int inHighlightMode = 0; 7731071Sminshall ScreenImage Terminal[MAXSCREENSIZE]; 7830074Sminshall 7930074Sminshall /* Variables for transparent mode */ 8030043Sminshall #if defined(unix) 8130043Sminshall static int tcflag = -1; /* transparent mode command flag */ 8230043Sminshall static int savefd[2]; /* for storing fds during transcom */ 8330074Sminshall extern int tin, tout; /* file descriptors */ 8430043Sminshall #endif /* defined(unix) */ 8530043Sminshall 8630730Sminshall 8730730Sminshall /* 8830730Sminshall * init_screen() 8930730Sminshall * 9030730Sminshall * Initialize variables used by screen. 9130730Sminshall */ 9230730Sminshall 9330730Sminshall void 9430730Sminshall init_screen() 9530730Sminshall { 9630730Sminshall bellwinup = 0; 9730730Sminshall inHighlightMode = 0; 9831071Sminshall ClearArray(Terminal); 9930730Sminshall } 10030730Sminshall 10130730Sminshall 10230043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 10330043Sminshall 10430043Sminshall static void 10535423Sminshall OurExitString(string, value) 10630043Sminshall char *string; 10730043Sminshall int value; 10830043Sminshall { 10930043Sminshall static int recursion = 0; 11030043Sminshall 11130043Sminshall if (!recursion) { 11230043Sminshall recursion = 1; 11335423Sminshall ExitString(string, value); 11430043Sminshall } 11530043Sminshall } 11630043Sminshall 11730043Sminshall 11830043Sminshall /* DoARefresh */ 11930043Sminshall 12030043Sminshall static void 12130043Sminshall DoARefresh() 12230043Sminshall { 12330043Sminshall if (ERR == refresh()) { 12435423Sminshall OurExitString("ERR from refresh\n", 1); 12530043Sminshall } 12630043Sminshall } 12730043Sminshall 12830043Sminshall static void 12930043Sminshall GoAway(from, where) 13030043Sminshall char *from; /* routine that gave error */ 13130043Sminshall int where; /* cursor address */ 13230043Sminshall { 13330043Sminshall char foo[100]; 13430043Sminshall 13530043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 13630043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 13735423Sminshall OurExitString(foo, 1); 13830043Sminshall /* NOTREACHED */ 13930043Sminshall } 14030043Sminshall 14130043Sminshall /* What is the screen address of the attribute byte for the terminal */ 14230043Sminshall 14330043Sminshall static int 14430043Sminshall WhereTermAttrByte(p) 14530043Sminshall register int p; 14630043Sminshall { 14730043Sminshall register int i; 14830043Sminshall 14930043Sminshall i = p; 15030043Sminshall 15130043Sminshall do { 15230043Sminshall if (TermIsStartField(i)) { 15330043Sminshall return(i); 15430043Sminshall } 15530043Sminshall i = ScreenDec(i); 15630043Sminshall } while (i != p); 15730043Sminshall 15830043Sminshall return(LowestScreen()); /* unformatted screen... */ 15930043Sminshall } 16030043Sminshall 16130043Sminshall /* 16230043Sminshall * There are two algorithms for updating the screen. 16330043Sminshall * The first, SlowScreen() optimizes the line between the 16430043Sminshall * computer and the screen (say a 9600 baud line). To do 16530043Sminshall * this, we break out of the loop every so often to look 16630043Sminshall * at any pending input from the network (so that successive 16730043Sminshall * screens will only partially print until the final screen, 16830043Sminshall * the one the user possibly wants to see, is displayed 16930043Sminshall * in its entirety). 17030043Sminshall * 17130043Sminshall * The second algorithm tries to optimize CPU time (by 17230043Sminshall * being simpler) at the cost of the bandwidth to the 17330043Sminshall * screen. 17430043Sminshall * 17530043Sminshall * Of course, curses(3X) gets in here also. 17630043Sminshall */ 17730043Sminshall 17830043Sminshall 17930043Sminshall #if defined(NOT43) 18030043Sminshall static int 18130043Sminshall #else /* defined(NOT43) */ 18230043Sminshall static void 18330043Sminshall #endif /* defined(NOT43) */ 18430043Sminshall SlowScreen() 18530043Sminshall { 18636243Sminshall register int is, shouldbe, isattr, shouldattr; 18730043Sminshall register int pointer; 18836243Sminshall register int fieldattr, termattr; 18930043Sminshall register int columnsleft; 19030043Sminshall 191*38206Sminshall #define NORMAL 0 19236243Sminshall #define HIGHLIGHT 1 /* Mask bits */ 19336243Sminshall #define NONDISPLAY 4 /* Mask bits */ 194*38206Sminshall #define UNDETERMINED 8 /* Mask bits */ 19536243Sminshall 19636243Sminshall #define DoAttributes(x) \ 19736243Sminshall switch (x&ATTR_DSPD_MASK) { \ 19836243Sminshall case ATTR_DSPD_NONDISPLAY: \ 19936243Sminshall x = NONDISPLAY; \ 20036243Sminshall break; \ 20136243Sminshall case ATTR_DSPD_HIGH: \ 20236243Sminshall x = HIGHLIGHT; \ 20336243Sminshall break; \ 20436243Sminshall default: \ 20536243Sminshall x = 0; \ 20636243Sminshall break; \ 20736243Sminshall } 20836243Sminshall 20936243Sminshall # define SetHighlightMode(x) \ 21036243Sminshall { \ 21136243Sminshall if ((x)&HIGHLIGHT) { \ 21230043Sminshall if (!inHighlightMode) { \ 21336243Sminshall inHighlightMode = HIGHLIGHT; \ 21430043Sminshall standout(); \ 21530043Sminshall } \ 21630043Sminshall } else { \ 21730043Sminshall if (inHighlightMode) { \ 21830043Sminshall inHighlightMode = 0; \ 21930043Sminshall standend(); \ 22030043Sminshall } \ 22130043Sminshall } \ 22230043Sminshall } 22330043Sminshall 22430043Sminshall # define DoCharacterAt(c,p) { \ 22530043Sminshall if (p != HighestScreen()) { \ 22636243Sminshall c = disp_asc[c&0xff]; \ 22730043Sminshall if (terminalCursorAddress != p) { \ 22830043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 22930043Sminshall ScreenLineOffset(p), c)) {\ 23030043Sminshall GoAway("mvaddch", p); \ 23130043Sminshall } \ 23230043Sminshall } else { \ 23330043Sminshall if (ERR == addch(c)) {\ 23430043Sminshall GoAway("addch", p); \ 23530043Sminshall } \ 23630043Sminshall } \ 23730043Sminshall terminalCursorAddress = ScreenInc(p); \ 23830043Sminshall } \ 23930043Sminshall } 24030043Sminshall 24130043Sminshall 24230043Sminshall /* run through screen, printing out non-null lines */ 24330043Sminshall 24430043Sminshall /* There are two separate reasons for wanting to terminate this 24530043Sminshall * loop early. One is to respond to new input (either from 24630043Sminshall * the terminal or from the network [host]). For this reason, 24730043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 24830043Sminshall * 24930043Sminshall * The second reason is a bit more difficult (for me) to understand. 25030043Sminshall * Basically, we don't want to get too far ahead of the characters that 25130043Sminshall * appear on the screen. Ideally, we would type out a few characters, 25230043Sminshall * wait until they appeared on the screen, then type out a few more. 25330043Sminshall * The reason for this is that the user, on seeing some characters 25430043Sminshall * appear on the screen may then start to type something. We would 25530043Sminshall * like to look at what the user types at about the same 'time' 25630043Sminshall * (measured by characters being sent to the terminal) that the 25730043Sminshall * user types them. For this reason, what we would like to do 25830043Sminshall * is update a bit, then call curses to do a refresh, flush the 25930043Sminshall * output to the terminal, then wait until the terminal data 26030043Sminshall * has been sent. 26130043Sminshall * 26230043Sminshall * Note that curses is useful for, among other things, deciding whether 26330043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 26430043Sminshall * at end of lines (beginning of next lines). 26530043Sminshall * 26630043Sminshall * The problems here are the following: If we do lots of write(2)s, 26730043Sminshall * we will be doing lots of context switches, thus lots of overhead 26830043Sminshall * (which we have already). Second, if we do a select to wait for 26930043Sminshall * the output to drain, we have to contend with the fact that NOW 27030043Sminshall * we are scheduled to run, but who knows what the scheduler will 27130043Sminshall * decide when the output has caught up. 27230043Sminshall */ 27330043Sminshall 27433923Sminshall if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ 27530043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 27630043Sminshall } 27730043Sminshall if (Lowest < LowestScreen()) { 27830043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 27930043Sminshall * unformatted screens. 28030043Sminshall */ 28130043Sminshall } 28230043Sminshall if (Highest >= (pointer = Lowest)) { 28330043Sminshall /* if there is anything to do, do it. We won't terminate 28430043Sminshall * the loop until we've gone at least to Highest. 28530043Sminshall */ 28630043Sminshall while ((pointer <= Highest) && !HaveInput) { 28730043Sminshall 28830043Sminshall /* point at the next place of disagreement */ 28930043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 29030043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 29130043Sminshall 29236243Sminshall /* 29336243Sminshall * How many characters to change until the end of the 29430043Sminshall * current line 29530043Sminshall */ 29630043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 29730043Sminshall /* 29830043Sminshall * Make sure we are where we think we are. 29930043Sminshall */ 30030043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 30130043Sminshall 30230043Sminshall /* what is the field attribute of the current position */ 303*38206Sminshall if (FormattedScreen()) { 304*38206Sminshall fieldattr = FieldAttributes(pointer); 305*38206Sminshall DoAttributes(fieldattr); 306*38206Sminshall } else { 307*38206Sminshall fieldattr = NORMAL; 308*38206Sminshall } 309*38206Sminshall if (TerminalFormattedScreen()) { 310*38206Sminshall termattr = TermAttributes(pointer); 311*38206Sminshall DoAttributes(termattr); 312*38206Sminshall } else { 313*38206Sminshall termattr = NORMAL; 314*38206Sminshall } 31530043Sminshall 31636243Sminshall SetHighlightMode(fieldattr); 31736243Sminshall /* 31836243Sminshall * The following will terminate at least when we get back 31936243Sminshall * to the original 'pointer' location (since we force 32036243Sminshall * things to be equal). 32136243Sminshall */ 32236243Sminshall for (;;) { 32336243Sminshall if (IsStartField(pointer)) { 32436243Sminshall shouldbe = DISP_BLANK; 32536243Sminshall shouldattr = 0; 32636243Sminshall fieldattr = GetHost(pointer); 32736243Sminshall DoAttributes(fieldattr); 32836243Sminshall } else { 32936243Sminshall if (fieldattr&NONDISPLAY) { 33036243Sminshall shouldbe = DISP_BLANK; 33136243Sminshall } else { 33236243Sminshall shouldbe = GetHost(pointer); 33336243Sminshall } 33436243Sminshall shouldattr = fieldattr; 33536243Sminshall } 33636243Sminshall if (TermIsStartField(pointer)) { 33736243Sminshall is = DISP_BLANK; 33836243Sminshall isattr = 0; 339*38206Sminshall termattr = UNDETERMINED; /* Need to find out AFTER update */ 34036243Sminshall } else { 34136243Sminshall if (termattr&NONDISPLAY) { 34236243Sminshall is = DISP_BLANK; 34336243Sminshall } else { 34436243Sminshall is = GetTerminal(pointer); 34536243Sminshall } 34636243Sminshall isattr = termattr; 34736243Sminshall } 34836243Sminshall if ((shouldbe == is) && (shouldattr == isattr) 34936243Sminshall && (GetHost(pointer) == GetTerminal(pointer)) 35036243Sminshall && (GetHost(ScreenInc(pointer)) 35136243Sminshall == GetTerminal(ScreenInc(pointer)))) { 35236243Sminshall break; 35336243Sminshall } 35430043Sminshall 35536243Sminshall if (shouldattr^inHighlightMode) { 35636243Sminshall SetHighlightMode(shouldattr); 35736243Sminshall } 35830043Sminshall 35936243Sminshall DoCharacterAt(shouldbe, pointer); 36030043Sminshall if (IsStartField(pointer)) { 36136243Sminshall TermNewField(pointer, FieldAttributes(pointer)); 362*38206Sminshall termattr = GetTerminal(pointer); 363*38206Sminshall DoAttributes(termattr); 36430043Sminshall } else { 36536243Sminshall SetTerminal(pointer, GetHost(pointer)); 366*38206Sminshall /* 367*38206Sminshall * If this USED to be a start field location, 368*38206Sminshall * recompute the terminal attributes. 369*38206Sminshall */ 370*38206Sminshall if (termattr == UNDETERMINED) { 371*38206Sminshall termattr = WhereTermAttrByte(pointer); 372*38206Sminshall if ((termattr != 0) || TermIsStartField(0)) { 373*38206Sminshall termattr = GetTerminal(termattr); 374*38206Sminshall DoAttributes(termattr); 375*38206Sminshall } else { /* Unformatted screen */ 376*38206Sminshall termattr = NORMAL; 377*38206Sminshall } 378*38206Sminshall } 37930043Sminshall } 38036243Sminshall pointer = ScreenInc(pointer); 38136243Sminshall if (!(--columnsleft)) { 38236243Sminshall DoARefresh(); 38336243Sminshall EmptyTerminal(); 38436243Sminshall if (HaveInput) { /* if input came in, take it */ 38536243Sminshall int c, j; 38630043Sminshall 38736243Sminshall /* 38836243Sminshall * We need to start a new terminal field 38936243Sminshall * at this location iff the terminal attributes 39036243Sminshall * of this location are not what we have had 39136243Sminshall * them as (ie: we've overwritten the terminal 39236243Sminshall * start field, a the previous field had different 39336243Sminshall * display characteristics). 39436243Sminshall */ 39530043Sminshall 39636243Sminshall isattr = TermAttributes(pointer); 39736243Sminshall DoAttributes(isattr); 39836243Sminshall if ((!TermIsStartField(pointer)) && 39936243Sminshall (isattr != termattr)) { 40030043Sminshall /* 40136243Sminshall * Since we are going to leave a new field 40236243Sminshall * at this terminal position, we 40336243Sminshall * need to make sure that we get an actual 40436243Sminshall * non-highlighted blank on the screen. 40530043Sminshall */ 40636243Sminshall if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { 40736243Sminshall SetHighlightMode(0); /* Turn off highlight */ 40836243Sminshall c = ScreenInc(pointer); 40936243Sminshall j = DISP_BLANK; 41036243Sminshall DoCharacterAt(j, c); 41136243Sminshall } 41236243Sminshall if (termattr&HIGHLIGHT) { 41336243Sminshall termattr = ATTR_DSPD_HIGH; 41436243Sminshall } else if (termattr&NONDISPLAY) { 41536243Sminshall termattr = ATTR_DSPD_NONDISPLAY; 41636243Sminshall } else { 41736243Sminshall termattr = 0; 41836243Sminshall } 41936243Sminshall TermNewField(pointer, termattr); 42036243Sminshall } 42130043Sminshall break; 42230043Sminshall } 42336243Sminshall move(ScreenLine(pointer), 0); 42436243Sminshall columnsleft = NumberColumns; 42530043Sminshall } 42636243Sminshall } /* end of for (;;) */ 42736243Sminshall } /* end of while (...) */ 42830043Sminshall } 42930043Sminshall DoARefresh(); 43030043Sminshall Lowest = pointer; 43130043Sminshall if (Lowest > Highest) { /* if we finished input... */ 43230043Sminshall Lowest = HighestScreen()+1; 43330043Sminshall Highest = LowestScreen()-1; 43430043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 43530043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 43630043Sminshall ScreenLineOffset(terminalCursorAddress))) { 43730043Sminshall GoAway("move", terminalCursorAddress); 43830043Sminshall } 43930043Sminshall DoARefresh(); 44030043Sminshall if (needToRing) { 44130043Sminshall StringToTerminal(bellSequence); 44230043Sminshall needToRing = 0; 44330043Sminshall } 44430043Sminshall } 44530043Sminshall EmptyTerminal(); /* move data along */ 44630043Sminshall return; 44730043Sminshall } 44830043Sminshall 44930043Sminshall #if defined(NOT43) 45030043Sminshall static int 45130043Sminshall #else /* defined(NOT43) */ 45230043Sminshall static void 45330043Sminshall #endif /* defined(NOT43) */ 45430043Sminshall FastScreen() 45530043Sminshall { 45631101Sminshall #if defined(MSDOS) 45730043Sminshall #define SaveCorner 0 45831101Sminshall #else /* defined(MSDOS) */ 45930043Sminshall #define SaveCorner 1 46031101Sminshall #endif /* defined(MSDOS) */ 46130043Sminshall 46230043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 46330043Sminshall standout(); \ 46430043Sminshall } else { \ 46530043Sminshall standend(); \ 46630043Sminshall } \ 46730043Sminshall if (IsNonDisplayAttr(a)) { \ 46830043Sminshall a = 0; /* zero == don't display */ \ 46930043Sminshall } \ 47030043Sminshall if (!FormattedScreen()) { \ 47130043Sminshall a = 1; /* one ==> do display on unformatted */\ 47230043Sminshall } 47330043Sminshall ScreenImage *p, *upper; 47430043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 47530043Sminshall 47630043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 47730043Sminshall * only need to go from Lowest to Highest. However, if we find a 47830043Sminshall * field in the middle, we do the whole screen. 47930043Sminshall * 48030043Sminshall * In particular, we separate out the two cases from the beginning. 48130043Sminshall */ 48230043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 48330043Sminshall register int columnsleft; 48430043Sminshall 48530043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 48630043Sminshall p = &Host[Lowest]; 48731101Sminshall #if !defined(MSDOS) 48830043Sminshall if (Highest == HighestScreen()) { 48930043Sminshall Highest = ScreenDec(Highest); 49030043Sminshall } 49131101Sminshall #endif /* !defined(MSDOS) */ 49230043Sminshall upper = &Host[Highest]; 49330043Sminshall fieldattr = FieldAttributes(Lowest); 49430043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 49530043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 49630043Sminshall 49730043Sminshall while (p <= upper) { 49830054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 49930043Sminshall Highest = HighestScreen(); 50030043Sminshall Lowest = LowestScreen(); 50130043Sminshall FastScreen(); /* Recurse */ 50230043Sminshall return; 50330043Sminshall } else if (fieldattr) { /* Should we display? */ 50431148Sminshall /* Display translated data */ 50535423Sminshall addch((char)disp_asc[GetTerminalPointer(p)]); 50630043Sminshall } else { 50730043Sminshall addch(' '); /* Display a blank */ 50830043Sminshall } 50930043Sminshall /* If the physical screen is larger than what we 51030043Sminshall * are using, we need to make sure that each line 51130043Sminshall * starts at the beginning of the line. Otherwise, 51230043Sminshall * we will just string all the lines together. 51330043Sminshall */ 51430043Sminshall p++; 51530043Sminshall if (--columnsleft == 0) { 51630043Sminshall int i = p-Host; 51730043Sminshall 51830043Sminshall move(ScreenLine(i), 0); 51930043Sminshall columnsleft = NumberColumns; 52030043Sminshall } 52130043Sminshall } 52230043Sminshall } else { /* Going from Lowest to Highest */ 52330043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 52430043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 52530043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 52630043Sminshall 52730043Sminshall *tmpend = 0; /* terminate from the beginning */ 52830043Sminshall move(0,0); 52930043Sminshall p = Host; 53030043Sminshall fieldattr = FieldAttributes(LowestScreen()); 53130043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 53230043Sminshall 53330043Sminshall while (p <= End) { 53430054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 53530043Sminshall if (tmp != tmpbuf) { 53630043Sminshall *tmp++ = 0; /* close out */ 53735423Sminshall addstr((char *)tmpbuf); 53830043Sminshall tmp = tmpbuf; 53936244Sminshall tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1; 54030043Sminshall } 54136244Sminshall standend(); 54236244Sminshall addch(' '); 54330054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 54430043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 54530043Sminshall } else { 54630043Sminshall if (fieldattr) { /* Should we display? */ 54730043Sminshall /* Display translated data */ 54831148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 54930043Sminshall } else { 55030043Sminshall *tmp++ = ' '; 55130043Sminshall } 55230043Sminshall } 55330043Sminshall /* If the physical screen is larger than what we 55430043Sminshall * are using, we need to make sure that each line 55530043Sminshall * starts at the beginning of the line. Otherwise, 55630043Sminshall * we will just string all the lines together. 55730043Sminshall */ 55830043Sminshall p++; 55930043Sminshall if (tmp == tmpend) { 56030043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 56130043Sminshall 56230043Sminshall *tmp++ = 0; 56335423Sminshall addstr((char *)tmpbuf); 56430043Sminshall tmp = tmpbuf; 56530043Sminshall move(ScreenLine(i), 0); 56630043Sminshall tmpend = tmpbuf + NumberColumns; 56730043Sminshall } 56830043Sminshall } 56930043Sminshall if (tmp != tmpbuf) { 57030043Sminshall *tmp++ = 0; 57135423Sminshall addstr((char *)tmpbuf); 57230043Sminshall tmp = tmpbuf; 57330043Sminshall } 57430043Sminshall } 57530043Sminshall Lowest = HighestScreen()+1; 57630043Sminshall Highest = LowestScreen()-1; 57730043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 57830043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 57930043Sminshall ScreenLineOffset(terminalCursorAddress))) { 58030043Sminshall GoAway("move", terminalCursorAddress); 58130043Sminshall } 58230043Sminshall DoARefresh(); 58330043Sminshall if (needToRing) { 58430043Sminshall StringToTerminal(bellSequence); 58530043Sminshall needToRing = 0; 58630043Sminshall } 58730043Sminshall EmptyTerminal(); /* move data along */ 58830043Sminshall return; 58930043Sminshall } 59030043Sminshall 59130043Sminshall 59230043Sminshall /* TryToSend - send data out to user's terminal */ 59330043Sminshall 59430043Sminshall #if defined(NOT43) 59530043Sminshall int 59630043Sminshall #else /* defined(NOT43) */ 59730043Sminshall void 59830043Sminshall #endif /* defined(NOT43) */ 59930043Sminshall (*TryToSend)() = FastScreen; 60030043Sminshall 60135423Sminshall /*ARGSUSED*/ 60231127Sminshall void 60331127Sminshall ScreenOIA(oia) 60431127Sminshall OIA *oia; 60531127Sminshall { 60631127Sminshall } 60731127Sminshall 60831127Sminshall 60930328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 61030043Sminshall 61130043Sminshall void 61230328Sminshall InitTerminal() 61330043Sminshall { 61430043Sminshall #if defined(unix) 61530043Sminshall struct sgttyb ourttyb; 61630043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 61730043Sminshall 2400, 4800, 9600 }; 61830043Sminshall #endif 61935423Sminshall extern void InitMapping(); 62030043Sminshall 62130328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 62230043Sminshall if (!screenInitd) { /* not initialized */ 62330043Sminshall #if defined(unix) 62430043Sminshall char KSEbuffer[2050]; 62530043Sminshall char *lotsofspace = KSEbuffer; 62630043Sminshall extern int abort(); 62730043Sminshall extern char *tgetstr(); 62830043Sminshall #endif /* defined(unix) */ 62930043Sminshall 63034294Sminshall if (initscr() == ERR) { /* Initialize curses to get line size */ 63134294Sminshall ExitString("InitTerminal: Error initializing curses", 1); 63234294Sminshall /*NOTREACHED*/ 63334294Sminshall } 63434294Sminshall MaxNumberLines = LINES; 63534294Sminshall MaxNumberColumns = COLS; 63631101Sminshall ClearArray(Terminal); 63730328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 63830043Sminshall #if defined(unix) 63930043Sminshall signal(SIGHUP, abort); 64030043Sminshall #endif 64130043Sminshall 64230043Sminshall TryToSend = FastScreen; 64331559Sminshall #if defined(unix) 64430043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 64530043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 64630043Sminshall max_changes_before_poll = 1920; 64730043Sminshall } else { 64830043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 64930043Sminshall if (max_changes_before_poll < 40) { 65030043Sminshall max_changes_before_poll = 40; 65130043Sminshall } 65230043Sminshall TryToSend = SlowScreen; 65330043Sminshall HaveInput = 1; /* get signals going */ 65430043Sminshall } 65531559Sminshall #endif /* defined(unix) */ 65630043Sminshall setcommandmode(); 65730043Sminshall /* 65830043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 65930043Sminshall * and the screen has been initialized. 66030043Sminshall */ 66130043Sminshall #if defined(unix) 66230043Sminshall nonl(); 66330043Sminshall /* the problem is that curses catches SIGTSTP to 66430043Sminshall * be nice, but it messes us up. 66530043Sminshall */ 66630043Sminshall signal(SIGTSTP, SIG_DFL); 66734315Sminshall if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 66834315Sminshall myKS = strsave(myKS); 66934315Sminshall StringToTerminal(myKS); 67030043Sminshall } 67134315Sminshall if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 67234315Sminshall myKE = strsave(myKE); 67330043Sminshall } 67430043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 67530043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 67630043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 67730043Sminshall } 67830043Sminshall #endif 67930043Sminshall DoARefresh(); 68030043Sminshall setconnmode(); 68130043Sminshall if (VB && *VB) { 68230043Sminshall bellSequence = VB; /* use visual bell */ 68330043Sminshall } 68430043Sminshall screenInitd = 1; 68530043Sminshall screenStopped = 0; /* Not stopped */ 68630043Sminshall } 68730043Sminshall } 68830043Sminshall 68930043Sminshall 69030043Sminshall /* StopScreen - called when we are going away... */ 69130043Sminshall 69230043Sminshall void 69330043Sminshall StopScreen(doNewLine) 69430043Sminshall int doNewLine; 69530043Sminshall { 69630043Sminshall if (screenInitd && !screenStopped) { 69730043Sminshall move(NumberLines-1, 1); 69830043Sminshall standend(); 69930043Sminshall inHighlightMode = 0; 70030043Sminshall DoARefresh(); 70130043Sminshall setcommandmode(); 70230043Sminshall endwin(); 70330043Sminshall setconnmode(); 70430043Sminshall #if defined(unix) 70534315Sminshall if (myKE) { 70634315Sminshall StringToTerminal(myKE); 70730043Sminshall } 70830043Sminshall #endif /* defined(unix) */ 70930043Sminshall if (doNewLine) { 71030043Sminshall StringToTerminal("\r\n"); 71130043Sminshall } 71230043Sminshall EmptyTerminal(); 71330043Sminshall screenStopped = 1; /* This is stopped */ 71430043Sminshall } 71530043Sminshall } 71630043Sminshall 71730043Sminshall 71830043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 71930043Sminshall 72030043Sminshall void 72130043Sminshall RefreshScreen() 72230043Sminshall { 72330043Sminshall clearok(curscr, TRUE); 72430043Sminshall (*TryToSend)(); 72530043Sminshall } 72630043Sminshall 72730043Sminshall 72830043Sminshall /* ConnectScreen - called to reconnect to the screen */ 72930043Sminshall 73030043Sminshall void 73130043Sminshall ConnectScreen() 73230043Sminshall { 73330043Sminshall if (screenInitd) { 73430043Sminshall #if defined(unix) 73534315Sminshall if (myKS) { 73634315Sminshall StringToTerminal(myKS); 73730043Sminshall } 73830043Sminshall #endif /* defined(unix) */ 73930043Sminshall RefreshScreen(); 74030043Sminshall (*TryToSend)(); 74130043Sminshall screenStopped = 0; 74230043Sminshall } 74330043Sminshall } 74430043Sminshall 74530043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 74630043Sminshall 74730043Sminshall void 74830043Sminshall LocalClearScreen() 74930043Sminshall { 75035423Sminshall extern void Clear3270(); 75135423Sminshall 75230043Sminshall outputPurge(); /* flush all data to terminal */ 75330043Sminshall clear(); /* clear in curses */ 75431101Sminshall ClearArray(Terminal); 75530043Sminshall Clear3270(); 75630043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 75730043Sminshall Highest = LowestScreen()+1; 75830043Sminshall } 75930043Sminshall 76030043Sminshall 76130043Sminshall void 76230043Sminshall BellOff() 76330043Sminshall { 76430043Sminshall if (bellwinup) { 76530043Sminshall delwin(bellwin); 76630043Sminshall bellwin = 0; 76730043Sminshall bellwinup = 0; 76830043Sminshall touchwin(stdscr); 76930043Sminshall DoARefresh(); 77030043Sminshall } 77130043Sminshall } 77230043Sminshall 77330043Sminshall 77430043Sminshall void 77530043Sminshall RingBell(s) 77630043Sminshall char *s; 77730043Sminshall { 77830043Sminshall needToRing = 1; 77930043Sminshall if (s) { 78030043Sminshall int len = strlen(s); 78130043Sminshall 78230043Sminshall if (len > COLS-2) { 78330043Sminshall len = COLS-2; 78430043Sminshall } 78530043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 78635423Sminshall OurExitString("Error from newwin in RingBell", 1); 78730043Sminshall } 78830043Sminshall werase(bellwin); 78930043Sminshall wstandout(bellwin); 79030043Sminshall box(bellwin, '|', '-'); 79130043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 79235423Sminshall OurExitString("Error from wmove in RingBell", 1); 79330043Sminshall } 79430043Sminshall while (len--) { 79530043Sminshall if (waddch(bellwin, *s++) == ERR) { 79635423Sminshall OurExitString("Error from waddch in RingBell", 1); 79730043Sminshall } 79830043Sminshall } 79930043Sminshall wstandend(bellwin); 80030043Sminshall if (wrefresh(bellwin) == ERR) { 80135423Sminshall OurExitString("Error from wrefresh in RingBell", 1); 80230043Sminshall } 80330043Sminshall bellwinup = 1; 80430043Sminshall } 80530043Sminshall } 80630043Sminshall 80730043Sminshall 80830043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 80930043Sminshall or a 0 if there is more output available (so, just poll the other 81030043Sminshall sources/destinations, don't block). 81130043Sminshall */ 81230043Sminshall 81330043Sminshall int 81430043Sminshall DoTerminalOutput() 81530043Sminshall { 81630043Sminshall /* called just before a select to conserve IO to terminal */ 81731462Sminshall if (!(screenInitd||screenStopped)) { 81830369Sminshall return 1; /* No output if not initialized */ 81930369Sminshall } 82030369Sminshall if ((Lowest <= Highest) || needToRing || 82130369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 82230043Sminshall (*TryToSend)(); 82330043Sminshall } 82430043Sminshall if (Lowest > Highest) { 82530369Sminshall return 1; /* no more output now */ 82630043Sminshall } else { 82730369Sminshall return 0; /* more output for future */ 82830043Sminshall } 82930043Sminshall } 83030074Sminshall 83130074Sminshall /* 83230074Sminshall * The following are defined to handle transparent data. 83330074Sminshall */ 83430074Sminshall 83530074Sminshall void 83630074Sminshall TransStop() 83730074Sminshall { 83830074Sminshall #if defined(unix) 83930074Sminshall if (tcflag == 0) { 84030074Sminshall tcflag = -1; 84130074Sminshall (void) signal(SIGCHLD, SIG_DFL); 84230074Sminshall } else if (tcflag > 0) { 84330074Sminshall setcommandmode(); 84430074Sminshall (void) close(tin); 84530074Sminshall (void) close(tout); 84630074Sminshall tin = savefd[0]; 84730074Sminshall tout = savefd[1]; 84830074Sminshall setconnmode(); 84930074Sminshall tcflag = -1; 85030074Sminshall (void) signal(SIGCHLD, SIG_DFL); 85130074Sminshall } 85230074Sminshall #endif /* defined(unix) */ 85330074Sminshall RefreshScreen(); 85430074Sminshall } 85530074Sminshall 85630074Sminshall void 85731863Sminshall TransOut(buffer, count, kind, control) 85830074Sminshall unsigned char *buffer; 85930074Sminshall int count; 86031863Sminshall int kind; /* 0 or 5 */ 86131863Sminshall int control; /* To see if we are done */ 86230074Sminshall { 86330074Sminshall #if defined(unix) 86430074Sminshall extern char *transcom; 86535423Sminshall int inpipefd[2], outpipefd[2]; 86630074Sminshall void aborttc(); 86730074Sminshall #endif /* defined(unix) */ 86830074Sminshall 86930074Sminshall while (DoTerminalOutput() == 0) { 87030074Sminshall #if defined(unix) 87130074Sminshall HaveInput = 0; 87230074Sminshall #endif /* defined(unix) */ 87330074Sminshall } 87430074Sminshall #if defined(unix) 87530074Sminshall if (transcom && tcflag == -1) { 87630074Sminshall while (1) { /* go thru once */ 87730074Sminshall if (pipe(outpipefd) < 0) { 87830074Sminshall break; 87930074Sminshall } 88030074Sminshall if (pipe(inpipefd) < 0) { 88130074Sminshall break; 88230074Sminshall } 88330074Sminshall if ((tcflag = fork()) == 0) { 88430074Sminshall (void) close(outpipefd[1]); 88530074Sminshall (void) close(0); 88630074Sminshall if (dup(outpipefd[0]) < 0) { 88730074Sminshall exit(1); 88830074Sminshall } 88930074Sminshall (void) close(outpipefd[0]); 89030074Sminshall (void) close(inpipefd[0]); 89130074Sminshall (void) close(1); 89230074Sminshall if (dup(inpipefd[1]) < 0) { 89330074Sminshall exit(1); 89430074Sminshall } 89530074Sminshall (void) close(inpipefd[1]); 89630074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 89730074Sminshall exit(1); 89830074Sminshall } 89930074Sminshall } 90030074Sminshall (void) close(inpipefd[1]); 90130074Sminshall (void) close(outpipefd[0]); 90230074Sminshall savefd[0] = tin; 90330074Sminshall savefd[1] = tout; 90430074Sminshall setcommandmode(); 90530074Sminshall tin = inpipefd[0]; 90630074Sminshall tout = outpipefd[1]; 90735423Sminshall (void) signal(SIGCHLD, (int (*)())aborttc); 90830074Sminshall setconnmode(); 90930074Sminshall tcflag = 1; 91030074Sminshall break; 91130074Sminshall } 91230074Sminshall if (tcflag < 1) { 91330074Sminshall tcflag = 0; 91430074Sminshall } 91530074Sminshall } 91630074Sminshall #endif /* defined(unix) */ 91735423Sminshall (void) DataToTerminal((char *)buffer, count); 91831863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 91931863Sminshall SendToIBM(); 92031863Sminshall } else { 92135423Sminshall extern void TransInput(); 92235423Sminshall 92331863Sminshall TransInput(1, kind); /* Go get some data */ 92431863Sminshall } 92530074Sminshall } 92630074Sminshall 92730074Sminshall 92830074Sminshall #if defined(unix) 92930074Sminshall static void 93030074Sminshall aborttc() 93130074Sminshall { 93230074Sminshall setcommandmode(); 93330074Sminshall (void) close(tin); 93430074Sminshall (void) close(tout); 93530074Sminshall tin = savefd[0]; 93630074Sminshall tout = savefd[1]; 93730074Sminshall setconnmode(); 93830074Sminshall tcflag = 0; 93930074Sminshall } 94030074Sminshall #endif /* defined(unix) */ 941