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*36244Sminshall static char sccsid[] = "@(#)termout.c 3.9 (Berkeley) 11/19/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" 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 19136243Sminshall #define HIGHLIGHT 1 /* Mask bits */ 19236243Sminshall #define NONDISPLAY 4 /* Mask bits */ 19336243Sminshall 19436243Sminshall #define DoAttributes(x) \ 19536243Sminshall switch (x&ATTR_DSPD_MASK) { \ 19636243Sminshall case ATTR_DSPD_NONDISPLAY: \ 19736243Sminshall x = NONDISPLAY; \ 19836243Sminshall break; \ 19936243Sminshall case ATTR_DSPD_HIGH: \ 20036243Sminshall x = HIGHLIGHT; \ 20136243Sminshall break; \ 20236243Sminshall default: \ 20336243Sminshall x = 0; \ 20436243Sminshall break; \ 20536243Sminshall } 20636243Sminshall 20736243Sminshall # define SetHighlightMode(x) \ 20836243Sminshall { \ 20936243Sminshall if ((x)&HIGHLIGHT) { \ 21030043Sminshall if (!inHighlightMode) { \ 21136243Sminshall inHighlightMode = HIGHLIGHT; \ 21230043Sminshall standout(); \ 21330043Sminshall } \ 21430043Sminshall } else { \ 21530043Sminshall if (inHighlightMode) { \ 21630043Sminshall inHighlightMode = 0; \ 21730043Sminshall standend(); \ 21830043Sminshall } \ 21930043Sminshall } \ 22030043Sminshall } 22130043Sminshall 22230043Sminshall # define DoCharacterAt(c,p) { \ 22330043Sminshall if (p != HighestScreen()) { \ 22436243Sminshall c = disp_asc[c&0xff]; \ 22530043Sminshall if (terminalCursorAddress != p) { \ 22630043Sminshall if (ERR == mvaddch(ScreenLine(p), \ 22730043Sminshall ScreenLineOffset(p), c)) {\ 22830043Sminshall GoAway("mvaddch", p); \ 22930043Sminshall } \ 23030043Sminshall } else { \ 23130043Sminshall if (ERR == addch(c)) {\ 23230043Sminshall GoAway("addch", p); \ 23330043Sminshall } \ 23430043Sminshall } \ 23530043Sminshall terminalCursorAddress = ScreenInc(p); \ 23630043Sminshall } \ 23730043Sminshall } 23830043Sminshall 23930043Sminshall 24030043Sminshall /* run through screen, printing out non-null lines */ 24130043Sminshall 24230043Sminshall /* There are two separate reasons for wanting to terminate this 24330043Sminshall * loop early. One is to respond to new input (either from 24430043Sminshall * the terminal or from the network [host]). For this reason, 24530043Sminshall * we expect to see 'HaveInput' come true when new input comes in. 24630043Sminshall * 24730043Sminshall * The second reason is a bit more difficult (for me) to understand. 24830043Sminshall * Basically, we don't want to get too far ahead of the characters that 24930043Sminshall * appear on the screen. Ideally, we would type out a few characters, 25030043Sminshall * wait until they appeared on the screen, then type out a few more. 25130043Sminshall * The reason for this is that the user, on seeing some characters 25230043Sminshall * appear on the screen may then start to type something. We would 25330043Sminshall * like to look at what the user types at about the same 'time' 25430043Sminshall * (measured by characters being sent to the terminal) that the 25530043Sminshall * user types them. For this reason, what we would like to do 25630043Sminshall * is update a bit, then call curses to do a refresh, flush the 25730043Sminshall * output to the terminal, then wait until the terminal data 25830043Sminshall * has been sent. 25930043Sminshall * 26030043Sminshall * Note that curses is useful for, among other things, deciding whether 26130043Sminshall * or not to send :ce: (clear to end of line), so we should call curses 26230043Sminshall * at end of lines (beginning of next lines). 26330043Sminshall * 26430043Sminshall * The problems here are the following: If we do lots of write(2)s, 26530043Sminshall * we will be doing lots of context switches, thus lots of overhead 26630043Sminshall * (which we have already). Second, if we do a select to wait for 26730043Sminshall * the output to drain, we have to contend with the fact that NOW 26830043Sminshall * we are scheduled to run, but who knows what the scheduler will 26930043Sminshall * decide when the output has caught up. 27030043Sminshall */ 27130043Sminshall 27233923Sminshall if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */ 27330043Sminshall Highest = ScreenDec(Highest); /* else, while loop will never end */ 27430043Sminshall } 27530043Sminshall if (Lowest < LowestScreen()) { 27630043Sminshall Lowest = LowestScreen(); /* could be -1 in some cases with 27730043Sminshall * unformatted screens. 27830043Sminshall */ 27930043Sminshall } 28030043Sminshall if (Highest >= (pointer = Lowest)) { 28130043Sminshall /* if there is anything to do, do it. We won't terminate 28230043Sminshall * the loop until we've gone at least to Highest. 28330043Sminshall */ 28430043Sminshall while ((pointer <= Highest) && !HaveInput) { 28530043Sminshall 28630043Sminshall /* point at the next place of disagreement */ 28730043Sminshall pointer += (bunequal(Host+pointer, Terminal+pointer, 28830043Sminshall (Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]); 28930043Sminshall 29036243Sminshall /* 29136243Sminshall * How many characters to change until the end of the 29230043Sminshall * current line 29330043Sminshall */ 29430043Sminshall columnsleft = NumberColumns - ScreenLineOffset(pointer); 29530043Sminshall /* 29630043Sminshall * Make sure we are where we think we are. 29730043Sminshall */ 29830043Sminshall move(ScreenLine(pointer), ScreenLineOffset(pointer)); 29930043Sminshall 30030043Sminshall /* what is the field attribute of the current position */ 30136243Sminshall fieldattr = FieldAttributes(pointer); 30236243Sminshall DoAttributes(fieldattr); 30336243Sminshall termattr = TermAttributes(pointer); 30436243Sminshall DoAttributes(termattr); 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; 32936243Sminshall termattr = GetTerminal(pointer); 33036243Sminshall DoAttributes(termattr); 33136243Sminshall } else { 33236243Sminshall if (termattr&NONDISPLAY) { 33336243Sminshall is = DISP_BLANK; 33436243Sminshall } else { 33536243Sminshall is = GetTerminal(pointer); 33636243Sminshall } 33736243Sminshall isattr = termattr; 33836243Sminshall } 33936243Sminshall if ((shouldbe == is) && (shouldattr == isattr) 34036243Sminshall && (GetHost(pointer) == GetTerminal(pointer)) 34136243Sminshall && (GetHost(ScreenInc(pointer)) 34236243Sminshall == GetTerminal(ScreenInc(pointer)))) { 34336243Sminshall break; 34436243Sminshall } 34530043Sminshall 34636243Sminshall if (shouldattr^inHighlightMode) { 34736243Sminshall SetHighlightMode(shouldattr); 34836243Sminshall } 34930043Sminshall 35036243Sminshall DoCharacterAt(shouldbe, pointer); 35130043Sminshall if (IsStartField(pointer)) { 35236243Sminshall TermNewField(pointer, FieldAttributes(pointer)); 35330043Sminshall } else { 35436243Sminshall SetTerminal(pointer, GetHost(pointer)); 35530043Sminshall } 35636243Sminshall pointer = ScreenInc(pointer); 35736243Sminshall if (!(--columnsleft)) { 35836243Sminshall DoARefresh(); 35936243Sminshall EmptyTerminal(); 36036243Sminshall if (HaveInput) { /* if input came in, take it */ 36136243Sminshall int c, j; 36230043Sminshall 36336243Sminshall /* 36436243Sminshall * We need to start a new terminal field 36536243Sminshall * at this location iff the terminal attributes 36636243Sminshall * of this location are not what we have had 36736243Sminshall * them as (ie: we've overwritten the terminal 36836243Sminshall * start field, a the previous field had different 36936243Sminshall * display characteristics). 37036243Sminshall */ 37130043Sminshall 37236243Sminshall isattr = TermAttributes(pointer); 37336243Sminshall DoAttributes(isattr); 37436243Sminshall if ((!TermIsStartField(pointer)) && 37536243Sminshall (isattr != termattr)) { 37630043Sminshall /* 37736243Sminshall * Since we are going to leave a new field 37836243Sminshall * at this terminal position, we 37936243Sminshall * need to make sure that we get an actual 38036243Sminshall * non-highlighted blank on the screen. 38130043Sminshall */ 38236243Sminshall if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { 38336243Sminshall SetHighlightMode(0); /* Turn off highlight */ 38436243Sminshall c = ScreenInc(pointer); 38536243Sminshall j = DISP_BLANK; 38636243Sminshall DoCharacterAt(j, c); 38736243Sminshall } 38836243Sminshall if (termattr&HIGHLIGHT) { 38936243Sminshall termattr = ATTR_DSPD_HIGH; 39036243Sminshall } else if (termattr&NONDISPLAY) { 39136243Sminshall termattr = ATTR_DSPD_NONDISPLAY; 39236243Sminshall } else { 39336243Sminshall termattr = 0; 39436243Sminshall } 39536243Sminshall TermNewField(pointer, termattr); 39636243Sminshall } 39730043Sminshall break; 39830043Sminshall } 39936243Sminshall move(ScreenLine(pointer), 0); 40036243Sminshall columnsleft = NumberColumns; 40130043Sminshall } 40236243Sminshall } /* end of for (;;) */ 40336243Sminshall } /* end of while (...) */ 40430043Sminshall } 40530043Sminshall DoARefresh(); 40630043Sminshall Lowest = pointer; 40730043Sminshall if (Lowest > Highest) { /* if we finished input... */ 40830043Sminshall Lowest = HighestScreen()+1; 40930043Sminshall Highest = LowestScreen()-1; 41030043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 41130043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 41230043Sminshall ScreenLineOffset(terminalCursorAddress))) { 41330043Sminshall GoAway("move", terminalCursorAddress); 41430043Sminshall } 41530043Sminshall DoARefresh(); 41630043Sminshall if (needToRing) { 41730043Sminshall StringToTerminal(bellSequence); 41830043Sminshall needToRing = 0; 41930043Sminshall } 42030043Sminshall } 42130043Sminshall EmptyTerminal(); /* move data along */ 42230043Sminshall return; 42330043Sminshall } 42430043Sminshall 42530043Sminshall #if defined(NOT43) 42630043Sminshall static int 42730043Sminshall #else /* defined(NOT43) */ 42830043Sminshall static void 42930043Sminshall #endif /* defined(NOT43) */ 43030043Sminshall FastScreen() 43130043Sminshall { 43231101Sminshall #if defined(MSDOS) 43330043Sminshall #define SaveCorner 0 43431101Sminshall #else /* defined(MSDOS) */ 43530043Sminshall #define SaveCorner 1 43631101Sminshall #endif /* defined(MSDOS) */ 43730043Sminshall 43830043Sminshall #define DoAttribute(a) if (IsHighlightedAttr(a)) { \ 43930043Sminshall standout(); \ 44030043Sminshall } else { \ 44130043Sminshall standend(); \ 44230043Sminshall } \ 44330043Sminshall if (IsNonDisplayAttr(a)) { \ 44430043Sminshall a = 0; /* zero == don't display */ \ 44530043Sminshall } \ 44630043Sminshall if (!FormattedScreen()) { \ 44730043Sminshall a = 1; /* one ==> do display on unformatted */\ 44830043Sminshall } 44930043Sminshall ScreenImage *p, *upper; 45030043Sminshall int fieldattr; /* spends most of its time == 0 or 1 */ 45130043Sminshall 45230043Sminshall /* OK. We want to do this a quickly as possible. So, we assume we 45330043Sminshall * only need to go from Lowest to Highest. However, if we find a 45430043Sminshall * field in the middle, we do the whole screen. 45530043Sminshall * 45630043Sminshall * In particular, we separate out the two cases from the beginning. 45730043Sminshall */ 45830043Sminshall if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) { 45930043Sminshall register int columnsleft; 46030043Sminshall 46130043Sminshall move(ScreenLine(Lowest), ScreenLineOffset(Lowest)); 46230043Sminshall p = &Host[Lowest]; 46331101Sminshall #if !defined(MSDOS) 46430043Sminshall if (Highest == HighestScreen()) { 46530043Sminshall Highest = ScreenDec(Highest); 46630043Sminshall } 46731101Sminshall #endif /* !defined(MSDOS) */ 46830043Sminshall upper = &Host[Highest]; 46930043Sminshall fieldattr = FieldAttributes(Lowest); 47030043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 47130043Sminshall columnsleft = NumberColumns-ScreenLineOffset(p-Host); 47230043Sminshall 47330043Sminshall while (p <= upper) { 47430054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 47530043Sminshall Highest = HighestScreen(); 47630043Sminshall Lowest = LowestScreen(); 47730043Sminshall FastScreen(); /* Recurse */ 47830043Sminshall return; 47930043Sminshall } else if (fieldattr) { /* Should we display? */ 48031148Sminshall /* Display translated data */ 48135423Sminshall addch((char)disp_asc[GetTerminalPointer(p)]); 48230043Sminshall } else { 48330043Sminshall addch(' '); /* Display a blank */ 48430043Sminshall } 48530043Sminshall /* If the physical screen is larger than what we 48630043Sminshall * are using, we need to make sure that each line 48730043Sminshall * starts at the beginning of the line. Otherwise, 48830043Sminshall * we will just string all the lines together. 48930043Sminshall */ 49030043Sminshall p++; 49130043Sminshall if (--columnsleft == 0) { 49230043Sminshall int i = p-Host; 49330043Sminshall 49430043Sminshall move(ScreenLine(i), 0); 49530043Sminshall columnsleft = NumberColumns; 49630043Sminshall } 49730043Sminshall } 49830043Sminshall } else { /* Going from Lowest to Highest */ 49930043Sminshall unsigned char tmpbuf[MAXNUMBERCOLUMNS+1]; 50030043Sminshall ScreenImage *End = &Host[ScreenSize]-1-SaveCorner; 50130043Sminshall register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns; 50230043Sminshall 50330043Sminshall *tmpend = 0; /* terminate from the beginning */ 50430043Sminshall move(0,0); 50530043Sminshall p = Host; 50630043Sminshall fieldattr = FieldAttributes(LowestScreen()); 50730043Sminshall DoAttribute(fieldattr); /* Set standout, non-display status */ 50830043Sminshall 50930043Sminshall while (p <= End) { 51030054Sminshall if (IsStartFieldPointer(p)) { /* New field? */ 51130043Sminshall if (tmp != tmpbuf) { 51230043Sminshall *tmp++ = 0; /* close out */ 51335423Sminshall addstr((char *)tmpbuf); 51430043Sminshall tmp = tmpbuf; 515*36244Sminshall tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1; 51630043Sminshall } 517*36244Sminshall standend(); 518*36244Sminshall addch(' '); 51930054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 52030043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 52130043Sminshall } else { 52230043Sminshall if (fieldattr) { /* Should we display? */ 52330043Sminshall /* Display translated data */ 52431148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 52530043Sminshall } else { 52630043Sminshall *tmp++ = ' '; 52730043Sminshall } 52830043Sminshall } 52930043Sminshall /* If the physical screen is larger than what we 53030043Sminshall * are using, we need to make sure that each line 53130043Sminshall * starts at the beginning of the line. Otherwise, 53230043Sminshall * we will just string all the lines together. 53330043Sminshall */ 53430043Sminshall p++; 53530043Sminshall if (tmp == tmpend) { 53630043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 53730043Sminshall 53830043Sminshall *tmp++ = 0; 53935423Sminshall addstr((char *)tmpbuf); 54030043Sminshall tmp = tmpbuf; 54130043Sminshall move(ScreenLine(i), 0); 54230043Sminshall tmpend = tmpbuf + NumberColumns; 54330043Sminshall } 54430043Sminshall } 54530043Sminshall if (tmp != tmpbuf) { 54630043Sminshall *tmp++ = 0; 54735423Sminshall addstr((char *)tmpbuf); 54830043Sminshall tmp = tmpbuf; 54930043Sminshall } 55030043Sminshall } 55130043Sminshall Lowest = HighestScreen()+1; 55230043Sminshall Highest = LowestScreen()-1; 55330043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 55430043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 55530043Sminshall ScreenLineOffset(terminalCursorAddress))) { 55630043Sminshall GoAway("move", terminalCursorAddress); 55730043Sminshall } 55830043Sminshall DoARefresh(); 55930043Sminshall if (needToRing) { 56030043Sminshall StringToTerminal(bellSequence); 56130043Sminshall needToRing = 0; 56230043Sminshall } 56330043Sminshall EmptyTerminal(); /* move data along */ 56430043Sminshall return; 56530043Sminshall } 56630043Sminshall 56730043Sminshall 56830043Sminshall /* TryToSend - send data out to user's terminal */ 56930043Sminshall 57030043Sminshall #if defined(NOT43) 57130043Sminshall int 57230043Sminshall #else /* defined(NOT43) */ 57330043Sminshall void 57430043Sminshall #endif /* defined(NOT43) */ 57530043Sminshall (*TryToSend)() = FastScreen; 57630043Sminshall 57735423Sminshall /*ARGSUSED*/ 57831127Sminshall void 57931127Sminshall ScreenOIA(oia) 58031127Sminshall OIA *oia; 58131127Sminshall { 58231127Sminshall } 58331127Sminshall 58431127Sminshall 58530328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 58630043Sminshall 58730043Sminshall void 58830328Sminshall InitTerminal() 58930043Sminshall { 59030043Sminshall #if defined(unix) 59130043Sminshall struct sgttyb ourttyb; 59230043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 59330043Sminshall 2400, 4800, 9600 }; 59430043Sminshall #endif 59535423Sminshall extern void InitMapping(); 59630043Sminshall 59730328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 59830043Sminshall if (!screenInitd) { /* not initialized */ 59930043Sminshall #if defined(unix) 60030043Sminshall char KSEbuffer[2050]; 60130043Sminshall char *lotsofspace = KSEbuffer; 60230043Sminshall extern int abort(); 60330043Sminshall extern char *tgetstr(); 60430043Sminshall #endif /* defined(unix) */ 60530043Sminshall 60634294Sminshall if (initscr() == ERR) { /* Initialize curses to get line size */ 60734294Sminshall ExitString("InitTerminal: Error initializing curses", 1); 60834294Sminshall /*NOTREACHED*/ 60934294Sminshall } 61034294Sminshall MaxNumberLines = LINES; 61134294Sminshall MaxNumberColumns = COLS; 61231101Sminshall ClearArray(Terminal); 61330328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 61430043Sminshall #if defined(unix) 61530043Sminshall signal(SIGHUP, abort); 61630043Sminshall #endif 61730043Sminshall 61830043Sminshall TryToSend = FastScreen; 61931559Sminshall #if defined(unix) 62030043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 62130043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 62230043Sminshall max_changes_before_poll = 1920; 62330043Sminshall } else { 62430043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 62530043Sminshall if (max_changes_before_poll < 40) { 62630043Sminshall max_changes_before_poll = 40; 62730043Sminshall } 62830043Sminshall TryToSend = SlowScreen; 62930043Sminshall HaveInput = 1; /* get signals going */ 63030043Sminshall } 63131559Sminshall #endif /* defined(unix) */ 63230043Sminshall setcommandmode(); 63330043Sminshall /* 63430043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 63530043Sminshall * and the screen has been initialized. 63630043Sminshall */ 63730043Sminshall #if defined(unix) 63830043Sminshall nonl(); 63930043Sminshall /* the problem is that curses catches SIGTSTP to 64030043Sminshall * be nice, but it messes us up. 64130043Sminshall */ 64230043Sminshall signal(SIGTSTP, SIG_DFL); 64334315Sminshall if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 64434315Sminshall myKS = strsave(myKS); 64534315Sminshall StringToTerminal(myKS); 64630043Sminshall } 64734315Sminshall if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 64834315Sminshall myKE = strsave(myKE); 64930043Sminshall } 65030043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 65130043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 65230043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 65330043Sminshall } 65430043Sminshall #endif 65530043Sminshall DoARefresh(); 65630043Sminshall setconnmode(); 65730043Sminshall if (VB && *VB) { 65830043Sminshall bellSequence = VB; /* use visual bell */ 65930043Sminshall } 66030043Sminshall screenInitd = 1; 66130043Sminshall screenStopped = 0; /* Not stopped */ 66230043Sminshall } 66330043Sminshall } 66430043Sminshall 66530043Sminshall 66630043Sminshall /* StopScreen - called when we are going away... */ 66730043Sminshall 66830043Sminshall void 66930043Sminshall StopScreen(doNewLine) 67030043Sminshall int doNewLine; 67130043Sminshall { 67230043Sminshall if (screenInitd && !screenStopped) { 67330043Sminshall move(NumberLines-1, 1); 67430043Sminshall standend(); 67530043Sminshall inHighlightMode = 0; 67630043Sminshall DoARefresh(); 67730043Sminshall setcommandmode(); 67830043Sminshall endwin(); 67930043Sminshall setconnmode(); 68030043Sminshall #if defined(unix) 68134315Sminshall if (myKE) { 68234315Sminshall StringToTerminal(myKE); 68330043Sminshall } 68430043Sminshall #endif /* defined(unix) */ 68530043Sminshall if (doNewLine) { 68630043Sminshall StringToTerminal("\r\n"); 68730043Sminshall } 68830043Sminshall EmptyTerminal(); 68930043Sminshall screenStopped = 1; /* This is stopped */ 69030043Sminshall } 69130043Sminshall } 69230043Sminshall 69330043Sminshall 69430043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 69530043Sminshall 69630043Sminshall void 69730043Sminshall RefreshScreen() 69830043Sminshall { 69930043Sminshall clearok(curscr, TRUE); 70030043Sminshall (*TryToSend)(); 70130043Sminshall } 70230043Sminshall 70330043Sminshall 70430043Sminshall /* ConnectScreen - called to reconnect to the screen */ 70530043Sminshall 70630043Sminshall void 70730043Sminshall ConnectScreen() 70830043Sminshall { 70930043Sminshall if (screenInitd) { 71030043Sminshall #if defined(unix) 71134315Sminshall if (myKS) { 71234315Sminshall StringToTerminal(myKS); 71330043Sminshall } 71430043Sminshall #endif /* defined(unix) */ 71530043Sminshall RefreshScreen(); 71630043Sminshall (*TryToSend)(); 71730043Sminshall screenStopped = 0; 71830043Sminshall } 71930043Sminshall } 72030043Sminshall 72130043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 72230043Sminshall 72330043Sminshall void 72430043Sminshall LocalClearScreen() 72530043Sminshall { 72635423Sminshall extern void Clear3270(); 72735423Sminshall 72830043Sminshall outputPurge(); /* flush all data to terminal */ 72930043Sminshall clear(); /* clear in curses */ 73031101Sminshall ClearArray(Terminal); 73130043Sminshall Clear3270(); 73230043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 73330043Sminshall Highest = LowestScreen()+1; 73430043Sminshall } 73530043Sminshall 73630043Sminshall 73730043Sminshall void 73830043Sminshall BellOff() 73930043Sminshall { 74030043Sminshall if (bellwinup) { 74130043Sminshall delwin(bellwin); 74230043Sminshall bellwin = 0; 74330043Sminshall bellwinup = 0; 74430043Sminshall touchwin(stdscr); 74530043Sminshall DoARefresh(); 74630043Sminshall } 74730043Sminshall } 74830043Sminshall 74930043Sminshall 75030043Sminshall void 75130043Sminshall RingBell(s) 75230043Sminshall char *s; 75330043Sminshall { 75430043Sminshall needToRing = 1; 75530043Sminshall if (s) { 75630043Sminshall int len = strlen(s); 75730043Sminshall 75830043Sminshall if (len > COLS-2) { 75930043Sminshall len = COLS-2; 76030043Sminshall } 76130043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 76235423Sminshall OurExitString("Error from newwin in RingBell", 1); 76330043Sminshall } 76430043Sminshall werase(bellwin); 76530043Sminshall wstandout(bellwin); 76630043Sminshall box(bellwin, '|', '-'); 76730043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 76835423Sminshall OurExitString("Error from wmove in RingBell", 1); 76930043Sminshall } 77030043Sminshall while (len--) { 77130043Sminshall if (waddch(bellwin, *s++) == ERR) { 77235423Sminshall OurExitString("Error from waddch in RingBell", 1); 77330043Sminshall } 77430043Sminshall } 77530043Sminshall wstandend(bellwin); 77630043Sminshall if (wrefresh(bellwin) == ERR) { 77735423Sminshall OurExitString("Error from wrefresh in RingBell", 1); 77830043Sminshall } 77930043Sminshall bellwinup = 1; 78030043Sminshall } 78130043Sminshall } 78230043Sminshall 78330043Sminshall 78430043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 78530043Sminshall or a 0 if there is more output available (so, just poll the other 78630043Sminshall sources/destinations, don't block). 78730043Sminshall */ 78830043Sminshall 78930043Sminshall int 79030043Sminshall DoTerminalOutput() 79130043Sminshall { 79230043Sminshall /* called just before a select to conserve IO to terminal */ 79331462Sminshall if (!(screenInitd||screenStopped)) { 79430369Sminshall return 1; /* No output if not initialized */ 79530369Sminshall } 79630369Sminshall if ((Lowest <= Highest) || needToRing || 79730369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 79830043Sminshall (*TryToSend)(); 79930043Sminshall } 80030043Sminshall if (Lowest > Highest) { 80130369Sminshall return 1; /* no more output now */ 80230043Sminshall } else { 80330369Sminshall return 0; /* more output for future */ 80430043Sminshall } 80530043Sminshall } 80630074Sminshall 80730074Sminshall /* 80830074Sminshall * The following are defined to handle transparent data. 80930074Sminshall */ 81030074Sminshall 81130074Sminshall void 81230074Sminshall TransStop() 81330074Sminshall { 81430074Sminshall #if defined(unix) 81530074Sminshall if (tcflag == 0) { 81630074Sminshall tcflag = -1; 81730074Sminshall (void) signal(SIGCHLD, SIG_DFL); 81830074Sminshall } else if (tcflag > 0) { 81930074Sminshall setcommandmode(); 82030074Sminshall (void) close(tin); 82130074Sminshall (void) close(tout); 82230074Sminshall tin = savefd[0]; 82330074Sminshall tout = savefd[1]; 82430074Sminshall setconnmode(); 82530074Sminshall tcflag = -1; 82630074Sminshall (void) signal(SIGCHLD, SIG_DFL); 82730074Sminshall } 82830074Sminshall #endif /* defined(unix) */ 82930074Sminshall RefreshScreen(); 83030074Sminshall } 83130074Sminshall 83230074Sminshall void 83331863Sminshall TransOut(buffer, count, kind, control) 83430074Sminshall unsigned char *buffer; 83530074Sminshall int count; 83631863Sminshall int kind; /* 0 or 5 */ 83731863Sminshall int control; /* To see if we are done */ 83830074Sminshall { 83930074Sminshall #if defined(unix) 84030074Sminshall extern char *transcom; 84135423Sminshall int inpipefd[2], outpipefd[2]; 84230074Sminshall void aborttc(); 84330074Sminshall #endif /* defined(unix) */ 84430074Sminshall 84530074Sminshall while (DoTerminalOutput() == 0) { 84630074Sminshall #if defined(unix) 84730074Sminshall HaveInput = 0; 84830074Sminshall #endif /* defined(unix) */ 84930074Sminshall } 85030074Sminshall #if defined(unix) 85130074Sminshall if (transcom && tcflag == -1) { 85230074Sminshall while (1) { /* go thru once */ 85330074Sminshall if (pipe(outpipefd) < 0) { 85430074Sminshall break; 85530074Sminshall } 85630074Sminshall if (pipe(inpipefd) < 0) { 85730074Sminshall break; 85830074Sminshall } 85930074Sminshall if ((tcflag = fork()) == 0) { 86030074Sminshall (void) close(outpipefd[1]); 86130074Sminshall (void) close(0); 86230074Sminshall if (dup(outpipefd[0]) < 0) { 86330074Sminshall exit(1); 86430074Sminshall } 86530074Sminshall (void) close(outpipefd[0]); 86630074Sminshall (void) close(inpipefd[0]); 86730074Sminshall (void) close(1); 86830074Sminshall if (dup(inpipefd[1]) < 0) { 86930074Sminshall exit(1); 87030074Sminshall } 87130074Sminshall (void) close(inpipefd[1]); 87230074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 87330074Sminshall exit(1); 87430074Sminshall } 87530074Sminshall } 87630074Sminshall (void) close(inpipefd[1]); 87730074Sminshall (void) close(outpipefd[0]); 87830074Sminshall savefd[0] = tin; 87930074Sminshall savefd[1] = tout; 88030074Sminshall setcommandmode(); 88130074Sminshall tin = inpipefd[0]; 88230074Sminshall tout = outpipefd[1]; 88335423Sminshall (void) signal(SIGCHLD, (int (*)())aborttc); 88430074Sminshall setconnmode(); 88530074Sminshall tcflag = 1; 88630074Sminshall break; 88730074Sminshall } 88830074Sminshall if (tcflag < 1) { 88930074Sminshall tcflag = 0; 89030074Sminshall } 89130074Sminshall } 89230074Sminshall #endif /* defined(unix) */ 89335423Sminshall (void) DataToTerminal((char *)buffer, count); 89431863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 89531863Sminshall SendToIBM(); 89631863Sminshall } else { 89735423Sminshall extern void TransInput(); 89835423Sminshall 89931863Sminshall TransInput(1, kind); /* Go get some data */ 90031863Sminshall } 90130074Sminshall } 90230074Sminshall 90330074Sminshall 90430074Sminshall #if defined(unix) 90530074Sminshall static void 90630074Sminshall aborttc() 90730074Sminshall { 90830074Sminshall setcommandmode(); 90930074Sminshall (void) close(tin); 91030074Sminshall (void) close(tout); 91130074Sminshall tin = savefd[0]; 91230074Sminshall tout = savefd[1]; 91330074Sminshall setconnmode(); 91430074Sminshall tcflag = 0; 91530074Sminshall } 91630074Sminshall #endif /* defined(unix) */ 917