📄 termout.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 lintstatic char sccsid[] = "@(#)termout.c 8.1 (Berkeley) 6/6/93";#endif /* not lint */#if defined(unix)#include <signal.h>#include <sgtty.h>#endif#include <stdio.h>#include <curses.h>#if defined(ultrix)/* Some version of this OS has a bad definition for nonl() */#undef nl#undef nonl#define nl() (_tty.sg_flags |= CRMOD,_pfast = _rawmode,stty(_tty_ch, &_tty))#define nonl() (_tty.sg_flags &= ~CRMOD, _pfast = TRUE, stty(_tty_ch, &_tty))#endif /* defined(ultrix) */#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. */voidinit_screen(){ bellwinup = 0; inHighlightMode = 0; ClearArray(Terminal);}/* OurExitString - designed to keep us from going through infinite recursion */static voidOurExitString(string, value)char *string;int value;{ static int recursion = 0; if (!recursion) { recursion = 1; ExitString(string, value); }}/* DoARefresh */static voidDoARefresh(){ if (ERR == refresh()) { OurExitString("ERR from refresh\n", 1); }}static voidGoAway(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 intWhereTermAttrByte(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(); \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -