summaryrefslogtreecommitdiffstats
path: root/ansi.c
diff options
context:
space:
mode:
Diffstat (limited to 'ansi.c')
-rw-r--r--ansi.c3207
1 files changed, 3207 insertions, 0 deletions
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..27983bb
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,3207 @@
+/* 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 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;
+}
+