#include <sys/types.h>
#include <fcntl.h>
#ifndef sun
# include <sys/ioctl.h>
#endif
#include "config.h"
#include "screen.h"
#include "braille.h"
#include "extern.h"
#include "logfile.h"
extern struct display *display, *displays;
extern struct win *fore;
extern struct layer *flayer;
extern struct NewWindow nwin_default;
extern int nversion;
extern int log_flush, logtstamp_on, logtstamp_after;
extern char *logtstamp_string;
extern char *captionstring;
extern char *hstatusstring;
extern char *wliststr;
#ifdef COPY_PASTE
extern int compacthist;
#endif
#ifdef MULTIUSER
extern struct acluser *EffectiveAclUser;
#endif
int Z0width, Z1width;
static struct win *curr;
static int rows, cols;
int visual_bell = 0;
int use_hardstatus = 1;
char *printcmd = 0;
int use_altscreen = 0;
unsigned char *blank;
unsigned char *null;
struct mline mline_old;
struct mline mline_blank;
struct mline mline_null;
struct mchar mchar_null;
struct mchar mchar_blank = {' ' };
struct mchar mchar_so = {' ', A_SO };
static char *string_t_string[] =
{
"NONE",
"DCS",
"OSC",
"APC",
"PM",
"AKA",
"GM",
"STATUS"
};
static char *state_t_string[] =
{
"LIT",
"ESC",
"ASTR",
"STRESC",
"CSI",
"PRIN",
"PRINESC",
"PRINCSI",
"PRIN4"
};
static int Special __P((int));
static void DoESC __P((int, int));
static void DoCSI __P((int, int));
static void StringStart __P((enum string_t));
static void StringChar __P((int));
static int StringEnd __P((void));
static void PrintStart __P((void));
static void PrintChar __P((int));
static void PrintFlush __P((void));
#ifdef FONT
static void DesignateCharset __P((int, int));
static void MapCharset __P((int));
static void MapCharsetR __P((int));
#endif
static void SaveCursor __P((void));
static void RestoreCursor __P((void));
static void BackSpace __P((void));
static void Return __P((void));
static void LineFeed __P((int));
static void ReverseLineFeed __P((void));
static void InsertChar __P((int));
static void DeleteChar __P((int));
static void DeleteLine __P((int));
static void InsertLine __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 ClearLineRegion __P((int, int));
static void CursorRight __P((int));
static void CursorUp __P((int));
static void CursorDown __P((int));
static void CursorLeft __P((int));
static void ASetMode __P((int));
static void SelectRendition __P((void));
static void RestorePosRendition __P((void));
static void FillWithEs __P((void));
static void FindAKA __P((void));
static void Report __P((char *, int, int));
static void ScrollRegion __P((int));
#ifdef COPY_PASTE
static void WAddLineToHist __P((struct win *, struct mline *));
#endif
static void WLogString __P((struct win *, char *, int));
static void WReverseVideo __P((struct win *, int));
static int WindowChangedCheck __P((char *, int, int *));
static void MFixLine __P((struct win *, int, struct mchar *));
static void MScrollH __P((struct win *, int, int, int, int, int));
static void MScrollV __P((struct win *, int, int, int, int));
static void MClearArea __P((struct win *, int, int, int, int, int));
static void MInsChar __P((struct win *, struct mchar *, int, int));
static void MPutChar __P((struct win *, struct mchar *, int, int));
static void MPutStr __P((struct win *, char *, int, struct mchar *, int, int));
static void MWrapChar __P((struct win *, struct mchar *, int, int, int, int));
#ifdef COLOR
static void MBceLine __P((struct win *, int, int, int, int));
#endif
#ifdef COLOR
# define CURR_BCE (curr->w_bce ? rend_getbg(&curr->w_rend) : 0)
#else
# define CURR_BCE 0
#endif
void
ResetAnsiState(p)
struct win *p;
{
p->w_state = LIT;
p->w_StringType = NONE;
}
void
ResetWindow(p)
register struct win *p;
{
register int i;
p->w_wrap = nwin_default.wrap;
p->w_origin = 0;
p->w_insert = 0;
p->w_revvid = 0;
p->w_mouse = 0;
p->w_curinv = 0;
p->w_curvvis = 0;
p->w_autolf = 0;
p->w_keypad = 0;
p->w_cursorkeys = 0;
p->w_top = 0;
p->w_bot = p->w_height - 1;
p->w_saved = 0;
p->w_x = p->w_y = 0;
p->w_state = LIT;
p->w_StringType = NONE;
bzero(p->w_tabs, p->w_width);
for (i = 8; i < p->w_width; i += 8)
p->w_tabs[i] = 1;
p->w_rend = mchar_null;
#ifdef FONT
ResetCharsets(p);
#endif
#ifdef COLOR
p->w_bce = nwin_default.bce;
#endif
}
int
GetAnsiStatus(w, buf)
struct win *w;
char *buf;
{
char *p = buf;
if (w->w_state == LIT)
return 0;
strcpy(p, state_t_string[w->w_state]);
p += strlen(p);
if (w->w_intermediate)
{
*p++ = '-';
if (w->w_intermediate > 0xff)
p += AddXChar(p, w->w_intermediate >> 8);
p += AddXChar(p, w->w_intermediate & 0xff);
*p = 0;
}
if (w->w_state == ASTR || w->w_state == STRESC)
sprintf(p, "-%s", string_t_string[w->w_StringType]);
p += strlen(p);
return p - buf;
}
#ifdef FONT
void
ResetCharsets(p)
struct win *p;
{
p->w_gr = nwin_default.gr;
p->w_c1 = nwin_default.c1;
SetCharsets(p, "BBBB02");
if (nwin_default.charset)
SetCharsets(p, nwin_default.charset);
#ifdef ENCODINGS
ResetEncoding(p);
#endif
}
void
SetCharsets(p, s)
struct win *p;
char *s;
{
int i;
for (i = 0; i < 4 && *s; i++, s++)
if (*s != '.')
p->w_charsets[i] = ((*s == 'B') ? ASCII : *s);
if (*s && *s++ != '.')
p->w_Charset = s[-1] - '0';
if (*s && *s != '.')
p->w_CharsetR = *s - '0';
p->w_ss = 0;
p->w_FontL = p->w_charsets[p->w_Charset];
p->w_FontR = p->w_charsets[p->w_CharsetR];
}
#endif
void
WriteString(wp, buf, len)
struct win *wp;
register char *buf;
register int len;
{
register int c;
#ifdef FONT
register int font;
#endif
struct canvas *cv;
if (!len)
return;
if (wp->w_log)
WLogString(wp, buf, len);
curr = wp;
cols = curr->w_width;
rows = curr->w_height;
if (curr->w_silence)
SetTimeout(&curr->w_silenceev, curr->w_silencewait * 1000);
if (curr->w_monitor == MON_ON)
{
debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
curr->w_monitor = MON_FOUND;
}
do
{
c = (unsigned char)*buf++;
#ifdef FONT
# ifdef DW_CHARS
if (!curr->w_mbcs)
# endif
curr->w_rend.font = curr->w_FontL;
#endif
if (curr->w_state == LIT &&
#ifdef UTF8
curr->w_encoding != UTF8 &&
#endif
#ifdef DW_CHARS
!is_dw_font(curr->w_rend.font) &&
# ifdef ENCODINGS
curr->w_rend.font != KANA && !curr->w_mbcs &&
# endif
#endif
#ifdef FONT
curr->w_rend.font != '<' &&
#endif
c >= ' ' && c != 0x7f &&
((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) && !curr->w_ss &&
!curr->w_insert && curr->w_x < cols - 1)
{
register int currx = curr->w_x;
char *imp = buf - 1;
while (currx < cols - 1)
{
currx++;
if (--len == 0)
break;
c = (unsigned char)*buf++;
if (c < ' ' || c == 0x7f || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
break;
}
currx -= curr->w_x;
if (currx > 0)
{
MPutStr(curr, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
LPutStr(&curr->w_layer, imp, currx, &curr->w_rend, curr->w_x, curr->w_y);
curr->w_x += currx;
}
if (len == 0)
break;
}
#ifdef UTF8
if (curr->w_encoding == UTF8)
{
c = FromUtf8(c, &curr->w_decodestate);
if (c == -1)
continue;
if (c == -2)
{
c = UCS_REPL;
buf--;
len++;
}
if (c > 0xff)
debug1("read UNICODE %04x\n", c);
}
#endif
tryagain:
switch (curr->w_state)
{
case PRIN:
switch (c)
{
case '\033':
curr->w_state = PRINESC;
break;
default:
PrintChar(c);
}
break;
case PRINESC:
switch (c)
{
case '[':
curr->w_state = PRINCSI;
break;
default:
PrintChar('\033');
PrintChar(c);
curr->w_state = PRIN;
}
break;
case PRINCSI:
switch (c)
{
case '4':
curr->w_state = PRIN4;
break;
default:
PrintChar('\033');
PrintChar('[');
PrintChar(c);
curr->w_state = PRIN;
}
break;
case PRIN4:
switch (c)
{
case 'i':
curr->w_state = LIT;
PrintFlush();
if (curr->w_pdisplay && curr->w_pdisplay->d_printfd >= 0)
{
close(curr->w_pdisplay->d_printfd);
curr->w_pdisplay->d_printfd = -1;
}
curr->w_pdisplay = 0;
break;
default:
PrintChar('\033');
PrintChar('[');
PrintChar('4');
PrintChar(c);
curr->w_state = PRIN;
}
break;
case ASTR:
if (c == 0)
break;
if (c == '\033')
{
curr->w_state = STRESC;
break;
}
if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
if (!curr->w_c1 || c != ('\\' ^ 0xc0))
{
StringChar(c);
break;
}
c = '\\';
case STRESC:
switch (c)
{
case '\\':
if (StringEnd() == 0 || len <= 1)
break;
for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
{
display = cv->c_display;
if (D_status == STATUS_ON_WIN)
break;
}
if (cv)
{
if (len > IOSIZE + 1)
len = IOSIZE + 1;
curr->w_outlen = len - 1;
bcopy(buf, curr->w_outbuf, len - 1);
return;
}
break;
case '\033':
StringChar('\033');
break;
default:
curr->w_state = ASTR;
StringChar('\033');
StringChar(c);
break;
}
break;
case ESC:
switch (c)
{
case '[':
curr->w_NumArgs = 0;
curr->w_intermediate = 0;
bzero((char *) curr->w_args, MAXARGS * sizeof(int));
curr->w_state = CSI;
break;
case ']':
StringStart(OSC);
break;
case '_':
StringStart(APC);
break;
case 'P':
StringStart(DCS);
break;
case '^':
StringStart(PM);
break;
case '!':
StringStart(GM);
break;
case '"':
case 'k':
StringStart(AKA);
break;
default:
if (Special(c))
{
curr->w_state = LIT;
break;
}
debug1("not special. c = %x\n", c);
if (c >= ' ' && c <= '/')
{
if (curr->w_intermediate)
{
#ifdef DW_CHARS
if (curr->w_intermediate == '$')
c |= '$' << 8;
else
#endif
c = -1;
}
curr->w_intermediate = c;
}
else if (c >= '0' && c <= '~')
{
DoESC(c, curr->w_intermediate);
curr->w_state = LIT;
}
else
{
curr->w_state = LIT;
goto tryagain;
}
}
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->w_NumArgs < MAXARGS)
{
if (curr->w_args[curr->w_NumArgs] < 100000000)
curr->w_args[curr->w_NumArgs] =
10 * curr->w_args[curr->w_NumArgs] + (c - '0');
}
break;
case ';':
case ':':
if (curr->w_NumArgs < MAXARGS)
curr->w_NumArgs++;
break;
default:
if (Special(c))
break;
if (c >= '@' && c <= '~')
{
if (curr->w_NumArgs < MAXARGS)
curr->w_NumArgs++;
DoCSI(c, curr->w_intermediate);
if (curr->w_state != PRIN)
curr->w_state = LIT;
}
else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?'))
curr->w_intermediate = curr->w_intermediate ? -1 : c;
else
{
curr->w_state = LIT;
goto tryagain;
}
}
break;
case LIT:
default:
#ifdef DW_CHARS
if (curr->w_mbcs)
if (c <= ' ' || c == 0x7f || (c >= 0x80 && c < 0xa0 && curr->w_c1))
curr->w_mbcs = 0;
#endif
if (c < ' ')
{
if (c == '\033')
{
curr->w_intermediate = 0;
curr->w_state = ESC;
if (curr->w_autoaka < 0)
curr->w_autoaka = 0;
}
else
Special(c);
break;
}
if (c >= 0x80 && c < 0xa0 && curr->w_c1)
#ifdef FONT
if ((curr->w_FontR & 0xf0) != 0x20
# ifdef UTF8
|| curr->w_encoding == UTF8
# endif
)
#endif
{
switch (c)
{
case 0xc0 ^ 'D':
case 0xc0 ^ 'E':
case 0xc0 ^ 'H':
case 0xc0 ^ 'M':
case 0xc0 ^ 'N':
case 0xc0 ^ 'O':
DoESC(c ^ 0xc0, 0);
break;
case 0xc0 ^ '[':
if (curr->w_autoaka < 0)
curr->w_autoaka = 0;
curr->w_NumArgs = 0;
curr->w_intermediate = 0;
bzero((char *) curr->w_args, MAXARGS * sizeof(int));
curr->w_state = CSI;
break;
case 0xc0 ^ 'P':
StringStart(DCS);
break;
default:
break;
}
break;
}
#ifdef FONT
# ifdef DW_CHARS
if (!curr->w_mbcs)
{
# endif
if (c < 0x80 || curr->w_gr == 0)
curr->w_rend.font = curr->w_FontL;
# ifdef ENCODINGS
else if (curr->w_gr == 2 && !curr->w_ss)
curr->w_rend.font = curr->w_FontE;
# endif
else
curr->w_rend.font = curr->w_FontR;
# ifdef DW_CHARS
}
# endif
# ifdef UTF8
if (curr->w_encoding == UTF8)
{
if (curr->w_rend.font == '0')
{
struct mchar mc, *mcp;
debug1("SPECIAL %x\n", c);
mc.image = c;
mc.mbcs = 0;
mc.font = '0';
mcp = recode_mchar(&mc, 0, UTF8);
debug2("%02x %02x\n", mcp->image, mcp->font);
c = mcp->image | mcp->font << 8;
}
curr->w_rend.font = 0;
}
# ifdef DW_CHARS
if (curr->w_encoding == UTF8 && c >= 0x1100 && utf8_isdouble(c))
curr->w_mbcs = 0xff;
# endif
if (curr->w_encoding == UTF8 && c >= 0x0300 && utf8_iscomb(c))
{
int ox, oy;
struct mchar omc;
ox = curr->w_x - 1;
oy = curr->w_y;
if (ox < 0)
{
ox = curr->w_width - 1;
oy--;
}
if (oy < 0)
oy = 0;
copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
if (omc.image == 0xff && omc.font == 0xff)
{
ox--;
if (ox >= 0)
{
copy_mline2mchar(&omc, &curr->w_mlines[oy], ox);
omc.mbcs = 0xff;
}
}
if (ox >= 0)
{
utf8_handle_comb(c, &omc);
MFixLine(curr, oy, &omc);
copy_mchar2mline(&omc, &curr->w_mlines[oy], ox);
LPutChar(&curr->w_layer, &omc, ox, oy);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
break;
}
font = curr->w_rend.font;
# endif
# ifdef DW_CHARS
# ifdef ENCODINGS
if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
{
debug1("%x may be first of SJIS\n", c);
if ((0x81 <= c && c <= 0x9f) || (0xe0 <= c && c <= 0xef))
{
debug("YES!\n");
curr->w_mbcs = c;
break;
}
}
# endif
if (font == 031 && c == 0x80 && !curr->w_mbcs)
font = curr->w_rend.font = 0;
if (is_dw_font(font) && c == ' ')
font = curr->w_rend.font = 0;
if (is_dw_font(font) || curr->w_mbcs)
{
int t = c;
if (curr->w_mbcs == 0)
{
curr->w_mbcs = c;
break;
}
if (curr->w_x == cols - 1)
{
curr->w_x += curr->w_wrap ? 1 : -1;
debug1("Patched w_x to %d\n", curr->w_x);
}
# ifdef UTF8
if (curr->w_encoding != UTF8)
# endif
{
c = curr->w_mbcs;
# ifdef ENCODINGS
if (font == KANA && curr->w_encoding == SJIS)
{
debug2("SJIS !! %x %x\n", c, t);
if (0x40 <= t && t <= 0xfc && t != 0x7f)
{
if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
else c = (c - 0xc1) * 2 + 0x21;
if (t <= 0x7e) t -= 0x1f;
else if (t <= 0x9e) t -= 0x20;
else t -= 0x7e, c++;
curr->w_rend.font = KANJI;
}
else
{
c = t;
t = 0;
}
debug2("SJIS after %x %x\n", c, t);
}
# endif
if (t && curr->w_gr && font != 030 && font != 031)
{
t &= 0x7f;
if (t < ' ')
goto tryagain;
}
if (t == '\177')
break;
curr->w_mbcs = t;
}
}
# endif
if (font == '<' && c >= ' ')
{
font = curr->w_rend.font = 0;
c |= 0x80;
}
# ifdef UTF8
else if (curr->w_gr && curr->w_encoding != UTF8)
# else
else if (curr->w_gr)
# endif
{
#ifdef ENCODINGS
if (c == 0x80 && font == 0 && curr->w_encoding == GBK)
c = 0xa4;
else
c &= 0x7f;
if (c < ' ' && font != 031)
goto tryagain;
#else
c &= 0x7f;
if (c < ' ')
goto tryagain;
#endif
}
#endif
if (c == '\177')
break;
curr->w_rend.image = c;
#ifdef UTF8
if (curr->w_encoding == UTF8)
curr->w_rend.font = c >> 8;
#endif
#ifdef DW_CHARS
curr->w_rend.mbcs = curr->w_mbcs;
#endif
if (curr->w_x < cols - 1)
{
if (curr->w_insert)
{
save_mline(&curr->w_mlines[curr->w_y], cols);
MInsChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
LInsChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y, &mline_old);
curr->w_x++;
}
else
{
MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
curr->w_x++;
}
}
else if (curr->w_x == cols - 1)
{
MPutChar(curr, &curr->w_rend, curr->w_x, curr->w_y);
LPutChar(&curr->w_layer, &curr->w_rend, curr->w_x, curr->w_y);
if (curr->w_wrap)
curr->w_x++;
}
else
{
MWrapChar(curr, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
LWrapChar(&curr->w_layer, &curr->w_rend, curr->w_y, curr->w_top, curr->w_bot, curr->w_insert);
if (curr->w_y != curr->w_bot && curr->w_y != curr->w_height - 1)
curr->w_y++;
curr->w_x = 1;
}
#ifdef FONT
# ifdef DW_CHARS
if (curr->w_mbcs)
{
curr->w_rend.mbcs = curr->w_mbcs = 0;
curr->w_x++;
}
# endif
if (curr->w_ss)
{
curr->w_FontL = curr->w_charsets[curr->w_Charset];
curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
curr->w_rend.font = curr->w_FontL;
LSetRendition(&curr->w_layer, &curr->w_rend);
curr->w_ss = 0;
}
#endif
break;
}
}
while (--len);
if (!printcmd && curr->w_state == PRIN)
PrintFlush();
}
static void
WLogString(p, buf, len)
struct win *p;
char *buf;
int len;
{
if (!p->w_log)
return;
if (logtstamp_on && p->w_logsilence >= logtstamp_after * 2)
{
char *t = MakeWinMsg(logtstamp_string, p, '%');
logfwrite(p->w_log, t, strlen(t));
}
p->w_logsilence = 0;
if (logfwrite(p->w_log, buf, len) < 1)
{
WMsg(p, errno, "Error writing logfile");
logfclose(p->w_log);
p->w_log = 0;
}
if (!log_flush)
logfflush(p->w_log);
}
static int
Special(c)
register int c;
{
switch (c)
{
case '\b':
BackSpace();
return 1;
case '\r':
Return();
return 1;
case '\n':
if (curr->w_autoaka)
FindAKA();
LineFeed(0);
return 1;
case '\007':
WBell(curr, visual_bell);
return 1;
case '\t':
ForwardTab();
return 1;
#ifdef FONT
case '\017':
MapCharset(G0);
return 1;
case '\016':
MapCharset(G1);
return 1;
#endif
}
return 0;
}
static void
DoESC(c, intermediate)
int c, intermediate;
{
debug2("DoESC: %x - inter = %x\n", c, intermediate);
switch (intermediate)
{
case 0:
switch (c)
{
case 'E':
LineFeed(1);
break;
case 'D':
LineFeed(0);
break;
case 'M':
ReverseLineFeed();
break;
case 'H':
curr->w_tabs[curr->w_x] = 1;
break;
case 'Z':
Report("\033[?%d;%dc", 1, 2);
break;
case '7':
SaveCursor();
break;
case '8':
RestoreCursor();
break;
case 'c':
ClearScreen();
ResetWindow(curr);
LKeypadMode(&curr->w_layer, 0);
LCursorkeysMode(&curr->w_layer, 0);
#ifndef TIOCPKT
WNewAutoFlow(curr, 1);
#endif
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
case '=':
LKeypadMode(&curr->w_layer, curr->w_keypad = 1);
#ifndef TIOCPKT
WNewAutoFlow(curr, 0);
#endif
break;
case '>':
LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
#ifndef TIOCPKT
WNewAutoFlow(curr, 1);
#endif
break;
#ifdef FONT
case 'n':
MapCharset(G2);
break;
case 'o':
MapCharset(G3);
break;
case '~':
MapCharsetR(G1);
break;
case '}':
MapCharsetR(G2);
break;
case '|':
MapCharsetR(G3);
break;
case 'N':
if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G2]
|| curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G2])
curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G2];
else
curr->w_ss = 0;
break;
case 'O':
if (curr->w_charsets[curr->w_Charset] != curr->w_charsets[G3]
|| curr->w_charsets[curr->w_CharsetR] != curr->w_charsets[G3])
curr->w_FontR = curr->w_FontL = curr->w_charsets[curr->w_ss = G3];
else
curr->w_ss = 0;
break;
#endif
case 'g':
WBell(curr, 1);
break;
}
break;
case '#':
switch (c)
{
case '8':
FillWithEs();
break;
}
break;
#ifdef FONT
case '(':
DesignateCharset(c, G0);
break;
case ')':
DesignateCharset(c, G1);
break;
case '*':
DesignateCharset(c, G2);
break;
case '+':
DesignateCharset(c, G3);
break;
# ifdef DW_CHARS
case '$':
case '$'<<8 | '(':
DesignateCharset(c & 037, G0);
break;
case '$'<<8 | ')':
DesignateCharset(c & 037, G1);
break;
case '$'<<8 | '*':
DesignateCharset(c & 037, G2);
break;
case '$'<<8 | '+':
DesignateCharset(c & 037, G3);
break;
# endif
#endif
}
}
static void
DoCSI(c, intermediate)
int c, intermediate;
{
register int i, a1 = curr->w_args[0], a2 = curr->w_args[1];
if (curr->w_NumArgs > MAXARGS)
curr->w_NumArgs = MAXARGS;
switch (intermediate)
{
case 0:
switch (c)
{
case 'H':
case 'f':
if (a1 < 1)
a1 = 1;
if (curr->w_origin)
a1 += curr->w_top;
if (a1 > rows)
a1 = rows;
if (a2 < 1)
a2 = 1;
if (a2 > cols)
a2 = cols;
LGotoPos(&curr->w_layer, --a2, --a1);
curr->w_x = a2;
curr->w_y = a1;
if (curr->w_autoaka)
curr->w_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();
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
}
break;
case 'K':
if (a1 < 0 || a1 > 2)
a1 %= 3;
switch (a1)
{
case 0:
ClearLineRegion(curr->w_x, cols - 1);
break;
case 1:
ClearLineRegion(0, curr->w_x);
break;
case 2:
ClearLineRegion(0, cols - 1);
break;
}
break;
case 'X':
a1 = curr->w_x + (a1 ? a1 - 1 : 0);
ClearLineRegion(curr->w_x, a1 < cols ? a1 : cols - 1);
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 'E':
curr->w_x = 0;
CursorDown(a1 ? a1 : 1);
break;
case 'F':
curr->w_x = 0;
CursorUp(a1 ? a1 : 1);
break;
case 'G':
case '`':
curr->w_x = a1 ? a1 - 1 : 0;
if (curr->w_x >= cols)
curr->w_x = cols - 1;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
case 'd':
curr->w_y = a1 ? a1 - 1 : 0;
if (curr->w_y >= rows)
curr->w_y = rows - 1;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
case 'm':
SelectRendition();
break;
case 'g':
if (a1 == 0)
curr->w_tabs[curr->w_x] = 0;
else if (a1 == 3)
bzero(curr->w_tabs, cols);
break;
case 'r':
if (!a1)
a1 = 1;
if (!a2)
a2 = rows;
if (a1 < 1 || a2 > rows || a1 >= a2)
break;
curr->w_top = a1 - 1;
curr->w_bot = a2 - 1;
if (curr->w_origin)
{
curr->w_y = curr->w_top;
curr->w_x = 0;
}
else
curr->w_y = curr->w_x = 0;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
case 's':
SaveCursor();
break;
case 't':
if (a1 != 8)
break;
a1 = curr->w_args[2];
if (a1 < 1)
a1 = curr->w_width;
if (a2 < 1)
a2 = curr->w_height;
if (a1 > 10000 || a2 > 10000)
break;
WChangeSize(curr, a1, a2);
cols = curr->w_width;
rows = curr->w_height;
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 (a1 == 5)
PrintStart();
break;
case 'n':
if (a1 == 5)
Report("\033[0n", 0, 0);
else if (a1 == 6)
Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
break;
case 'c':
if (a1 == 0)
Report("\033[?%d;%dc", 1, 2);
break;
case 'x':
if (a1 == 0 || a1 == 1)
Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
break;
case 'p':
if (a1 == 6 || a1 == 7)
{
curr->w_curinv = 7 - a1;
LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
}
break;
case 'S':
ScrollRegion(a1 ? a1 : 1);
break;
case 'T':
case '^':
ScrollRegion(a1 ? -a1 : -1);
break;
}
break;
case '?':
for (a2 = 0; a2 < curr->w_NumArgs; a2++)
{
a1 = curr->w_args[a2];
debug2("\\E[?%d%c\n",a1,c);
if (c != 'h' && c != 'l')
break;
i = (c == 'h');
switch (a1)
{
case 1:
LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
#ifndef TIOCPKT
WNewAutoFlow(curr, !i);
#endif
break;
case 2:
if (i)
{
#ifdef FONT
# ifdef ENCODINGS
if (curr->w_encoding)
break;
# endif
curr->w_charsets[0] = curr->w_charsets[1] =
curr->w_charsets[2] = curr->w_charsets[2] =
curr->w_FontL = curr->w_FontR = ASCII;
curr->w_Charset = 0;
curr->w_CharsetR = 2;
curr->w_ss = 0;
#endif
}
break;
case 3:
i = (i ? Z0width : Z1width);
WChangeSize(curr, i, curr->w_height);
cols = curr->w_width;
rows = curr->w_height;
break;
case 5:
if (i != curr->w_revvid)
WReverseVideo(curr, i);
curr->w_revvid = i;
break;
case 6:
if ((curr->w_origin = i) != 0)
{
curr->w_y = curr->w_top;
curr->w_x = 0;
}
else
curr->w_y = curr->w_x = 0;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
break;
case 7:
curr->w_wrap = i;
break;
case 9:
curr->w_mouse = i ? 9 : 0;
LMouseMode(&curr->w_layer, curr->w_mouse);
break;
case 25:
curr->w_curinv = !i;
LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
break;
case 47:
case 1047:
case 1049:
if (use_altscreen)
{
if (i)
EnterAltScreen(curr);
else
LeaveAltScreen(curr);
if (a1 == 47 && !i)
curr->w_saved = 0;
LRefreshAll(&curr->w_layer, 0);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
break;
case 1000:
case 1001:
case 1002:
case 1003:
curr->w_mouse = i ? a1 : 0;
LMouseMode(&curr->w_layer, curr->w_mouse);
break;
}
}
break;
case '>':
switch (c)
{
case 'c':
if (a1 == 0)
Report("\033[>%d;%d;0c", 83, nversion);
break;
}
break;
}
}
static void
StringStart(type)
enum string_t type;
{
curr->w_StringType = type;
curr->w_stringp = curr->w_string;
curr->w_state = ASTR;
}
static void
StringChar(c)
int c;
{
if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
curr->w_state = LIT;
else
*(curr->w_stringp)++ = c;
}
static int
StringEnd()
{
struct canvas *cv;
char *p;
int typ;
curr->w_state = LIT;
*curr->w_stringp = '\0';
switch (curr->w_StringType)
{
case OSC:
if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
break;
typ = atoi(curr->w_string);
p++;
#ifdef MULTIUSER
if (typ == 83)
{
char *args[MAXARGS];
int argl[MAXARGS];
struct acluser *windowuser;
windowuser = *FindUserPtr(":window:");
if (windowuser && Parse(p, sizeof(curr->w_string) - (p - curr->w_string), args, argl))
{
for (display = displays; display; display = display->d_next)
if (D_forecv->c_layer->l_bottom == &curr->w_layer)
break;
if (display == 0 && curr->w_layer.l_cvlist)
display = curr->w_layer.l_cvlist->c_display;
if (display == 0)
display = displays;
EffectiveAclUser = windowuser;
fore = curr;
flayer = fore->w_savelayer ? fore->w_savelayer : &fore->w_layer;
DoCommand(args, argl);
EffectiveAclUser = 0;
fore = 0;
flayer = 0;
}
break;
}
#endif
#ifdef RXVT_OSC
if (typ == 0 || typ == 1 || typ == 20 || typ == 39 || typ == 49)
{
int typ2;
typ2 = typ / 10;
if (--typ2 < 0)
typ2 = 0;
if (strcmp(curr->w_xtermosc[typ2], p))
{
strncpy(curr->w_xtermosc[typ2], p, sizeof(curr->w_xtermosc[typ2]) - 1);
curr->w_xtermosc[typ2][sizeof(curr->w_xtermosc[typ2]) - 1] = 0;
for (display = displays; display; display = display->d_next)
{
if (!D_CXT)
continue;
if (D_forecv->c_layer->l_bottom == &curr->w_layer)
SetXtermOSC(typ2, curr->w_xtermosc[typ2]);
if ((typ2 == 2 || typ2 == 3) && D_xtermosc[typ2])
Redisplay(0);
}
}
}
if (typ != 0 && typ != 2)
break;
#else
if (typ < 0 || typ > 2)
break;
#endif
curr->w_stringp -= p - curr->w_string;
if (curr->w_stringp > curr->w_string)
bcopy(p, curr->w_string, curr->w_stringp - curr->w_string);
*curr->w_stringp = '\0';
case APC:
if (curr->w_hstatus)
{
if (strcmp(curr->w_hstatus, curr->w_string) == 0)
break;
free(curr->w_hstatus);
curr->w_hstatus = 0;
}
if (curr->w_string != curr->w_stringp)
curr->w_hstatus = SaveStr(curr->w_string);
WindowChanged(curr, 'h');
break;
case PM:
case GM:
for (display = displays; display; display = display->d_next)
{
for (cv = D_cvlist; cv; cv = cv->c_next)
if (cv->c_layer->l_bottom == &curr->w_layer)
break;
if (cv || curr->w_StringType == GM)
MakeStatus(curr->w_string);
}
return -1;
case DCS:
LAY_DISPLAYS(&curr->w_layer, AddStr(curr->w_string));
break;
case AKA:
if (curr->w_title == curr->w_akabuf && !*curr->w_string)
break;
ChangeAKA(curr, curr->w_string, strlen(curr->w_string));
if (!*curr->w_string)
curr->w_autoaka = curr->w_y + 1;
break;
default:
break;
}
return 0;
}
static void
PrintStart()
{
curr->w_pdisplay = 0;
display = curr->w_lastdisp;
if (!(display && curr == D_fore && (printcmd || D_PO)))
for (display = displays; display; display = display->d_next)
if (curr == D_fore && (printcmd || D_PO))
break;
if (!display)
{
struct canvas *cv;
for (cv = curr->w_layer.l_cvlist; cv; cv = cv->c_lnext)
{
display = cv->c_display;
if (printcmd || D_PO)
break;
}
if (!cv)
{
display = displays;
if (!display || display->d_next || !(printcmd || D_PO))
return;
}
}
curr->w_pdisplay = display;
curr->w_stringp = curr->w_string;
curr->w_state = PRIN;
if (printcmd && curr->w_pdisplay->d_printfd < 0)
curr->w_pdisplay->d_printfd = printpipe(curr, printcmd);
}
static void
PrintChar(c)
int c;
{
if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
PrintFlush();
*(curr->w_stringp)++ = c;
}
static void
PrintFlush()
{
display = curr->w_pdisplay;
if (display && printcmd)
{
char *bp = curr->w_string;
int len = curr->w_stringp - curr->w_string;
int r;
while (len && display->d_printfd >= 0)
{
r = write(display->d_printfd, bp, len);
if (r <= 0)
{
WMsg(curr, errno, "printing aborted");
close(display->d_printfd);
display->d_printfd = -1;
break;
}
bp += r;
len -= r;
}
}
else if (display && curr->w_stringp > curr->w_string)
{
AddCStr(D_PO);
AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
AddCStr(D_PF);
Flush();
}
curr->w_stringp = curr->w_string;
}
void
WNewAutoFlow(win, on)
struct win *win;
int on;
{
debug1("WNewAutoFlow: %d\n", on);
if (win->w_flow & FLOW_AUTOFLAG)
win->w_flow = FLOW_AUTOFLAG | (FLOW_AUTO|FLOW_NOW) * on;
else
win->w_flow = (win->w_flow & ~FLOW_AUTO) | FLOW_AUTO * on;
LSetFlow(&win->w_layer, win->w_flow & FLOW_NOW);
}
#ifdef FONT
static void
DesignateCharset(c, n)
int c, n;
{
curr->w_ss = 0;
# ifdef ENCODINGS
if (c == ('@' & 037))
c = KANJI;
# endif
if (c == 'B')
c = ASCII;
if (curr->w_charsets[n] != c)
{
curr->w_charsets[n] = c;
if (curr->w_Charset == n)
{
curr->w_FontL = c;
curr->w_rend.font = curr->w_FontL;
LSetRendition(&curr->w_layer, &curr->w_rend);
}
if (curr->w_CharsetR == n)
curr->w_FontR = c;
}
}
static void
MapCharset(n)
int n;
{
curr->w_ss = 0;
if (curr->w_Charset != n)
{
curr->w_Charset = n;
curr->w_FontL = curr->w_charsets[n];
curr->w_rend.font = curr->w_FontL;
LSetRendition(&curr->w_layer, &curr->w_rend);
}
}
static void
MapCharsetR(n)
int n;
{
curr->w_ss = 0;
if (curr->w_CharsetR != n)
{
curr->w_CharsetR = n;
curr->w_FontR = curr->w_charsets[n];
}
curr->w_gr = 1;
}
#endif
static void
SaveCursor()
{
curr->w_saved = 1;
curr->w_Saved_x = curr->w_x;
curr->w_Saved_y = curr->w_y;
curr->w_SavedRend = curr->w_rend;
#ifdef FONT
curr->w_SavedCharset = curr->w_Charset;
curr->w_SavedCharsetR = curr->w_CharsetR;
bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
4 * sizeof(int));
#endif
}
static void
RestoreCursor()
{
if (!curr->w_saved)
return;
LGotoPos(&curr->w_layer, curr->w_Saved_x, curr->w_Saved_y);
curr->w_x = curr->w_Saved_x;
curr->w_y = curr->w_Saved_y;
curr->w_rend = curr->w_SavedRend;
#ifdef FONT
bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
4 * sizeof(int));
curr->w_Charset = curr->w_SavedCharset;
curr->w_CharsetR = curr->w_SavedCharsetR;
curr->w_ss = 0;
curr->w_FontL = curr->w_charsets[curr->w_Charset];
curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
#endif
LSetRendition(&curr->w_layer, &curr->w_rend);
}
static void
BackSpace()
{
if (curr->w_x > 0)
{
curr->w_x--;
}
else if (curr->w_wrap && curr->w_y > 0)
{
curr->w_x = cols - 1;
curr->w_y--;
}
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
Return()
{
if (curr->w_x == 0)
return;
curr->w_x = 0;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
LineFeed(out_mode)
int out_mode;
{
if (out_mode)
curr->w_x = 0;
if (curr->w_y != curr->w_bot)
{
if (curr->w_y < rows-1)
curr->w_y++;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
return;
}
if (curr->w_autoaka > 1)
curr->w_autoaka--;
MScrollV(curr, 1, curr->w_top, curr->w_bot, CURR_BCE);
LScrollV(&curr->w_layer, 1, curr->w_top, curr->w_bot, CURR_BCE);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
ReverseLineFeed()
{
if (curr->w_y == curr->w_top)
{
MScrollV(curr, -1, curr->w_top, curr->w_bot, CURR_BCE);
LScrollV(&curr->w_layer, -1, curr->w_top, curr->w_bot, CURR_BCE);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
else if (curr->w_y > 0)
CursorUp(1);
}
static void
InsertChar(n)
int n;
{
register int y = curr->w_y, x = curr->w_x;
if (n <= 0)
return;
if (x == cols)
x--;
save_mline(&curr->w_mlines[y], cols);
MScrollH(curr, -n, y, x, curr->w_width - 1, CURR_BCE);
LScrollH(&curr->w_layer, -n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
LGotoPos(&curr->w_layer, x, y);
}
static void
DeleteChar(n)
int n;
{
register int y = curr->w_y, x = curr->w_x;
if (x == cols)
x--;
save_mline(&curr->w_mlines[y], cols);
MScrollH(curr, n, y, x, curr->w_width - 1, CURR_BCE);
LScrollH(&curr->w_layer, n, y, x, curr->w_width - 1, CURR_BCE, &mline_old);
LGotoPos(&curr->w_layer, x, y);
}
static void
DeleteLine(n)
int n;
{
if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
return;
if (n > curr->w_bot - curr->w_y + 1)
n = curr->w_bot - curr->w_y + 1;
MScrollV(curr, n, curr->w_y, curr->w_bot, CURR_BCE);
LScrollV(&curr->w_layer, n, curr->w_y, curr->w_bot, CURR_BCE);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
InsertLine(n)
int n;
{
if (curr->w_y < curr->w_top || curr->w_y > curr->w_bot)
return;
if (n > curr->w_bot - curr->w_y + 1)
n = curr->w_bot - curr->w_y + 1;
MScrollV(curr, -n, curr->w_y, curr->w_bot, CURR_BCE);
LScrollV(&curr->w_layer, -n, curr->w_y, curr->w_bot, CURR_BCE);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
ScrollRegion(n)
int n;
{
MScrollV(curr, n, curr->w_top, curr->w_bot, CURR_BCE);
LScrollV(&curr->w_layer, n, curr->w_top, curr->w_bot, CURR_BCE);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
ForwardTab()
{
register int x = curr->w_x;
if (x == cols)
{
LineFeed(1);
x = 0;
}
if (curr->w_tabs[x] && x < cols - 1)
x++;
while (x < cols - 1 && !curr->w_tabs[x])
x++;
curr->w_x = x;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
BackwardTab()
{
register int x = curr->w_x;
if (curr->w_tabs[x] && x > 0)
x--;
while (x > 0 && !curr->w_tabs[x])
x--;
curr->w_x = x;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
ClearScreen()
{
LClearArea(&curr->w_layer, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE, 1);
#ifdef COPY_PASTE
MScrollV(curr, curr->w_height, 0, curr->w_height - 1, CURR_BCE);
#else
MClearArea(curr, 0, 0, curr->w_width - 1, curr->w_height - 1, CURR_BCE);
#endif
}
static void
ClearFromBOS()
{
register int y = curr->w_y, x = curr->w_x;
LClearArea(&curr->w_layer, 0, 0, x, y, CURR_BCE, 1);
MClearArea(curr, 0, 0, x, y, CURR_BCE);
RestorePosRendition();
}
static void
ClearToEOS()
{
register int y = curr->w_y, x = curr->w_x;
if (x == 0 && y == 0)
{
ClearScreen();
RestorePosRendition();
return;
}
LClearArea(&curr->w_layer, x, y, cols - 1, rows - 1, CURR_BCE, 1);
MClearArea(curr, x, y, cols - 1, rows - 1, CURR_BCE);
RestorePosRendition();
}
static void
ClearLineRegion(from, to)
int from, to;
{
register int y = curr->w_y;
LClearArea(&curr->w_layer, from, y, to, y, CURR_BCE, 1);
MClearArea(curr, from, y, to, y, CURR_BCE);
RestorePosRendition();
}
static void
CursorRight(n)
register int n;
{
register int x = curr->w_x;
if (x == cols)
{
LineFeed(1);
x = 0;
}
if ((curr->w_x += n) >= cols)
curr->w_x = cols - 1;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
CursorUp(n)
register int n;
{
if (curr->w_y < curr->w_top)
{
if ((curr->w_y -= n) < 0)
curr->w_y = 0;
}
else
if ((curr->w_y -= n) < curr->w_top)
curr->w_y = curr->w_top;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
CursorDown(n)
register int n;
{
if (curr->w_y > curr->w_bot)
{
if ((curr->w_y += n) > rows - 1)
curr->w_y = rows - 1;
}
else
if ((curr->w_y += n) > curr->w_bot)
curr->w_y = curr->w_bot;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
CursorLeft(n)
register int n;
{
if ((curr->w_x -= n) < 0)
curr->w_x = 0;
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
static void
ASetMode(on)
int on;
{
register int i;
for (i = 0; i < curr->w_NumArgs; ++i)
{
switch (curr->w_args[i])
{
case 4:
curr->w_insert = on;
LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
break;
case 20:
curr->w_autolf = on;
break;
case 34:
curr->w_curvvis = !on;
LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
break;
default:
break;
}
}
}
static char rendlist[] =
{
~((1 << NATTR) - 1), A_BD, A_DI, A_SO, A_US, A_BL, 0, A_RV, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, ~(A_BD|A_SO|A_DI), ~A_SO, ~A_US, ~A_BL, 0, ~A_RV
};
static void
SelectRendition()
{
#ifdef COLOR
register int j, i = 0, a = curr->w_rend.attr, c = curr->w_rend.color;
# ifdef COLORS256
int cx = curr->w_rend.colorx;
# endif
#else
register int j, i = 0, a = curr->w_rend.attr;
#endif
do
{
j = curr->w_args[i];
#ifdef COLOR
if ((j == 38 || j == 48) && i + 2 < curr->w_NumArgs && curr->w_args[i + 1] == 5)
{
int jj;
i += 2;
jj = curr->w_args[i];
if (jj < 0 || jj > 255)
continue;
# ifdef COLORS256
if (j == 38)
{
c = (c & 0xf0) | ((jj & 0x0f) ^ 9);
a |= A_BFG;
if (jj >= 8 && jj < 16)
c |= 0x08;
else
a ^= A_BFG;
a = (a & 0xbf) | (jj & 8 ? 0x40 : 0);
cx = (cx & 0xf0) | (jj >> 4 & 0x0f);
}
else
{
c = (c & 0x0f) | ((jj & 0x0f) ^ 9) << 4;
a |= A_BBG;
if (jj >= 8 && jj < 16)
c |= 0x80;
else
a ^= A_BBG;
cx = (cx & 0x0f) | (jj & 0xf0);
}
continue;
# else
jj = color256to16(jj) + 30;
if (jj >= 38)
jj += 60 - 8;
j = j == 38 ? jj : jj + 10;
# endif
}
# ifdef COLORS16
if (j == 0 || (j >= 30 && j <= 39 && j != 38))
a &= 0xbf;
if (j == 0 || (j >= 40 && j <= 49 && j != 48))
a &= 0x7f;
if (j >= 90 && j <= 97)
a |= 0x40;
if (j >= 100 && j <= 107)
a |= 0x80;
# endif
if (j >= 90 && j <= 97)
j -= 60;
if (j >= 100 && j <= 107)
j -= 60;
if (j >= 30 && j <= 39 && j != 38)
c = (c & 0xf0) | ((j - 30) ^ 9);
else if (j >= 40 && j <= 49 && j != 48)
c = (c & 0x0f) | (((j - 40) ^ 9) << 4);
if (j == 0)
c = 0;
# ifdef COLORS256
if (j == 0 || (j >= 30 && j <= 39 && j != 38))
cx &= 0xf0;
if (j == 0 || (j >= 40 && j <= 49 && j != 48))
cx &= 0x0f;
# endif
#endif
if (j < 0 || j >= (int)(sizeof(rendlist)/sizeof(*rendlist)))
continue;
j = rendlist[j];
if (j & (1 << NATTR))
a &= j;
else
a |= j;
}
while (++i < curr->w_NumArgs);
curr->w_rend.attr = a;
#ifdef COLOR
curr->w_rend.color = c;
# ifdef COLORS256
curr->w_rend.colorx = cx;
# endif
#endif
LSetRendition(&curr->w_layer, &curr->w_rend);
}
static void
FillWithEs()
{
register int i;
register unsigned char *p, *ep;
LClearAll(&curr->w_layer, 1);
curr->w_y = curr->w_x = 0;
for (i = 0; i < rows; ++i)
{
clear_mline(&curr->w_mlines[i], 0, cols + 1);
p = curr->w_mlines[i].image;
ep = p + cols;
while (p < ep)
*p++ = 'E';
}
LRefreshAll(&curr->w_layer, 1);
}
void
ChangeAKA(p, s, l)
struct win *p;
char *s;
int l;
{
int i, c;
for (i = 0; l > 0; l--)
{
if (p->w_akachange + i == p->w_akabuf + sizeof(p->w_akabuf) - 1)
break;
c = (unsigned char)*s++;
if (c == 0)
break;
if (c < 32 || c == 127 || (c >= 128 && c < 160 && p->w_c1))
continue;
p->w_akachange[i++] = c;
}
p->w_akachange[i] = 0;
p->w_title = p->w_akachange;
if (p->w_akachange != p->w_akabuf)
if (p->w_akachange[0] == 0 || p->w_akachange[-1] == ':')
p->w_title = p->w_akabuf + strlen(p->w_akabuf) + 1;
WindowChanged(p, 't');
WindowChanged((struct win *)0, 'w');
WindowChanged((struct win *)0, 'W');
}
static void
FindAKA()
{
register unsigned char *cp, *line;
register struct win *wp = curr;
register int len = strlen(wp->w_akabuf);
int y;
y = (wp->w_autoaka > 0 && wp->w_autoaka <= wp->w_height) ? wp->w_autoaka - 1 : wp->w_y;
cols = wp->w_width;
try_line:
cp = line = wp->w_mlines[y].image;
if (wp->w_autoaka > 0 && *wp->w_akabuf != '\0')
{
for (;;)
{
if (cp - line >= cols - len)
{
if (++y == wp->w_autoaka && y < rows)
goto try_line;
return;
}
if (strncmp((char *)cp, wp->w_akabuf, len) == 0)
break;
cp++;
}
cp += len;
}
for (len = cols - (cp - line); len && *cp == ' '; len--, cp++)
;
if (len)
{
if (wp->w_autoaka > 0 && (*cp == '!' || *cp == '%' || *cp == '^'))
wp->w_autoaka = -1;
else
wp->w_autoaka = 0;
line = cp;
while (len && *cp != ' ')
{
if (*cp++ == '/')
line = cp;
len--;
}
ChangeAKA(wp, (char *)line, cp - line);
}
else
wp->w_autoaka = 0;
}
static void
RestorePosRendition()
{
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
LSetRendition(&curr->w_layer, &curr->w_rend);
}
static void
Report(fmt, n1, n2)
char *fmt;
int n1, n2;
{
register int len;
char rbuf[40];
sprintf(rbuf, fmt, n1, n2);
len = strlen(rbuf);
if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
{
bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
curr->w_inlen += len;
}
}
static void
MFixLine(p, y, mc)
struct win *p;
int y;
struct mchar *mc;
{
struct mline *ml = &p->w_mlines[y];
if (mc->attr && ml->attr == null)
{
if ((ml->attr = (unsigned char *)malloc(p->w_width + 1)) == 0)
{
ml->attr = null;
mc->attr = p->w_rend.attr = 0;
WMsg(p, 0, "Warning: no space for attr - turned off");
}
bzero((char *)ml->attr, p->w_width + 1);
}
#ifdef FONT
if (mc->font && ml->font == null)
{
if ((ml->font = (unsigned char *)malloc(p->w_width + 1)) == 0)
{
ml->font = null;
p->w_FontL = p->w_charsets[p->w_ss ? p->w_ss : p->w_Charset] = 0;
p->w_FontR = p->w_charsets[p->w_ss ? p->w_ss : p->w_CharsetR] = 0;
mc->font = p->w_rend.font = 0;
WMsg(p, 0, "Warning: no space for font - turned off");
}
bzero((char *)ml->font, p->w_width + 1);
}
#endif
#ifdef COLOR
if (mc->color && ml->color == null)
{
if ((ml->color = (unsigned char *)malloc(p->w_width + 1)) == 0)
{
ml->color = null;
mc->color = p->w_rend.color = 0;
WMsg(p, 0, "Warning: no space for color - turned off");
}
bzero((char *)ml->color, p->w_width + 1);
}
# ifdef COLORS256
if (mc->colorx && ml->colorx == null)
{
if ((ml->colorx = (unsigned char *)malloc(p->w_width + 1)) == 0)
{
ml->colorx = null;
mc->colorx = p->w_rend.colorx = 0;
WMsg(p, 0, "Warning: no space for extended colors - turned off");
}
bzero((char *)ml->colorx, p->w_width + 1);
}
# endif
#endif
}
#ifdef DW_CHARS
# define MKillDwRight(p, ml, x) \
if (dw_right(ml, x, p->w_encoding)) \
{ \
if (x > 0) \
copy_mchar2mline(&mchar_blank, ml, x - 1); \
copy_mchar2mline(&mchar_blank, ml, x); \
}
# define MKillDwLeft(p, ml, x) \
if (dw_left(ml, x, p->w_encoding)) \
{ \
copy_mchar2mline(&mchar_blank, ml, x); \
copy_mchar2mline(&mchar_blank, ml, x + 1); \
}
#else
# define MKillDwRight(p, ml, x) ;
# define MKillDwLeft(p, ml, x) ;
#endif
static void
MScrollH(p, n, y, xs, xe, bce)
struct win *p;
int n, y, xs, xe, bce;
{
struct mline *ml;
if (n == 0)
return;
ml = &p->w_mlines[y];
MKillDwRight(p, ml, xs);
MKillDwLeft(p, ml, xe);
if (n > 0)
{
if (xe - xs + 1 > n)
{
MKillDwRight(p, ml, xs + n);
bcopy_mline(ml, xs + n, xs, xe + 1 - xs - n);
}
else
n = xe - xs + 1;
clear_mline(ml, xe + 1 - n, n);
#ifdef COLOR
if (bce)
MBceLine(p, y, xe + 1 - n, n, bce);
#endif
}
else
{
n = -n;
if (xe - xs + 1 > n)
{
MKillDwLeft(p, ml, xe - n);
bcopy_mline(ml, xs, xs + n, xe + 1 - xs - n);
}
else
n = xe - xs + 1;
clear_mline(ml, xs, n);
#ifdef COLOR
if (bce)
MBceLine(p, y, xs, n, bce);
#endif
}
}
static void
MScrollV(p, n, ys, ye, bce)
struct win *p;
int n, ys, ye, bce;
{
int i, cnt1, cnt2;
struct mline tmp[256];
struct mline *ml;
if (n == 0)
return;
if (n > 0)
{
if (n > 256)
{
MScrollV(p, n - 256, ys, ye, bce);
n = 256;
}
if (ye - ys + 1 < n)
n = ye - ys + 1;
#ifdef COPY_PASTE
if (compacthist)
{
ye = MFindUsedLine(p, ye, ys);
if (ye - ys + 1 < n)
n = ye - ys + 1;
if (n <= 0)
return;
}
#endif
ml = p->w_mlines + ys;
for (i = ys; i < ys + n; i++, ml++)
{
#ifdef COPY_PASTE
if (ys == p->w_top)
WAddLineToHist(p, ml);
#endif
if (ml->attr != null)
free(ml->attr);
ml->attr = null;
#ifdef FONT
if (ml->font != null)
free(ml->font);
ml->font = null;
#endif
#ifdef COLOR
if (ml->color != null)
free(ml->color);
ml->color = null;
# ifdef COLORS256
if (ml->colorx != null)
free(ml->colorx);
ml->colorx = null;
# endif
#endif
bclear((char *)ml->image, p->w_width + 1);
#ifdef COLOR
if (bce)
MBceLine(p, i, 0, p->w_width, bce);
#endif
}
cnt1 = n * sizeof(struct mline);
cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
if (cnt1 && cnt2)
Scroll((char *)(p->w_mlines + ys), cnt1, cnt2, (char *)tmp);
}
else
{
if (n < -256)
{
MScrollV(p, n + 256, ys, ye, bce);
n = -256;
}
n = -n;
if (ye - ys + 1 < n)
n = ye - ys + 1;
ml = p->w_mlines + ye;
for (i = ye; i > ye - n; i--, ml--)
{
if (ml->attr != null)
free(ml->attr);
ml->attr = null;
#ifdef FONT
if (ml->font != null)
free(ml->font);
ml->font = null;
#endif
#ifdef COLOR
if (ml->color != null)
free(ml->color);
ml->color = null;
# ifdef COLORS256
if (ml->colorx != null)
free(ml->colorx);
ml->colorx = null;
# endif
#endif
bclear((char *)ml->image, p->w_width + 1);
#ifdef COLOR
if (bce)
MBceLine(p, i, 0, p->w_width, bce);
#endif
}
cnt1 = n * sizeof(struct mline);
cnt2 = (ye - ys + 1 - n) * sizeof(struct mline);
if (cnt1 && cnt2)
Scroll((char *)(p->w_mlines + ys), cnt2, cnt1, (char *)tmp);
}
}
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
MClearArea(p, xs, ys, xe, ye, bce)
struct win *p;
int xs, ys, xe, ye, bce;
{
int n, y;
int xxe;
struct mline *ml;
if (xs >= p->w_width)
xs = p->w_width - 1;
if (xe >= p->w_width)
xe = p->w_width - 1;
MKillDwRight(p, p->w_mlines + ys, xs);
MKillDwLeft(p, p->w_mlines + ye, xe);
ml = p->w_mlines + ys;
for (y = ys; y <= ye; y++, ml++)
{
xxe = (y == ye) ? xe : p->w_width - 1;
n = xxe - xs + 1;
if (n > 0)
clear_mline(ml, xs, n);
#ifdef COLOR
if (n > 0 && bce)
MBceLine(p, y, xs, xs + n - 1, bce);
#endif
xs = 0;
}
}
static void
MInsChar(p, c, x, y)
struct win *p;
struct mchar *c;
int x, y;
{
int n;
struct mline *ml;
ASSERT(x >= 0 && x < p->w_width);
MFixLine(p, y, c);
ml = p->w_mlines + y;
n = p->w_width - x - 1;
MKillDwRight(p, ml, x);
if (n > 0)
{
MKillDwRight(p, ml, p->w_width - 1);
bcopy_mline(ml, x, x + 1, n);
}
copy_mchar2mline(c, ml, x);
#ifdef DW_CHARS
if (c->mbcs)
{
if (--n > 0)
{
MKillDwRight(p, ml, p->w_width - 1);
bcopy_mline(ml, x + 1, x + 2, n);
}
copy_mchar2mline(c, ml, x + 1);
ml->image[x + 1] = c->mbcs;
# ifdef UTF8
if (p->w_encoding != UTF8)
ml->font[x + 1] |= 0x80;
else if (p->w_encoding == UTF8 && c->mbcs)
ml->font[x + 1] = c->mbcs;
# else
ml->font[x + 1] |= 0x80;
# endif
}
#endif
}
static void
MPutChar(p, c, x, y)
struct win *p;
struct mchar *c;
int x, y;
{
struct mline *ml;
MFixLine(p, y, c);
ml = &p->w_mlines[y];
MKillDwRight(p, ml, x);
MKillDwLeft(p, ml, x);
copy_mchar2mline(c, ml, x);
#ifdef DW_CHARS
if (c->mbcs)
{
MKillDwLeft(p, ml, x + 1);
copy_mchar2mline(c, ml, x + 1);
ml->image[x + 1] = c->mbcs;
# ifdef UTF8
if (p->w_encoding != UTF8)
ml->font[x + 1] |= 0x80;
else if (p->w_encoding == UTF8 && c->mbcs)
ml->font[x + 1] = c->mbcs;
# else
ml->font[x + 1] |= 0x80;
# endif
}
#endif
}
static void
MWrapChar(p, c, y, top, bot, ins)
struct win *p;
struct mchar *c;
int y, top, bot;
int ins;
{
struct mline *ml;
int bce;
#ifdef COLOR
bce = rend_getbg(c);
#else
bce = 0;
#endif
MFixLine(p, y, c);
ml = &p->w_mlines[y];
copy_mchar2mline(&mchar_null, ml, p->w_width);
if (y == bot)
MScrollV(p, 1, top, bot, bce);
else if (y < p->w_height - 1)
y++;
if (ins)
MInsChar(p, c, 0, y);
else
MPutChar(p, c, 0, y);
}
static void
MPutStr(p, s, n, r, x, y)
struct win *p;
char *s;
int n;
struct mchar *r;
int x, y;
{
struct mline *ml;
int i;
unsigned char *b;
if (n <= 0)
return;
MFixLine(p, y, r);
ml = &p->w_mlines[y];
MKillDwRight(p, ml, x);
MKillDwLeft(p, ml, x + n - 1);
bcopy(s, (char *)ml->image + x, n);
b = ml->attr + x;
for (i = n; i-- > 0;)
*b++ = r->attr;
#ifdef FONT
b = ml->font + x;
for (i = n; i-- > 0;)
*b++ = r->font;
#endif
#ifdef COLOR
b = ml->color + x;
for (i = n; i-- > 0;)
*b++ = r->color;
# ifdef COLORS256
b = ml->colorx + x;
for (i = n; i-- > 0;)
*b++ = r->colorx;
# endif
#endif
}
#ifdef COLOR
static void
MBceLine(p, y, xs, xe, bce)
struct win *p;
int y, xs, xe, bce;
{
struct mchar mc;
struct mline *ml;
int x;
mc = mchar_null;
rend_setbg(&mc, bce);
MFixLine(p, y, &mc);
ml = p->w_mlines + y;
# ifdef COLORS16
if (mc.attr)
for (x = xs; x <= xe; x++)
ml->attr[x] = mc.attr;
# endif
if (mc.color)
for (x = xs; x <= xe; x++)
ml->color[x] = mc.color;
# ifdef COLORS256
if (mc.colorx)
for (x = xs; x <= xe; x++)
ml->colorx[x] = mc.colorx;
# endif
}
#endif
#ifdef COPY_PASTE
static void
WAddLineToHist(wp, ml)
struct win *wp;
struct mline *ml;
{
register unsigned char *q, *o;
struct mline *hml;
if (wp->w_histheight == 0)
return;
hml = &wp->w_hlines[wp->w_histidx];
q = ml->image; ml->image = hml->image; hml->image = q;
q = ml->attr; o = hml->attr; hml->attr = q; ml->attr = null;
if (o != null)
free(o);
#ifdef FONT
q = ml->font; o = hml->font; hml->font = q; ml->font = null;
if (o != null)
free(o);
#endif
#ifdef COLOR
q = ml->color; o = hml->color; hml->color = q; ml->color = null;
if (o != null)
free(o);
# ifdef COLORS256
q = ml->colorx; o = hml->colorx; hml->colorx = q; ml->colorx = null;
if (o != null)
free(o);
# endif
#endif
if (++wp->w_histidx >= wp->w_histheight)
wp->w_histidx = 0;
}
#endif
int
MFindUsedLine(p, ye, ys)
struct win *p;
int ys, ye;
{
int y;
struct mline *ml = p->w_mlines + ye;
debug2("MFindUsedLine: %d %d\n", ye, ys);
for (y = ye; y >= ys; y--, ml--)
{
if (bcmp((char*)ml->image, blank, p->w_width))
break;
if (ml->attr != null && bcmp((char*)ml->attr, null, p->w_width))
break;
#ifdef COLOR
if (ml->color != null && bcmp((char*)ml->color, null, p->w_width))
break;
# ifdef COLORS256
if (ml->colorx != null && bcmp((char*)ml->colorx, null, p->w_width))
break;
# endif
#endif
}
debug1("MFindUsedLine returning %d\n", y);
return y;
}
void
WBell(p, visual)
struct win *p;
int visual;
{
struct canvas *cv;
for (display = displays; display; display = display->d_next)
{
for (cv = D_cvlist; cv; cv = cv->c_next)
if (cv->c_layer->l_bottom == &p->w_layer)
break;
if (cv && !visual)
AddCStr(D_BL);
else if (cv && D_VB)
AddCStr(D_VB);
else
p->w_bell = visual ? BELL_VISUAL : BELL_FOUND;
}
}
static void
WReverseVideo(p, on)
struct win *p;
int on;
{
struct canvas *cv;
for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
{
display = cv->c_display;
if (cv != D_forecv)
continue;
ReverseVideo(on);
if (!on && p->w_revvid && !D_CVR)
{
if (D_VB)
AddCStr(D_VB);
else
p->w_bell = BELL_VISUAL;
}
}
}
void
WMsg(p, err, str)
struct win *p;
int err;
char *str;
{
extern struct layer *flayer;
struct layer *oldflayer = flayer;
flayer = &p->w_layer;
LMsg(err, str);
flayer = oldflayer;
}
void
WChangeSize(p, w, h)
struct win *p;
int w, h;
{
int wok = 0;
struct canvas *cv;
if (p->w_layer.l_cvlist == 0)
{
ChangeWindowSize(p, w, h, p->w_histheight);
return;
}
for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
{
display = cv->c_display;
if (p != D_fore)
continue;
if (D_CWS)
break;
if (D_CZ0 && (w == Z0width || w == Z1width))
wok = 1;
}
if (cv == 0 && wok == 0)
return;
if (!D_CWS)
h = p->w_height;
ChangeWindowSize(p, w, h, p->w_histheight);
for (display = displays; display; display = display->d_next)
{
if (p == D_fore)
{
if (D_cvlist && D_cvlist->c_next == 0)
ResizeDisplay(w, h);
else
ResizeDisplay(w, D_height);
ResizeLayersToCanvases();
continue;
}
for (cv = D_cvlist; cv; cv = cv->c_next)
if (cv->c_layer->l_bottom == &p->w_layer)
break;
if (cv)
Redisplay(0);
}
}
static int
WindowChangedCheck(s, what, hp)
char *s;
int what;
int *hp;
{
int h = 0;
int l;
while(*s)
{
if (*s++ != (hp ? '%' : '\005'))
continue;
l = 0;
while (*s >= '0' && *s <= '9')
s++;
if (*s == 'L')
{
s++;
l = 0x100;
}
if (*s == 'h')
h = 1;
if (*s == what || ((*s | l) == what) || what == 'd')
break;
if (*s)
s++;
}
if (hp)
*hp = h;
return *s ? 1 : 0;
}
void
WindowChanged(p, what)
struct win *p;
int what;
{
int inwstr, inhstr, inlstr;
int inwstrh = 0, inhstrh = 0, inlstrh = 0;
int got, ox, oy;
struct display *olddisplay = display;
struct canvas *cv;
inwstr = inhstr = 0;
if (what == 'f')
{
WindowChanged((struct win *)0, 'w'|0x100);
WindowChanged((struct win *)0, 'W'|0x100);
}
if (what)
{
inwstr = WindowChangedCheck(captionstring, what, &inwstrh);
inhstr = WindowChangedCheck(hstatusstring, what, &inhstrh);
inlstr = WindowChangedCheck(wliststr, what, &inlstrh);
}
else
{
inwstr = inhstr = 0;
inlstr = 1;
}
if (p == 0)
{
for (display = displays; display; display = display->d_next)
{
ox = D_x;
oy = D_y;
for (cv = D_cvlist; cv; cv = cv->c_next)
{
if (inlstr || (inlstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
WListUpdatecv(cv, (struct win *)0);
p = Layer2Window(cv->c_layer);
if (inwstr || (inwstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
if (cv->c_ye + 1 < D_height)
RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
}
p = D_fore;
if (inhstr || (inhstrh && p && p->w_hstatus && *p->w_hstatus && WindowChangedCheck(p->w_hstatus, what, (int *)0)))
RefreshHStatus();
if (ox != -1 && ox != -1)
GotoPos(ox, oy);
}
display = olddisplay;
return;
}
if (p->w_hstatus && *p->w_hstatus && (inwstrh || inhstrh || inlstrh) && WindowChangedCheck(p->w_hstatus, what, (int *)0))
{
inwstr |= inwstrh;
inhstr |= inhstrh;
inlstr |= inlstrh;
}
if (!inwstr && !inhstr && !inlstr)
return;
for (display = displays; display; display = display->d_next)
{
got = 0;
ox = D_x;
oy = D_y;
for (cv = D_cvlist; cv; cv = cv->c_next)
{
if (inlstr)
WListUpdatecv(cv, p);
if (Layer2Window(cv->c_layer) != p)
continue;
got = 1;
if (inwstr && cv->c_ye + 1 < D_height)
RefreshLine(cv->c_ye + 1, 0, D_width - 1, 0);
}
if (got && inhstr && p == D_fore)
RefreshHStatus();
if (ox != -1 && ox != -1)
GotoPos(ox, oy);
}
display = olddisplay;
}