* 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
* 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)
****************************************************************
static char rcs_id
[] = "$Id: ansi.c,v 1.2 92/02/03 02:27:30 jnweiger Exp $ FAU";
#ifndef sun /* we want to know about TIOCGWINSZ. jw. */
extern char *getenv(), *tgetstr(), *tgoto();
extern force_vt
, assume_LP
;
extern int BellDisplayed
;
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 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
;
char *blank
, *null
, *LastMsg
;
char Term
[MAXSTR
+5]; /* +5: "TERM=" */
char screenterm
[20] = "screen";
time_t TimeDisplayed
, time();
* the termcap routines need this to work
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 *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
];
* 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
;
char *OldImage
, *OldAttr
, *OldFont
;
static UPcost
, DOcost
, LEcost
, NDcost
, CRcost
, IMcost
, EIcost
, NLcost
;
void (*ovl_RedisplayLine
)();
"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:";
if ((s
= getenv("SCREENCAP")) != 0)
if ((Termcap
= malloc(strlen(s
) + 10)) != 0)
sprintf(Termcap
, "TERMCAP=%s", s
);
Termcap
= malloc((unsigned) 1024);
tbuf
= malloc((unsigned) 1024);
tentry
= tp
= malloc((unsigned) 1024);
if (!(Termcap
&& tbuf
&& tentry
))
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
);
debug1("Extra incap: %s\n", extra_incap
);
debug1("Extra outcap: %s\n", extra_outcap
);
TermcapCOLS
= TermcapROWS
= 0;
if (s
= getenv("COLUMNS"))
TermcapCOLS
= e_tgetnum("co");
TermcapROWS
= e_tgetnum("li");
Msg(0, "You can't run screen on a hardcopy terminal.");
Msg(0, "You can't run screen on a terminal that overstrikes.");
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.");
default_flow
= e_tgetflag("NF") ? FLOW_NOW
* 0 :
e_tgetflag("xo") ? FLOW_NOW
* 1 :
LP
= assume_LP
|| (!extra_incap
&& !strncmp(termname
, "vt", 2))
|| !AM
|| e_tgetflag("LP") || e_tgetflag("xv");
HO
= e_tgetstr("ho", &tp
);
TI
= e_tgetstr("ti", &tp
);
TE
= e_tgetstr("te", &tp
);
if (!(BL
= e_tgetstr("bl", &tp
)))
VB
= e_tgetstr("vb", &tp
);
if (!(BC
= e_tgetstr("bc", &tp
)))
BC
= e_tgetstr("le", &tp
);
if (!(CR
= e_tgetstr("cr", &tp
)))
if (!(NL
= e_tgetstr("nl", &tp
)))
IS
= e_tgetstr("is", &tp
);
if (e_tgetnum("sg") <= 0 && e_tgetnum("ug") <= 0)
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)))
if (SE
&& (ME
&& strcmp(ME
, SE
) == 0))
/* Set up missing entries */
for (i
= NATTR
-1; i
>= 0; i
--)
for (i
= 0; i
< NATTR
; i
++)
US
= UE
= SO
= SE
= MB
= MD
= MH
= MR
= ME
= 0;
for (i
= 0; i
< NATTR
; i
++)
CE
= e_tgetstr("ce", &tp
);
CD
= e_tgetstr("cd", &tp
);
if (!(DO
= e_tgetstr("do", &tp
)))
UP
= e_tgetstr("up", &tp
);
ND
= e_tgetstr("nd", &tp
);
SR
= e_tgetstr("sr", &tp
);
if (!(SF
= e_tgetstr("sf", &tp
)))
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 (CIC
&& CIC
[0] == '\0')
if (IC
&& IM
&& strcmp(IC
, IM
) == 0)
KS
= e_tgetstr("ks", &tp
);
KE
= e_tgetstr("ke", &tp
);
ISO2022
= e_tgetflag("G0");
if ((S0
= e_tgetstr("S0", &tp
)) == NULL
)
if ((E0
= e_tgetstr("E0", &tp
)) == NULL
)
C0
= e_tgetstr("C0", &tp
);
else if ((S0
= e_tgetstr("as", &tp
)) != NULL
&& (E0
= e_tgetstr("ae", &tp
)) != NULL
)
C0
= e_tgetstr("ac", &tp
);
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
++)
for (i
= strlen(C0
)&~1; i
>= 0; i
-=2)
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
)))
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
)
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)
for (i
= 0; i
< NKEYCAPS
; i
++)
KeyCapsArr
[i
] = e_tgetstr(KeyCaps
[i
], &tp
);
* if the adaptflag is on, we keep the size of this display, else
* we may try to restore our old window sizes.
screentop
= screenbot
= -1;
if (IM
&& strcmp(IM
, EI
))
if (KS
&& strcmp(KS
, KE
))
ResizeScreen((struct win
*)0);
ChangeScrollRegion(0, screenheight
-1);
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);
ResizeScreen((struct win
*)0);
ChangeScrollRegion(0, screenheight
- 1);
GotoPos(0, screenheight
- 1);
debug("FinitTerm: old termcap freed\n");
debug("FinitTerm: old tbuf freed\n");
debug("FinitTerm: old tentry freed\n");
if (tcLineLen
+ (n
= strlen(s
)) > 55 && Termcaplen
< 1024-4)
strcpy(Termcap
+ Termcaplen
, "\\\n\t:");
if (Termcaplen
+ n
< 1024)
strcpy(Termcap
+ Termcaplen
, s
);
Msg(0, "TERMCAP overflow - sorry.");
register char *p
, *cp
, ch
;
sprintf(Term
, "TERM=screen");
if (screenterm
== 0 || *screenterm
== '\0')
debug("MakeTermcap sets screenterm=screen\n");
strcpy(screenterm
, "screen");
if (!aflag
&& strlen(screenterm
) + strlen(termname
) < MAXSTR
-1)
sprintf(p
, "%s.%s", screenterm
, termname
);
if (tgetent(buf
, p
) == 1)
sprintf(p
, "%s-w", screenterm
);
if (tgetent(buf
, p
) == 1)
sprintf(p
, "%s", screenterm
);
if (tgetent(buf
, p
) == 1)
tcLineLen
= 100; /* Force NL */
"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
)
tcLineLen
= 100; /* Force NL */
if (Termcaplen
+ strlen(TermcapConst
) < 1024)
strcpy(Termcap
+ Termcaplen
, TermcapConst
);
Termcaplen
+= strlen(TermcapConst
);
sprintf(buf
, "li#%d:co#%d:", screenheight
, screenwidth
);
if ((force_vt
&& !COP
) || LP
|| !AM
)
AddCap("vb=\\E[?5h\\E[?5l:");
if (MB
|| MD
|| MH
|| MR
)
if ((CS
&& SR
) || AL
|| CAL
|| aflag
)
if (CS
|| DL
|| CDL
|| aflag
)
AddCap("cs=\\E[%i%d;%dr:");
if (CIC
|| IC
|| IM
|| aflag
)
AddCap("WS=\\E[8;%d;%dt:");
for (i
= 0; i
< NKEYCAPS
; i
++)
MakeString(KeyCaps
[i
], buf
, sizeof(buf
), KeyCapsArr
[i
]);
static void MakeString(cap
, buf
, buflen
, s
)
pmax
= p
+ buflen
- (3+4+2);
while ((c
= *s
++) && (p
< pmax
))
sprintf(p
, "\\%03o", c
& 0377);
debug1("Activate(%d)\n", norefresh
);
display
= fore
->active
= 1;
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
)
Redisplay(norefresh
|| all_norefresh
);
bzero(p
->tabs
, p
->width
);
for (i
= 8; i
< p
->width
; i
+= 8)
for (i
= G0
; i
<= G3
; i
++)
WriteString(wp
, buf
, len
)
register int c
, intermediate
= 0;
if ((int)fwrite(buf
, len
, 1, wp
->logfp
) < 1)
Msg(errno
, "Error writing logfile");
* SetCurr() here may prevent output, as it may set display = 0
else if (curr
->monitor
== MON_ON
)
curr
->monitor
= MON_FOUND
;
c
= (unsigned char)*buf
++;
if (c
== '\0' || c
== '\177')
switch (curr
->StringType
)
MakeStatus(curr
->string
);
if (!HS
&& status
&& len
> 1)
bcopy(buf
, curr
->outbuf
, curr
->outlen
);
printf("%s", curr
->string
);
if (curr
->akapos
== 0 && !*curr
->string
)
strncpy(curr
->cmd
+ curr
->akapos
, curr
->string
, 20);
curr
->autoaka
= curr
->y
+ 1;
bzero((char *) curr
->args
, MAXARGS
* sizeof(int));
if (c
>= ' ' && c
<= '/')
intermediate
= intermediate
? -1 : c
;
else if (c
>= '0' && c
<= '~')
if (curr
->NumArgs
< MAXARGS
)
curr
->args
[curr
->NumArgs
] =
10 * curr
->args
[curr
->NumArgs
] + c
- '0';
if (c
>= '@' && c
<= '~')
else if ((c
>= ' ' && c
<= '/') || (c
>= '<' && c
<= '?'))
intermediate
= intermediate
? -1 : c
;
if (display
&& lp_missing
&& (CIC
|| IC
|| IM
))
RedisplayLine(blank
, null
, null
, screenbot
,
GotoPos(curr
->x
, curr
->y
);
NewRendition(curr
->LocalAttr
);
NewCharset(curr
->charsets
[(curr
->ss
) ? curr
->ss
:
else if (curr
->x
== cols
- 1)
if (curr
->wrap
&& (LP
|| !force_vt
|| COP
))
curr
->x
= 0; /* terminal auto-wrapped */
if (LP
|| curr
->y
!= screenbot
)
GotoPos(curr
->x
, curr
->y
);
LineFeed(2); /* cr+lf, handle LP */
NewCharset(curr
->charsets
[curr
->LocalCharset
]);
curr
->bell
= BELL_VISUAL
;
static void DoESC(c
, intermediate
)
case 'Z': /* jph: Identify as VT100 */
Report(curr
, "\033[?%d;%dc", 1, 2);
ChangeScrollRegion(0, rows
-1);
KeypadMode(curr
->keypad
= 1);
#if !defined(TIOCPKT) || defined(sgi)
#endif /* !TIOCPKT || sgi */
KeypadMode(curr
->keypad
= 0);
#if !defined(TIOCPKT) || defined(sgi)
#endif /* !TIOCPKT || sgi */
if (curr
->charsets
[curr
->LocalCharset
] != curr
->charsets
[G2
])
if (curr
->charsets
[curr
->LocalCharset
] != curr
->charsets
[G3
])
static void DoCSI(c
, intermediate
)
register int i
, a1
= curr
->args
[0], a2
= curr
->args
[1];
if (curr
->NumArgs
> MAXARGS
)
GotoPos(curr
->x
, curr
->y
);
CursorRight(a1
? a1
: 1);
if (a1
< 1 || a2
> rows
|| a1
>= a2
)
ChangeScrollRegion(curr
->top
, curr
->bot
);
if (Z0
== NULL
|| (a1
!= Z0width
&& a1
!= Z1width
))
if (a1
== curr
->width
&& a2
== curr
->height
)
ChangeWindowSize(curr
, a1
, a2
);
curr
->stringp
= curr
->string
;
if (a1
== 6) /* Report cursor position */
Report(curr
, "\033[%d;%dR", curr
->y
+ 1, curr
->x
+ 1);
case 'c': /* Identify as VT100 */
Report(curr
, "\033[?%d;%dc", 1, 2);
debug2("\\E[?%d%c\n",a1
,c
);
if (c
!= 'h' && c
!= 'l')
i
= (i
? Z0width
: Z1width
);
if ((Z0
|| WS
) && curr
->width
!= i
)
ChangeWindowSize(curr
, i
, curr
->height
);
if ((curr
->origin
= i
) != 0)
debug1("Cursor %svisible\n", i
?"in":"");
curr
->cursor_invisible
= i
;
if (!insert
&& (IC
|| CIC
))
RefreshLine(screeny
, screenx
, screenwidth
-1);
* RAW_PUTCHAR() is for all text that will be displayed.
* NOTE, that charset Nr. 0 has a conversion table, but c1, c2, ... don't.
if (GlobalCharset
== '0')
if (screenx
< screenwidth
- 1)
if ((AM
&& !LP
) || screenx
> screenwidth
)
if (screeny
< screenheight
-1 && screeny
!= screenbot
)
/* this PutChar for ESC-sequences only */
static void CPutStr(s
, c
)
tputs(tgoto(s
, 0, c
), 1, PutChar
);
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
)
curr
->stringp
= curr
->string
;
if (curr
->stringp
>= curr
->string
+ MAXSTR
- 1)
if (curr
->stringp
>= curr
->string
+ MAXSTR
- 1)
if (curr
->stringp
> curr
->string
)
(void) write(1, curr
->string
, curr
->stringp
- curr
->string
);
curr
->stringp
= curr
->string
;
/* Insert mode is a toggle on some terminals, so we need this hack:
if (display
&& on
!= insert
&& IM
)
/* ...and maybe keypad application mode is a toggle, too:
static void KeypadMode(on
)
if (display
&& keypad
!= on
&& KS
)
debug1("NewAutoFlow: %d\n", on
);
if (win
->flow
& FLOW_AUTOFLAG
)
win
->flow
= FLOW_AUTOFLAG
| (FLOW_AUTO
|FLOW_NOW
) * on
;
win
->flow
= (win
->flow
& ~FLOW_AUTO
) | FLOW_AUTO
* on
;
SetFlow(win
->flow
& FLOW_NOW
);
static void DesignateCharset(c
, n
)
if (curr
->charsets
[n
] != c
)
if (curr
->LocalCharset
== n
)
static void MapCharset(n
)
if (curr
->LocalCharset
!= n
)
NewCharset(curr
->charsets
[n
]);
if (!display
|| GlobalCharset
== new)
curr
->SavedLocalAttr
= curr
->LocalAttr
;
curr
->SavedLocalCharset
= curr
->LocalCharset
;
bcopy((char *) curr
->charsets
, (char *) curr
->SavedCharsets
,
static void RestoreCursor()
GotoPos(curr
->Saved_x
, curr
->Saved_y
);
curr
->LocalAttr
= curr
->SavedLocalAttr
;
NewRendition(curr
->LocalAttr
);
bcopy((char *) curr
->SavedCharsets
, (char *) curr
->charsets
,
curr
->LocalCharset
= curr
->SavedLocalCharset
;
NewCharset(curr
->charsets
[curr
->LocalCharset
]);
static void CountChars(c
)
register int dy
, dx
, x1
, y1
;
register int costx
, costy
;
enum move_t xm
= M_NONE
, ym
= M_NONE
;
x1
= -1; /* don't know how the terminal treats this */
if (!MS
&& GlobalAttr
) /* Safe to move in SO mode ? */
if (y1
< 0 /* don't know the y position */
|| (y2
> screenbot
&& y1
<= screenbot
) /* have to cross border */
|| (y2
< screentop
&& y1
>= screentop
)) /* of scrollregion ? */
PutStr(tgoto(CM
, x2
, y2
));
/* Calculate the cost to move the cursor to the right x position */
if (x1
>= 0) /* relativ x positioning only if we know where we are */
if (CRI
&& (dx
> 1 || !ND
))
costx
= CalcCost(tgoto(CRI
, 0, dx
));
if ((m
= NDcost
* dx
) < costx
)
/* Speedup: dx <= Rewrite() */
if (dx
< costx
&& (m
= Rewrite(y1
, x1
, x2
, 0)) < costx
)
if (CLE
&& (dx
< -1 || !BC
))
costx
= CalcCost(tgoto(CLE
, 0, -dx
));
if ((m
= -dx
* LEcost
) < costx
)
/* Speedup: Rewrite() >= x2 */
if (x2
+ CRcost
< costx
&& (m
= Rewrite(y1
, 0, x2
, 0) + CRcost
) < costx
)
/* Check if it is already cheaper to do CM */
/* Calculate the cost to move the cursor to the right y position */
if (CDO
&& dy
> 1) /* DO & NL are always != 0 */
costy
= CalcCost(tgoto(CDO
, 0, dy
));
if ((m
= dy
* ((x2
== 0) ? NLcost
: DOcost
)) < costy
)
if (CUP
&& (dy
< -1 || !UP
))
costy
= CalcCost(tgoto(CUP
, 0, -dy
));
if ((m
= -dy
* UPcost
) < costy
)
/* Finally check if it is cheaper to do CM */
if (costx
+ costy
>= CMcost
)
(void) Rewrite(y1
, x1
, x2
, 1);
register char *p
, *f
, *i
;
return ((*ovl_Rewrite
)(y
, x1
, x2
, doit
));
if (*p
++ != GlobalAttr
|| *f
++ != GlobalCharset
)
else if (curr
->wrap
&& curr
->y
> 0)
GotoPos(curr
->x
, curr
->y
);
GotoPos(curr
->x
, curr
->y
);
static void LineFeed(out_mode
)
/* out_mode: 0=no-output lf, 1=lf, 2=cr+lf */
if (curr
->y
!= curr
->bot
) /* Don't scroll */
GotoPos(curr
->x
, curr
->y
);
ScrollRegion(curr
->top
, curr
->bot
, 1);
GotoPos(curr
->x
, curr
->y
);
static void ReverseLineFeed()
if (curr
->y
== curr
->top
)
ScrollRegion(curr
->top
, curr
->bot
, -1);
GotoPos(curr
->x
, curr
->y
);
static void InsertAChar(c
)
register int y
= curr
->y
, x
= curr
->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);
InsertMode(curr
->insert
);
RedisplayLine(OldImage
, OldAttr
, OldFont
, y
, x
, cols
- 1);
static void InsertChar(n
)
register int i
, y
= curr
->y
, x
= curr
->x
;
* 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 ?)
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
+ 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);
RedisplayLine(OldImage
, OldAttr
, OldFont
, y
, x
, cols
- 1);
static void DeleteChar(n
)
register int i
, y
= curr
->y
, x
= curr
->x
;
bcopy(curr
->image
[y
], OldImage
, cols
);
bcopy(curr
->attr
[y
], OldAttr
, cols
);
bcopy(curr
->font
[y
], OldFont
, cols
);
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 (CDC
&& !(n
== 1 && DC
))
if (lp_missing
&& y
== screenbot
)
if (lp_missing
&& y
== screenbot
)
RedisplayLine(OldImage
, OldAttr
, OldFont
, y
, x
, cols
- 1);
static void DeleteLine(n
)
register int old
= curr
->top
;
if (curr
->y
< curr
->top
|| curr
->y
> curr
->bot
)
if (n
> curr
->bot
- curr
->y
+ 1)
n
= curr
->bot
- curr
->y
+ 1;
ScrollRegion(curr
->y
, curr
->bot
, n
);
GotoPos(curr
->x
, curr
->y
);
static void InsertLine(n
)
register int old
= curr
->top
;
if (curr
->y
< curr
->top
|| curr
->y
> curr
->bot
)
if (n
> curr
->bot
- curr
->y
+ 1)
n
= curr
->bot
- curr
->y
+ 1;
ScrollRegion(curr
->y
, curr
->bot
, -n
);
GotoPos(curr
->x
, curr
->y
);
int alok
, dlok
, aldlfaster
;
if (ys
== 0 && ye
== screenheight
-1 &&
(n
>= screenheight
|| -n
>= screenheight
))
if (screenbot
>ye
|| screenbot
<ys
)
if (missy
>ye
|| missy
<ys
)
ChangeScrollRegion(ys
, ye
);
alok
= (AL
|| CAL
|| (ye
== screenbot
&& up
));
dlok
= (DL
|| CDL
|| (ye
== screenbot
&& !up
));
if (screentop
!= ys
&& !(alok
&& dlok
))
ChangeScrollRegion(ys
, ye
);
(oldbot
== screenbot
&& up
&& screentop
== ys
&& screenbot
== ye
)))
GotoPos(screenwidth
-1, oldbot
);
SaveSetAttr(curr
->attr
[missy
][screenwidth
-1], curr
->font
[missy
][screenwidth
-1]);
PUTCHAR(curr
->image
[missy
][screenwidth
-1]);
if (oldbot
== screenbot
) /* have scrolled */
ChangeScrollRegion(oldtop
, oldbot
);
aldlfaster
= (n
> 1 && ye
== screenbot
&& ((up
&& CDL
) || (!up
&& CAL
)));
if ((up
|| SR
) && screentop
== ys
&& screenbot
== ye
&& !aldlfaster
)
PutStr(NL
); /* was SF, I think NL is faster */
if (up
|| ye
!= screenbot
)
GotoPos(0, up
? ys
: ye
+1-n
);
if (CDL
&& !(n
== 1 && DL
))
if (!up
|| ye
!= screenbot
)
GotoPos(0, up
? ye
+1-n
: ys
);
if (CAL
&& !(n
== 1 && AL
))
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
)
char tmp
[256 * sizeof(char *)];
register int ii
, i
, cnt1
, cnt2
;
register char **ppi
, **ppa
, **ppf
;
cnt1
= n
* sizeof(char *);
cnt2
= (curr
->bot
- i
+ 1) * sizeof(char *);
for(ii
= curr
->top
; ii
< i
; ii
++)
AddLineToHist(curr
, &curr
->image
[ii
], &curr
->attr
[ii
], &curr
->font
[ii
]);
Scroll((char *) ppi
, cnt1
, cnt2
, tmp
);
Scroll((char *) ppa
, cnt1
, cnt2
, tmp
);
Scroll((char *) ppf
, cnt1
, cnt2
, tmp
);
static void ScrollDownMap(n
)
char tmp
[256 * sizeof(char *)];
register int i
, cnt1
, cnt2
;
register char **ppi
, **ppa
, **ppf
;
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
);
static void Scroll(cp
, cnt1
, cnt2
, tmp
)
bcopy(cp
+ cnt1
, cp
, cnt2
);
bcopy(tmp
, cp
+ cnt2
, cnt1
);
bcopy(cp
+ cnt1
, tmp
, cnt2
);
bcopy(cp
, cp
+ cnt2
, cnt1
);
register int x
= curr
->x
;
if (curr
->tabs
[x
] && x
< cols
- 1)
while (x
< cols
- 1 && !curr
->tabs
[x
])
static void BackwardTab()
register int x
= curr
->x
;
if (curr
->tabs
[x
] && x
> 0)
while (x
> 0 && !curr
->tabs
[x
])
static void ClearScreen()
register char **ppi
= curr
->image
, **ppa
= curr
->attr
, **ppf
= curr
->font
;
for (i
= 0; i
< rows
; ++i
)
AddLineToHist(curr
, ppi
, ppa
, ppf
);
static void ClearFromBOS()
register int n
, y
= curr
->y
, x
= curr
->x
;
ClearInLine(1, n
, 0, cols
- 1);
register int n
, y
= curr
->y
, x
= curr
->x
;
ClearInLine(!CD
, y
, x
, cols
- 1);
for (n
= y
+ 1; n
< rows
; n
++)
ClearInLine(!CD
, n
, 0, cols
- 1);
register int y
= curr
->y
, x
= curr
->x
;
ClearInLine(1, y
, 0, cols
- 1);
register int y
= curr
->y
, x
= curr
->x
;
ClearInLine(1, y
, x
, cols
- 1);
static void ClearFromBOL()
register int y
= curr
->y
, x
= curr
->x
;
static void ClearInLine(displ
, y
, x1
, x2
)
if ((n
= x2
- x1
+ 1) != 0)
if (x2
== cols
- 1 && CE
)
DisplayLine(curr
->image
[y
], curr
->attr
[y
], curr
->font
[y
],
blank
, null
, null
, y
, x1
, x2
);
bclear(curr
->image
[y
] + x1
, n
);
bzero(curr
->attr
[y
] + x1
, n
);
bzero(curr
->font
[y
] + x1
, n
);
static void CursorRight(n
)
register int x
= curr
->x
;
if ((curr
->x
+= n
) >= cols
)
GotoPos(curr
->x
, curr
->y
);
if (curr
->y
< curr
->top
) /* if above scrolling rgn, */
if ((curr
->y
-= n
) < 0) /* ignore its limits */
if ((curr
->y
-= n
) < curr
->top
)
GotoPos(curr
->x
, curr
->y
);
static void CursorDown(n
)
if (curr
->y
> curr
->bot
) /* if below scrolling rgn, */
if ((curr
->y
+= n
) > rows
- 1) /* ignore its limits */
if ((curr
->y
+= n
) > curr
->bot
)
GotoPos(curr
->x
, curr
->y
);
static void CursorLeft(n
)
GotoPos(curr
->x
, curr
->y
);
for (i
= 0; i
< curr
->NumArgs
; ++i
)
static void SelectRendition()
register int i
= 0, a
= curr
->LocalAttr
;
a
&= ~(A_BD
| A_SO
| A_DI
);
} while (++i
< curr
->NumArgs
);
NewRendition(curr
->LocalAttr
= a
);
register int i
, old
= GlobalAttr
;
if (!display
|| old
== new)
for (i
= 1; i
<= A_MAX
; i
<<= 1)
if ((old
& i
) && !(new & i
))
PutStr(attrtab
[ATTR_DI
]);
PutStr(attrtab
[ATTR_US
]);
PutStr(attrtab
[ATTR_BD
]);
PutStr(attrtab
[ATTR_RV
]);
PutStr(attrtab
[ATTR_SO
]);
PutStr(attrtab
[ATTR_BL
]);
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
]);
SaveSetAttr(newattr
, newcharset
)
NewRendition(curr
->LocalAttr
);
NewCharset(curr
->charsets
[curr
->LocalCharset
]);
for (i
= 0; i
< rows
; ++i
)
bzero(curr
->attr
[i
], cols
);
bzero(curr
->font
[i
], cols
);
* if cur_only, we only redisplay current line, as a full refresh is
(*ovl_RedisplayLine
)(i
, 0, cols
- 1, 1);
DisplayLine(blank
, null
, null
, curr
->image
[i
], curr
->attr
[i
],
curr
->font
[i
], i
, 0, cols
- 1);
GotoPos(curr
->x
, curr
->y
);
NewRendition(curr
->LocalAttr
);
NewCharset(curr
->charsets
[curr
->LocalCharset
]);
DisplayLine(os
, oa
, of
, s
, as
, fs
, y
, from
, to
)
register char *os
, *oa
, *of
, *s
, *as
, *fs
;
int last2flag
= 0, delete_lp
= 0;
if (!LP
&& y
== screenbot
&& to
== cols
- 1)
|| s
[to
] != os
[to
] || as
[to
] != oa
[to
] || of
[to
] != fs
[to
])
if ((IC
|| IM
) && (from
< to
|| !in_ovl
))
if ((to
-= 2) < from
- 1)
delete_lp
= (CE
|| DC
|| CDC
);
lp_missing
= (s
[to
] != ' ' || as
[to
] || fs
[to
]);
for (x
= from
; x
<= to
; ++x
)
if (s
[x
] == os
[x
] && as
[x
] == oa
[x
] && of
[x
] == fs
[x
])
if (CE
&& to
== screenwidth
-1)
(*ovl_RedisplayLine
)(y
, from
, to
, (oi
== blank
));
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
)
DisplayLine(os
, oa
, of
, curr
->image
[y
], curr
->attr
[y
],
curr
->font
[y
], y
, from
, to
);
NewRendition(curr
->LocalAttr
);
NewCharset(curr
->charsets
[curr
->LocalCharset
]);
register struct win
*p
= curr
;
SaveSetAttr(p
->attr
[y2
][x2
], p
->font
[y2
][x2
]);
PUTCHAR(p
->image
[y2
][x2
]);
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
];
n_fo
= curr
->charsets
[curr
->LocalCharset
];
if (n_ch
== o_ch
&& n_at
== o_at
&& n_fo
== o_fo
)
if (n_ch
!= ' ' || n_at
|| n_fo
)
if (o_ch
!= ' ' || o_at
|| o_fo
)
register char *cp
, *line
, ch
;
register struct win
*wp
= curr
;
register int len
= strlen(wp
->cmd
);
y
= (wp
->autoaka
> 0 && wp
->autoaka
<= wp
->height
) ? wp
->autoaka
- 1 : wp
->y
;
cp
= line
= wp
->image
[y
];
if (wp
->autoaka
> 0 && (ch
= *wp
->cmd
) != '\0')
if ((cp
= index(cp
, ch
)) != NULL
&& !strncmp(cp
, wp
->cmd
, len
))
if (!cp
|| ++cp
- line
>= cols
- len
)
if (++y
== wp
->autoaka
&& y
< rows
)
for (len
= cols
- (cp
- line
); len
&& *cp
== ' '; len
--, cp
++)
if (wp
->autoaka
> 0 && (*cp
== '!' || *cp
== '%' || *cp
== '^'))
line
= wp
->cmd
+ wp
->akapos
;
while (len
&& *cp
!= ' ')
if ((*line
++ = *cp
++) == '/')
line
= wp
->cmd
+ wp
->akapos
;
/* 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
static void (*inpfinfunc
)();
Input(istr
, len
, finfunc
)
inpstringlen
= strlen(istr
);
maxlen
= screenwidth
- inpstringlen
;
if (!LP
&& STATLINE
== screenbot
)
Msg(0, "Width too small");
InitOverlayPage(process_inp_input
, inpRedisplayLine
, (int (*)())0, 1);
DisplayLine(curr
->image
[screeny
], curr
->attr
[screeny
],
blank
, null
, null
, screeny
, 0, cols
- 1);
inpRedisplayLine(STATLINE
, 0, inpstringlen
- 1, 0);
GotoPos(inpstringlen
, STATLINE
);
process_inp_input(ppbuf
, plen
)
if (ch
>= ' ' && ch
<= '~' && inplen
< inpmaxlen
)
SaveSetAttr(A_SO
, ASCII
);
else if ((ch
== '\b' || ch
== 0177) && inplen
> 0)
else if (ch
== '\004' || ch
== '\003' || ch
== '\000' || ch
== '\n' || ch
== '\r')
if (ch
!= '\n' && ch
!= '\r')
AbortInp(); /* redisplays... */
(*inpfinfunc
)(inpbuf
, inplen
);
in_ovl
= 0; /* So we can use RefreshLine() */
RefreshLine(STATLINE
, 0, screenwidth
-1);
inpRedisplayLine(y
, xs
, xe
, isblank
)
SaveSetAttr(A_SO
, ASCII
);
printf("%-*.*s", l
, l
, inpstring
+ q
- s
);
SaveSetAttr(A_SO
, ASCII
);
printf("%-*.*s", l
, l
, inpbuf
+ q
- s
);
if (!isblank
&& v
> 0 && q
< r
)
printf("%-*.*s", l
, l
, "");
strcpy(curr
->cmd
+ curr
->akapos
, buf
);
Input("Set window's a.k.a. to: ", 20, AKAfin
);
void Input(), Colonfin();
Input(":", 100, Colonfin
);
max
= !LP
? cols
- 1 : cols
;
ti
= time((time_t *) 0) - TimeDisplayed
;
for (s
= t
= msg
; *s
&& t
- msg
< max
; ++s
)
else if (*s
>= ' ' && *s
<= '~')
strncpy(LastMsg
, msg
, maxwidth
);
SaveSetAttr(A_SO
, ASCII
);
(void) time(&TimeDisplayed
);
(*ovl_RedisplayLine
)(STATLINE
, 0, StatLen
- 1, 0);
RedisplayLine(null
, null
, null
, STATLINE
, 0, StatLen
- 1);
GotoPos(status_lastx
, status_lasty
);
InitOverlayPage(pro
, red
, rewrite
, blockfore
)
ChangeScrollRegion(0, screenheight
- 1);
ovl_blockfore
= blockfore
;
ChangeScrollRegion(curr
->top
, curr
->bot
);
GotoPos(curr
->x
, curr
->y
);
SetFlow(curr
->flow
& FLOW_NOW
);
debug2("(display=%d:WSresize says:'%s'\n", display
, tgoto(WS
, width
, height
));
PutStr(tgoto(WS
, width
, height
));
ChangeScrollRegion(top
, bot
)
screenbot
= screenheight
- 1;
if (top
== screentop
&& bot
== screenbot
)
debug2("ChangeScrollRegion: (%d - %d)\n", top
, bot
);
PutStr(tgoto(CS
, bot
, top
));
screeny
= screenx
= -1; /* Just in case... */
void AddLineToHist(wp
, pi
, pa
, pf
)
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
)
* Termcap routines that use our extra_incap
* cap = capability we are looking for
* tepp = pointer to bufferpointer
* n = size of buffer (0 = infinity)
int mode
; /* mode: 0=LIT 1=^ 2=\x 3,4,5=\nnn */
for (p
= extra_incap
; *p
; )
if (strncmp(p
, cap
, capl
) == 0)
if (c
&& c
!= ':' && c
!= '@')
if (c
== 0 || c
== '@' || c
== '=' || c
== ':' || c
== '#')
num
= num
* 8 + (c
- '0');
if (mode
++ == 5 || (*p
< '0' || *p
> '9'))
debug2("'%s' found in extra_incap -> %s\n", cap
, tep
);
if (tep
= findcap(cap
, tepp
, 0))
return((*tep
== '@') ? 0 : tep
);
return (tgetstr(cap
, tepp
));
if (tep
= findcap(cap
, &bufp
, 2))
return((*tep
== '@') ? 0 : 1);
if (tep
= findcap(cap
, &bufp
, 20))
while ((c
= *tep
++) >= '0' && c
<= '9')
res
= res
* base
+ (c
- '0');