1
0
Fork 0
screen/ansi.c
Daniel Baumann e88291c4cd
Adding upstream version 4.9.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 15:19:57 +02:00

3207 lines
69 KiB
C

/* Copyright (c) 2008, 2009
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Micah Cowan (micah@cowan.name)
* Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
* Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
* Copyright (c) 1987 Oliver Laumann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING); if not, see
* https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
****************************************************************
*/
#include <sys/types.h>
#include <fcntl.h>
#ifndef sun /* we want to know about TIOCPKT. */
# 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; /* for 83 escape */
extern struct layer *flayer; /* for 83 escape */
extern struct NewWindow nwin_default; /* for ResetWindow() */
extern int nversion; /* numerical version of screen */
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
/* widths for Z0/Z1 switching */
const int Z0width = 132;
const int Z1width = 80;
/* globals set in WriteString */
static struct win *curr; /* window we are working on */
static int rows, cols; /* window size of the curr window */
int visual_bell = 0;
int use_hardstatus = 1; /* display status line in hs */
char *printcmd = 0;
int use_altscreen = 0; /* enable alternate screen support? */
unsigned char *blank; /* line filled with spaces */
unsigned char *null; /* line filled with '\0' */
struct mline mline_old;
struct mline mline_blank;
struct mline mline_null;
struct mchar mchar_null;
struct mchar mchar_blank = {' ' /* , 0, 0, ... */};
struct mchar mchar_so = {' ', A_SO /* , 0, 0, ... */};
int renditions[NUM_RENDS] = {65529 /* =ub */, 65531 /* =b */, 65533 /* =u */ };
/* keep string_t and string_t_string in sync! */
static char *string_t_string[] =
{
"NONE",
"DCS", /* Device control string */
"OSC", /* Operating system command */
"APC", /* Application program command */
/* - used for status change */
"PM", /* Privacy message */
"AKA", /* title for current screen */
"GM", /* Global message to every display */
"STATUS" /* User hardstatus line */
};
/* keep state_t and state_t_string in sync! */
static char *state_t_string[] =
{
"LIT", /* Literal input */
"ESC", /* Start of escape sequence */
"ASTR", /* Start of control string */
"STRESC", /* ESC seen in control string */
"CSI", /* Reading arguments in "CSI Pn ;...*/
"PRIN", /* Printer mode */
"PRINESC", /* ESC seen in printer mode */
"PRINCSI", /* CSI seen in printer mode */
"PRIN4" /* CSI 4 seen in printer mode */
};
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((struct cursor *));
static void RestoreCursor __P((struct cursor *));
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.on = 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
}
/* adds max 22 bytes */
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 /* FONT */
/*****************************************************************/
/*
* Here comes the vt100 emulator
* - writes logfiles,
* - sets timestamp and flags activity in window.
* - record program output in window scrollback
* - translate program output for the display and put it into the obuf.
*
*/
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);
/* set global variables (yuck!) */
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;
}
if (cols > 0 && rows > 0)
{
do
{
c = (unsigned char)*buf++;
#ifdef FONT
# ifdef DW_CHARS
if (!curr->w_mbcs)
# endif
curr->w_rend.font = curr->w_FontL; /* Default: GL */
#endif
/* The next part is only for speedup */
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;
}
/* end of speedup code */
#ifdef UTF8
if (curr->w_encoding == UTF8)
{
c = FromUtf8(c, &curr->w_decodestate);
if (c == -1)
continue;
if (c == -2)
{
c = UCS_REPL;
/* try char again */
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;
}
/* special xterm hack: accept SetStatus sequence. Yucc! */
/* allow ^E for title escapes */
if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
if (!curr->w_c1 || c != ('\\' ^ 0xc0))
{
StringChar(c);
break;
}
c = '\\';
/* FALLTHROUGH */
case STRESC:
switch (c)
{
case '\\':
if (StringEnd() == 0 || len <= 1)
break;
/* check if somewhere a status is displayed */
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; /* wait till status is gone */
}
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 >= 0 && 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': /* SS2 */
case 0xc0 ^ 'O': /* SS3 */
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';
mc.fontx = 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;
}
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 && omc.fontx == 0)
{
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;
}
# ifdef DW_CHARS
if (curr->w_encoding == UTF8 && utf8_isdouble(c))
curr->w_mbcs = 0xff;
# endif
font = curr->w_rend.font;
# endif
# ifdef DW_CHARS
# ifdef ENCODINGS
if (font == KANA && curr->w_encoding == SJIS && curr->w_mbcs == 0)
{
/* Lets see if it is the first byte of a kanji */
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);
/*
* SJIS -> EUC mapping:
* First byte:
* 81,82...9f -> 21,23...5d
* e0,e1...ef -> 5f,61...7d
* Second byte:
* 40-7e -> 21-5f
* 80-9e -> 60-7e
* 9f-fc -> 21-7e (increment first byte!)
*/
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
{
/* Incomplete shift-jis - skip first byte */
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 /* DW_CHARS */
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 < ' ') /* this is ugly but kanji support */
goto tryagain; /* prevents nicer programming */
#endif
}
#endif /* FONT */
if (c == '\177')
break;
curr->w_rend.image = c;
#ifdef UTF8
if (curr->w_encoding == UTF8)
{
curr->w_rend.font = c >> 8;
curr->w_rend.fontx = c >> 16;
}
#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 /* FONT */
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)); /* long time no write */
}
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();
case '\013': /* Vertical tab is the same as Line Feed */
LineFeed(0);
return 1;
case '\007':
WBell(curr, visual_bell);
return 1;
case '\t':
ForwardTab();
return 1;
#ifdef FONT
case '\017': /* SI */
MapCharset(G0);
return 1;
case '\016': /* SO */
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': /* jph: Identify as VT100 */
Report("\033[?%d;%dc", 1, 2);
break;
case '7':
SaveCursor(&curr->w_saved);
break;
case '8':
RestoreCursor(&curr->w_saved);
break;
case 'c':
ClearScreen();
ResetWindow(curr);
LKeypadMode(&curr->w_layer, 0);
LCursorkeysMode(&curr->w_layer, 0);
#ifndef TIOCPKT
WNewAutoFlow(curr, 1);
#endif
/* XXX
SetRendition(&mchar_null);
InsertMode(0);
ChangeScrollRegion(0, rows - 1);
*/
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 /* !TIOCPKT */
break;
case '>':
LKeypadMode(&curr->w_layer, curr->w_keypad = 0);
#ifndef TIOCPKT
WNewAutoFlow(curr, 1);
#endif /* !TIOCPKT */
break;
#ifdef FONT
case 'n': /* LS2 */
MapCharset(G2);
break;
case 'o': /* LS3 */
MapCharset(G3);
break;
case '~':
MapCharsetR(G1); /* LS1R */
break;
/* { */
case '}':
MapCharsetR(G2); /* LS2R */
break;
case '|':
MapCharsetR(G3); /* LS3R */
break;
case 'N': /* SS2 */
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': /* SS3 */
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 /* FONT */
case 'g': /* VBELL, private screen sequence */
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
/*
* ESC $ ( Fn: invoke multi-byte charset, Fn, to G0
* ESC $ Fn: same as above. (old sequence)
* ESC $ ) Fn: invoke multi-byte charset, Fn, to G1
* ESC $ * Fn: invoke multi-byte charset, Fn, to G2
* ESC $ + Fn: invoke multi-byte charset, Fn, to G3
*/
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 /* FONT */
}
}
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); /* positions cursor */
break;
case 'F':
curr->w_x = 0;
CursorUp(a1 ? a1 : 1); /* positions cursor */
break;
case 'G':
case '`': /* HPA */
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': /* VPA */
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;
/* ChangeScrollRegion(curr->w_top, curr->w_bot); */
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(&curr->w_saved);
break;
case 't':
switch(a1)
{
case 11:
if (curr->w_layer.l_cvlist)
Report("\033[1t", 0, 0);
else
Report("\033[2t", 0, 0);
break;
case 7:
LRefreshAll(&curr->w_layer, 0);
break;
case 21:
a1 = strlen(curr->w_title);
if ((unsigned)(curr->w_inlen + 5 + a1) <= sizeof(curr->w_inbuf))
{
bcopy("\033]l", curr->w_inbuf + curr->w_inlen, 3);
bcopy(curr->w_title, curr->w_inbuf + curr->w_inlen + 3, a1);
bcopy("\033\\", curr->w_inbuf + curr->w_inlen + 3 + a1, 2);
curr->w_inlen += 5 + a1;
}
break;
case 8:
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;
default:
break;
}
break;
case 'u':
RestoreCursor(&curr->w_saved);
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': /* MC Media Control */
if (a1 == 5)
PrintStart();
break;
case 'n':
if (a1 == 5) /* Report terminal status */
Report("\033[0n", 0, 0);
else if (a1 == 6) /* Report cursor position */
Report("\033[%d;%dR", curr->w_y + 1, curr->w_x + 1);
break;
case 'c': /* Identify as VT100 */
if (a1 == 0)
Report("\033[?%d;%dc", 1, 2);
break;
case 'x': /* decreqtparm */
if (a1 == 0 || a1 == 1)
Report("\033[%d;1;1;112;112;1;0x", a1 + 2, 0);
break;
case 'p': /* obscure code from a 97801 term */
if (a1 == 6 || a1 == 7)
{
curr->w_curinv = 7 - a1;
LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
}
break;
case 'S': /* code from a 97801 term / DEC vt400 */
ScrollRegion(a1 ? a1 : 1);
break;
case 'T': /* code from a 97801 term / DEC vt400 */
case '^': /* SD as per ISO 6429 */
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: /* CKM: cursor key mode */
LCursorkeysMode(&curr->w_layer, curr->w_cursorkeys = i);
#ifndef TIOCPKT
WNewAutoFlow(curr, !i);
#endif /* !TIOCPKT */
break;
case 2: /* ANM: ansi/vt52 mode */
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[3] =
curr->w_FontL = curr->w_FontR = ASCII;
curr->w_Charset = 0;
curr->w_CharsetR = 2;
curr->w_ss = 0;
#endif
}
break;
case 3: /* COLM: column mode */
i = (i ? Z0width : Z1width);
ClearScreen();
curr->w_x = 0;
curr->w_y = 0;
WChangeSize(curr, i, curr->w_height);
cols = curr->w_width;
rows = curr->w_height;
break;
/* case 4: SCLM: scrolling mode */
case 5: /* SCNM: screen mode */
if (i != curr->w_revvid)
WReverseVideo(curr, i);
curr->w_revvid = i;
break;
case 6: /* OM: origin mode */
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: /* AWM: auto wrap mode */
curr->w_wrap = i;
break;
/* case 8: ARM: auto repeat mode */
/* case 9: INLM: interlace mode */
case 9: /* X10 mouse tracking */
curr->w_mouse = i ? 9 : 0;
LMouseMode(&curr->w_layer, curr->w_mouse);
break;
/* case 10: EDM: edit mode */
/* case 11: LTM: line transmit mode */
/* case 13: SCFDM: space compression / field delimiting */
/* case 14: TEM: transmit execution mode */
/* case 16: EKEM: edit key execution mode */
/* case 18: PFF: Printer term form feed */
/* case 19: PEX: Printer extend screen / scroll. reg */
case 25: /* TCEM: text cursor enable mode */
curr->w_curinv = !i;
LCursorVisibility(&curr->w_layer, curr->w_curinv ? -1 : curr->w_curvvis);
break;
/* case 34: RLM: Right to left mode */
/* case 35: HEBM: hebrew keyboard map */
/* case 36: HEM: hebrew encoding */
/* case 38: TeK Mode */
/* case 40: 132 col enable */
/* case 42: NRCM: 7bit NRC character mode */
/* case 44: margin bell enable */
case 47: /* xterm-like alternate screen */
case 1047: /* xterm-like alternate screen */
case 1049: /* xterm-like alternate screen */
if (use_altscreen)
{
if (i)
{
if (!curr->w_alt.on) {
SaveCursor(&curr->w_alt.cursor);
EnterAltScreen(curr);
}
}
else
{
if (curr->w_alt.on) {
RestoreCursor(&curr->w_alt.cursor);
LeaveAltScreen(curr);
}
}
if (a1 == 47 && !i)
curr->w_saved.on = 0;
LRefreshAll(&curr->w_layer, 0);
LGotoPos(&curr->w_layer, curr->w_x, curr->w_y);
}
break;
case 1048:
if (i)
SaveCursor(&curr->w_saved);
else
RestoreCursor(&curr->w_saved);
break;
/* case 66: NKM: Numeric keypad appl mode */
/* case 68: KBUM: Keyboard usage mode (data process) */
case 1000: /* VT200 mouse tracking */
case 1001: /* VT200 highlight mouse */
case 1002: /* button event mouse*/
case 1003: /* any event mouse*/
curr->w_mouse = i ? a1 : 0;
LMouseMode(&curr->w_layer, curr->w_mouse);
break;
/* case 1005: UTF-8 mouse mode rejected */
case 1006: /* SGR mouse mode */
curr->w_extmouse = i ? a1 : 0;
LExtMouseMode(&curr->w_layer, curr->w_extmouse);
break;
/* case 1015: UXRVT mouse mode rejected */
}
}
break;
case '>':
switch (c)
{
case 'c': /* secondary DA */
if (a1 == 0)
Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
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;
}
/*
* Do string processing. Returns -1 if output should be suspended
* until status is gone.
*/
static int
StringEnd()
{
struct canvas *cv;
char *p;
int typ;
char *t;
/* There's two ways to terminate an OSC. If we've seen an ESC
* then it's been ST otherwise it's BEL. */
t = curr->w_state == STRESC ? "\033\\" : "\a";
curr->w_state = LIT;
*curr->w_stringp = '\0';
switch (curr->w_StringType)
{
case OSC: /* special xterm compatibility hack */
if (curr->w_string[0] == ';' || (p = index(curr->w_string, ';')) == 0)
break;
typ = atoi(curr->w_string);
p++;
#ifdef MULTIUSER
if (typ == 83) /* 83 = 'S' */
{
/* special execute commands sequence */
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; /* found it */
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 == 2 || typ == 11 || typ == 20 || typ == 39 || typ == 49)
{
int typ2;
typ2 = typ / 10;
if (strcmp(curr->w_xtermosc[typ2], p))
{
if (typ != 11 || strcmp("?", 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, p, t);
if ((typ2 == 3 || typ2 == 4) && D_xtermosc[typ2])
Redisplay(0);
if (typ == 11 && !strcmp("?", p))
break;
}
}
}
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';
/* FALLTHROUGH */
case APC:
if (curr->w_hstatus)
{
if (strcmp(curr->w_hstatus, curr->w_string) == 0)
break; /* not changed */
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;
if (curr->w_dynamicaka)
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;
/* find us a nice display to print on, fore preferred */
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(3);
}
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)) /* map JIS 6226 to 0208 */
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 /* FONT */
static void
SaveCursor(cursor)
struct cursor *cursor;
{
cursor->on = 1;
cursor->x = curr->w_x;
cursor->y = curr->w_y;
cursor->Rend = curr->w_rend;
#ifdef FONT
cursor->Charset = curr->w_Charset;
cursor->CharsetR = curr->w_CharsetR;
bcopy((char *) curr->w_charsets, (char *) cursor->Charsets,
4 * sizeof(int));
#endif
}
static void
RestoreCursor(cursor)
struct cursor *cursor;
{
if (!cursor->on)
return;
LGotoPos(&curr->w_layer, cursor->x, cursor->y);
curr->w_x = cursor->x;
curr->w_y = cursor->y;
curr->w_rend = cursor->Rend;
#ifdef FONT
bcopy((char *) cursor->Charsets, (char *) curr->w_charsets,
4 * sizeof(int));
curr->w_Charset = cursor->Charset;
curr->w_CharsetR = cursor->CharsetR;
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;
{
/* out_mode: 0=lf, 1=cr+lf */
if (out_mode)
curr->w_x = 0;
if (curr->w_y != curr->w_bot) /* Don't scroll */
{
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 above scrolling rgn, */
{
if ((curr->w_y -= n) < 0) /* ignore its limits */
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 below scrolling rgn, */
{
if ((curr->w_y += n) > rows - 1) /* ignore its limits */
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 2: KAM: Lock keyboard */
case 4: /* IRM: Insert mode */
curr->w_insert = on;
LAY_DISPLAYS(&curr->w_layer, InsertMode(on));
break;
/* case 12: SRM: Echo mode on */
case 20: /* LNM: Linefeed mode */
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);
}
/*
* Ugly autoaka hack support:
* ChangeAKA() sets a new aka
* FindAKA() searches for an autoaka match
*/
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);
}
/* Send a terminal report as if it were typed. */
static void
Report(fmt, n1, n2)
char *fmt;
int n1, n2;
{
register int len;
char rbuf[40]; /* enough room for all replies */
sprintf(rbuf, fmt, n1, n2);
len = strlen(rbuf);
#ifdef PSEUDOS
if (W_UWP(curr))
{
if ((unsigned)(curr->w_pwin->p_inlen + len) <= sizeof(curr->w_pwin->p_inbuf))
{
bcopy(rbuf, curr->w_pwin->p_inbuf + curr->w_pwin->p_inlen, len);
curr->w_pwin->p_inlen += len;
}
}
else
#endif
{
if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
{
bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
curr->w_inlen += len;
}
}
}
/*
*====================================================================*
*====================================================================*
*/
/**********************************************************************
*
* Memory subsystem.
*
*/
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 *)calloc(p->w_width + 1, 1)) == 0)
{
ml->attr = null;
mc->attr = p->w_rend.attr = 0;
WMsg(p, 0, "Warning: no space for attr - turned off");
}
}
#ifdef FONT
if (mc->font && ml->font == null)
{
if ((ml->font = (unsigned char *)calloc(p->w_width + 1, 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 = mc->fontx = p->w_rend.font = 0;
WMsg(p, 0, "Warning: no space for font - turned off");
}
}
if (mc->fontx && ml->fontx == null)
{
if ((ml->fontx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
{
ml->fontx = null;
mc->fontx = 0;
}
}
#endif
#ifdef COLOR
if (mc->color && ml->color == null)
{
if ((ml->color = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
{
ml->color = null;
mc->color = p->w_rend.color = 0;
WMsg(p, 0, "Warning: no space for color - turned off");
}
}
# ifdef COLORS256
if (mc->colorx && ml->colorx == null)
{
if ((ml->colorx = (unsigned char *)calloc(p->w_width + 1, 1)) == 0)
{
ml->colorx = null;
mc->colorx = p->w_rend.colorx = 0;
WMsg(p, 0, "Warning: no space for extended colors - turned off");
}
}
# 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 (ye - ys + 1 < n)
n = ye - ys + 1;
if (n > 256)
{
MScrollV(p, n - 256, ys, ye, bce);
n = 256;
}
#ifdef COPY_PASTE
if (compacthist)
{
ye = MFindUsedLine(p, ye, ys);
if (ye - ys + 1 < n)
n = ye - ys + 1;
if (n <= 0)
return;
}
#endif
/* Clear lines */
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;
if (ml->fontx != null)
free(ml->fontx);
ml->fontx = 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
}
/* switch 'em over */
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
{
n = -n;
if (ye - ys + 1 < n)
n = ye - ys + 1;
if (n > 256)
{
MScrollV(p, - (n - 256), ys, ye, bce);
n = 256;
}
ml = p->w_mlines + ye;
/* Clear lines */
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;
if (ml->fontx != null)
free(ml->fontx);
ml->fontx = 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;
/* Check for zero-height window */
if (ys < 0 || ye < ys)
return;
/* check for magic margin condition */
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;
ml->fontx[x + 1] = 0;
}
# 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;
ml->fontx[x + 1] = 0;
}
# 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);
if (ml->attr != null)
{
b = ml->attr + x;
for (i = n; i-- > 0;)
*b++ = r->attr;
}
#ifdef FONT
if (ml->font != null)
{
b = ml->font + x;
for (i = n; i-- > 0;)
*b++ = r->font;
}
if (ml->fontx != null)
{
b = ml->fontx + x;
for (i = n; i-- > 0;)
*b++ = r->fontx;
}
#endif
#ifdef COLOR
if (ml->color != null)
{
b = ml->color + x;
for (i = n; i-- > 0;)
*b++ = r->color;
}
# ifdef COLORS256
if (ml->colorx != null)
{
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);
q = ml->fontx; o = hml->fontx; hml->fontx = q; ml->fontx = 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;
if (wp->w_scrollback_height < wp->w_histheight)
++wp->w_scrollback_height;
}
#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
#ifdef UTF8
if (p->w_encoding == UTF8)
{
if (ml->font != null && bcmp((char*)ml->font, null, p->w_width))
break;
if (ml->fontx != null && bcmp((char*)ml->fontx, null, p->w_width))
break;
}
#endif
}
debug1("MFindUsedLine returning %d\n", y);
return y;
}
/*
*====================================================================*
*====================================================================*
*/
/*
* Tricky: send only one bell even if the window is displayed
* more than once.
*/
void
WBell(p, visual)
struct win *p;
int visual;
{
struct canvas *cv;
if (displays == NULL)
p->w_bell = BELL_DONE;
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;
}
}
/*
* This should be reverse video.
* Only change video if window is fore.
* Because it is used in some termcaps to emulate
* a visual bell we do this hack here.
* (screen uses \Eg as special vbell sequence)
*/
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, "%s", 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)
{
/* window not displayed -> works always */
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; /* change only fore */
if (D_CWS)
break;
if (D_CZ0 && (w == Z0width || w == Z1width))
wok = 1;
}
if (cv == 0 && wok == 0) /* can't change any display */
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(); /* XXX Hmm ? */
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;
s += (*s == '+');
s += (*s == '-');
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 && oy != -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 && oy != -1)
GotoPos(ox, oy);
}
display = olddisplay;
}