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 6*35423Sminshall * provided that the above copyright notice and this paragraph are 7*35423Sminshall * duplicated in all such forms and that any documentation, 8*35423Sminshall * advertising materials, and other materials related to such 9*35423Sminshall * distribution and use acknowledge that the software was developed 10*35423Sminshall * by the University of California, Berkeley. The name of the 11*35423Sminshall * University may not be used to endorse or promote products derived 12*35423Sminshall * from this software without specific prior written permission. 13*35423Sminshall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35423Sminshall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35423Sminshall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1630043Sminshall */ 1730043Sminshall 1830043Sminshall #ifndef lint 19*35423Sminshall static char sccsid[] = "@(#)termout.c 3.7 (Berkeley) 08/28/88"; 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" 44*35423Sminshall #include "../ctlr/externs.h" 45*35423Sminshall #include "../ctlr/declare.h" 4631127Sminshall #include "../ctlr/oia.h" 4730043Sminshall #include "../ctlr/screen.h" 4830043Sminshall 4931179Sminshall #include "../general/globals.h" 5030043Sminshall 51*35423Sminshall #include "../telextrn.h" 5230043Sminshall 5330043Sminshall #define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \ 5431839Sminshall CursorAddress:UnLocked? CursorAddress: HighestScreen()) 5530043Sminshall 5630043Sminshall 5730328Sminshall static int terminalCursorAddress; /* where the cursor is on term */ 5830328Sminshall static int screenInitd; /* the screen has been initialized */ 5930328Sminshall static int screenStopped; /* the screen has been stopped */ 6030043Sminshall static int max_changes_before_poll; /* how many characters before looking */ 6130043Sminshall /* at terminal and net again */ 6230043Sminshall 6330328Sminshall static int needToRing; /* need to ring terinal bell */ 6430043Sminshall static char *bellSequence = "\07"; /* bell sequence (may be replaced by 6530043Sminshall * VB during initialization) 6630043Sminshall */ 6730328Sminshall static WINDOW *bellwin = 0; /* The window the bell message is in */ 6830043Sminshall int bellwinup = 0; /* Are we up with it or not */ 6930043Sminshall 7030043Sminshall #if defined(unix) 7134315Sminshall static char *myKS, *myKE; 7230043Sminshall #endif /* defined(unix) */ 7330043Sminshall 7430074Sminshall 7530074Sminshall static int inHighlightMode = 0; 7631071Sminshall ScreenImage Terminal[MAXSCREENSIZE]; 7730074Sminshall 7830074Sminshall /* Variables for transparent mode */ 7930043Sminshall #if defined(unix) 8030043Sminshall static int tcflag = -1; /* transparent mode command flag */ 8130043Sminshall static int savefd[2]; /* for storing fds during transcom */ 8230074Sminshall extern int tin, tout; /* file descriptors */ 8330043Sminshall #endif /* defined(unix) */ 8430043Sminshall 8530730Sminshall 8630730Sminshall /* 8730730Sminshall * init_screen() 8830730Sminshall * 8930730Sminshall * Initialize variables used by screen. 9030730Sminshall */ 9130730Sminshall 9230730Sminshall void 9330730Sminshall init_screen() 9430730Sminshall { 9530730Sminshall bellwinup = 0; 9630730Sminshall inHighlightMode = 0; 9731071Sminshall ClearArray(Terminal); 9830730Sminshall } 9930730Sminshall 10030730Sminshall 10130043Sminshall /* OurExitString - designed to keep us from going through infinite recursion */ 10230043Sminshall 10330043Sminshall static void 104*35423Sminshall OurExitString(string, value) 10530043Sminshall char *string; 10630043Sminshall int value; 10730043Sminshall { 10830043Sminshall static int recursion = 0; 10930043Sminshall 11030043Sminshall if (!recursion) { 11130043Sminshall recursion = 1; 112*35423Sminshall ExitString(string, value); 11330043Sminshall } 11430043Sminshall } 11530043Sminshall 11630043Sminshall 11730043Sminshall /* DoARefresh */ 11830043Sminshall 11930043Sminshall static void 12030043Sminshall DoARefresh() 12130043Sminshall { 12230043Sminshall if (ERR == refresh()) { 123*35423Sminshall OurExitString("ERR from refresh\n", 1); 12430043Sminshall } 12530043Sminshall } 12630043Sminshall 12730043Sminshall static void 12830043Sminshall GoAway(from, where) 12930043Sminshall char *from; /* routine that gave error */ 13030043Sminshall int where; /* cursor address */ 13130043Sminshall { 13230043Sminshall char foo[100]; 13330043Sminshall 13430043Sminshall sprintf(foo, "ERR from %s at %d (%d, %d)\n", 13530043Sminshall from, where, ScreenLine(where), ScreenLineOffset(where)); 136*35423Sminshall OurExitString(foo, 1); 13730043Sminshall /* NOTREACHED */ 13830043Sminshall } 13930043Sminshall 14030043Sminshall /* What is the screen address of the attribute byte for the terminal */ 14130043Sminshall 14230043Sminshall static int 14330043Sminshall WhereTermAttrByte(p) 14430043Sminshall register int p; 14530043Sminshall { 14630043Sminshall register int i; 14730043Sminshall 14830043Sminshall i = p; 14930043Sminshall 15030043Sminshall do { 15130043Sminshall if (TermIsStartField(i)) { 15230043Sminshall return(i); 15330043Sminshall } 15430043Sminshall i = ScreenDec(i); 15530043Sminshall } while (i != p); 15630043Sminshall 15730043Sminshall return(LowestScreen()); /* unformatted screen... */ 15830043Sminshall } 15930043Sminshall 16030043Sminshall /* 16130043Sminshall * There are two algorithms for updating the screen. 16230043Sminshall * The first, SlowScreen() optimizes the line between the 16330043Sminshall * computer and the screen (say a 9600 baud line). To do 16430043Sminshall * this, we break out of the loop every so often to look 16530043Sminshall * at any pending input from the network (so that successive 16630043Sminshall * screens will only partially print until the final screen, 16730043Sminshall * the one the user possibly wants to see, is displayed 16830043Sminshall * in its entirety). 16930043Sminshall * 17030043Sminshall * The second algorithm tries to optimize CPU time (by 17130043Sminshall * being simpler) at the cost of the bandwidth to the 17230043Sminshall * screen. 17330043Sminshall * 17430043Sminshall * Of course, curses(3X) gets in here also. 17530043Sminshall */ 17630043Sminshall 17730043Sminshall 17830043Sminshall #if defined(NOT43) 17930043Sminshall static int 18030043Sminshall #else /* defined(NOT43) */ 18130043Sminshall static void 18230043Sminshall #endif /* defined(NOT43) */ 18330043Sminshall SlowScreen() 18430043Sminshall { 18530043Sminshall register int pointer; 18630043Sminshall register int c; 18730043Sminshall register int fieldattr; 18830043Sminshall register int columnsleft; 18930043Sminshall 19030043Sminshall # define SetHighlightMode(p) { \ 19130043Sminshall if (!IsStartField(p) && IsHighlightedAttr(fieldattr)) { \ 19230043Sminshall if (!inHighlightMode) { \ 19330043Sminshall inHighlightMode = 1; \ 19430043Sminshall standout(); \ 19530043Sminshall } \ 19630043Sminshall } else { \ 19730043Sminshall if (inHighlightMode) { \ 19830043Sminshall inHighlightMode = 0; \ 19930043Sminshall standend(); \ 20030043Sminshall } \ 20130043Sminshall } \ 20230043Sminshall } 20330043Sminshall 20430043Sminshall # define DoCharacterAt(c,p) { \ 20530043Sminshall SetTerminal(p, c); \ 20630043Sminshall if (p != HighestScreen()) { \ 20730043Sminshall c = TerminalCharacterAttr(disp_asc[c&0xff], p, \ 20830043Sminshall fieldattr); \ 20930043Sminshall if (terminalCursorAddress != p) { \ 21030043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 21130043Sminshall ScreenLineOffset(p), c)) {\ 21230043Sminshall GoAway("mvaddch", p); \ 21330043Sminshall } \ 21430043Sminshall } else { \ 21530043Sminshall if (ERR == addch(c)) {\ 21630043Sminshall GoAway("addch", p); \ 21730043Sminshall } \ 21830043Sminshall } \ 21930043Sminshall terminalCursorAddress = ScreenInc(p); \ 22030043Sminshall } \ 22130043Sminshall } 22230043Sminshall 22330043Sminshall 22430043Sminshall /* run through screen, printing out non-null lines */ 22530043Sminshall 22630043Sminshall /* There are two separate reasons for wanting to terminate this 22730043Sminshall * loop early. One is to respond to new input (either from 22830043Sminshall * the terminal or from the network [host]). For this reason, 22930043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 23030043Sminshall * 23130043Sminshall * The second reason is a bit more difficult (for me) to understand. 23230043Sminshall * Basically, we don't want to get too far ahead of the characters that 23330043Sminshall * appear on the screen. Ideally, we would type out a few characters, 23430043Sminshall * wait until they appeared on the screen, then type out a few more. 23530043Sminshall * The reason for this is that the user, on seeing some characters 23630043Sminshall * appear on the screen may then start to type something. We would 23730043Sminshall * like to look at what the user types at about the same 'time' 23830043Sminshall * (measured by characters being sent to the terminal) that the 23930043Sminshall * user types them. For this reason, what we would like to do 24030043Sminshall * is update a bit, then call curses to do a refresh, flush the 24130043Sminshall * output to the terminal, then wait until the terminal data 24230043Sminshall * has been sent. 24330043Sminshall * 24430043Sminshall * Note that curses is useful for, among other things, deciding whether 24530043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 24630043Sminshall * at end of lines (beginning of next lines). 24730043Sminshall * 24830043Sminshall * The problems here are the following: If we do lots of write(2)s, 24930043Sminshall * we will be doing lots of context switches, thus lots of overhead 25030043Sminshall * (which we have already). Second, if we do a select to wait for 25130043Sminshall * the output to drain, we have to contend with the fact that NOW 25230043Sminshall * we are scheduled to run, but who knows what the scheduler will 25330043Sminshall * decide when the output has caught up. 25430043Sminshall */ 25530043Sminshall 25633923Sminshall if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ 25730043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 25830043Sminshall } 25930043Sminshall if (Lowest < LowestScreen()) { 26030043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 26130043Sminshall * unformatted screens. 26230043Sminshall */ 26330043Sminshall } 26430043Sminshall if (Highest >= (pointer = Lowest)) { 26530043Sminshall /* if there is anything to do, do it. We won't terminate 26630043Sminshall * the loop until we've gone at least to Highest. 26730043Sminshall */ 26830043Sminshall while ((pointer <= Highest) && !HaveInput) { 26930043Sminshall 27030043Sminshall /* point at the next place of disagreement */ 27130043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 27230043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 27330043Sminshall 27430043Sminshall /* how many characters to change until the end of the 27530043Sminshall * current line 27630043Sminshall */ 27730043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 27830043Sminshall /* 27930043Sminshall * Make sure we are where we think we are. 28030043Sminshall */ 28130043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 28230043Sminshall 28330043Sminshall /* what is the field attribute of the current position */ 28430043Sminshall fieldattr = FieldAttributes(WhereAttrByte(pointer)); 28530043Sminshall 28630043Sminshall if ((IsStartField(pointer) != TermIsStartField(pointer)) || 28730043Sminshall (IsStartField(pointer) && 28830043Sminshall fieldattr != TermAttributes(pointer))) { 28930043Sminshall 29030043Sminshall int oldterm; 29130043Sminshall 29230043Sminshall oldterm = TermAttributes(pointer); 29330043Sminshall if (IsStartField(pointer)) { 29430043Sminshall TermNewField(pointer, fieldattr); 29530043Sminshall SetTerminal(pointer, 0); 29630043Sminshall } else { 29730043Sminshall TermDeleteField(pointer); 29830043Sminshall } 29930043Sminshall /* We always do the first character in a divergent 30030043Sminshall * field, since otherwise the start of a field in 30130043Sminshall * the Host structure may leave a highlighted blank 30230043Sminshall * on the screen, and the start of a field in the 30330043Sminshall * Terminal structure may leave a non-highlighted 30430043Sminshall * something in the middle of a highlighted field 30530043Sminshall * on the screen. 30630043Sminshall */ 30730043Sminshall SetHighlightMode(pointer); 30830043Sminshall c = GetHost(pointer); 30930043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 31030043Sminshall 31130043Sminshall if (NotVisuallyCompatibleAttributes 31230043Sminshall (pointer, fieldattr, oldterm)) { 31330043Sminshall int j; 31430043Sminshall 31530043Sminshall j = pointer; 31630043Sminshall 31730043Sminshall pointer = ScreenInc(pointer); 31830043Sminshall if (!(--columnsleft)) { 31930043Sminshall DoARefresh(); 32030043Sminshall EmptyTerminal(); 32130043Sminshall move(ScreenLine(pointer), 0); 32230043Sminshall columnsleft = NumberColumns; 32330043Sminshall } 32430043Sminshall SetHighlightMode(pointer); /* Turn on highlighting */ 32531452Sminshall while ((!IsStartField(pointer)) && 32631452Sminshall (!TermIsStartField(pointer))) { 32730043Sminshall c = GetHost(pointer); 32830043Sminshall DoCharacterAt(c,pointer); /* MACRO */ 32930043Sminshall pointer = ScreenInc(pointer); 33030043Sminshall if (!(--columnsleft)) { 33130043Sminshall DoARefresh(); 33230043Sminshall EmptyTerminal(); 33330043Sminshall move(ScreenLine(pointer), 0); 33430043Sminshall columnsleft = NumberColumns; 33530043Sminshall /* We don't look at HaveInput here, since 33630043Sminshall * if we leave this loop before the end of 33730043Sminshall * the 3270 field, we could have pointer 33830043Sminshall * higher than Highest. This would cause 33930043Sminshall * us to end the highest "while" loop, 34030043Sminshall * but we may, in fact, need to go around the 34130043Sminshall * screen once again. 34230043Sminshall */ 34330043Sminshall } 34430043Sminshall /* The loop needs to be protected 34530043Sminshall * from the situation where there had been only 34630043Sminshall * one field on the Terminal, and none on the Host. 34730043Sminshall * In this case, we have just deleted our last 34830043Sminshall * field. Hence, the break. 34930043Sminshall */ 35030043Sminshall if (j == pointer) { 35130043Sminshall break; 35230043Sminshall } 35330043Sminshall } 35430043Sminshall if (IsStartField(pointer) && !TermIsStartField(pointer)) { 35530043Sminshall /* Remember what the terminal looked like */ 35630043Sminshall TermNewField(pointer, oldterm); 35730043Sminshall /* 35830043Sminshall * The danger here is that the current position may 35930043Sminshall * be the start of a Host field. If so, and the 36030043Sminshall * field is highlighted, and our terminal was 36130043Sminshall * highlighted, then we will leave a highlighted 36230043Sminshall * blank at this position. 36330043Sminshall */ 36430043Sminshall SetHighlightMode(pointer); 36530043Sminshall c = GetHost(pointer); 36630043Sminshall DoCharacterAt(c,pointer); 36730043Sminshall } 36830043Sminshall /* We could be in the situation of needing to exit. 36930043Sminshall * This could happen if the current field wrapped around 37030043Sminshall * the end of the screen. 37130043Sminshall */ 37230043Sminshall if (j > pointer) { 37331452Sminshall /* 37431452Sminshall * pointer is guaranteed to be higher than Highest... 37531452Sminshall */ 37631452Sminshall pointer = Highest+1; /* We did the highest thing */ 37730043Sminshall break; 37830043Sminshall } 37930043Sminshall } else { 38030043Sminshall c = GetHost(pointer); 38130043Sminshall /* We always do the first character in a divergent 38230043Sminshall * field, since otherwise the start of a field in 38330043Sminshall * the Host structure may leave a highlighted blank 38430043Sminshall * on the screen, and the start of a field in the 38530043Sminshall * Terminal structure may leave a non-highlighted 38630043Sminshall * something in the middle of a highlighted field 38730043Sminshall * on the screen. 38830043Sminshall */ 38930043Sminshall SetHighlightMode(pointer); 39030043Sminshall DoCharacterAt(c,pointer); 39130043Sminshall } 39230043Sminshall } else { 39330043Sminshall SetHighlightMode(pointer); 39430054Sminshall /* 39530054Sminshall * The following will terminate at least when we get back 39630043Sminshall * to the original 'pointer' location (since we force 39730043Sminshall * things to be equal). 39830043Sminshall */ 39930043Sminshall while (((c = GetHost(pointer)) != GetTerminal(pointer)) && 40030043Sminshall !IsStartField(pointer) && !TermIsStartField(pointer)) { 40130043Sminshall DoCharacterAt(c, pointer); 40230043Sminshall pointer = ScreenInc(pointer); 40330043Sminshall if (!(--columnsleft)) { 40430043Sminshall DoARefresh(); 40530043Sminshall EmptyTerminal(); 40630043Sminshall if (HaveInput) { /* if input came in, take it */ 40730043Sminshall break; 40830043Sminshall } 40930043Sminshall move(ScreenLine(pointer), 0); 41030043Sminshall columnsleft = NumberColumns; 41130043Sminshall } 41230043Sminshall } 41330043Sminshall } 41430043Sminshall } 41530043Sminshall } 41630043Sminshall DoARefresh(); 41730043Sminshall Lowest = pointer; 41830043Sminshall if (Lowest > Highest) { /* if we finished input... */ 41930043Sminshall Lowest = HighestScreen()+1; 42030043Sminshall Highest = LowestScreen()-1; 42130043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 42230043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 42330043Sminshall ScreenLineOffset(terminalCursorAddress))) { 42430043Sminshall GoAway("move", terminalCursorAddress); 42530043Sminshall } 42630043Sminshall DoARefresh(); 42730043Sminshall if (needToRing) { 42830043Sminshall StringToTerminal(bellSequence); 42930043Sminshall needToRing = 0; 43030043Sminshall } 43130043Sminshall } 43230043Sminshall EmptyTerminal(); /* move data along */ 43330043Sminshall return; 43430043Sminshall } 43530043Sminshall 43630043Sminshall #if defined(NOT43) 43730043Sminshall static int 43830043Sminshall #else /* defined(NOT43) */ 43930043Sminshall static void 44030043Sminshall #endif /* defined(NOT43) */ 44130043Sminshall FastScreen() 44230043Sminshall { 44331101Sminshall #if defined(MSDOS) 44430043Sminshall #define SaveCorner 0 44531101Sminshall #else /* defined(MSDOS) */ 44630043Sminshall #define SaveCorner 1 44731101Sminshall #endif /* defined(MSDOS) */ 44830043Sminshall 44930043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 45030043Sminshall standout(); \ 45130043Sminshall } else { \ 45230043Sminshall standend(); \ 45330043Sminshall } \ 45430043Sminshall if (IsNonDisplayAttr(a)) { \ 45530043Sminshall a = 0; /* zero == don't display */ \ 45630043Sminshall } \ 45730043Sminshall if (!FormattedScreen()) { \ 45830043Sminshall a = 1; /* one ==> do display on unformatted */\ 45930043Sminshall } 46030043Sminshall ScreenImage *p, *upper; 46130043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 46230043Sminshall 46330043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 46430043Sminshall * only need to go from Lowest to Highest. However, if we find a 46530043Sminshall * field in the middle, we do the whole screen. 46630043Sminshall * 46730043Sminshall * In particular, we separate out the two cases from the beginning. 46830043Sminshall */ 46930043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 47030043Sminshall register int columnsleft; 47130043Sminshall 47230043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 47330043Sminshall p = &Host[Lowest]; 47431101Sminshall #if !defined(MSDOS) 47530043Sminshall if (Highest == HighestScreen()) { 47630043Sminshall Highest = ScreenDec(Highest); 47730043Sminshall } 47831101Sminshall #endif /* !defined(MSDOS) */ 47930043Sminshall upper = &Host[Highest]; 48030043Sminshall fieldattr = FieldAttributes(Lowest); 48130043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 48230043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 48330043Sminshall 48430043Sminshall while (p <= upper) { 48530054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 48630043Sminshall Highest = HighestScreen(); 48730043Sminshall Lowest = LowestScreen(); 48830043Sminshall FastScreen(); /* Recurse */ 48930043Sminshall return; 49030043Sminshall } else if (fieldattr) { /* Should we display? */ 49131148Sminshall /* Display translated data */ 492*35423Sminshall addch((char)disp_asc[GetTerminalPointer(p)]); 49330043Sminshall } else { 49430043Sminshall addch(' '); /* Display a blank */ 49530043Sminshall } 49630043Sminshall /* If the physical screen is larger than what we 49730043Sminshall * are using, we need to make sure that each line 49830043Sminshall * starts at the beginning of the line. Otherwise, 49930043Sminshall * we will just string all the lines together. 50030043Sminshall */ 50130043Sminshall p++; 50230043Sminshall if (--columnsleft == 0) { 50330043Sminshall int i = p-Host; 50430043Sminshall 50530043Sminshall move(ScreenLine(i), 0); 50630043Sminshall columnsleft = NumberColumns; 50730043Sminshall } 50830043Sminshall } 50930043Sminshall } else { /* Going from Lowest to Highest */ 51030043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 51130043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 51230043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 51330043Sminshall 51430043Sminshall *tmpend = 0; /* terminate from the beginning */ 51530043Sminshall move(0,0); 51630043Sminshall p = Host; 51730043Sminshall fieldattr = FieldAttributes(LowestScreen()); 51830043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 51930043Sminshall 52030043Sminshall while (p <= End) { 52130054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 52230043Sminshall if (tmp != tmpbuf) { 52330043Sminshall *tmp++ = 0; /* close out */ 524*35423Sminshall addstr((char *)tmpbuf); 52530043Sminshall tmp = tmpbuf; 52630043Sminshall tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 52730043Sminshall } 52830054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 52930043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 53030043Sminshall *tmp++ = ' '; 53130043Sminshall } else { 53230043Sminshall if (fieldattr) { /* Should we display? */ 53330043Sminshall /* Display translated data */ 53431148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 53530043Sminshall } else { 53630043Sminshall *tmp++ = ' '; 53730043Sminshall } 53830043Sminshall } 53930043Sminshall /* If the physical screen is larger than what we 54030043Sminshall * are using, we need to make sure that each line 54130043Sminshall * starts at the beginning of the line. Otherwise, 54230043Sminshall * we will just string all the lines together. 54330043Sminshall */ 54430043Sminshall p++; 54530043Sminshall if (tmp == tmpend) { 54630043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 54730043Sminshall 54830043Sminshall *tmp++ = 0; 549*35423Sminshall addstr((char *)tmpbuf); 55030043Sminshall tmp = tmpbuf; 55130043Sminshall move(ScreenLine(i), 0); 55230043Sminshall tmpend = tmpbuf + NumberColumns; 55330043Sminshall } 55430043Sminshall } 55530043Sminshall if (tmp != tmpbuf) { 55630043Sminshall *tmp++ = 0; 557*35423Sminshall addstr((char *)tmpbuf); 55830043Sminshall tmp = tmpbuf; 55930043Sminshall } 56030043Sminshall } 56130043Sminshall Lowest = HighestScreen()+1; 56230043Sminshall Highest = LowestScreen()-1; 56330043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 56430043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 56530043Sminshall ScreenLineOffset(terminalCursorAddress))) { 56630043Sminshall GoAway("move", terminalCursorAddress); 56730043Sminshall } 56830043Sminshall DoARefresh(); 56930043Sminshall if (needToRing) { 57030043Sminshall StringToTerminal(bellSequence); 57130043Sminshall needToRing = 0; 57230043Sminshall } 57330043Sminshall EmptyTerminal(); /* move data along */ 57430043Sminshall return; 57530043Sminshall } 57630043Sminshall 57730043Sminshall 57830043Sminshall /* TryToSend - send data out to user's terminal */ 57930043Sminshall 58030043Sminshall #if defined(NOT43) 58130043Sminshall int 58230043Sminshall #else /* defined(NOT43) */ 58330043Sminshall void 58430043Sminshall #endif /* defined(NOT43) */ 58530043Sminshall (*TryToSend)() = FastScreen; 58630043Sminshall 587*35423Sminshall /*ARGSUSED*/ 58831127Sminshall void 58931127Sminshall ScreenOIA(oia) 59031127Sminshall OIA *oia; 59131127Sminshall { 59231127Sminshall } 59331127Sminshall 59431127Sminshall 59530328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 59630043Sminshall 59730043Sminshall void 59830328Sminshall InitTerminal() 59930043Sminshall { 60030043Sminshall #if defined(unix) 60130043Sminshall struct sgttyb ourttyb; 60230043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 60330043Sminshall 2400, 4800, 9600 }; 60430043Sminshall #endif 605*35423Sminshall extern void InitMapping(); 60630043Sminshall 60730328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 60830043Sminshall if (!screenInitd) { /* not initialized */ 60930043Sminshall #if defined(unix) 61030043Sminshall char KSEbuffer[2050]; 61130043Sminshall char *lotsofspace = KSEbuffer; 61230043Sminshall extern int abort(); 61330043Sminshall extern char *tgetstr(); 61430043Sminshall #endif /* defined(unix) */ 61530043Sminshall 61634294Sminshall if (initscr() == ERR) { /* Initialize curses to get line size */ 61734294Sminshall ExitString("InitTerminal: Error initializing curses", 1); 61834294Sminshall /*NOTREACHED*/ 61934294Sminshall } 62034294Sminshall MaxNumberLines = LINES; 62134294Sminshall MaxNumberColumns = COLS; 62231101Sminshall ClearArray(Terminal); 62330328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 62430043Sminshall #if defined(unix) 62530043Sminshall signal(SIGHUP, abort); 62630043Sminshall #endif 62730043Sminshall 62830043Sminshall TryToSend = FastScreen; 62931559Sminshall #if defined(unix) 63030043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 63130043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 63230043Sminshall max_changes_before_poll = 1920; 63330043Sminshall } else { 63430043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 63530043Sminshall if (max_changes_before_poll < 40) { 63630043Sminshall max_changes_before_poll = 40; 63730043Sminshall } 63830043Sminshall TryToSend = SlowScreen; 63930043Sminshall HaveInput = 1; /* get signals going */ 64030043Sminshall } 64131559Sminshall #endif /* defined(unix) */ 64230043Sminshall setcommandmode(); 64330043Sminshall /* 64430043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 64530043Sminshall * and the screen has been initialized. 64630043Sminshall */ 64730043Sminshall #if defined(unix) 64830043Sminshall nonl(); 64930043Sminshall /* the problem is that curses catches SIGTSTP to 65030043Sminshall * be nice, but it messes us up. 65130043Sminshall */ 65230043Sminshall signal(SIGTSTP, SIG_DFL); 65334315Sminshall if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 65434315Sminshall myKS = strsave(myKS); 65534315Sminshall StringToTerminal(myKS); 65630043Sminshall } 65734315Sminshall if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 65834315Sminshall myKE = strsave(myKE); 65930043Sminshall } 66030043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 66130043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 66230043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 66330043Sminshall } 66430043Sminshall #endif 66530043Sminshall DoARefresh(); 66630043Sminshall setconnmode(); 66730043Sminshall if (VB && *VB) { 66830043Sminshall bellSequence = VB; /* use visual bell */ 66930043Sminshall } 67030043Sminshall screenInitd = 1; 67130043Sminshall screenStopped = 0; /* Not stopped */ 67230043Sminshall } 67330043Sminshall } 67430043Sminshall 67530043Sminshall 67630043Sminshall /* StopScreen - called when we are going away... */ 67730043Sminshall 67830043Sminshall void 67930043Sminshall StopScreen(doNewLine) 68030043Sminshall int doNewLine; 68130043Sminshall { 68230043Sminshall if (screenInitd && !screenStopped) { 68330043Sminshall move(NumberLines-1, 1); 68430043Sminshall standend(); 68530043Sminshall inHighlightMode = 0; 68630043Sminshall DoARefresh(); 68730043Sminshall setcommandmode(); 68830043Sminshall endwin(); 68930043Sminshall setconnmode(); 69030043Sminshall #if defined(unix) 69134315Sminshall if (myKE) { 69234315Sminshall StringToTerminal(myKE); 69330043Sminshall } 69430043Sminshall #endif /* defined(unix) */ 69530043Sminshall if (doNewLine) { 69630043Sminshall StringToTerminal("\r\n"); 69730043Sminshall } 69830043Sminshall EmptyTerminal(); 69930043Sminshall screenStopped = 1; /* This is stopped */ 70030043Sminshall } 70130043Sminshall } 70230043Sminshall 70330043Sminshall 70430043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 70530043Sminshall 70630043Sminshall void 70730043Sminshall RefreshScreen() 70830043Sminshall { 70930043Sminshall clearok(curscr, TRUE); 71030043Sminshall (*TryToSend)(); 71130043Sminshall } 71230043Sminshall 71330043Sminshall 71430043Sminshall /* ConnectScreen - called to reconnect to the screen */ 71530043Sminshall 71630043Sminshall void 71730043Sminshall ConnectScreen() 71830043Sminshall { 71930043Sminshall if (screenInitd) { 72030043Sminshall #if defined(unix) 72134315Sminshall if (myKS) { 72234315Sminshall StringToTerminal(myKS); 72330043Sminshall } 72430043Sminshall #endif /* defined(unix) */ 72530043Sminshall RefreshScreen(); 72630043Sminshall (*TryToSend)(); 72730043Sminshall screenStopped = 0; 72830043Sminshall } 72930043Sminshall } 73030043Sminshall 73130043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 73230043Sminshall 73330043Sminshall void 73430043Sminshall LocalClearScreen() 73530043Sminshall { 736*35423Sminshall extern void Clear3270(); 737*35423Sminshall 73830043Sminshall outputPurge(); /* flush all data to terminal */ 73930043Sminshall clear(); /* clear in curses */ 74031101Sminshall ClearArray(Terminal); 74130043Sminshall Clear3270(); 74230043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 74330043Sminshall Highest = LowestScreen()+1; 74430043Sminshall } 74530043Sminshall 74630043Sminshall 74730043Sminshall void 74830043Sminshall BellOff() 74930043Sminshall { 75030043Sminshall if (bellwinup) { 75130043Sminshall delwin(bellwin); 75230043Sminshall bellwin = 0; 75330043Sminshall bellwinup = 0; 75430043Sminshall touchwin(stdscr); 75530043Sminshall DoARefresh(); 75630043Sminshall } 75730043Sminshall } 75830043Sminshall 75930043Sminshall 76030043Sminshall void 76130043Sminshall RingBell(s) 76230043Sminshall char *s; 76330043Sminshall { 76430043Sminshall needToRing = 1; 76530043Sminshall if (s) { 76630043Sminshall int len = strlen(s); 76730043Sminshall 76830043Sminshall if (len > COLS-2) { 76930043Sminshall len = COLS-2; 77030043Sminshall } 77130043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 772*35423Sminshall OurExitString("Error from newwin in RingBell", 1); 77330043Sminshall } 77430043Sminshall werase(bellwin); 77530043Sminshall wstandout(bellwin); 77630043Sminshall box(bellwin, '|', '-'); 77730043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 778*35423Sminshall OurExitString("Error from wmove in RingBell", 1); 77930043Sminshall } 78030043Sminshall while (len--) { 78130043Sminshall if (waddch(bellwin, *s++) == ERR) { 782*35423Sminshall OurExitString("Error from waddch in RingBell", 1); 78330043Sminshall } 78430043Sminshall } 78530043Sminshall wstandend(bellwin); 78630043Sminshall if (wrefresh(bellwin) == ERR) { 787*35423Sminshall OurExitString("Error from wrefresh in RingBell", 1); 78830043Sminshall } 78930043Sminshall bellwinup = 1; 79030043Sminshall } 79130043Sminshall } 79230043Sminshall 79330043Sminshall 79430043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 79530043Sminshall or a 0 if there is more output available (so, just poll the other 79630043Sminshall sources/destinations, don't block). 79730043Sminshall */ 79830043Sminshall 79930043Sminshall int 80030043Sminshall DoTerminalOutput() 80130043Sminshall { 80230043Sminshall /* called just before a select to conserve IO to terminal */ 80331462Sminshall if (!(screenInitd||screenStopped)) { 80430369Sminshall return 1; /* No output if not initialized */ 80530369Sminshall } 80630369Sminshall if ((Lowest <= Highest) || needToRing || 80730369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 80830043Sminshall (*TryToSend)(); 80930043Sminshall } 81030043Sminshall if (Lowest > Highest) { 81130369Sminshall return 1; /* no more output now */ 81230043Sminshall } else { 81330369Sminshall return 0; /* more output for future */ 81430043Sminshall } 81530043Sminshall } 81630074Sminshall 81730074Sminshall /* 81830074Sminshall * The following are defined to handle transparent data. 81930074Sminshall */ 82030074Sminshall 82130074Sminshall void 82230074Sminshall TransStop() 82330074Sminshall { 82430074Sminshall #if defined(unix) 82530074Sminshall if (tcflag == 0) { 82630074Sminshall tcflag = -1; 82730074Sminshall (void) signal(SIGCHLD, SIG_DFL); 82830074Sminshall } else if (tcflag > 0) { 82930074Sminshall setcommandmode(); 83030074Sminshall (void) close(tin); 83130074Sminshall (void) close(tout); 83230074Sminshall tin = savefd[0]; 83330074Sminshall tout = savefd[1]; 83430074Sminshall setconnmode(); 83530074Sminshall tcflag = -1; 83630074Sminshall (void) signal(SIGCHLD, SIG_DFL); 83730074Sminshall } 83830074Sminshall #endif /* defined(unix) */ 83930074Sminshall RefreshScreen(); 84030074Sminshall } 84130074Sminshall 84230074Sminshall void 84331863Sminshall TransOut(buffer, count, kind, control) 84430074Sminshall unsigned char *buffer; 84530074Sminshall int count; 84631863Sminshall int kind; /* 0 or 5 */ 84731863Sminshall int control; /* To see if we are done */ 84830074Sminshall { 84930074Sminshall #if defined(unix) 85030074Sminshall extern char *transcom; 851*35423Sminshall int inpipefd[2], outpipefd[2]; 85230074Sminshall void aborttc(); 85330074Sminshall #endif /* defined(unix) */ 85430074Sminshall 85530074Sminshall while (DoTerminalOutput() == 0) { 85630074Sminshall #if defined(unix) 85730074Sminshall HaveInput = 0; 85830074Sminshall #endif /* defined(unix) */ 85930074Sminshall } 86030074Sminshall #if defined(unix) 86130074Sminshall if (transcom && tcflag == -1) { 86230074Sminshall while (1) { /* go thru once */ 86330074Sminshall if (pipe(outpipefd) < 0) { 86430074Sminshall break; 86530074Sminshall } 86630074Sminshall if (pipe(inpipefd) < 0) { 86730074Sminshall break; 86830074Sminshall } 86930074Sminshall if ((tcflag = fork()) == 0) { 87030074Sminshall (void) close(outpipefd[1]); 87130074Sminshall (void) close(0); 87230074Sminshall if (dup(outpipefd[0]) < 0) { 87330074Sminshall exit(1); 87430074Sminshall } 87530074Sminshall (void) close(outpipefd[0]); 87630074Sminshall (void) close(inpipefd[0]); 87730074Sminshall (void) close(1); 87830074Sminshall if (dup(inpipefd[1]) < 0) { 87930074Sminshall exit(1); 88030074Sminshall } 88130074Sminshall (void) close(inpipefd[1]); 88230074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 88330074Sminshall exit(1); 88430074Sminshall } 88530074Sminshall } 88630074Sminshall (void) close(inpipefd[1]); 88730074Sminshall (void) close(outpipefd[0]); 88830074Sminshall savefd[0] = tin; 88930074Sminshall savefd[1] = tout; 89030074Sminshall setcommandmode(); 89130074Sminshall tin = inpipefd[0]; 89230074Sminshall tout = outpipefd[1]; 893*35423Sminshall (void) signal(SIGCHLD, (int (*)())aborttc); 89430074Sminshall setconnmode(); 89530074Sminshall tcflag = 1; 89630074Sminshall break; 89730074Sminshall } 89830074Sminshall if (tcflag < 1) { 89930074Sminshall tcflag = 0; 90030074Sminshall } 90130074Sminshall } 90230074Sminshall #endif /* defined(unix) */ 903*35423Sminshall (void) DataToTerminal((char *)buffer, count); 90431863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 90531863Sminshall SendToIBM(); 90631863Sminshall } else { 907*35423Sminshall extern void TransInput(); 908*35423Sminshall 90931863Sminshall TransInput(1, kind); /* Go get some data */ 91031863Sminshall } 91130074Sminshall } 91230074Sminshall 91330074Sminshall 91430074Sminshall #if defined(unix) 91530074Sminshall static void 91630074Sminshall aborttc() 91730074Sminshall { 91830074Sminshall setcommandmode(); 91930074Sminshall (void) close(tin); 92030074Sminshall (void) close(tout); 92130074Sminshall tin = savefd[0]; 92230074Sminshall tout = savefd[1]; 92330074Sminshall setconnmode(); 92430074Sminshall tcflag = 0; 92530074Sminshall } 92630074Sminshall #endif /* defined(unix) */ 927