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