949 lines
24 KiB
C
949 lines
24 KiB
C
/*-
|
||
* Copyright (c) 1988, 1993
|
||
* The Regents of the University of California. All rights reserved.
|
||
*
|
||
* Redistribution and use in source and binary forms, with or without
|
||
* modification, are permitted provided that the following conditions
|
||
* are met:
|
||
* 1. Redistributions of source code must retain the above copyright
|
||
* notice, this list of conditions and the following disclaimer.
|
||
* 2. Redistributions in binary form must reproduce the above copyright
|
||
* notice, this list of conditions and the following disclaimer in the
|
||
* documentation and/or other materials provided with the distribution.
|
||
* 3. All advertising materials mentioning features or use of this software
|
||
* must display the following acknowledgement:
|
||
* This product includes software developed by the University of
|
||
* California, Berkeley and its contributors.
|
||
* 4. Neither the name of the University nor the names of its contributors
|
||
* may be used to endorse or promote products derived from this software
|
||
* without specific prior written permission.
|
||
*
|
||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
* SUCH DAMAGE.
|
||
*/
|
||
|
||
#ifndef lint
|
||
static char sccsid[] = "@(#)termout.c 8.1 (Berkeley) 6/6/93";
|
||
#endif /* not lint */
|
||
|
||
#if defined(unix)
|
||
#include <signal.h>
|
||
#include <termios.h>
|
||
#endif
|
||
#include <stdio.h>
|
||
#include <curses.h>
|
||
|
||
#include "../general/general.h"
|
||
|
||
#include "terminal.h"
|
||
|
||
#include "../api/disp_asc.h"
|
||
|
||
#include "../ctlr/hostctlr.h"
|
||
#include "../ctlr/externs.h"
|
||
#include "../ctlr/declare.h"
|
||
#include "../ctlr/oia.h"
|
||
#include "../ctlr/screen.h"
|
||
#include "../ctlr/scrnctlr.h"
|
||
|
||
#include "../general/globals.h"
|
||
|
||
#include "telextrn.h"
|
||
|
||
#define CorrectTerminalCursor() ((TransparentClock == OutputClock)? \
|
||
CursorAddress:UnLocked? CursorAddress: HighestScreen())
|
||
|
||
|
||
static int terminalCursorAddress; /* where the cursor is on term */
|
||
static int screenInitd; /* the screen has been initialized */
|
||
static int screenStopped; /* the screen has been stopped */
|
||
static int max_changes_before_poll; /* how many characters before looking */
|
||
/* at terminal and net again */
|
||
|
||
static int needToRing; /* need to ring terinal bell */
|
||
static char *bellSequence = "\07"; /* bell sequence (may be replaced by
|
||
* VB during initialization)
|
||
*/
|
||
static WINDOW *bellwin = 0; /* The window the bell message is in */
|
||
int bellwinup = 0; /* Are we up with it or not */
|
||
|
||
#if defined(unix)
|
||
static char *myKS, *myKE;
|
||
#endif /* defined(unix) */
|
||
|
||
|
||
static int inHighlightMode = 0;
|
||
ScreenImage Terminal[MAXSCREENSIZE];
|
||
|
||
/* Variables for transparent mode */
|
||
#if defined(unix)
|
||
static int tcflag = -1; /* transparent mode command flag */
|
||
static int savefd[2]; /* for storing fds during transcom */
|
||
extern int tin, tout; /* file descriptors */
|
||
#endif /* defined(unix) */
|
||
|
||
|
||
/*
|
||
* init_screen()
|
||
*
|
||
* Initialize variables used by screen.
|
||
*/
|
||
|
||
void
|
||
init_screen()
|
||
{
|
||
bellwinup = 0;
|
||
inHighlightMode = 0;
|
||
ClearArray(Terminal);
|
||
}
|
||
|
||
|
||
/* OurExitString - designed to keep us from going through infinite recursion */
|
||
|
||
static void
|
||
OurExitString(string, value)
|
||
char *string;
|
||
int value;
|
||
{
|
||
static int recursion = 0;
|
||
|
||
if (!recursion) {
|
||
recursion = 1;
|
||
ExitString(string, value);
|
||
}
|
||
}
|
||
|
||
|
||
/* DoARefresh */
|
||
|
||
static void
|
||
DoARefresh()
|
||
{
|
||
if (ERR == refresh()) {
|
||
OurExitString("ERR from refresh\n", 1);
|
||
}
|
||
}
|
||
|
||
static void
|
||
GoAway(from, where)
|
||
char *from; /* routine that gave error */
|
||
int where; /* cursor address */
|
||
{
|
||
char foo[100];
|
||
|
||
sprintf(foo, "ERR from %s at %d (%d, %d)\n",
|
||
from, where, ScreenLine(where), ScreenLineOffset(where));
|
||
OurExitString(foo, 1);
|
||
/* NOTREACHED */
|
||
}
|
||
|
||
/* What is the screen address of the attribute byte for the terminal */
|
||
|
||
static int
|
||
WhereTermAttrByte(p)
|
||
register int p;
|
||
{
|
||
register int i;
|
||
|
||
i = p;
|
||
|
||
do {
|
||
if (TermIsStartField(i)) {
|
||
return(i);
|
||
}
|
||
i = ScreenDec(i);
|
||
} while (i != p);
|
||
|
||
return(LowestScreen()); /* unformatted screen... */
|
||
}
|
||
|
||
/*
|
||
* There are two algorithms for updating the screen.
|
||
* The first, SlowScreen() optimizes the line between the
|
||
* computer and the screen (say a 9600 baud line). To do
|
||
* this, we break out of the loop every so often to look
|
||
* at any pending input from the network (so that successive
|
||
* screens will only partially print until the final screen,
|
||
* the one the user possibly wants to see, is displayed
|
||
* in its entirety).
|
||
*
|
||
* The second algorithm tries to optimize CPU time (by
|
||
* being simpler) at the cost of the bandwidth to the
|
||
* screen.
|
||
*
|
||
* Of course, curses(3X) gets in here also.
|
||
*/
|
||
|
||
|
||
#if defined(NOT43)
|
||
static int
|
||
#else /* defined(NOT43) */
|
||
static void
|
||
#endif /* defined(NOT43) */
|
||
SlowScreen()
|
||
{
|
||
register int is, shouldbe, isattr, shouldattr;
|
||
register int pointer;
|
||
register int fieldattr, termattr;
|
||
register int columnsleft;
|
||
|
||
#define NORMAL 0
|
||
#define HIGHLIGHT 1 /* Mask bits */
|
||
#define NONDISPLAY 4 /* Mask bits */
|
||
#define UNDETERMINED 8 /* Mask bits */
|
||
|
||
#define DoAttributes(x) \
|
||
switch (x&ATTR_DSPD_MASK) { \
|
||
case ATTR_DSPD_NONDISPLAY: \
|
||
x = NONDISPLAY; \
|
||
break; \
|
||
case ATTR_DSPD_HIGH: \
|
||
x = HIGHLIGHT; \
|
||
break; \
|
||
default: \
|
||
x = 0; \
|
||
break; \
|
||
}
|
||
|
||
# define SetHighlightMode(x) \
|
||
{ \
|
||
if ((x)&HIGHLIGHT) { \
|
||
if (!inHighlightMode) { \
|
||
inHighlightMode = HIGHLIGHT; \
|
||
standout(); \
|
||
} \
|
||
} else { \
|
||
if (inHighlightMode) { \
|
||
inHighlightMode = 0; \
|
||
standend(); \
|
||
} \
|
||
} \
|
||
}
|
||
|
||
# define DoCharacterAt(c,p) { \
|
||
if (p != HighestScreen()) { \
|
||
c = disp_asc[c&0xff]; \
|
||
if (terminalCursorAddress != p) { \
|
||
if (ERR == mvaddch(ScreenLine(p), \
|
||
ScreenLineOffset(p), c)) {\
|
||
GoAway("mvaddch", p); \
|
||
} \
|
||
} else { \
|
||
if (ERR == addch(c)) {\
|
||
GoAway("addch", p); \
|
||
} \
|
||
} \
|
||
terminalCursorAddress = ScreenInc(p); \
|
||
} \
|
||
}
|
||
|
||
|
||
/* run through screen, printing out non-null lines */
|
||
|
||
/* There are two separate reasons for wanting to terminate this
|
||
* loop early. One is to respond to new input (either from
|
||
* the terminal or from the network [host]). For this reason,
|
||
* we expect to see 'HaveInput' come true when new input comes in.
|
||
*
|
||
* The second reason is a bit more difficult (for me) to understand.
|
||
* Basically, we don't want to get too far ahead of the characters that
|
||
* appear on the screen. Ideally, we would type out a few characters,
|
||
* wait until they appeared on the screen, then type out a few more.
|
||
* The reason for this is that the user, on seeing some characters
|
||
* appear on the screen may then start to type something. We would
|
||
* like to look at what the user types at about the same 'time'
|
||
* (measured by characters being sent to the terminal) that the
|
||
* user types them. For this reason, what we would like to do
|
||
* is update a bit, then call curses to do a refresh, flush the
|
||
* output to the terminal, then wait until the terminal data
|
||
* has been sent.
|
||
*
|
||
* Note that curses is useful for, among other things, deciding whether
|
||
* or not to send :ce: (clear to end of line), so we should call curses
|
||
* at end of lines (beginning of next lines).
|
||
*
|
||
* The problems here are the following: If we do lots of write(2)s,
|
||
* we will be doing lots of context switches, thus lots of overhead
|
||
* (which we have already). Second, if we do a select to wait for
|
||
* the output to drain, we have to contend with the fact that NOW
|
||
* we are scheduled to run, but who knows what the scheduler will
|
||
* decide when the output has caught up.
|
||
*/
|
||
|
||
if (Highest >= HighestScreen()) { /* Could be > if screen shrunk... */
|
||
Highest = ScreenDec(Highest); /* else, while loop will never end */
|
||
}
|
||
if (Lowest < LowestScreen()) {
|
||
Lowest = LowestScreen(); /* could be -1 in some cases with
|
||
* unformatted screens.
|
||
*/
|
||
}
|
||
if (Highest >= (pointer = Lowest)) {
|
||
/* if there is anything to do, do it. We won't terminate
|
||
* the loop until we've gone at least to Highest.
|
||
*/
|
||
while ((pointer <= Highest) && !HaveInput) {
|
||
|
||
/* point at the next place of disagreement */
|
||
pointer += (bunequal(Host+pointer, Terminal+pointer,
|
||
(Highest-pointer+1)*sizeof Host[0])/sizeof Host[0]);
|
||
|
||
/*
|
||
* How many characters to change until the end of the
|
||
* current line
|
||
*/
|
||
columnsleft = NumberColumns - ScreenLineOffset(pointer);
|
||
/*
|
||
* Make sure we are where we think we are.
|
||
*/
|
||
move(ScreenLine(pointer), ScreenLineOffset(pointer));
|
||
|
||
/* what is the field attribute of the current position */
|
||
if (FormattedScreen()) {
|
||
fieldattr = FieldAttributes(pointer);
|
||
DoAttributes(fieldattr);
|
||
} else {
|
||
fieldattr = NORMAL;
|
||
}
|
||
if (TerminalFormattedScreen()) {
|
||
termattr = TermAttributes(pointer);
|
||
DoAttributes(termattr);
|
||
} else {
|
||
termattr = NORMAL;
|
||
}
|
||
|
||
SetHighlightMode(fieldattr);
|
||
/*
|
||
* The following will terminate at least when we get back
|
||
* to the original 'pointer' location (since we force
|
||
* things to be equal).
|
||
*/
|
||
for (;;) {
|
||
if (IsStartField(pointer)) {
|
||
shouldbe = DISP_BLANK;
|
||
shouldattr = 0;
|
||
fieldattr = GetHost(pointer);
|
||
DoAttributes(fieldattr);
|
||
} else {
|
||
if (fieldattr&NONDISPLAY) {
|
||
shouldbe = DISP_BLANK;
|
||
} else {
|
||
shouldbe = GetHost(pointer);
|
||
}
|
||
shouldattr = fieldattr;
|
||
}
|
||
if (TermIsStartField(pointer)) {
|
||
is = DISP_BLANK;
|
||
isattr = 0;
|
||
termattr = UNDETERMINED; /* Need to find out AFTER update */
|
||
} else {
|
||
if (termattr&NONDISPLAY) {
|
||
is = DISP_BLANK;
|
||
} else {
|
||
is = GetTerminal(pointer);
|
||
}
|
||
isattr = termattr;
|
||
}
|
||
if ((shouldbe == is) && (shouldattr == isattr)
|
||
&& (GetHost(pointer) == GetTerminal(pointer))
|
||
&& (GetHost(ScreenInc(pointer))
|
||
== GetTerminal(ScreenInc(pointer)))) {
|
||
break;
|
||
}
|
||
|
||
if (shouldattr^inHighlightMode) {
|
||
SetHighlightMode(shouldattr);
|
||
}
|
||
|
||
DoCharacterAt(shouldbe, pointer);
|
||
if (IsStartField(pointer)) {
|
||
TermNewField(pointer, FieldAttributes(pointer));
|
||
termattr = GetTerminal(pointer);
|
||
DoAttributes(termattr);
|
||
} else {
|
||
SetTerminal(pointer, GetHost(pointer));
|
||
/*
|
||
* If this USED to be a start field location,
|
||
* recompute the terminal attributes.
|
||
*/
|
||
if (termattr == UNDETERMINED) {
|
||
termattr = WhereTermAttrByte(pointer);
|
||
if ((termattr != 0) || TermIsStartField(0)) {
|
||
termattr = GetTerminal(termattr);
|
||
DoAttributes(termattr);
|
||
} else { /* Unformatted screen */
|
||
termattr = NORMAL;
|
||
}
|
||
}
|
||
}
|
||
pointer = ScreenInc(pointer);
|
||
if (!(--columnsleft)) {
|
||
DoARefresh();
|
||
EmptyTerminal();
|
||
if (HaveInput) { /* if input came in, take it */
|
||
int c, j;
|
||
|
||
/*
|
||
* We need to start a new terminal field
|
||
* at this location iff the terminal attributes
|
||
* of this location are not what we have had
|
||
* them as (ie: we've overwritten the terminal
|
||
* start field, a the previous field had different
|
||
* display characteristics).
|
||
*/
|
||
|
||
isattr = TermAttributes(pointer);
|
||
DoAttributes(isattr);
|
||
if ((!TermIsStartField(pointer)) &&
|
||
(isattr != termattr)) {
|
||
/*
|
||
* Since we are going to leave a new field
|
||
* at this terminal position, we
|
||
* need to make sure that we get an actual
|
||
* non-highlighted blank on the screen.
|
||
*/
|
||
if ((is != DISP_BLANK) || (termattr&HIGHLIGHT)) {
|
||
SetHighlightMode(0); /* Turn off highlight */
|
||
c = ScreenInc(pointer);
|
||
j = DISP_BLANK;
|
||
DoCharacterAt(j, c);
|
||
}
|
||
if (termattr&HIGHLIGHT) {
|
||
termattr = ATTR_DSPD_HIGH;
|
||
} else if (termattr&NONDISPLAY) {
|
||
termattr = ATTR_DSPD_NONDISPLAY;
|
||
} else {
|
||
termattr = 0;
|
||
}
|
||
TermNewField(pointer, termattr);
|
||
}
|
||
break;
|
||
}
|
||
move(ScreenLine(pointer), 0);
|
||
columnsleft = NumberColumns;
|
||
}
|
||
} /* end of for (;;) */
|
||
} /* end of while (...) */
|
||
}
|
||
DoARefresh();
|
||
Lowest = pointer;
|
||
if (Lowest > Highest) { /* if we finished input... */
|
||
Lowest = HighestScreen()+1;
|
||
Highest = LowestScreen()-1;
|
||
terminalCursorAddress = CorrectTerminalCursor();
|
||
if (ERR == move(ScreenLine(terminalCursorAddress),
|
||
ScreenLineOffset(terminalCursorAddress))) {
|
||
GoAway("move", terminalCursorAddress);
|
||
}
|
||
DoARefresh();
|
||
if (needToRing) {
|
||
StringToTerminal(bellSequence);
|
||
needToRing = 0;
|
||
}
|
||
}
|
||
EmptyTerminal(); /* move data along */
|
||
return;
|
||
}
|
||
|
||
#if defined(NOT43)
|
||
static int
|
||
#else /* defined(NOT43) */
|
||
static void
|
||
#endif /* defined(NOT43) */
|
||
FastScreen()
|
||
{
|
||
#if defined(MSDOS)
|
||
#define SaveCorner 0
|
||
#else /* defined(MSDOS) */
|
||
#define SaveCorner 1
|
||
#endif /* defined(MSDOS) */
|
||
|
||
#define DoAttribute(a) if (IsHighlightedAttr(a)) { \
|
||
standout(); \
|
||
} else { \
|
||
standend(); \
|
||
} \
|
||
if (IsNonDisplayAttr(a)) { \
|
||
a = 0; /* zero == don't display */ \
|
||
} \
|
||
if (!FormattedScreen()) { \
|
||
a = 1; /* one ==> do display on unformatted */\
|
||
}
|
||
ScreenImage *p, *upper;
|
||
int fieldattr; /* spends most of its time == 0 or 1 */
|
||
|
||
/* OK. We want to do this a quickly as possible. So, we assume we
|
||
* only need to go from Lowest to Highest. However, if we find a
|
||
* field in the middle, we do the whole screen.
|
||
*
|
||
* In particular, we separate out the two cases from the beginning.
|
||
*/
|
||
if ((Highest != HighestScreen()) || (Lowest != LowestScreen())) {
|
||
register int columnsleft;
|
||
|
||
move(ScreenLine(Lowest), ScreenLineOffset(Lowest));
|
||
p = &Host[Lowest];
|
||
#if !defined(MSDOS)
|
||
if (Highest == HighestScreen()) {
|
||
Highest = ScreenDec(Highest);
|
||
}
|
||
#endif /* !defined(MSDOS) */
|
||
upper = &Host[Highest];
|
||
fieldattr = FieldAttributes(Lowest);
|
||
DoAttribute(fieldattr); /* Set standout, non-display status */
|
||
columnsleft = NumberColumns-ScreenLineOffset(p-Host);
|
||
|
||
while (p <= upper) {
|
||
if (IsStartFieldPointer(p)) { /* New field? */
|
||
Highest = HighestScreen();
|
||
Lowest = LowestScreen();
|
||
FastScreen(); /* Recurse */
|
||
return;
|
||
} else if (fieldattr) { /* Should we display? */
|
||
/* Display translated data */
|
||
addch((char)disp_asc[GetTerminalPointer(p)]);
|
||
} else {
|
||
addch(' '); /* Display a blank */
|
||
}
|
||
/* If the physical screen is larger than what we
|
||
* are using, we need to make sure that each line
|
||
* starts at the beginning of the line. Otherwise,
|
||
* we will just string all the lines together.
|
||
*/
|
||
p++;
|
||
if (--columnsleft == 0) {
|
||
int i = p-Host;
|
||
|
||
move(ScreenLine(i), 0);
|
||
columnsleft = NumberColumns;
|
||
}
|
||
}
|
||
} else { /* Going from Lowest to Highest */
|
||
unsigned char tmpbuf[MAXNUMBERCOLUMNS+1];
|
||
ScreenImage *End = &Host[ScreenSize]-1-SaveCorner;
|
||
register unsigned char *tmp = tmpbuf, *tmpend = tmpbuf+NumberColumns;
|
||
|
||
*tmpend = 0; /* terminate from the beginning */
|
||
move(0,0);
|
||
p = Host;
|
||
fieldattr = FieldAttributes(LowestScreen());
|
||
DoAttribute(fieldattr); /* Set standout, non-display status */
|
||
|
||
while (p <= End) {
|
||
if (IsStartFieldPointer(p)) { /* New field? */
|
||
if (tmp != tmpbuf) {
|
||
*tmp++ = 0; /* close out */
|
||
addstr((char *)tmpbuf);
|
||
tmp = tmpbuf;
|
||
tmpend = tmpbuf+NumberColumns-ScreenLineOffset(p-Host)-1;
|
||
}
|
||
standend();
|
||
addch(' ');
|
||
fieldattr = FieldAttributesPointer(p); /* Get attributes */
|
||
DoAttribute(fieldattr); /* Set standout, non-display */
|
||
} else {
|
||
if (fieldattr) { /* Should we display? */
|
||
/* Display translated data */
|
||
*tmp++ = disp_asc[GetTerminalPointer(p)];
|
||
} else {
|
||
*tmp++ = ' ';
|
||
}
|
||
}
|
||
/* If the physical screen is larger than what we
|
||
* are using, we need to make sure that each line
|
||
* starts at the beginning of the line. Otherwise,
|
||
* we will just string all the lines together.
|
||
*/
|
||
p++;
|
||
if (tmp == tmpend) {
|
||
int i = p-Host; /* Be sure the "p++" happened first! */
|
||
|
||
*tmp++ = 0;
|
||
addstr((char *)tmpbuf);
|
||
tmp = tmpbuf;
|
||
move(ScreenLine(i), 0);
|
||
tmpend = tmpbuf + NumberColumns;
|
||
}
|
||
}
|
||
if (tmp != tmpbuf) {
|
||
*tmp++ = 0;
|
||
addstr((char *)tmpbuf);
|
||
tmp = tmpbuf;
|
||
}
|
||
}
|
||
Lowest = HighestScreen()+1;
|
||
Highest = LowestScreen()-1;
|
||
terminalCursorAddress = CorrectTerminalCursor();
|
||
if (ERR == move(ScreenLine(terminalCursorAddress),
|
||
ScreenLineOffset(terminalCursorAddress))) {
|
||
GoAway("move", terminalCursorAddress);
|
||
}
|
||
DoARefresh();
|
||
if (needToRing) {
|
||
StringToTerminal(bellSequence);
|
||
needToRing = 0;
|
||
}
|
||
EmptyTerminal(); /* move data along */
|
||
return;
|
||
}
|
||
|
||
|
||
/* TryToSend - send data out to user's terminal */
|
||
|
||
#if defined(NOT43)
|
||
int
|
||
#else /* defined(NOT43) */
|
||
void
|
||
#endif /* defined(NOT43) */
|
||
(*TryToSend)() = FastScreen;
|
||
|
||
/*ARGSUSED*/
|
||
void
|
||
ScreenOIA(oia)
|
||
OIA *oia;
|
||
{
|
||
}
|
||
|
||
|
||
/* InitTerminal - called to initialize the screen, etc. */
|
||
|
||
void
|
||
InitTerminal()
|
||
{
|
||
#if defined(unix)
|
||
struct termios termios_info;
|
||
speed_t speed;
|
||
#endif
|
||
extern void InitMapping();
|
||
|
||
InitMapping(); /* Go do mapping file (MAP3270) first */
|
||
if (!screenInitd) { /* not initialized */
|
||
#if defined(unix)
|
||
char KSEbuffer[2050];
|
||
char *lotsofspace = KSEbuffer;
|
||
extern void abort();
|
||
extern char *tgetstr();
|
||
#endif /* defined(unix) */
|
||
|
||
if (initscr() == ERR) { /* Initialize curses to get line size */
|
||
ExitString("InitTerminal: Error initializing curses", 1);
|
||
/*NOTREACHED*/
|
||
}
|
||
MaxNumberLines = LINES;
|
||
MaxNumberColumns = COLS;
|
||
ClearArray(Terminal);
|
||
terminalCursorAddress = SetBufferAddress(0,0);
|
||
#if defined(unix)
|
||
signal(SIGHUP, abort);
|
||
#endif
|
||
|
||
TryToSend = FastScreen;
|
||
#if defined(unix)
|
||
(void) tcgetattr(1, &termios_info);
|
||
speed = cfgetospeed(&termios_info);
|
||
if (speed > 19200) {
|
||
max_changes_before_poll = 1920;
|
||
} else {
|
||
max_changes_before_poll = speed/10;
|
||
if (max_changes_before_poll < 40)
|
||
max_changes_before_poll = 40;
|
||
TryToSend = SlowScreen;
|
||
HaveInput = 1; /* get signals going */
|
||
}
|
||
#endif /* defined(unix) */
|
||
setcommandmode();
|
||
/*
|
||
* By now, initscr() (in curses) has been called (from telnet.c),
|
||
* and the screen has been initialized.
|
||
*/
|
||
#if defined(unix)
|
||
nonl();
|
||
/* the problem is that curses catches SIGTSTP to
|
||
* be nice, but it messes us up.
|
||
*/
|
||
signal(SIGTSTP, SIG_DFL);
|
||
if ((myKS = tgetstr("ks", &lotsofspace)) != 0) {
|
||
myKS = strsave(myKS);
|
||
StringToTerminal(myKS);
|
||
}
|
||
if ((myKE = tgetstr("ke", &lotsofspace)) != 0) {
|
||
myKE = strsave(myKE);
|
||
}
|
||
if (tgetstr("md", &lotsofspace) && tgetstr("me", &lotsofspace)) {
|
||
SO = strsave(tgetstr("md", &lotsofspace));
|
||
SE = strsave(tgetstr("me", &lotsofspace));
|
||
}
|
||
#endif
|
||
DoARefresh();
|
||
setconnmode();
|
||
if (VB && *VB) {
|
||
bellSequence = VB; /* use visual bell */
|
||
}
|
||
screenInitd = 1;
|
||
screenStopped = 0; /* Not stopped */
|
||
}
|
||
}
|
||
|
||
|
||
/* StopScreen - called when we are going away... */
|
||
|
||
void
|
||
StopScreen(doNewLine)
|
||
int doNewLine;
|
||
{
|
||
if (screenInitd && !screenStopped) {
|
||
move(NumberLines-1, 1);
|
||
standend();
|
||
inHighlightMode = 0;
|
||
DoARefresh();
|
||
setcommandmode();
|
||
endwin();
|
||
setconnmode();
|
||
#if defined(unix)
|
||
if (myKE) {
|
||
StringToTerminal(myKE);
|
||
}
|
||
#endif /* defined(unix) */
|
||
if (doNewLine) {
|
||
StringToTerminal("\r\n");
|
||
}
|
||
EmptyTerminal();
|
||
screenStopped = 1; /* This is stopped */
|
||
}
|
||
}
|
||
|
||
|
||
/* RefreshScreen - called to cause the screen to be refreshed */
|
||
|
||
void
|
||
RefreshScreen()
|
||
{
|
||
clearok(curscr, TRUE);
|
||
(*TryToSend)();
|
||
}
|
||
|
||
|
||
/* ConnectScreen - called to reconnect to the screen */
|
||
|
||
void
|
||
ConnectScreen()
|
||
{
|
||
if (screenInitd) {
|
||
#if defined(unix)
|
||
if (myKS) {
|
||
StringToTerminal(myKS);
|
||
}
|
||
#endif /* defined(unix) */
|
||
RefreshScreen();
|
||
(*TryToSend)();
|
||
screenStopped = 0;
|
||
}
|
||
}
|
||
|
||
/* LocalClearScreen() - clear the whole ball of wax, cheaply */
|
||
|
||
void
|
||
LocalClearScreen()
|
||
{
|
||
extern void Clear3270();
|
||
|
||
outputPurge(); /* flush all data to terminal */
|
||
clear(); /* clear in curses */
|
||
ClearArray(Terminal);
|
||
Clear3270();
|
||
Lowest = HighestScreen()+1; /* everything in sync... */
|
||
Highest = LowestScreen()+1;
|
||
}
|
||
|
||
|
||
void
|
||
BellOff()
|
||
{
|
||
if (bellwinup) {
|
||
delwin(bellwin);
|
||
bellwin = 0;
|
||
bellwinup = 0;
|
||
touchwin(stdscr);
|
||
DoARefresh();
|
||
}
|
||
}
|
||
|
||
|
||
void
|
||
RingBell(s)
|
||
char *s;
|
||
{
|
||
needToRing = 1;
|
||
if (s) {
|
||
int len = strlen(s);
|
||
|
||
if (len > COLS-2) {
|
||
len = COLS-2;
|
||
}
|
||
if ((bellwin = newwin(3, len+2, LINES/2, 0)) == NULL) {
|
||
OurExitString("Error from newwin in RingBell", 1);
|
||
}
|
||
werase(bellwin);
|
||
wstandout(bellwin);
|
||
box(bellwin, '|', '-');
|
||
if (wmove(bellwin, 1, 1) == ERR) {
|
||
OurExitString("Error from wmove in RingBell", 1);
|
||
}
|
||
while (len--) {
|
||
if (waddch(bellwin, *s++) == ERR) {
|
||
OurExitString("Error from waddch in RingBell", 1);
|
||
}
|
||
}
|
||
wstandend(bellwin);
|
||
if (wrefresh(bellwin) == ERR) {
|
||
OurExitString("Error from wrefresh in RingBell", 1);
|
||
}
|
||
bellwinup = 1;
|
||
}
|
||
}
|
||
|
||
|
||
/* returns a 1 if no more output available (so, go ahead and block),
|
||
or a 0 if there is more output available (so, just poll the other
|
||
sources/destinations, don't block).
|
||
*/
|
||
|
||
int
|
||
DoTerminalOutput()
|
||
{
|
||
/* called just before a select to conserve IO to terminal */
|
||
if (!(screenInitd||screenStopped)) {
|
||
return 1; /* No output if not initialized */
|
||
}
|
||
if ((Lowest <= Highest) || needToRing ||
|
||
(terminalCursorAddress != CorrectTerminalCursor())) {
|
||
(*TryToSend)();
|
||
}
|
||
if (Lowest > Highest) {
|
||
return 1; /* no more output now */
|
||
} else {
|
||
return 0; /* more output for future */
|
||
}
|
||
}
|
||
|
||
/*
|
||
* The following are defined to handle transparent data.
|
||
*/
|
||
|
||
void
|
||
TransStop()
|
||
{
|
||
#if defined(unix)
|
||
if (tcflag == 0) {
|
||
tcflag = -1;
|
||
(void) signal(SIGCHLD, SIG_DFL);
|
||
} else if (tcflag > 0) {
|
||
setcommandmode();
|
||
(void) close(tin);
|
||
(void) close(tout);
|
||
tin = savefd[0];
|
||
tout = savefd[1];
|
||
setconnmode();
|
||
tcflag = -1;
|
||
(void) signal(SIGCHLD, SIG_DFL);
|
||
}
|
||
#endif /* defined(unix) */
|
||
RefreshScreen();
|
||
}
|
||
|
||
void
|
||
TransOut(buffer, count, kind, control)
|
||
unsigned char *buffer;
|
||
int count;
|
||
int kind; /* 0 or 5 */
|
||
int control; /* To see if we are done */
|
||
{
|
||
#if defined(unix)
|
||
extern char *transcom;
|
||
int inpipefd[2], outpipefd[2];
|
||
static void aborttc();
|
||
#endif /* defined(unix) */
|
||
|
||
while (DoTerminalOutput() == 0) {
|
||
#if defined(unix)
|
||
HaveInput = 0;
|
||
#endif /* defined(unix) */
|
||
}
|
||
#if defined(unix)
|
||
if (transcom && tcflag == -1) {
|
||
while (1) { /* go thru once */
|
||
if (pipe(outpipefd) < 0) {
|
||
break;
|
||
}
|
||
if (pipe(inpipefd) < 0) {
|
||
break;
|
||
}
|
||
if ((tcflag = fork()) == 0) {
|
||
(void) close(outpipefd[1]);
|
||
(void) close(0);
|
||
if (dup(outpipefd[0]) < 0) {
|
||
exit(1);
|
||
}
|
||
(void) close(outpipefd[0]);
|
||
(void) close(inpipefd[0]);
|
||
(void) close(1);
|
||
if (dup(inpipefd[1]) < 0) {
|
||
exit(1);
|
||
}
|
||
(void) close(inpipefd[1]);
|
||
if (execl("/bin/csh", "csh", "-c", transcom, (char *) 0)) {
|
||
exit(1);
|
||
}
|
||
}
|
||
(void) close(inpipefd[1]);
|
||
(void) close(outpipefd[0]);
|
||
savefd[0] = tin;
|
||
savefd[1] = tout;
|
||
setcommandmode();
|
||
tin = inpipefd[0];
|
||
tout = outpipefd[1];
|
||
(void) signal(SIGCHLD, aborttc);
|
||
setconnmode();
|
||
tcflag = 1;
|
||
break;
|
||
}
|
||
if (tcflag < 1) {
|
||
tcflag = 0;
|
||
}
|
||
}
|
||
#endif /* defined(unix) */
|
||
(void) DataToTerminal((char *)buffer, count);
|
||
if (control && (kind == 0)) { /* Send in AID byte */
|
||
SendToIBM();
|
||
} else {
|
||
extern void TransInput();
|
||
|
||
TransInput(1, kind); /* Go get some data */
|
||
}
|
||
}
|
||
|
||
|
||
#if defined(unix)
|
||
static void
|
||
aborttc(signo)
|
||
int signo;
|
||
{
|
||
setcommandmode();
|
||
(void) close(tin);
|
||
(void) close(tout);
|
||
tin = savefd[0];
|
||
tout = savefd[1];
|
||
setconnmode();
|
||
tcflag = 0;
|
||
}
|
||
#endif /* defined(unix) */
|