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*36243Sminshall static char sccsid[] = "@(#)termout.c 3.8 (Berkeley) 11/18/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" 48*36243Sminshall #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 { 186*36243Sminshall register int is, shouldbe, isattr, shouldattr; 18730043Sminshall register int pointer; 188*36243Sminshall register int fieldattr, termattr; 18930043Sminshall register int columnsleft; 19030043Sminshall 191*36243Sminshall #define HIGHLIGHT 1 /* Mask bits */ 192*36243Sminshall #define NONDISPLAY 4 /* Mask bits */ 193*36243Sminshall 194*36243Sminshall #define DoAttributes(x) \ 195*36243Sminshall switch (x&ATTR_DSPD_MASK) { \ 196*36243Sminshall case ATTR_DSPD_NONDISPLAY: \ 197*36243Sminshall x = NONDISPLAY; \ 198*36243Sminshall break; \ 199*36243Sminshall case ATTR_DSPD_HIGH: \ 200*36243Sminshall x = HIGHLIGHT; \ 201*36243Sminshall break; \ 202*36243Sminshall default: \ 203*36243Sminshall x = 0; \ 204*36243Sminshall break; \ 205*36243Sminshall } 206*36243Sminshall 207*36243Sminshall # define SetHighlightMode(x) \ 208*36243Sminshall { \ 209*36243Sminshall if ((x)&HIGHLIGHT) { \ 21030043Sminshall if (!inHighlightMode) { \ 211*36243Sminshall 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()) { \ 224*36243Sminshall 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 290*36243Sminshall /* 291*36243Sminshall * 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 */ 301*36243Sminshall fieldattr = FieldAttributes(pointer); 302*36243Sminshall DoAttributes(fieldattr); 303*36243Sminshall termattr = TermAttributes(pointer); 304*36243Sminshall DoAttributes(termattr); 30530043Sminshall 306*36243Sminshall SetHighlightMode(fieldattr); 307*36243Sminshall /* 308*36243Sminshall * The following will terminate at least when we get back 309*36243Sminshall * to the original 'pointer' location (since we force 310*36243Sminshall * things to be equal). 311*36243Sminshall */ 312*36243Sminshall for (;;) { 313*36243Sminshall if (IsStartField(pointer)) { 314*36243Sminshall shouldbe = DISP_BLANK; 315*36243Sminshall shouldattr = 0; 316*36243Sminshall fieldattr = GetHost(pointer); 317*36243Sminshall DoAttributes(fieldattr); 318*36243Sminshall } else { 319*36243Sminshall if (fieldattr&NONDISPLAY) { 320*36243Sminshall shouldbe = DISP_BLANK; 321*36243Sminshall } else { 322*36243Sminshall shouldbe = GetHost(pointer); 323*36243Sminshall } 324*36243Sminshall shouldattr = fieldattr; 325*36243Sminshall } 326*36243Sminshall if (TermIsStartField(pointer)) { 327*36243Sminshall is = DISP_BLANK; 328*36243Sminshall isattr = 0; 329*36243Sminshall termattr = GetTerminal(pointer); 330*36243Sminshall DoAttributes(termattr); 331*36243Sminshall } else { 332*36243Sminshall if (termattr&NONDISPLAY) { 333*36243Sminshall is = DISP_BLANK; 334*36243Sminshall } else { 335*36243Sminshall is = GetTerminal(pointer); 336*36243Sminshall } 337*36243Sminshall isattr = termattr; 338*36243Sminshall } 339*36243Sminshall if ((shouldbe == is) && (shouldattr == isattr) 340*36243Sminshall && (GetHost(pointer) == GetTerminal(pointer)) 341*36243Sminshall && (GetHost(ScreenInc(pointer)) 342*36243Sminshall == GetTerminal(ScreenInc(pointer)))) { 343*36243Sminshall break; 344*36243Sminshall } 34530043Sminshall 346*36243Sminshall if (shouldattr^inHighlightMode) { 347*36243Sminshall SetHighlightMode(shouldattr); 348*36243Sminshall } 34930043Sminshall 350*36243Sminshall DoCharacterAt(shouldbe, pointer); 35130043Sminshall if (IsStartField(pointer)) { 352*36243Sminshall TermNewField(pointer, FieldAttributes(pointer)); 35330043Sminshall } else { 354*36243Sminshall SetTerminal(pointer, GetHost(pointer)); 35530043Sminshall } 356*36243Sminshall pointer = ScreenInc(pointer); 357*36243Sminshall if (!(--columnsleft)) { 358*36243Sminshall DoARefresh(); 359*36243Sminshall EmptyTerminal(); 360*36243Sminshall if (HaveInput) { /* if input came in, take it */ 361*36243Sminshall int c, j; 36230043Sminshall 363*36243Sminshall /* 364*36243Sminshall * We need to start a new terminal field 365*36243Sminshall * at this location iff the terminal attributes 366*36243Sminshall * of this location are not what we have had 367*36243Sminshall * them as (ie: we've overwritten the terminal 368*36243Sminshall * start field, a the previous field had different 369*36243Sminshall * display characteristics). 370*36243Sminshall */ 37130043Sminshall 372*36243Sminshall isattr = TermAttributes(pointer); 373*36243Sminshall DoAttributes(isattr); 374*36243Sminshall if ((!TermIsStartField(pointer)) && 375*36243Sminshall (isattr != termattr)) { 37630043Sminshall /* 377*36243Sminshall * Since we are going to leave a new field 378*36243Sminshall * at this terminal position, we 379*36243Sminshall * need to make sure that we get an actual 380*36243Sminshall * non-highlighted blank on the screen. 38130043Sminshall */ 382*36243Sminshall if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) { 383*36243Sminshall SetHighlightMode(0); /* Turn off highlight */ 384*36243Sminshall c = ScreenInc(pointer); 385*36243Sminshall j = DISP_BLANK; 386*36243Sminshall DoCharacterAt(j, c); 387*36243Sminshall } 388*36243Sminshall if (termattr&HIGHLIGHT) { 389*36243Sminshall termattr = ATTR_DSPD_HIGH; 390*36243Sminshall } else if (termattr&NONDISPLAY) { 391*36243Sminshall termattr = ATTR_DSPD_NONDISPLAY; 392*36243Sminshall } else { 393*36243Sminshall termattr = 0; 394*36243Sminshall } 395*36243Sminshall TermNewField(pointer, termattr); 396*36243Sminshall } 39730043Sminshall break; 39830043Sminshall } 399*36243Sminshall move(ScreenLine(pointer), 0); 400*36243Sminshall columnsleft = NumberColumns; 40130043Sminshall } 402*36243Sminshall } /* end of for (;;) */ 403*36243Sminshall } /* 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; 51530043Sminshall tmpend = tmpbuf + NumberColumns - ScreenLineOffset(p-Host); 51630043Sminshall } 51730054Sminshall fieldattr = FieldAttributesPointer(p); /* Get attributes */ 51830043Sminshall DoAttribute(fieldattr); /* Set standout, non-display */ 51930043Sminshall *tmp++ = ' '; 52030043Sminshall } else { 52130043Sminshall if (fieldattr) { /* Should we display? */ 52230043Sminshall /* Display translated data */ 52331148Sminshall *tmp++ = disp_asc[GetTerminalPointer(p)]; 52430043Sminshall } else { 52530043Sminshall *tmp++ = ' '; 52630043Sminshall } 52730043Sminshall } 52830043Sminshall /* If the physical screen is larger than what we 52930043Sminshall * are using, we need to make sure that each line 53030043Sminshall * starts at the beginning of the line. Otherwise, 53130043Sminshall * we will just string all the lines together. 53230043Sminshall */ 53330043Sminshall p++; 53430043Sminshall if (tmp == tmpend) { 53530043Sminshall int i = p-Host; /* Be sure the "p++" happened first! */ 53630043Sminshall 53730043Sminshall *tmp++ = 0; 53835423Sminshall addstr((char *)tmpbuf); 53930043Sminshall tmp = tmpbuf; 54030043Sminshall move(ScreenLine(i), 0); 54130043Sminshall tmpend = tmpbuf + NumberColumns; 54230043Sminshall } 54330043Sminshall } 54430043Sminshall if (tmp != tmpbuf) { 54530043Sminshall *tmp++ = 0; 54635423Sminshall addstr((char *)tmpbuf); 54730043Sminshall tmp = tmpbuf; 54830043Sminshall } 54930043Sminshall } 55030043Sminshall Lowest = HighestScreen()+1; 55130043Sminshall Highest = LowestScreen()-1; 55230043Sminshall terminalCursorAddress = CorrectTerminalCursor(); 55330043Sminshall if (ERR == move(ScreenLine(terminalCursorAddress), 55430043Sminshall ScreenLineOffset(terminalCursorAddress))) { 55530043Sminshall GoAway("move", terminalCursorAddress); 55630043Sminshall } 55730043Sminshall DoARefresh(); 55830043Sminshall if (needToRing) { 55930043Sminshall StringToTerminal(bellSequence); 56030043Sminshall needToRing = 0; 56130043Sminshall } 56230043Sminshall EmptyTerminal(); /* move data along */ 56330043Sminshall return; 56430043Sminshall } 56530043Sminshall 56630043Sminshall 56730043Sminshall /* TryToSend - send data out to user's terminal */ 56830043Sminshall 56930043Sminshall #if defined(NOT43) 57030043Sminshall int 57130043Sminshall #else /* defined(NOT43) */ 57230043Sminshall void 57330043Sminshall #endif /* defined(NOT43) */ 57430043Sminshall (*TryToSend)() = FastScreen; 57530043Sminshall 57635423Sminshall /*ARGSUSED*/ 57731127Sminshall void 57831127Sminshall ScreenOIA(oia) 57931127Sminshall OIA *oia; 58031127Sminshall { 58131127Sminshall } 58231127Sminshall 58331127Sminshall 58430328Sminshall /* InitTerminal - called to initialize the screen, etc. */ 58530043Sminshall 58630043Sminshall void 58730328Sminshall InitTerminal() 58830043Sminshall { 58930043Sminshall #if defined(unix) 59030043Sminshall struct sgttyb ourttyb; 59130043Sminshall static int speeds[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 59230043Sminshall 2400, 4800, 9600 }; 59330043Sminshall #endif 59435423Sminshall extern void InitMapping(); 59530043Sminshall 59630328Sminshall InitMapping(); /* Go do mapping file (MAP3270) first */ 59730043Sminshall if (!screenInitd) { /* not initialized */ 59830043Sminshall #if defined(unix) 59930043Sminshall char KSEbuffer[2050]; 60030043Sminshall char *lotsofspace = KSEbuffer; 60130043Sminshall extern int abort(); 60230043Sminshall extern char *tgetstr(); 60330043Sminshall #endif /* defined(unix) */ 60430043Sminshall 60534294Sminshall if (initscr() == ERR) { /* Initialize curses to get line size */ 60634294Sminshall ExitString("InitTerminal: Error initializing curses", 1); 60734294Sminshall /*NOTREACHED*/ 60834294Sminshall } 60934294Sminshall MaxNumberLines = LINES; 61034294Sminshall MaxNumberColumns = COLS; 61131101Sminshall ClearArray(Terminal); 61230328Sminshall terminalCursorAddress = SetBufferAddress(0,0); 61330043Sminshall #if defined(unix) 61430043Sminshall signal(SIGHUP, abort); 61530043Sminshall #endif 61630043Sminshall 61730043Sminshall TryToSend = FastScreen; 61831559Sminshall #if defined(unix) 61930043Sminshall ioctl(1, TIOCGETP, (char *) &ourttyb); 62030043Sminshall if ((ourttyb.sg_ospeed < 0) || (ourttyb.sg_ospeed > B9600)) { 62130043Sminshall max_changes_before_poll = 1920; 62230043Sminshall } else { 62330043Sminshall max_changes_before_poll = speeds[ourttyb.sg_ospeed]/10; 62430043Sminshall if (max_changes_before_poll < 40) { 62530043Sminshall max_changes_before_poll = 40; 62630043Sminshall } 62730043Sminshall TryToSend = SlowScreen; 62830043Sminshall HaveInput = 1; /* get signals going */ 62930043Sminshall } 63031559Sminshall #endif /* defined(unix) */ 63130043Sminshall setcommandmode(); 63230043Sminshall /* 63330043Sminshall * By now, initscr() (in curses) has been called (from telnet.c), 63430043Sminshall * and the screen has been initialized. 63530043Sminshall */ 63630043Sminshall #if defined(unix) 63730043Sminshall nonl(); 63830043Sminshall /* the problem is that curses catches SIGTSTP to 63930043Sminshall * be nice, but it messes us up. 64030043Sminshall */ 64130043Sminshall signal(SIGTSTP, SIG_DFL); 64234315Sminshall if ((myKS = tgetstr("ks", &lotsofspace)) != 0) { 64334315Sminshall myKS = strsave(myKS); 64434315Sminshall StringToTerminal(myKS); 64530043Sminshall } 64634315Sminshall if ((myKE = tgetstr("ke", &lotsofspace)) != 0) { 64734315Sminshall myKE = strsave(myKE); 64830043Sminshall } 64930043Sminshall if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) { 65030043Sminshall SO = strsave(tgetstr("md", &lotsofspace)); 65130043Sminshall SE = strsave(tgetstr("me", &lotsofspace)); 65230043Sminshall } 65330043Sminshall #endif 65430043Sminshall DoARefresh(); 65530043Sminshall setconnmode(); 65630043Sminshall if (VB && *VB) { 65730043Sminshall bellSequence = VB; /* use visual bell */ 65830043Sminshall } 65930043Sminshall screenInitd = 1; 66030043Sminshall screenStopped = 0; /* Not stopped */ 66130043Sminshall } 66230043Sminshall } 66330043Sminshall 66430043Sminshall 66530043Sminshall /* StopScreen - called when we are going away... */ 66630043Sminshall 66730043Sminshall void 66830043Sminshall StopScreen(doNewLine) 66930043Sminshall int doNewLine; 67030043Sminshall { 67130043Sminshall if (screenInitd && !screenStopped) { 67230043Sminshall move(NumberLines-1, 1); 67330043Sminshall standend(); 67430043Sminshall inHighlightMode = 0; 67530043Sminshall DoARefresh(); 67630043Sminshall setcommandmode(); 67730043Sminshall endwin(); 67830043Sminshall setconnmode(); 67930043Sminshall #if defined(unix) 68034315Sminshall if (myKE) { 68134315Sminshall StringToTerminal(myKE); 68230043Sminshall } 68330043Sminshall #endif /* defined(unix) */ 68430043Sminshall if (doNewLine) { 68530043Sminshall StringToTerminal("\r\n"); 68630043Sminshall } 68730043Sminshall EmptyTerminal(); 68830043Sminshall screenStopped = 1; /* This is stopped */ 68930043Sminshall } 69030043Sminshall } 69130043Sminshall 69230043Sminshall 69330043Sminshall /* RefreshScreen - called to cause the screen to be refreshed */ 69430043Sminshall 69530043Sminshall void 69630043Sminshall RefreshScreen() 69730043Sminshall { 69830043Sminshall clearok(curscr, TRUE); 69930043Sminshall (*TryToSend)(); 70030043Sminshall } 70130043Sminshall 70230043Sminshall 70330043Sminshall /* ConnectScreen - called to reconnect to the screen */ 70430043Sminshall 70530043Sminshall void 70630043Sminshall ConnectScreen() 70730043Sminshall { 70830043Sminshall if (screenInitd) { 70930043Sminshall #if defined(unix) 71034315Sminshall if (myKS) { 71134315Sminshall StringToTerminal(myKS); 71230043Sminshall } 71330043Sminshall #endif /* defined(unix) */ 71430043Sminshall RefreshScreen(); 71530043Sminshall (*TryToSend)(); 71630043Sminshall screenStopped = 0; 71730043Sminshall } 71830043Sminshall } 71930043Sminshall 72030043Sminshall /* LocalClearScreen() - clear the whole ball of wax, cheaply */ 72130043Sminshall 72230043Sminshall void 72330043Sminshall LocalClearScreen() 72430043Sminshall { 72535423Sminshall extern void Clear3270(); 72635423Sminshall 72730043Sminshall outputPurge(); /* flush all data to terminal */ 72830043Sminshall clear(); /* clear in curses */ 72931101Sminshall ClearArray(Terminal); 73030043Sminshall Clear3270(); 73130043Sminshall Lowest = HighestScreen()+1; /* everything in sync... */ 73230043Sminshall Highest = LowestScreen()+1; 73330043Sminshall } 73430043Sminshall 73530043Sminshall 73630043Sminshall void 73730043Sminshall BellOff() 73830043Sminshall { 73930043Sminshall if (bellwinup) { 74030043Sminshall delwin(bellwin); 74130043Sminshall bellwin = 0; 74230043Sminshall bellwinup = 0; 74330043Sminshall touchwin(stdscr); 74430043Sminshall DoARefresh(); 74530043Sminshall } 74630043Sminshall } 74730043Sminshall 74830043Sminshall 74930043Sminshall void 75030043Sminshall RingBell(s) 75130043Sminshall char *s; 75230043Sminshall { 75330043Sminshall needToRing = 1; 75430043Sminshall if (s) { 75530043Sminshall int len = strlen(s); 75630043Sminshall 75730043Sminshall if (len > COLS-2) { 75830043Sminshall len = COLS-2; 75930043Sminshall } 76030043Sminshall if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) { 76135423Sminshall OurExitString("Error from newwin in RingBell", 1); 76230043Sminshall } 76330043Sminshall werase(bellwin); 76430043Sminshall wstandout(bellwin); 76530043Sminshall box(bellwin, '|', '-'); 76630043Sminshall if (wmove(bellwin, 1, 1) == ERR) { 76735423Sminshall OurExitString("Error from wmove in RingBell", 1); 76830043Sminshall } 76930043Sminshall while (len--) { 77030043Sminshall if (waddch(bellwin, *s++) == ERR) { 77135423Sminshall OurExitString("Error from waddch in RingBell", 1); 77230043Sminshall } 77330043Sminshall } 77430043Sminshall wstandend(bellwin); 77530043Sminshall if (wrefresh(bellwin) == ERR) { 77635423Sminshall OurExitString("Error from wrefresh in RingBell", 1); 77730043Sminshall } 77830043Sminshall bellwinup = 1; 77930043Sminshall } 78030043Sminshall } 78130043Sminshall 78230043Sminshall 78330043Sminshall /* returns a 1 if no more output available (so, go ahead and block), 78430043Sminshall or a 0 if there is more output available (so, just poll the other 78530043Sminshall sources/destinations, don't block). 78630043Sminshall */ 78730043Sminshall 78830043Sminshall int 78930043Sminshall DoTerminalOutput() 79030043Sminshall { 79130043Sminshall /* called just before a select to conserve IO to terminal */ 79231462Sminshall if (!(screenInitd||screenStopped)) { 79330369Sminshall return 1; /* No output if not initialized */ 79430369Sminshall } 79530369Sminshall if ((Lowest <= Highest) || needToRing || 79630369Sminshall (terminalCursorAddress != CorrectTerminalCursor())) { 79730043Sminshall (*TryToSend)(); 79830043Sminshall } 79930043Sminshall if (Lowest > Highest) { 80030369Sminshall return 1; /* no more output now */ 80130043Sminshall } else { 80230369Sminshall return 0; /* more output for future */ 80330043Sminshall } 80430043Sminshall } 80530074Sminshall 80630074Sminshall /* 80730074Sminshall * The following are defined to handle transparent data. 80830074Sminshall */ 80930074Sminshall 81030074Sminshall void 81130074Sminshall TransStop() 81230074Sminshall { 81330074Sminshall #if defined(unix) 81430074Sminshall if (tcflag == 0) { 81530074Sminshall tcflag = -1; 81630074Sminshall (void) signal(SIGCHLD, SIG_DFL); 81730074Sminshall } else if (tcflag > 0) { 81830074Sminshall setcommandmode(); 81930074Sminshall (void) close(tin); 82030074Sminshall (void) close(tout); 82130074Sminshall tin = savefd[0]; 82230074Sminshall tout = savefd[1]; 82330074Sminshall setconnmode(); 82430074Sminshall tcflag = -1; 82530074Sminshall (void) signal(SIGCHLD, SIG_DFL); 82630074Sminshall } 82730074Sminshall #endif /* defined(unix) */ 82830074Sminshall RefreshScreen(); 82930074Sminshall } 83030074Sminshall 83130074Sminshall void 83231863Sminshall TransOut(buffer, count, kind, control) 83330074Sminshall unsigned char *buffer; 83430074Sminshall int count; 83531863Sminshall int kind; /* 0 or 5 */ 83631863Sminshall int control; /* To see if we are done */ 83730074Sminshall { 83830074Sminshall #if defined(unix) 83930074Sminshall extern char *transcom; 84035423Sminshall int inpipefd[2], outpipefd[2]; 84130074Sminshall void aborttc(); 84230074Sminshall #endif /* defined(unix) */ 84330074Sminshall 84430074Sminshall while (DoTerminalOutput() == 0) { 84530074Sminshall #if defined(unix) 84630074Sminshall HaveInput = 0; 84730074Sminshall #endif /* defined(unix) */ 84830074Sminshall } 84930074Sminshall #if defined(unix) 85030074Sminshall if (transcom && tcflag == -1) { 85130074Sminshall while (1) { /* go thru once */ 85230074Sminshall if (pipe(outpipefd) < 0) { 85330074Sminshall break; 85430074Sminshall } 85530074Sminshall if (pipe(inpipefd) < 0) { 85630074Sminshall break; 85730074Sminshall } 85830074Sminshall if ((tcflag = fork()) == 0) { 85930074Sminshall (void) close(outpipefd[1]); 86030074Sminshall (void) close(0); 86130074Sminshall if (dup(outpipefd[0]) < 0) { 86230074Sminshall exit(1); 86330074Sminshall } 86430074Sminshall (void) close(outpipefd[0]); 86530074Sminshall (void) close(inpipefd[0]); 86630074Sminshall (void) close(1); 86730074Sminshall if (dup(inpipefd[1]) < 0) { 86830074Sminshall exit(1); 86930074Sminshall } 87030074Sminshall (void) close(inpipefd[1]); 87130074Sminshall if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) { 87230074Sminshall exit(1); 87330074Sminshall } 87430074Sminshall } 87530074Sminshall (void) close(inpipefd[1]); 87630074Sminshall (void) close(outpipefd[0]); 87730074Sminshall savefd[0] = tin; 87830074Sminshall savefd[1] = tout; 87930074Sminshall setcommandmode(); 88030074Sminshall tin = inpipefd[0]; 88130074Sminshall tout = outpipefd[1]; 88235423Sminshall (void) signal(SIGCHLD, (int (*)())aborttc); 88330074Sminshall setconnmode(); 88430074Sminshall tcflag = 1; 88530074Sminshall break; 88630074Sminshall } 88730074Sminshall if (tcflag < 1) { 88830074Sminshall tcflag = 0; 88930074Sminshall } 89030074Sminshall } 89130074Sminshall #endif /* defined(unix) */ 89235423Sminshall (void) DataToTerminal((char *)buffer, count); 89331863Sminshall if (control && (kind == 0)) { /* Send in AID byte */ 89431863Sminshall SendToIBM(); 89531863Sminshall } else { 89635423Sminshall extern void TransInput(); 89735423Sminshall 89831863Sminshall TransInput(1, kind); /* Go get some data */ 89931863Sminshall } 90030074Sminshall } 90130074Sminshall 90230074Sminshall 90330074Sminshall #if defined(unix) 90430074Sminshall static void 90530074Sminshall aborttc() 90630074Sminshall { 90730074Sminshall setcommandmode(); 90830074Sminshall (void) close(tin); 90930074Sminshall (void) close(tout); 91030074Sminshall tin = savefd[0]; 91130074Sminshall tout = savefd[1]; 91230074Sminshall setconnmode(); 91330074Sminshall tcflag = 0; 91430074Sminshall } 91530074Sminshall #endif /* defined(unix) */ 916