386BSD 0.1 development
[unix-history] / usr / othersrc / public / screen-3.2 / screen3.2 / ansi.c
/* Copyright (c) 1991
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Copyright (c) 1987 Oliver Laumann
* All rights reserved. Not derived from licensed software.
*
* Permission is granted to freely use, copy, modify, and redistribute
* this software, provided that no attempt is made to gain profit from it,
* the authors are not construed to be liable for any results of using the
* software, alterations are clearly marked as such, and this notice is
* not modified.
*
* Noteworthy contributors to screen's design and implementation:
* Wayne Davison (davison@borland.com)
* Patrick Wolfe (pat@kai.com, kailand!pat)
* Bart Schaefer (schaefer@cse.ogi.edu)
* Nathan Glasser (nathan@brokaw.lcs.mit.edu)
* Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
* Howard Chu (hyc@hanauma.jpl.nasa.gov)
* Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
* Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
* Marc Boucher (marc@CAM.ORG)
*
****************************************************************
*/
#ifndef lint
static char rcs_id[] = "$Id: ansi.c,v 1.2 92/02/03 02:27:30 jnweiger Exp $ FAU";
#endif
#include <stdio.h>
#include <sys/types.h>
#ifdef BSDI
#include <sys/signal.h>
#endif /* BSDI */
#include <fcntl.h>
#include "config.h"
#include "screen.h"
#include "ansi.h"
#include "extern.h"
#ifndef sun /* we want to know about TIOCGWINSZ. jw. */
# include <sys/ioctl.h>
#endif
extern char *getenv(), *tgetstr(), *tgoto();
#ifndef __STDC__
extern char *malloc();
#endif
extern struct win *fore;
extern int ForeNum;
extern force_vt, assume_LP;
extern int BellDisplayed;
extern int MsgMinWait;
extern int all_norefresh;
int TermcapROWS, TermcapCOLS; /* defaults that we learned from termcap */
int default_width, default_height; /* width/height a new window will get */
int maxwidth;
int Z0width, Z1width; /* widths for Z0/Z1 switching */
char display_tty[MAXPATH];
int screenwidth, screenheight; /* width/height of the screen */
int screentop, screenbot; /* scrollregion start/end */
int screenx, screeny; /* cursor position */
char GlobalAttr; /* current attributes */
char GlobalCharset; /* current font */
int insert; /* insert mode */
int keypad; /* application keypad */
int flow = 1; /* flow control */
int status; /* status is displayed */
static int status_lastx, status_lasty;
static int rows, cols; /* window size of the curr window */
int default_flow = -1, wrap = 1, default_monitor = 0;
int visual_bell = 0, termcapHS, use_hardstatus = 1;
char *Termcap, *extra_incap, *extra_outcap;
static int Termcaplen;
char *blank, *null, *LastMsg;
char Term[MAXSTR+5]; /* +5: "TERM=" */
char screenterm[20] = "screen";
char *Z0, *Z1;
int ISO2022, HS;
time_t TimeDisplayed, time();
/*
* the termcap routines need this to work
*/
short ospeed;
char *BC;
char *UP;
static void AddCap __P((char *));
static void MakeString __P((char *, char *, int, char *));
static int Special __P((int));
static void DoESC __P((int, int ));
static void DoCSI __P((int, int ));
static void CPutStr __P((char *, int));
static void SetChar __P(());
static void StartString __P((enum string_t));
static void AddChar __P((int ));
static void PrintChar __P((int ));
static void PrintFlush __P((void));
static void KeypadMode __P((int));
static void DesignateCharset __P((int, int ));
static void MapCharset __P((int));
static void SaveCursor __P((void));
static void RestoreCursor __P((void));
static void CountChars __P((int));
static int CalcCost __P((char *));
static int Rewrite __P((int, int, int, int));
static void BackSpace __P((void));
static void Return __P((void));
static void LineFeed __P((int));
static void ReverseLineFeed __P((void));
static void InsertAChar __P((int));
static void InsertChar __P((int));
static void DeleteChar __P((int));
static void DeleteLine __P((int));
static void InsertLine __P((int));
static void ScrollUpMap __P((int));
static void ScrollDownMap __P((int));
static void Scroll __P((char *, int, int, char *));
static void ForwardTab __P((void));
static void BackwardTab __P((void));
static void ClearScreen __P((void));
static void ClearFromBOS __P((void));
static void ClearToEOS __P((void));
static void ClearLine __P((void));
static void ClearToEOL __P((void));
static void ClearFromBOL __P((void));
static void ClearInLine __P((int, int, int, int ));
static void CursorRight __P(());
static void CursorUp __P(());
static void CursorDown __P(());
static void CursorLeft __P(());
static void ASetMode __P((int));
static void SelectRendition __P((void));
static void FillWithEs __P((void));
static void RedisplayLine __P((char *, char *, char *, int, int, int ));
static void FindAKA __P((void));
static void SetCurr __P((struct win *));
static void inpRedisplayLine __P((int, int, int, int));
static void process_inp_input __P((char **, int *));
static void AbortInp __P((void));
static void AKAfin __P((char *, int));
static void Colonfin __P((char *, int));
static void RAW_PUTCHAR __P((int));
static char *e_tgetstr __P((char *, char **));
static int e_tgetflag __P((char *));
static int e_tgetnum __P((char *));
static char *tbuf, *tentry, *termname;
static char *tp;
static char *TI, *TE, *BL, *VB, *CR, *NL, *CL, *IS;
char *WS; /* used in ResizeScreen() */
char *CE; /* used in help.c */
static char *CM, *US, *UE, *SO, *SE, *CD, *DO, *SR, *SF, *AL;
static char *CS, *DL, *DC, *IC, *IM, *EI, *ND, *KS, *KE;
static char *MB, *MD, *MH, *MR, *ME, *PO, *PF, *HO;
static char *TS, *FS, *DS, *VI, *VE, *VS;
static char *CDC, *CDL, *CAL, *CUP, *CDO, *CLE, *CRI, *CIC;
static char *attrtab[NATTR];
static AM, MS, COP;
int LP;
/*
* Do not confuse S0 (es-zero), E0 (e-zero) with SO (es-oh), PO (pe-oh),
* Z0 (z-zero), DO (de-oh)... :-)
*/
static char *C0, *S0, *E0;
static char c0_tab[256];
/*
*/
static screencap = 0;
char *OldImage, *OldAttr, *OldFont;
static struct win *curr;
static display = 1;
static StrCost;
static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost, NLcost;
static tcLineLen;
static StatLen;
static lp_missing = 0;
int in_ovl;
int ovl_blockfore;
void (*ovl_process)();
void (*ovl_RedisplayLine)();
int (*ovl_Rewrite)();
static char *KeyCaps[] =
{
"k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
"kb", "kd", "kh", "kl", "ko", "kr", "ku",
"K1", "K2", "K3", "K4", "K5",
"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", "l8", "l9"
};
#define NKEYCAPS ((int)(sizeof(KeyCaps)/sizeof(*KeyCaps)))
static char *KeyCapsArr[NKEYCAPS];
static char TermcapConst[] = "\\\n\
\t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
\t:cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
\t:do=^J:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\EM:\\\n\
\t:le=^H:bl=^G:cr=^M:it#8:ho=\\E[H:nw=\\EE:ta=^I:is=\\E)0:xv:";
void
InitTermcap()
{
register char *s;
int i;
screencap = 0;
if ((s = getenv("SCREENCAP")) != 0)
{
if ((Termcap = malloc(strlen(s) + 10)) != 0)
{
sprintf(Termcap, "TERMCAP=%s", s);
screencap = 1;
}
}
else
Termcap = malloc((unsigned) 1024);
Termcaplen = 0;
tbuf = malloc((unsigned) 1024);
tentry = tp = malloc((unsigned) 1024);
if (!(Termcap && tbuf && tentry))
Msg_nomem;
bzero(tbuf, 1024);
if ((termname = getenv("TERM")) == 0)
Msg(0, "No TERM in environment.");
debug1("InitTermcap: looking for tgetent('%s');\n", termname);
if (tgetent(tbuf, termname) != 1)
Msg(0, "Cannot find termcap entry for %s.", termname);
debug1("got it:\n%s\n",tbuf);
#ifdef DEBUG
if (extra_incap)
debug1("Extra incap: %s\n", extra_incap);
if (extra_outcap)
debug1("Extra outcap: %s\n", extra_outcap);
#endif
TermcapCOLS = TermcapROWS = 0;
if (s = getenv("COLUMNS"))
TermcapCOLS = atoi(s);
if (TermcapCOLS <= 0)
TermcapCOLS = e_tgetnum("co");
if (TermcapCOLS <= 0)
TermcapCOLS = 80;
if (s = getenv("LINES"))
TermcapROWS = atoi(s);
if (TermcapROWS <= 0)
TermcapROWS = e_tgetnum("li");
if (TermcapROWS <= 0)
TermcapROWS = 24;
if (e_tgetflag("hc"))
Msg(0, "You can't run screen on a hardcopy terminal.");
if (e_tgetflag("os"))
Msg(0, "You can't run screen on a terminal that overstrikes.");
if (e_tgetflag("ns"))
Msg(0, "Terminal must support scrolling.");
if (!(CL = e_tgetstr("cl", &tp)))
Msg(0, "Clear screen capability required.");
if (!(CM = e_tgetstr("cm", &tp)))
Msg(0, "Addressable cursor capability required.");
if (default_flow < 0)
default_flow = e_tgetflag("NF") ? FLOW_NOW * 0 :
e_tgetflag("xo") ? FLOW_NOW * 1 :
FLOW_AUTOFLAG;
AM = e_tgetflag("am");
LP = assume_LP || (!extra_incap && !strncmp(termname, "vt", 2))
|| !AM || e_tgetflag("LP") || e_tgetflag("xv");
COP = e_tgetflag("OP");
HO = e_tgetstr("ho", &tp);
TI = e_tgetstr("ti", &tp);
TE = e_tgetstr("te", &tp);
if (!(BL = e_tgetstr("bl", &tp)))
BL = "\007";
VB = e_tgetstr("vb", &tp);
if (!(BC = e_tgetstr("bc", &tp)))
{
if (e_tgetflag("bs"))
BC = "\b";
else
BC = e_tgetstr("le", &tp);
}
if (!(CR = e_tgetstr("cr", &tp)))
CR = "\r";
if (!(NL = e_tgetstr("nl", &tp)))
NL = "\n";
IS = e_tgetstr("is", &tp);
MS = 1;
if (e_tgetnum("sg") <= 0 && e_tgetnum("ug") <= 0)
{
MS = e_tgetflag("ms");
attrtab[ATTR_DI] = MH = e_tgetstr("mh", &tp); /* Dim */
attrtab[ATTR_US] = US = e_tgetstr("us", &tp); /* Underline */
attrtab[ATTR_BD] = MD = e_tgetstr("md", &tp); /* Bold */
attrtab[ATTR_RV] = MR = e_tgetstr("mr", &tp); /* Reverse */
attrtab[ATTR_SO] = SO = e_tgetstr("so", &tp); /* Standout */
attrtab[ATTR_BL] = MB = e_tgetstr("mb", &tp); /* Blinking */
ME = e_tgetstr("me", &tp);
SE = e_tgetstr("se", &tp);
UE = e_tgetstr("ue", &tp);
/*
* Does ME also reverse the effect of SO and/or US? This is not
* clearly specified by the termcap manual. Anyway, we should at
* least look whether ME and SE/UE are equal:
*/
if (UE && ((SE && strcmp(SE, UE) == 0) || (ME && strcmp(ME, UE) == 0)))
UE = 0;
if (SE && (ME && strcmp(ME, SE) == 0))
SE = 0;
/* Set up missing entries */
s = 0;
for (i = NATTR-1; i >= 0; i--)
if (attrtab[i])
s = attrtab[i];
for (i = 0; i < NATTR; i++)
{
if (attrtab[i] == 0)
attrtab[i] = s;
else
s = attrtab[i];
}
}
else
{
US = UE = SO = SE = MB = MD = MH = MR = ME = 0;
for (i = 0; i < NATTR; i++)
attrtab[i] = 0;
}
CE = e_tgetstr("ce", &tp);
CD = e_tgetstr("cd", &tp);
if (!(DO = e_tgetstr("do", &tp)))
DO = NL;
UP = e_tgetstr("up", &tp);
ND = e_tgetstr("nd", &tp);
SR = e_tgetstr("sr", &tp);
if (!(SF = e_tgetstr("sf", &tp)))
SF = NL;
AL = e_tgetstr("al", &tp);
DL = e_tgetstr("dl", &tp);
CS = e_tgetstr("cs", &tp);
DC = e_tgetstr("dc", &tp);
IC = e_tgetstr("ic", &tp);
CIC = e_tgetstr("IC", &tp);
CDC = e_tgetstr("DC", &tp);
CDL = e_tgetstr("DL", &tp);
CAL = e_tgetstr("AL", &tp);
CUP = e_tgetstr("UP", &tp);
CDO = e_tgetstr("DO", &tp);
CLE = e_tgetstr("LE", &tp);
CRI = e_tgetstr("RI", &tp);
IM = e_tgetstr("im", &tp);
EI = e_tgetstr("ei", &tp);
if (e_tgetflag("in"))
IC = IM = 0;
if (IC && IC[0] == '\0')
IC = 0;
if (CIC && CIC[0] == '\0')
CIC = 0;
if (IM && IM[0] == '\0')
IM = 0;
if (EI && EI[0] == '\0')
EI = 0;
if (EI == 0)
IM = 0;
if (IC && IM && strcmp(IC, IM) == 0)
IC = 0;
KS = e_tgetstr("ks", &tp);
KE = e_tgetstr("ke", &tp);
if (KE == 0)
KS = 0;
ISO2022 = e_tgetflag("G0");
if (ISO2022)
{
if ((S0 = e_tgetstr("S0", &tp)) == NULL)
#ifdef TERMINFO
S0 = "\033(%p1%c";
#else
S0 = "\033(%.";
#endif
if ((E0 = e_tgetstr("E0", &tp)) == NULL)
E0 = "\033(B";
C0 = e_tgetstr("C0", &tp);
}
else if ((S0 = e_tgetstr("as", &tp)) != NULL
&& (E0 = e_tgetstr("ae", &tp)) != NULL)
{
ISO2022 = 1;
C0 = e_tgetstr("ac", &tp);
}
else
{
S0 = E0 = "";
C0 = "g.h.i'j-k-l-m-n+o~p\"q-r-s_t+u+v+w+x|y<z>";
}
for (i = 0; i < 256; i++)
c0_tab[i] = i;
if (C0)
for (i = strlen(C0)&~1; i >= 0; i-=2)
c0_tab[C0[i]] = C0[i+1];
debug1("ISO2022 = %d\n", ISO2022);
/* WS changes the window size */
WS = e_tgetstr("WS", &tp);
VI = e_tgetstr("vi", &tp);
VE = e_tgetstr("ve", &tp);
VS = e_tgetstr("vs", &tp);
PO = e_tgetstr("po", &tp);
if (!(PF = e_tgetstr("pf", &tp)))
PO = 0;
debug2("terminal size is %d, %d (says TERMCAP)\n", TermcapCOLS, TermcapROWS);
/* Termcap fields Z0 & Z1 contain width-changing sequences. */
if ((Z0 = e_tgetstr("Z0", &tp)) != NULL
&& (Z1 = e_tgetstr("Z1", &tp)) == NULL)
Z0 = NULL;
Z0width = 132;
Z1width = 80;
CheckScreenSize(0);
if ((HS = e_tgetflag("hs")) != 0)
{
debug("oy! we have a hardware status line, says termcap\n");
TS = e_tgetstr("ts", &tp);
FS = e_tgetstr("fs", &tp);
DS = e_tgetstr("ds", &tp);
if ((HS = e_tgetnum("ws")) <= 0)
HS = screenwidth;
if (!TS || !FS || !DS)
HS = 0;
}
termcapHS = HS;
if (!use_hardstatus)
HS = 0;
UPcost = CalcCost(UP);
DOcost = CalcCost(DO);
NLcost = CalcCost(NL);
LEcost = CalcCost(BC);
NDcost = CalcCost(ND);
CRcost = CalcCost(CR);
IMcost = CalcCost(IM);
EIcost = CalcCost(EI);
for (i = 0; i < NKEYCAPS; i++)
KeyCapsArr[i] = e_tgetstr(KeyCaps[i], &tp);
MakeTermcap(0);
}
/*
* if the adaptflag is on, we keep the size of this display, else
* we may try to restore our old window sizes.
*/
void
InitTerm(adapt)
int adapt;
{
display = 1;
screentop = screenbot = -1;
PutStr(IS);
PutStr(TI);
if (IM && strcmp(IM, EI))
PutStr(EI);
insert = 0;
if (KS && strcmp(KS, KE))
PutStr(KE);
keypad = 0;
PutStr(E0);
GlobalCharset = ASCII;
ResizeScreen((struct win *)0);
ChangeScrollRegion(0, screenheight-1);
PutStr(CL);
screenx = screeny = 0;
fflush(stdout);
debug1("we %swant to adapt all our windows to the display\n",
(adapt) ? "" : "don't ");
/* In case the size was changed by a init sequence */
CheckScreenSize((adapt) ? 2 : 0);
}
void
FinitTerm()
{
display = 1;
InsertMode(0);
KeypadMode(0);
ResizeScreen((struct win *)0);
ChangeScrollRegion(0, screenheight - 1);
SaveSetAttr(0, ASCII);
screenx = screeny = -1;
GotoPos(0, screenheight - 1);
PutStr(TE);
fflush(stdout);
if (Termcap)
{
Free(Termcap);
debug("FinitTerm: old termcap freed\n");
}
if (tbuf)
{
Free(tbuf);
debug("FinitTerm: old tbuf freed\n");
}
if (tentry)
{
Free(tentry);
debug("FinitTerm: old tentry freed\n");
}
}
static void AddCap(s)
char *s;
{
register int n;
if (tcLineLen + (n = strlen(s)) > 55 && Termcaplen < 1024-4)
{
strcpy(Termcap + Termcaplen, "\\\n\t:");
Termcaplen += 4;
tcLineLen = 0;
}
if (Termcaplen + n < 1024)
{
strcpy(Termcap + Termcaplen, s);
Termcaplen += n;
tcLineLen += n;
}
else
Msg(0, "TERMCAP overflow - sorry.");
}
char *MakeTermcap(aflag)
int aflag;
{
char buf[1024];
register char *p, *cp, ch;
int i;
if (screencap)
{
sprintf(Term, "TERM=screen");
return Termcap;
}
if (screenterm == 0 || *screenterm == '\0')
{
debug("MakeTermcap sets screenterm=screen\n");
strcpy(screenterm, "screen");
}
for (;;)
{
sprintf(Term, "TERM=");
p = Term + 5;
if (!aflag && strlen(screenterm) + strlen(termname) < MAXSTR-1)
{
sprintf(p, "%s.%s", screenterm, termname);
if (tgetent(buf, p) == 1)
break;
}
if (screenwidth >= 132)
{
sprintf(p, "%s-w", screenterm);
if (tgetent(buf, p) == 1)
break;
}
sprintf(p, "%s", screenterm);
if (tgetent(buf, p) == 1)
break;
sprintf(p, "vt100");
break;
}
tcLineLen = 100; /* Force NL */
sprintf(Termcap,
"TERMCAP=SC|%s|VT 100/ANSI X3.64 virtual terminal|", p);
Termcaplen = strlen(Termcap);
if (extra_outcap && *extra_outcap)
{
for (cp = extra_outcap; p = index(cp, ':'); cp = p)
{
ch = *++p;
*p = '\0';
AddCap(cp);
*p = ch;
}
tcLineLen = 100; /* Force NL */
}
if (Termcaplen + strlen(TermcapConst) < 1024)
{
strcpy(Termcap + Termcaplen, TermcapConst);
Termcaplen += strlen(TermcapConst);
}
sprintf(buf, "li#%d:co#%d:", screenheight, screenwidth);
AddCap(buf);
if ((force_vt && !COP) || LP || !AM)
AddCap("LP:");
else
AddCap("am:");
if (VB)
AddCap("vb=\\E[?5h\\E[?5l:");
if (US)
{
AddCap("us=\\E[4m:");
AddCap("ue=\\E[24m:");
}
if (SO)
{
AddCap("so=\\E[3m:");
AddCap("se=\\E[23m:");
}
if (MB)
AddCap("mb=\\E[5m:");
if (MD)
AddCap("md=\\E[1m:");
if (MH)
AddCap("mh=\\E[2m:");
if (MR)
AddCap("mr=\\E[7m:");
if (MB || MD || MH || MR)
AddCap("me=\\E[m:ms:");
if ((CS && SR) || AL || CAL || aflag)
{
AddCap("sr=\\EM:");
AddCap("al=\\E[L:");
AddCap("AL=\\E[%dL:");
}
else if (SR)
AddCap("sr=\\EM:");
if (CS || DL || CDL || aflag)
{
AddCap("dl=\\E[M:");
AddCap("DL=\\E[%dM:");
}
if (CS)
AddCap("cs=\\E[%i%d;%dr:");
if (DC || CDC || aflag)
{
AddCap("dc=\\E[P:");
AddCap("DC=\\E[%dP:");
}
if (CIC || IC || IM || aflag)
{
AddCap("im=\\E[4h:");
AddCap("ei=\\E[4l:");
AddCap("mi:");
AddCap("ic=\\E[@:");
AddCap("IC=\\E[%d@:");
}
if (KS)
AddCap("ks=\\E=:");
if (KE)
AddCap("ke=\\E>:");
if (ISO2022)
AddCap("G0:");
if (PO)
{
AddCap("po=\\E[5i:");
AddCap("pf=\\E[4i:");
}
if (Z0)
{
AddCap("Z0=\\E[?3h:");
AddCap("Z1=\\E[?3l:");
}
if (WS)
AddCap("WS=\\E[8;%d;%dt:");
for (i = 0; i < NKEYCAPS; i++)
{
if (KeyCapsArr[i] == 0)
continue;
MakeString(KeyCaps[i], buf, sizeof(buf), KeyCapsArr[i]);
AddCap(buf);
}
return Termcap;
}
static void MakeString(cap, buf, buflen, s)
char *cap, *buf;
int buflen;
char *s;
{
register char *p, *pmax;
register unsigned int c;
p = buf;
pmax = p + buflen - (3+4+2);
*p++ = *cap++;
*p++ = *cap;
*p++ = '=';
while ((c = *s++) && (p < pmax))
{
switch (c)
{
case '\033':
*p++ = '\\';
*p++ = 'E';
break;
case ':':
sprintf(p, "\\072");
p += 4;
break;
case '^':
case '\\':
*p++ = '\\';
*p++ = c;
break;
default:
if (c >= 200)
{
sprintf(p, "\\%03o", c & 0377);
p += 4;
}
else if (c < ' ')
{
*p++ = '^';
*p++ = c + '@';
}
else
*p++ = c;
}
}
*p++ = ':';
*p = '\0';
}
void
Activate(norefresh)
int norefresh;
{
debug1("Activate(%d)\n", norefresh);
if (display)
RemoveStatus();
display = fore->active = 1;
ResizeScreen(fore);
SetCurr(fore);
debug3("Fore (%d) has size %dx%d", ForeNum, curr->width, curr->height);
debug1("(%d)\n", curr->histheight);
ChangeScrollRegion(curr->top, curr->bot);
KeypadMode(curr->keypad);
SetFlow(curr->flow & FLOW_NOW);
if (curr->monitor != MON_OFF)
curr->monitor = MON_ON;
curr->bell = BELL_OFF;
Redisplay(norefresh || all_norefresh);
}
void
ResetScreen(p)
register struct win *p;
{
register int i;
p->wrap = wrap;
p->origin = 0;
p->insert = 0;
p->vbwait = 0;
p->keypad = 0;
p->top = 0;
p->bot = p->height - 1;
p->saved = 0;
p->LocalAttr = 0;
p->x = p->y = 0;
p->state = LIT;
p->StringType = NONE;
p->ss = 0;
p->LocalCharset = G0;
bzero(p->tabs, p->width);
for (i = 8; i < p->width; i += 8)
p->tabs[i] = 1;
for (i = G0; i <= G3; i++)
p->charsets[i] = ASCII;
}
void
WriteString(wp, buf, len)
struct win *wp;
char *buf;
int len;
{
register int c, intermediate = 0;
if (!len)
return;
if (wp->logfp != NULL)
if ((int)fwrite(buf, len, 1, wp->logfp) < 1)
{
extern int errno;
Msg(errno, "Error writing logfile");
fclose(wp->logfp);
wp->logfp = NULL;
}
/*
* SetCurr() here may prevent output, as it may set display = 0
*/
SetCurr(wp);
if (display)
{
if (!HS)
RemoveStatus();
}
else if (curr->monitor == MON_ON)
curr->monitor = MON_FOUND;
do
{
c = (unsigned char)*buf++;
if (c == '\0' || c == '\177')
continue;
NextChar:
switch (curr->state)
{
case PRIN:
switch (c)
{
case '\033':
curr->state = PRINESC;
break;
default:
PrintChar(c);
}
break;
case PRINESC:
switch (c)
{
case '[':
curr->state = PRINCSI;
break;
default:
PrintChar('\033');
PrintChar(c);
curr->state = PRIN;
}
break;
case PRINCSI:
switch (c)
{
case '4':
curr->state = PRIN4;
break;
default:
PrintChar('\033');
PrintChar('[');
PrintChar(c);
curr->state = PRIN;
}
break;
case PRIN4:
switch (c)
{
case 'i':
curr->state = LIT;
PrintFlush();
break;
default:
PrintChar('\033');
PrintChar('[');
PrintChar('4');
PrintChar(c);
curr->state = PRIN;
}
break;
case STRESC:
switch (c)
{
case '\\':
curr->state = LIT;
*(curr->stringp) = '\0';
switch (curr->StringType)
{
case PM:
if (!display)
break;
MakeStatus(curr->string);
if (!HS && status && len > 1)
{
curr->outlen = len - 1;
bcopy(buf, curr->outbuf, curr->outlen);
return;
}
break;
case DCS:
if (display)
printf("%s", curr->string);
break;
case AKA:
if (curr->akapos == 0 && !*curr->string)
break;
strncpy(curr->cmd + curr->akapos, curr->string, 20);
if (!*curr->string)
curr->autoaka = curr->y + 1;
break;
default:
break;
}
break;
default:
curr->state = ASTR;
AddChar('\033');
AddChar(c);
}
break;
case ASTR:
switch (c)
{
case '\0':
break;
case '\033':
curr->state = STRESC;
break;
default:
AddChar(c);
}
break;
case ESC:
switch (c)
{
case '[':
curr->NumArgs = 0;
intermediate = 0;
bzero((char *) curr->args, MAXARGS * sizeof(int));
curr->state = CSI;
break;
case ']':
StartString(OSC);
break;
case '_':
StartString(APC);
break;
case 'P':
StartString(DCS);
break;
case '^':
StartString(PM);
break;
case '"':
case 'k':
StartString(AKA);
break;
default:
if (Special(c))
break;
if (c >= ' ' && c <= '/')
intermediate = intermediate ? -1 : c;
else if (c >= '0' && c <= '~')
{
DoESC(c, intermediate);
curr->state = LIT;
}
else
{
curr->state = LIT;
goto NextChar;
}
}
break;
case CSI:
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (curr->NumArgs < MAXARGS)
{
curr->args[curr->NumArgs] =
10 * curr->args[curr->NumArgs] + c - '0';
}
break;
case ';':
case ':':
curr->NumArgs++;
break;
default:
if (Special(c))
break;
if (c >= '@' && c <= '~')
{
curr->NumArgs++;
DoCSI(c, intermediate);
if (curr->state != PRIN)
curr->state = LIT;
}
else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
intermediate = intermediate ? -1 : c;
else
{
curr->state = LIT;
goto NextChar;
}
}
break;
case LIT:
default:
if (!Special(c))
{
if (c == '\033')
{
intermediate = 0;
curr->state = ESC;
if (display && lp_missing && (CIC || IC || IM))
{
RedisplayLine(blank, null, null, screenbot,
cols - 2, cols - 1);
GotoPos(curr->x, curr->y);
}
if (curr->autoaka < 0)
curr->autoaka = 0;
}
else if (c < ' ')
break;
else
{
NewRendition(curr->LocalAttr);
NewCharset(curr->charsets[(curr->ss) ? curr->ss :
curr->LocalCharset]);
if (curr->x < cols - 1)
{
if (curr->insert)
InsertAChar(c);
else
{
if (display)
PUTCHAR(c);
SetChar(c);
}
curr->x++;
}
else if (curr->x == cols - 1)
{
if (curr->wrap && (LP || !force_vt || COP))
{
if (display)
RAW_PUTCHAR(c);
SetChar(c);
if (AM && !LP)
{
curr->x = 0; /* terminal auto-wrapped */
LineFeed(0);
}
else
curr->x++;
}
else
{
if (display)
{
if (LP || curr->y != screenbot)
{
RAW_PUTCHAR(c);
GotoPos(curr->x, curr->y);
}
else
CheckLP(c);
}
SetChar(c);
if (curr->wrap)
curr->x++;
}
}
else
{
LineFeed(2); /* cr+lf, handle LP */
if (curr->insert)
InsertAChar(c);
else
{
if (display)
PUTCHAR(c);
SetChar(c);
}
curr->x = 1;
}
if (curr->ss)
{
NewCharset(curr->charsets[curr->LocalCharset]);
curr->ss = 0;
}
}
}
}
} while (--len);
curr->outlen = 0;
if (curr->state == PRIN)
PrintFlush();
}
static int Special(c)
register int c;
{
switch (c)
{
case '\b':
BackSpace();
return 1;
case '\r':
Return();
return 1;
case '\n':
if (curr->autoaka)
FindAKA();
LineFeed(1);
return 1;
case '\007':
if (!visual_bell)
PutStr(BL);
else
{
if (!VB)
curr->bell = BELL_VISUAL;
else
PutStr(VB);
}
if (!display)
curr->bell = BELL_ON;
return 1;
case '\t':
ForwardTab();
return 1;
case '\017': /* SI */
MapCharset(G0);
return 1;
case '\016': /* SO */
MapCharset(G1);
return 1;
}
return 0;
}
static void DoESC(c, intermediate)
int c, intermediate;
{
switch (intermediate)
{
case 0:
switch (c)
{
case 'E':
LineFeed(2);
break;
case 'D':
LineFeed(1);
break;
case 'M':
ReverseLineFeed();
break;
case 'H':
curr->tabs[curr->x] = 1;
break;
case 'Z': /* jph: Identify as VT100 */
Report(curr, "\033[?%d;%dc", 1, 2);
break;
case '7':
SaveCursor();
break;
case '8':
RestoreCursor();
break;
case 'c':
ClearScreen();
ResetScreen(curr);
NewRendition(0);
NewCharset(ASCII);
InsertMode(0);
KeypadMode(0);
ChangeScrollRegion(0, rows-1);
break;
case '=':
KeypadMode(curr->keypad = 1);
#if !defined(TIOCPKT) || defined(sgi)
NewAutoFlow(curr, 0);
#endif /* !TIOCPKT || sgi */
break;
case '>':
KeypadMode(curr->keypad = 0);
#if !defined(TIOCPKT) || defined(sgi)
NewAutoFlow(curr, 1);
#endif /* !TIOCPKT || sgi */
break;
case 'n': /* LS2 */
MapCharset(G2);
break;
case 'o': /* LS3 */
MapCharset(G3);
break;
case 'N': /* SS2 */
if (curr->charsets[curr->LocalCharset] != curr->charsets[G2])
curr->ss = G2;
else
curr->ss = 0;
break;
case 'O': /* SS3 */
if (curr->charsets[curr->LocalCharset] != curr->charsets[G3])
curr->ss = G3;
else
curr->ss = 0;
break;
}
break;
case '#':
switch (c)
{
case '8':
FillWithEs();
break;
}
break;
case '(':
DesignateCharset(c, G0);
break;
case ')':
DesignateCharset(c, G1);
break;
case '*':
DesignateCharset(c, G2);
break;
case '+':
DesignateCharset(c, G3);
break;
}
}
static void DoCSI(c, intermediate)
int c, intermediate;
{
register int i, a1 = curr->args[0], a2 = curr->args[1];
if (curr->NumArgs > MAXARGS)
curr->NumArgs = MAXARGS;
switch (intermediate)
{
case 0:
switch (c)
{
case 'H':
case 'f':
if (a1 < 1)
a1 = 1;
if (curr->origin)
a1 += curr->top;
if (a1 > rows)
a1 = rows;
if (a2 < 1)
a2 = 1;
if (a2 > cols)
a2 = cols;
GotoPos(--a2, --a1);
curr->x = a2;
curr->y = a1;
if (curr->autoaka)
curr->autoaka = a1 + 1;
break;
case 'J':
if (a1 < 0 || a1 > 2)
a1 = 0;
switch (a1)
{
case 0:
ClearToEOS();
break;
case 1:
ClearFromBOS();
break;
case 2:
ClearScreen();
GotoPos(curr->x, curr->y);
break;
}
break;
case 'K':
if (a1 < 0 || a1 > 2)
a1 %= 3;
switch (a1)
{
case 0:
ClearToEOL();
break;
case 1:
ClearFromBOL();
break;
case 2:
ClearLine();
break;
}
break;
case 'A':
CursorUp(a1 ? a1 : 1);
break;
case 'B':
CursorDown(a1 ? a1 : 1);
break;
case 'C':
CursorRight(a1 ? a1 : 1);
break;
case 'D':
CursorLeft(a1 ? a1 : 1);
break;
case 'm':
SelectRendition();
break;
case 'g':
if (a1 == 0)
curr->tabs[curr->x] = 0;
else if (a1 == 3)
bzero(curr->tabs, cols);
break;
case 'r':
if (!a1)
a1 = 1;
if (!a2)
a2 = rows;
if (a1 < 1 || a2 > rows || a1 >= a2)
break;
curr->top = a1 - 1;
curr->bot = a2 - 1;
ChangeScrollRegion(curr->top, curr->bot);
if (curr->origin)
{
GotoPos(0, curr->top);
curr->y = curr->top;
curr->x = 0;
}
else
{
GotoPos(0, 0);
curr->y = curr->x = 0;
}
break;
case 's':
SaveCursor();
break;
case 't':
if (a1 != 8)
break;
a1 = curr->args[2];
if (a1 < 1)
a1 = curr->width;
if (a2 < 1)
a2 = curr->height;
if (WS == NULL)
{
a2 = curr->height;
if (Z0 == NULL || (a1 != Z0width && a1 != Z1width))
a1 = curr->width;
}
if (a1 == curr->width && a2 == curr->height)
break;
ChangeWindowSize(curr, a1, a2);
SetCurr(curr);
if (display)
Activate(0);
break;
case 'u':
RestoreCursor();
break;
case 'I':
if (!a1)
a1 = 1;
while (a1--)
ForwardTab();
break;
case 'Z':
if (!a1)
a1 = 1;
while (a1--)
BackwardTab();
break;
case 'L':
InsertLine(a1 ? a1 : 1);
break;
case 'M':
DeleteLine(a1 ? a1 : 1);
break;
case 'P':
DeleteChar(a1 ? a1 : 1);
break;
case '@':
InsertChar(a1 ? a1 : 1);
break;
case 'h':
ASetMode(1);
break;
case 'l':
ASetMode(0);
break;
case 'i':
if (PO && a1 == 5)
{
curr->stringp = curr->string;
curr->state = PRIN;
}
break;
case 'n':
if (a1 == 6) /* Report cursor position */
Report(curr, "\033[%d;%dR", curr->y + 1, curr->x + 1);
break;
case 'c': /* Identify as VT100 */
Report(curr, "\033[?%d;%dc", 1, 2);
break;
}
break;
case '?':
debug2("\\E[?%d%c\n",a1,c);
if (c != 'h' && c != 'l')
break;
i = (c == 'h');
switch (a1)
{
case 3:
i = (i ? Z0width : Z1width);
if ((Z0 || WS) && curr->width != i)
{
ChangeWindowSize(curr, i, curr->height);
SetCurr(curr);
if (display)
Activate(0);
}
break;
case 5:
if (i)
curr->vbwait = 1;
else
{
if (curr->vbwait)
PutStr(VB);
curr->vbwait = 0;
}
break;
case 6:
if ((curr->origin = i) != 0)
{
GotoPos(0, curr->top);
curr->y = curr->top;
curr->x = 0;
}
else
{
GotoPos(0, 0);
curr->y = curr->x = 0;
}
break;
case 7:
curr->wrap = i;
break;
case 35:
debug1("Cursor %svisible\n", i?"in":"");
curr->cursor_invisible = i;
break;
}
break;
}
}
void
INSERTCHAR(c)
int c;
{
if (!insert && (IC || CIC))
{
if (IC)
PutStr(IC);
else
CPutStr(CIC, 1);
RAW_PUTCHAR(c);
return;
}
InsertMode(1);
if (insert)
RAW_PUTCHAR(c);
else
RefreshLine(screeny, screenx, screenwidth-1);
}
void
PUTCHAR(c)
int c;
{
if (insert)
InsertMode(0);
RAW_PUTCHAR(c);
}
/*
* RAW_PUTCHAR() is for all text that will be displayed.
* NOTE, that charset Nr. 0 has a conversion table, but c1, c2, ... don't.
*/
static void
RAW_PUTCHAR(c)
int c;
{
if (GlobalCharset == '0')
putchar(c0_tab[c]);
else
putchar(c);
if (screenx < screenwidth - 1)
screenx++;
else
{
screenx++;
if ((AM && !LP) || screenx > screenwidth)
{
screenx -= screenwidth;
if (screeny < screenheight-1 && screeny != screenbot)
screeny++;
}
}
}
void
PutChar(c)
int c;
{
/* this PutChar for ESC-sequences only */
putchar(c);
}
void
PutStr(s)
char *s;
{
if (display && s)
tputs(s, 1, PutChar);
}
static void CPutStr(s, c)
char *s;
int c;
{
if (display && s)
tputs(tgoto(s, 0, c), 1, PutChar);
}
static void SetChar(c)
register int c;
{
register struct win *p = curr;
p->image[p->y][p->x] = c;
p->attr[p->y][p->x] = p->LocalAttr;
p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
}
static void StartString(type)
enum string_t type;
{
curr->StringType = type;
curr->stringp = curr->string;
curr->state = ASTR;
}
static void AddChar(c)
int c;
{
if (curr->stringp >= curr->string + MAXSTR - 1)
curr->state = LIT;
else
*(curr->stringp)++ = c;
}
static void PrintChar(c)
int c;
{
if (curr->stringp >= curr->string + MAXSTR - 1)
PrintFlush();
*(curr->stringp)++ = c;
}
static void PrintFlush()
{
if (curr->stringp > curr->string)
{
tputs(PO, 1, PutChar);
(void) fflush(stdout);
(void) write(1, curr->string, curr->stringp - curr->string);
tputs(PF, 1, PutChar);
(void) fflush(stdout);
curr->stringp = curr->string;
}
}
/* Insert mode is a toggle on some terminals, so we need this hack:
*/
void
InsertMode(on)
int on;
{
if (display && on != insert && IM)
{
insert = on;
if (insert)
PutStr(IM);
else
PutStr(EI);
}
}
/* ...and maybe keypad application mode is a toggle, too:
*/
static void KeypadMode(on)
int on;
{
if (display && keypad != on && KS)
{
keypad = on;
if (keypad)
PutStr(KS);
else
PutStr(KE);
}
}
void
NewAutoFlow(win, on)
struct win *win;
int on;
{
debug1("NewAutoFlow: %d\n", on);
SetCurr(win);
if (win->flow & FLOW_AUTOFLAG)
win->flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
else
win->flow = (win->flow & ~FLOW_AUTO) | FLOW_AUTO * on;
if (display)
SetFlow(win->flow & FLOW_NOW);
}
static void DesignateCharset(c, n)
int c, n;
{
curr->ss = 0;
if (c == 'B')
c = ASCII;
if (curr->charsets[n] != c)
{
curr->charsets[n] = c;
if (curr->LocalCharset == n)
NewCharset(c);
}
}
static void MapCharset(n)
int n;
{
curr->ss = 0;
if (curr->LocalCharset != n)
{
curr->LocalCharset = n;
NewCharset(curr->charsets[n]);
}
}
void
NewCharset(new)
int new;
{
if (!display || GlobalCharset == new)
return;
GlobalCharset = new;
if (new == ASCII)
PutStr(E0);
else
CPutStr(S0, new);
}
static void SaveCursor()
{
curr->saved = 1;
curr->Saved_x = curr->x;
curr->Saved_y = curr->y;
curr->SavedLocalAttr = curr->LocalAttr;
curr->SavedLocalCharset = curr->LocalCharset;
bcopy((char *) curr->charsets, (char *) curr->SavedCharsets,
4 * sizeof(int));
}
static void RestoreCursor()
{
if (curr->saved)
{
GotoPos(curr->Saved_x, curr->Saved_y);
curr->x = curr->Saved_x;
curr->y = curr->Saved_y;
curr->LocalAttr = curr->SavedLocalAttr;
NewRendition(curr->LocalAttr);
bcopy((char *) curr->SavedCharsets, (char *) curr->charsets,
4 * sizeof(int));
curr->LocalCharset = curr->SavedLocalCharset;
NewCharset(curr->charsets[curr->LocalCharset]);
}
}
/*ARGSUSED*/
static void CountChars(c)
int c;
{
StrCost++;
}
static int CalcCost(s)
register char *s;
{
if (s)
{
StrCost = 0;
tputs(s, 1, CountChars);
return StrCost;
}
else
return EXPENSIVE;
}
void
GotoPos(x2, y2)
int x2, y2;
{
register int dy, dx, x1, y1;
register int costx, costy;
register int m;
register char *s;
int CMcost;
enum move_t xm = M_NONE, ym = M_NONE;
if (!display)
return;
x1 = screenx;
y1 = screeny;
if (x1 == screenwidth)
if (LP && AM)
x1 = -1; /* don't know how the terminal treats this */
else
x1--;
if (x2 == screenwidth)
x2--;
dx = x2 - x1;
dy = y2 - y1;
if (dy == 0 && dx == 0)
{
return;
}
if (!MS && GlobalAttr) /* Safe to move in SO mode ? */
NewRendition(0);
if (y1 < 0 /* don't know the y position */
|| (y2 > screenbot && y1 <= screenbot) /* have to cross border */
|| (y2 < screentop && y1 >= screentop)) /* of scrollregion ? */
{
DoCM:
if (HO && !x2 && !y2)
PutStr(HO);
else
PutStr(tgoto(CM, x2, y2));
screenx = x2;
screeny = y2;
return;
}
/* Calculate CMcost */
if (HO && !x2 && !y2)
s = HO;
else
s = tgoto(CM, x2, y2);
CMcost = CalcCost(s);
/* Calculate the cost to move the cursor to the right x position */
costx = EXPENSIVE;
if (x1 >= 0) /* relativ x positioning only if we know where we are */
{
if (dx > 0)
{
if (CRI && (dx > 1 || !ND))
{
costx = CalcCost(tgoto(CRI, 0, dx));
xm = M_CRI;
}
if ((m = NDcost * dx) < costx)
{
costx = m;
xm = M_RI;
}
/* Speedup: dx <= Rewrite() */
if (dx < costx && (m = Rewrite(y1, x1, x2, 0)) < costx)
{
costx = m;
xm = M_RW;
}
}
else if (dx < 0)
{
if (CLE && (dx < -1 || !BC))
{
costx = CalcCost(tgoto(CLE, 0, -dx));
xm = M_CLE;
}
if ((m = -dx * LEcost) < costx)
{
costx = m;
xm = M_LE;
}
}
else
costx = 0;
}
/* Speedup: Rewrite() >= x2 */
if (x2 + CRcost < costx && (m = Rewrite(y1, 0, x2, 0) + CRcost) < costx)
{
costx = m;
xm = M_CR;
}
/* Check if it is already cheaper to do CM */
if (costx >= CMcost)
goto DoCM;
/* Calculate the cost to move the cursor to the right y position */
costy = EXPENSIVE;
if (dy > 0)
{
if (CDO && dy > 1) /* DO & NL are always != 0 */
{
costy = CalcCost(tgoto(CDO, 0, dy));
ym = M_CDO;
}
if ((m = dy * ((x2 == 0) ? NLcost : DOcost)) < costy)
{
costy = m;
ym = M_DO;
}
}
else if (dy < 0)
{
if (CUP && (dy < -1 || !UP))
{
costy = CalcCost(tgoto(CUP, 0, -dy));
ym = M_CUP;
}
if ((m = -dy * UPcost) < costy)
{
costy = m;
ym = M_UP;
}
}
else
costy = 0;
/* Finally check if it is cheaper to do CM */
if (costx + costy >= CMcost)
goto DoCM;
switch (xm)
{
case M_LE:
while (dx++ < 0)
PutStr(BC);
break;
case M_CLE:
CPutStr(CLE, -dx);
break;
case M_RI:
while (dx-- > 0)
PutStr(ND);
break;
case M_CRI:
CPutStr(CRI, dx);
break;
case M_CR:
PutStr(CR);
screenx = 0;
x1 = 0;
/* FALLTHROUGH */
case M_RW:
if (x1 < x2)
(void) Rewrite(y1, x1, x2, 1);
break;
default:
break;
}
switch (ym)
{
case M_UP:
while (dy++ < 0)
PutStr(UP);
break;
case M_CUP:
CPutStr(CUP, -dy);
break;
case M_DO:
s = (x2 == 0) ? NL : DO;
while (dy-- > 0)
PutStr(s);
break;
case M_CDO:
CPutStr(CDO, dy);
break;
default:
break;
}
screenx = x2;
screeny = y2;
}
static int
Rewrite(y, x1, x2, doit)
int y, x1, x2, doit;
{
register int cost, dx;
register char *p, *f, *i;
if (x1 == x2)
return(0);
if (in_ovl)
{
if (ovl_Rewrite == 0)
return EXPENSIVE;
else
return ((*ovl_Rewrite)(y, x1, x2, doit));
}
dx = x2 - x1;
if (doit)
{
i = curr->image[y] + x1;
while (dx-- > 0)
PUTCHAR(*i++);
return(0);
}
p = curr->attr[y] + x1;
f = curr->font[y] + x1;
cost = dx = x2 - x1;
if (insert)
cost += EIcost + IMcost;
while(dx-- > 0)
{
if (*p++ != GlobalAttr || *f++ != GlobalCharset)
return EXPENSIVE;
}
return cost;
}
static void BackSpace()
{
if (curr->x > 0)
{
curr->x--;
}
else if (curr->wrap && curr->y > 0)
{
curr->x = cols - 1;
curr->y--;
}
if (display)
GotoPos(curr->x, curr->y);
}
static void Return()
{
if (curr->x > 0)
{
curr->x = 0;
if (display)
GotoPos(curr->x, curr->y);
}
}
static void LineFeed(out_mode)
int out_mode;
{
/* out_mode: 0=no-output lf, 1=lf, 2=cr+lf */
if (out_mode == 2)
curr->x = 0;
if (curr->y != curr->bot) /* Don't scroll */
{
if (curr->y < rows-1)
curr->y++;
if (out_mode && display)
GotoPos(curr->x, curr->y);
return;
}
ScrollUpMap(1);
if (curr->autoaka > 1)
curr->autoaka--;
if (out_mode && display)
{
ScrollRegion(curr->top, curr->bot, 1);
GotoPos(curr->x, curr->y);
}
}
static void ReverseLineFeed()
{
if (curr->y == curr->top)
{
ScrollDownMap(1);
if (!display)
return;
ScrollRegion(curr->top, curr->bot, -1);
GotoPos(curr->x, curr->y);
}
else if (curr->y > 0)
CursorUp(1);
}
static void InsertAChar(c)
int c;
{
register int y = curr->y, x = curr->x;
if (x == cols)
x--;
bcopy(curr->image[y], OldImage, cols);
bcopy(curr->attr[y], OldAttr, cols);
bcopy(curr->font[y], OldFont, cols);
bcopy(curr->image[y] + x, curr->image[y] + x + 1, cols - x - 1);
bcopy(curr->attr[y] + x, curr->attr[y] + x + 1, cols - x - 1);
bcopy(curr->font[y] + x, curr->font[y] + x + 1, cols - x - 1);
SetChar(c);
if (!display)
return;
if (CIC || IC || IM)
{
InsertMode(curr->insert);
INSERTCHAR(c);
if (y == screenbot)
lp_missing = 0;
}
else
{
RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
GotoPos(++x, y);
}
}
static void InsertChar(n)
int n;
{
register int i, y = curr->y, x = curr->x;
if (n <= 0)
return;
/*
* The termcap manual states that only one of IM and IC is
* to be defined unless the terminal needs both sequences.
* We don't like this because we think that there may be cases
* where it is preferable to send IC instead of IM/EI.
* The hack is to ignore the IC sequence if we are already
* in insert mode, so that programs which follow the termcap
* guidelines still work. (I don't believe that there are
* terminals which need IC in the insert mode. Why switch to
* insert mode if you must send IC before every character ?)
*/
if (curr->insert)
return;
if (x == cols)
--x;
bcopy(curr->image[y], OldImage, cols);
bcopy(curr->attr[y], OldAttr, cols);
bcopy(curr->font[y], OldFont, cols);
if (n > cols - x)
n = cols - x;
bcopy(curr->image[y] + x, curr->image[y] + x + n, cols - x - n);
bcopy(curr->attr[y] + x, curr->attr[y] + x + n, cols - x - n);
bcopy(curr->font[y] + x, curr->font[y] + x + n, cols - x - n);
ClearInLine(0, y, x, x + n - 1);
if (!display)
return;
if (IC || CIC || IM)
{
if (y == screenbot)
lp_missing = 0;
if (!insert)
{
if (n == 1 && IC)
{
PutStr(IC);
return;
}
if (CIC)
{
CPutStr(CIC, n);
return;
}
}
InsertMode(1);
for (i = n; i--; )
INSERTCHAR(' ');
GotoPos(x, y);
}
else
{
RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
GotoPos(x, y);
}
}
static void DeleteChar(n)
int n;
{
register int i, y = curr->y, x = curr->x;
if (x == cols)
--x;
bcopy(curr->image[y], OldImage, cols);
bcopy(curr->attr[y], OldAttr, cols);
bcopy(curr->font[y], OldFont, cols);
if (n > cols - x)
n = cols - x;
bcopy(curr->image[y] + x + n, curr->image[y] + x, cols - x - n);
bcopy(curr->attr[y] + x + n, curr->attr[y] + x, cols - x - n);
bcopy(curr->font[y] + x + n, curr->font[y] + x, cols - x - n);
ClearInLine(0, y, cols - n, cols - 1);
if (!display)
return;
if (CDC && !(n == 1 && DC))
{
CPutStr(CDC, n);
if (lp_missing && y == screenbot)
{
FixLP(cols - 1 - n, y);
GotoPos(x, y);
}
}
else if (DC)
{
for (i = n; i; i--)
PutStr(DC);
if (lp_missing && y == screenbot)
{
FixLP(cols - 1 - n, y);
GotoPos(x, y);
}
}
else
{
RedisplayLine(OldImage, OldAttr, OldFont, y, x, cols - 1);
GotoPos(x, y);
}
}
static void DeleteLine(n)
int n;
{
register int old = curr->top;
if (curr->y < curr->top || curr->y > curr->bot)
return;
if (n > curr->bot - curr->y + 1)
n = curr->bot - curr->y + 1;
curr->top = curr->y;
ScrollUpMap(n);
curr->top = old;
if (!display)
return;
ScrollRegion(curr->y, curr->bot, n);
GotoPos(curr->x, curr->y);
}
static void InsertLine(n)
int n;
{
register int old = curr->top;
if (curr->y < curr->top || curr->y > curr->bot)
return;
if (n > curr->bot - curr->y + 1)
n = curr->bot - curr->y + 1;
curr->top = curr->y;
ScrollDownMap(n);
curr->top = old;
if (!display)
return;
ScrollRegion(curr->y, curr->bot, -n);
GotoPos(curr->x, curr->y);
}
void
ScrollRegion(ys, ye, n)
int ys, ye, n;
{
int i;
int up;
int oldtop, oldbot;
int alok, dlok, aldlfaster;
int missy = 0;
if (n == 0)
return;
if (ys == 0 && ye == screenheight-1 &&
(n >= screenheight || -n >= screenheight))
{
PutStr(CL);
screeny = screenx = 0;
lp_missing = 0;
return;
}
if (lp_missing)
{
if (screenbot>ye || screenbot<ys)
missy = screenbot;
else
{
missy = screenbot - n;
if (missy>ye || missy<ys)
lp_missing = 0;
}
}
up = 1;
if (n < 0)
{
up = 0;
n = -n;
}
if (n >= ye-ys+1)
n = ye-ys+1;
oldtop = screentop;
oldbot = screenbot;
if (screenbot != ye)
ChangeScrollRegion(ys, ye);
alok = (AL || CAL || (ye == screenbot && up));
dlok = (DL || CDL || (ye == screenbot && !up));
if (screentop != ys && !(alok && dlok))
ChangeScrollRegion(ys, ye);
if (lp_missing &&
(oldbot != screenbot ||
(oldbot == screenbot && up && screentop == ys && screenbot == ye)))
{
/* Can't use FixLP */
GotoPos(screenwidth-1, oldbot);
SaveSetAttr(curr->attr[missy][screenwidth-1], curr->font[missy][screenwidth-1]);
PUTCHAR(curr->image[missy][screenwidth-1]);
RestoreAttr();
lp_missing = 0;
if (oldbot == screenbot) /* have scrolled */
{
if (--n == 0)
{
ChangeScrollRegion(oldtop, oldbot);
return;
}
}
}
aldlfaster = (n > 1 && ye == screenbot && ((up && CDL) || (!up && CAL)));
if ((up || SR) && screentop == ys && screenbot == ye && !aldlfaster)
{
if (up)
{
GotoPos(0, ye);
while (n-- > 0)
PutStr(NL); /* was SF, I think NL is faster */
}
else
{
GotoPos(0, ys);
while (n-- > 0)
PutStr(SR);
}
}
else if (alok && dlok)
{
if (up || ye != screenbot)
{
GotoPos(0, up ? ys : ye+1-n);
if (CDL && !(n == 1 && DL))
CPutStr(CDL, n);
else
for(i=n; i--; )
PutStr(DL);
}
if (!up || ye != screenbot)
{
GotoPos(0, up ? ye+1-n : ys);
if (CAL && !(n == 1 && AL))
CPutStr(CAL, n);
else
for(i=n; i--; )
PutStr(AL);
}
}
else
{
Redisplay(0);
return;
}
if (lp_missing && missy != screenbot)
FixLP(screenwidth-1, missy);
ChangeScrollRegion(oldtop, oldbot);
if (lp_missing && missy != screenbot)
FixLP(screenwidth-1, missy);
}
static void ScrollUpMap(n)
int n;
{
char tmp[256 * sizeof(char *)];
register int ii, i, cnt1, cnt2;
register char **ppi, **ppa, **ppf;
i = curr->top + n;
cnt1 = n * sizeof(char *);
cnt2 = (curr->bot - i + 1) * sizeof(char *);
ppi = curr->image + i;
ppa = curr->attr + i;
ppf = curr->font + i;
for(ii = curr->top; ii < i; ii++)
AddLineToHist(curr, &curr->image[ii], &curr->attr[ii], &curr->font[ii]);
for (i = n; i; --i)
{
bclear(*--ppi, cols);
bzero(*--ppa, cols);
bzero(*--ppf, cols);
}
Scroll((char *) ppi, cnt1, cnt2, tmp);
Scroll((char *) ppa, cnt1, cnt2, tmp);
Scroll((char *) ppf, cnt1, cnt2, tmp);
}
static void ScrollDownMap(n)
int n;
{
char tmp[256 * sizeof(char *)];
register int i, cnt1, cnt2;
register char **ppi, **ppa, **ppf;
i = curr->top;
cnt1 = (curr->bot - i - n + 1) * sizeof(char *);
cnt2 = n * sizeof(char *);
Scroll((char *) (ppi = curr->image + i), cnt1, cnt2, tmp);
Scroll((char *) (ppa = curr->attr + i), cnt1, cnt2, tmp);
Scroll((char *) (ppf = curr->font + i), cnt1, cnt2, tmp);
for (i = n; i; --i)
{
bclear(*ppi++, cols);
bzero(*ppa++, cols);
bzero(*ppf++, cols);
}
}
static void Scroll(cp, cnt1, cnt2, tmp)
char *cp, *tmp;
int cnt1, cnt2;
{
if (!cnt1 || !cnt2)
return;
if (cnt1 <= cnt2)
{
bcopy(cp, tmp, cnt1);
bcopy(cp + cnt1, cp, cnt2);
bcopy(tmp, cp + cnt2, cnt1);
}
else
{
bcopy(cp + cnt1, tmp, cnt2);
bcopy(cp, cp + cnt2, cnt1);
bcopy(tmp, cp, cnt2);
}
}
static void ForwardTab()
{
register int x = curr->x;
if (x == cols)
{
LineFeed(2);
x = 0;
}
if (curr->tabs[x] && x < cols - 1)
x++;
while (x < cols - 1 && !curr->tabs[x])
x++;
GotoPos(x, curr->y);
curr->x = x;
}
static void BackwardTab()
{
register int x = curr->x;
if (curr->tabs[x] && x > 0)
x--;
while (x > 0 && !curr->tabs[x])
x--;
GotoPos(x, curr->y);
curr->x = x;
}
static void ClearScreen()
{
register int i;
register char **ppi = curr->image, **ppa = curr->attr, **ppf = curr->font;
for (i = 0; i < rows; ++i)
{
AddLineToHist(curr, ppi, ppa, ppf);
bclear(*ppi++, cols);
bzero(*ppa++, cols);
bzero(*ppf++, cols);
}
if (display)
{
PutStr(CL);
screenx = screeny = 0;
lp_missing = 0;
}
}
static void ClearFromBOS()
{
register int n, y = curr->y, x = curr->x;
for (n = 0; n < y; ++n)
ClearInLine(1, n, 0, cols - 1);
ClearInLine(1, y, 0, x);
GotoPos(x, y);
RestoreAttr();
}
static void ClearToEOS()
{
register int n, y = curr->y, x = curr->x;
if (!y && !x)
{
ClearScreen();
return;
}
if (display && CD)
{
PutStr(CD);
lp_missing = 0;
}
ClearInLine(!CD, y, x, cols - 1);
for (n = y + 1; n < rows; n++)
ClearInLine(!CD, n, 0, cols - 1);
GotoPos(x, y);
RestoreAttr();
}
static void ClearLine()
{
register int y = curr->y, x = curr->x;
ClearInLine(1, y, 0, cols - 1);
GotoPos(x, y);
RestoreAttr();
}
static void ClearToEOL()
{
register int y = curr->y, x = curr->x;
ClearInLine(1, y, x, cols - 1);
GotoPos(x, y);
RestoreAttr();
}
static void ClearFromBOL()
{
register int y = curr->y, x = curr->x;
ClearInLine(1, y, 0, x);
GotoPos(x, y);
RestoreAttr();
}
static void ClearInLine(displ, y, x1, x2)
int displ, y, x1, x2;
{
register int n;
if (x1 == cols)
x1--;
if (x2 == cols)
x2--;
if ((n = x2 - x1 + 1) != 0)
{
if (displ && display)
{
if (x2 == cols - 1 && CE)
{
GotoPos(x1, y);
PutStr(CE);
if (y == screenbot)
lp_missing = 0;
}
else
DisplayLine(curr->image[y], curr->attr[y], curr->font[y],
blank, null, null, y, x1, x2);
}
if (curr)
{
bclear(curr->image[y] + x1, n);
bzero(curr->attr[y] + x1, n);
bzero(curr->font[y] + x1, n);
}
}
}
static void CursorRight(n)
register int n;
{
register int x = curr->x;
if (x == cols)
{
LineFeed(2);
x = 0;
}
if ((curr->x += n) >= cols)
curr->x = cols - 1;
GotoPos(curr->x, curr->y);
}
static void CursorUp(n)
register int n;
{
if (curr->y < curr->top) /* if above scrolling rgn, */
{
if ((curr->y -= n) < 0) /* ignore its limits */
curr->y = 0;
}
else
if ((curr->y -= n) < curr->top)
curr->y = curr->top;
GotoPos(curr->x, curr->y);
}
static void CursorDown(n)
register int n;
{
if (curr->y > curr->bot) /* if below scrolling rgn, */
{
if ((curr->y += n) > rows - 1) /* ignore its limits */
curr->y = rows - 1;
}
else
if ((curr->y += n) > curr->bot)
curr->y = curr->bot;
GotoPos(curr->x, curr->y);
}
static void CursorLeft(n)
register int n;
{
if ((curr->x -= n) < 0)
curr->x = 0;
GotoPos(curr->x, curr->y);
}
static void ASetMode(on)
int on;
{
register int i;
for (i = 0; i < curr->NumArgs; ++i)
{
switch (curr->args[i])
{
case 4:
curr->insert = on;
InsertMode(on);
break;
}
}
}
static void SelectRendition()
{
register int i = 0, a = curr->LocalAttr;
do
{
switch (curr->args[i])
{
case 0:
a = 0;
break;
case 1:
a |= A_BD;
break;
case 2:
a |= A_DI;
break;
case 3:
a |= A_SO;
break;
case 4:
a |= A_US;
break;
case 5:
a |= A_BL;
break;
case 7:
a |= A_RV;
break;
case 22:
a &= ~(A_BD | A_SO | A_DI);
break;
case 23:
a &= ~A_SO;
break;
case 24:
a &= ~A_US;
break;
case 25:
a &= ~A_BL;
break;
case 27:
a &= ~A_RV;
break;
}
} while (++i < curr->NumArgs);
NewRendition(curr->LocalAttr = a);
}
void
NewRendition(new)
register int new;
{
register int i, old = GlobalAttr;
if (!display || old == new)
return;
GlobalAttr = new;
for (i = 1; i <= A_MAX; i <<= 1)
{
if ((old & i) && !(new & i))
{
PutStr(UE);
PutStr(SE);
PutStr(ME);
if (new & A_DI)
PutStr(attrtab[ATTR_DI]);
if (new & A_US)
PutStr(attrtab[ATTR_US]);
if (new & A_BD)
PutStr(attrtab[ATTR_BD]);
if (new & A_RV)
PutStr(attrtab[ATTR_RV]);
if (new & A_SO)
PutStr(attrtab[ATTR_SO]);
if (new & A_BL)
PutStr(attrtab[ATTR_BL]);
return;
}
}
if ((new & A_DI) && !(old & A_DI))
PutStr(attrtab[ATTR_DI]);
if ((new & A_US) && !(old & A_US))
PutStr(attrtab[ATTR_US]);
if ((new & A_BD) && !(old & A_BD))
PutStr(attrtab[ATTR_BD]);
if ((new & A_RV) && !(old & A_RV))
PutStr(attrtab[ATTR_RV]);
if ((new & A_SO) && !(old & A_SO))
PutStr(attrtab[ATTR_SO]);
if ((new & A_BL) && !(old & A_BL))
PutStr(attrtab[ATTR_BL]);
}
void
SaveSetAttr(newattr, newcharset)
int newattr, newcharset;
{
NewRendition(newattr);
NewCharset(newcharset);
}
void
RestoreAttr()
{
NewRendition(curr->LocalAttr);
NewCharset(curr->charsets[curr->LocalCharset]);
}
static void FillWithEs()
{
register int i;
register char *p, *ep;
curr->y = curr->x = 0;
for (i = 0; i < rows; ++i)
{
bzero(curr->attr[i], cols);
bzero(curr->font[i], cols);
p = curr->image[i];
ep = p + cols;
while (p < ep)
*p++ = 'E';
}
if (display)
Redisplay(0);
}
/*
* if cur_only, we only redisplay current line, as a full refresh is
* too expensive.
*/
void Redisplay(cur_only)
int cur_only;
{
register int i, stop;
PutStr(CL);
screenx = screeny = 0;
lp_missing = 0;
stop = rows; i = 0;
if (cur_only)
{
i = stop = curr->y;
stop++;
}
for (; i < stop; ++i)
{
if (in_ovl)
(*ovl_RedisplayLine)(i, 0, cols - 1, 1);
else
DisplayLine(blank, null, null, curr->image[i], curr->attr[i],
curr->font[i], i, 0, cols - 1);
}
if (!in_ovl)
{
GotoPos(curr->x, curr->y);
NewRendition(curr->LocalAttr);
NewCharset(curr->charsets[curr->LocalCharset]);
}
}
void
DisplayLine(os, oa, of, s, as, fs, y, from, to)
int from, to, y;
register char *os, *oa, *of, *s, *as, *fs;
{
register int x;
int last2flag = 0, delete_lp = 0;
if (!LP && y == screenbot && to == cols - 1)
if (lp_missing
|| s[to] != os[to] || as[to] != oa[to] || of[to] != fs[to])
{
if ((IC || IM) && (from < to || !in_ovl))
{
if ((to -= 2) < from - 1)
from--;
last2flag = 1;
lp_missing = 0;
}
else
{
to--;
delete_lp = (CE || DC || CDC);
lp_missing = (s[to] != ' ' || as[to] || fs[to]);
}
}
else
to--;
for (x = from; x <= to; ++x)
{
if (s[x] == os[x] && as[x] == oa[x] && of[x] == fs[x])
continue;
GotoPos(x, y);
NewRendition(as[x]);
NewCharset(fs[x]);
PUTCHAR(s[x]);
}
if (last2flag)
{
GotoPos(x, y);
NewRendition(as[x + 1]);
NewCharset(fs[x + 1]);
PUTCHAR(s[x + 1]);
GotoPos(x, y);
NewRendition(as[x]);
NewCharset(fs[x]);
INSERTCHAR(s[x]);
}
else if (delete_lp)
{
if (DC)
PutStr(DC);
else if (CDC)
CPutStr(CDC, 1);
else if (CE)
PutStr(CE);
}
}
void
RefreshLine(y, from, to)
int y, from, to;
{
char *oi = null;
if (CE && to == screenwidth-1)
{
GotoPos(from, y);
PutStr(CE);
oi = blank;
}
if (in_ovl)
(*ovl_RedisplayLine)(y, from, to, (oi == blank));
else
DisplayLine(oi, null, null, curr->image[y], curr->attr[y],
curr->font[y], y, from, to);
}
static void RedisplayLine(os, oa, of, y, from, to)
int from, to, y;
char *os, *oa, *of;
{
DisplayLine(os, oa, of, curr->image[y], curr->attr[y],
curr->font[y], y, from, to);
NewRendition(curr->LocalAttr);
NewCharset(curr->charsets[curr->LocalCharset]);
}
void
FixLP(x2, y2)
register int x2, y2;
{
register struct win *p = curr;
GotoPos(x2, y2);
SaveSetAttr(p->attr[y2][x2], p->font[y2][x2]);
PUTCHAR(p->image[y2][x2]);
RestoreAttr();
lp_missing = 0;
}
void
CheckLP(n_ch)
char n_ch;
{
register int y = screenbot, x = cols - 1;
register char n_at, n_fo, o_ch, o_at, o_fo;
o_ch = curr->image[y][x];
o_at = curr->attr[y][x];
o_fo = curr->font[y][x];
n_at = curr->LocalAttr;
n_fo = curr->charsets[curr->LocalCharset];
lp_missing = 0;
if (n_ch == o_ch && n_at == o_at && n_fo == o_fo)
{
return;
}
if (n_ch != ' ' || n_at || n_fo)
lp_missing = 1;
if (o_ch != ' ' || o_at || o_fo)
{
if (DC)
PutStr(DC);
else if (CDC)
CPutStr(CDC, 1);
else if (CE)
PutStr(CE);
else
lp_missing = 1;
}
}
static void FindAKA()
{
register char *cp, *line, ch;
register struct win *wp = curr;
register int len = strlen(wp->cmd);
int y;
y = (wp->autoaka > 0 && wp->autoaka <= wp->height) ? wp->autoaka - 1 : wp->y;
cols = wp->width;
try_line:
cp = line = wp->image[y];
if (wp->autoaka > 0 && (ch = *wp->cmd) != '\0')
{
for (;;)
{
if ((cp = index(cp, ch)) != NULL
&& !strncmp(cp, wp->cmd, len))
break;
if (!cp || ++cp - line >= cols - len)
{
if (++y == wp->autoaka && y < rows)
goto try_line;
return;
}
}
cp += len;
}
for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
;
if (len)
{
if (wp->autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
wp->autoaka = -1;
else
wp->autoaka = 0;
line = wp->cmd + wp->akapos;
while (len && *cp != ' ')
{
if ((*line++ = *cp++) == '/')
line = wp->cmd + wp->akapos;
len--;
}
*line = '\0';
}
else
wp->autoaka = 0;
}
/* We dont use HS status line with Input.
* If we would use it, then we should check e_tgetflag("es") if
* we are allowed to use esc sequences there.
* For now, we hope that Goto(,,STATLINE,0) brings us in the bottom
* line. jw.
*/
static char inpbuf[101];
static int inplen;
static int inpmaxlen;
static char *inpstring;
static int inpstringlen;
static void (*inpfinfunc)();
void
Input(istr, len, finfunc)
char *istr;
int len;
void (*finfunc)();
{
int maxlen;
inpstring = istr;
inpstringlen = strlen(istr);
if (len > 100)
len = 100;
maxlen = screenwidth - inpstringlen;
if (!LP && STATLINE == screenbot)
maxlen--;
if (len > maxlen)
len = maxlen;
if (len < 2)
{
Msg(0, "Width too small");
return;
}
inpmaxlen = len;
inpfinfunc = finfunc;
InitOverlayPage(process_inp_input, inpRedisplayLine, (int (*)())0, 1);
inplen = 0;
GotoPos(0, STATLINE);
if (CE)
PutStr(CE);
else
{
DisplayLine(curr->image[screeny], curr->attr[screeny],
curr->font[screeny],
blank, null, null, screeny, 0, cols - 1);
}
inpRedisplayLine(STATLINE, 0, inpstringlen - 1, 0);
GotoPos(inpstringlen, STATLINE);
}
static void
process_inp_input(ppbuf, plen)
char **ppbuf;
int *plen;
{
int len, x;
char *pbuf;
char ch;
if (ppbuf == 0)
{
AbortInp();
return;
}
x = inpstringlen+inplen;
len = *plen;
pbuf = *ppbuf;
while (len)
{
ch = *pbuf++;
len--;
if (ch >= ' ' && ch <= '~' && inplen < inpmaxlen)
{
inpbuf[inplen++] = ch;
GotoPos(x, STATLINE);
SaveSetAttr(A_SO, ASCII);
PUTCHAR(ch);
x++;
}
else if ((ch == '\b' || ch == 0177) && inplen > 0)
{
inplen--;
x--;
GotoPos(x, STATLINE);
SaveSetAttr(0, ASCII);
PUTCHAR(' ');
GotoPos(x, STATLINE);
}
else if (ch == '\004' || ch == '\003' || ch == '\000' || ch == '\n' || ch == '\r')
{
if (ch != '\n' && ch != '\r')
inplen = 0;
inpbuf[inplen] = 0;
AbortInp(); /* redisplays... */
(*inpfinfunc)(inpbuf, inplen);
break;
}
}
*ppbuf = pbuf;
*plen = len;
}
static void
AbortInp()
{
in_ovl = 0; /* So we can use RefreshLine() */
RefreshLine(STATLINE, 0, screenwidth-1);
ExitOverlayPage();
}
static void
inpRedisplayLine(y, xs, xe, isblank)
int y, xs, xe, isblank;
{
int q, r, s, l, v;
if (y != STATLINE)
return;
inpbuf[inplen] = 0;
GotoPos(xs,y);
q = xs;
v = xe - xs + 1;
s = 0;
r = inpstringlen;
if (v > 0 && q < r)
{
SaveSetAttr(A_SO, ASCII);
l = v;
if (l > r-q)
l = r-q;
printf("%-*.*s", l, l, inpstring + q - s);
q += l;
v -= l;
}
s = r;
r += inplen;
if (v > 0 && q < r)
{
SaveSetAttr(A_SO, ASCII);
l = v;
if (l > r-q)
l = r-q;
printf("%-*.*s", l, l, inpbuf + q - s);
q += l;
v -= l;
}
s = r;
r = screenwidth;
if (!isblank && v > 0 && q < r)
{
SaveSetAttr(0, ASCII);
l = v;
if (l > r-q)
l = r-q;
printf("%-*.*s", l, l, "");
q += l;
}
SetLastPos(q, y);
}
static void
AKAfin(buf, len)
char *buf;
int len;
{
if (len)
{
strcpy(curr->cmd + curr->akapos, buf);
}
}
void
InputAKA()
{
void Input(), AKAfin();
Input("Set window's a.k.a. to: ", 20, AKAfin);
}
static void
Colonfin(buf, len)
char *buf;
int len;
{
if (len)
RcLine(buf);
}
void
InputColon()
{
void Input(), Colonfin();
Input(":", 100, Colonfin);
}
void
MakeBlankLine(p, n)
register char *p;
register int n;
{
while (n--)
*p++ = ' ';
}
void
MakeStatus(msg)
char *msg;
{
register char *s, *t;
register int max, ti;
SetCurr(fore);
display = 1;
if (!(max = HS))
{
max = !LP ? cols - 1 : cols;
}
if (status)
{
if (!BellDisplayed)
{
ti = time((time_t *) 0) - TimeDisplayed;
if (ti < MsgMinWait)
sleep(MsgMinWait - ti);
}
RemoveStatus();
}
for (s = t = msg; *s && t - msg < max; ++s)
if (*s == BELL)
PutStr(BL);
else if (*s >= ' ' && *s <= '~')
*t++ = *s;
*t = '\0';
if (t > msg)
{
strncpy(LastMsg, msg, maxwidth);
status = 1;
status_lastx = screenx;
status_lasty = screeny;
StatLen = t - msg;
if (!HS)
{
GotoPos(0, STATLINE);
SaveSetAttr(A_SO, ASCII);
InsertMode(0);
printf("%s", msg);
screenx = -1;
}
else
{
debug("HS:");
SaveSetAttr(0, ASCII);
InsertMode(0);
CPutStr(TS, 0);
printf("%s", msg);
PutStr(FS);
}
(void) fflush(stdout);
(void) time(&TimeDisplayed);
}
}
void
RemoveStatus()
{
if (!status)
return;
status = 0;
BellDisplayed = 0;
SetCurr(fore);
display = 1;
if (!HS)
{
GotoPos(0, STATLINE);
if (in_ovl)
(*ovl_RedisplayLine)(STATLINE, 0, StatLen - 1, 0);
else
RedisplayLine(null, null, null, STATLINE, 0, StatLen - 1);
GotoPos(status_lastx, status_lasty);
}
else
{
SaveSetAttr(0, ASCII);
PutStr(DS);
}
}
void
ClearDisplay()
{
PutStr(CL);
screeny = screenx = 0;
fflush(stdout);
}
static void SetCurr(wp)
struct win *wp;
{
curr = wp;
cols = curr->width;
rows = curr->height;
display = curr->active;
}
void
InitOverlayPage(pro, red, rewrite, blockfore)
void (*pro)();
void (*red)();
int (*rewrite)();
int blockfore;
{
RemoveStatus();
SetOvlCurr();
ChangeScrollRegion(0, screenheight - 1);
SetFlow(1);
ovl_process = pro;
ovl_RedisplayLine = red;
ovl_Rewrite = rewrite;
ovl_blockfore = blockfore;
curr->active = 0;
in_ovl = 1;
}
void
ExitOverlayPage()
{
ChangeScrollRegion(curr->top, curr->bot);
GotoPos(curr->x, curr->y);
RestoreAttr();
SetFlow(curr->flow & FLOW_NOW);
curr->active = 1;
in_ovl = 0;
}
void
SetOvlCurr()
{
SetCurr(fore);
SaveSetAttr(0, ASCII);
InsertMode(0);
display = 1;
}
void
SetLastPos(x,y)
int x,y;
{
screenx = x;
screeny = y;
}
void
WSresize(width, height)
int width, height;
{
debug2("(display=%d:WSresize says:'%s'\n", display, tgoto(WS, width, height));
PutStr(tgoto(WS, width, height));
}
void
ChangeScrollRegion(top, bot)
int top, bot;
{
if (display == 0)
return;
if (CS == 0)
{
screentop = 0;
screenbot = screenheight - 1;
return;
}
if (top == screentop && bot == screenbot)
return;
debug2("ChangeScrollRegion: (%d - %d)\n", top, bot);
PutStr(tgoto(CS, bot, top));
screentop = top;
screenbot = bot;
screeny = screenx = -1; /* Just in case... */
}
void AddLineToHist(wp, pi, pa, pf)
struct win *wp;
char **pi, **pa, **pf;
{
register char *q;
if (wp->histheight == 0)
return;
q = *pi; *pi = wp->ihist[wp->histidx]; wp->ihist[wp->histidx] = q;
q = *pa; *pa = wp->ahist[wp->histidx]; wp->ahist[wp->histidx] = q;
q = *pf; *pf = wp->fhist[wp->histidx]; wp->fhist[wp->histidx] = q;
if (++wp->histidx >= wp->histheight)
wp->histidx = 0;
}
/*
*
* Termcap routines that use our extra_incap
*
*/
/* findcap:
* cap = capability we are looking for
* tepp = pointer to bufferpointer
* n = size of buffer (0 = infinity)
*/
char *
findcap(cap, tepp, n)
char *cap;
char **tepp;
int n;
{
char *tep;
char c, *p, *cp;
int mode; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
int num = 0, capl;
if (!extra_incap)
return (0);
tep = *tepp;
capl = strlen(cap);
cp = 0;
mode = 0;
for (p = extra_incap; *p; )
{
if (strncmp(p, cap, capl) == 0)
{
p+=capl;
c = *p;
if (c && c != ':' && c != '@')
p++;
if (c == 0 || c == '@' || c == '=' || c == ':' || c == '#')
cp = tep;
}
while (c = *p)
{
p++;
if (mode == 0)
{
if (c == ':')
break;
if (c == '^')
mode = 1;
if (c == '\\')
mode = 2;
}
else if (mode == 1)
{
c = c & 0x1f;
mode = 0;
}
else if (mode == 2)
{
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
mode = 3;
num = 0;
break;
case 'E':
c = 27;
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
}
if (mode == 2)
mode = 0;
}
if (mode > 2)
{
num = num * 8 + (c - '0');
if (mode++ == 5 || (*p < '0' || *p > '9'))
{
c = num;
mode = 0;
}
}
if (mode)
continue;
if (cp && n != 1)
{
*cp++ = c;
n--;
}
}
if (cp)
{
*cp++ = 0;
*tepp = cp;
debug2("'%s' found in extra_incap -> %s\n", cap, tep);
return(tep);
}
}
return(0);
}
static char *
e_tgetstr(cap, tepp)
char *cap;
char **tepp;
{
char *tep;
if (tep = findcap(cap, tepp, 0))
return((*tep == '@') ? 0 : tep);
return (tgetstr(cap, tepp));
}
static int
e_tgetflag(cap)
char *cap;
{
char buf[2], *bufp;
char *tep;
bufp = buf;
if (tep = findcap(cap, &bufp, 2))
return((*tep == '@') ? 0 : 1);
return (tgetflag(cap));
}
static int
e_tgetnum(cap)
char *cap;
{
char buf[20], *bufp;
char *tep, c;
int res, base = 10;
bufp = buf;
if (tep = findcap(cap, &bufp, 20))
{
c = *tep;
if (c == '@')
return(-1);
if (c == '0')
base = 8;
res = 0;
while ((c = *tep++) >= '0' && c <= '9')
res = res * base + (c - '0');
return(res);
}
return (tgetnum(cap));
}