diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:20:21 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 02:20:21 +0000 |
commit | 4f64827f3a395072f300b86ef17f730805b47048 (patch) | |
tree | c16297f7d68903dc80c86e3003b8e3ab5f030f7d /ansi.c | |
parent | Initial commit. (diff) | |
download | screen-upstream.tar.xz screen-upstream.zip |
Adding upstream version 4.6.2.upstream/4.6.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | ansi.c | 3193 |
1 files changed, 3193 insertions, 0 deletions
@@ -0,0 +1,3193 @@ +/* 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 + * http://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; + } +# ifdef DW_CHARS + if (curr->w_encoding == UTF8 && 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 && 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; + } + 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; + } + } + 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; + + 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 == 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'; + /* 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 prefered */ + 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 replys */ + + 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; +} + |