summaryrefslogtreecommitdiff
path: root/ansi.c
diff options
context:
space:
mode:
authorAxel Beckert <abe@deuxchevaux.org>2011-09-03 14:05:19 +0200
committerAxel Beckert <abe@deuxchevaux.org>2011-09-03 14:05:19 +0200
commit0636e9ecb5a32db4d4520f50a20652faa825feaf (patch)
treeb94df9221e8ae0de0dc3afac301d5b63b136a7b4 /ansi.c
downloadscreen-0636e9ecb5a32db4d4520f50a20652faa825feaf.tar.gz
Imported Upstream version 3.7.2upstream/3.7.2
Diffstat (limited to 'ansi.c')
-rw-r--r--ansi.c2511
1 files changed, 2511 insertions, 0 deletions
diff --git a/ansi.c b/ansi.c
new file mode 100644
index 0000000..3edbc81
--- /dev/null
+++ b/ansi.c
@@ -0,0 +1,2511 @@
+/* Copyright (c) 1993
+ * 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 2, 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, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ ****************************************************************
+ */
+
+#include "rcs.h"
+RCS_ID("$Id: ansi.c,v 1.22 1994/05/31 12:31:25 mlschroe Exp $ FAU")
+
+#include <sys/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifndef sun /* we want to know about TIOCPKT. */
+# include <sys/ioctl.h>
+#endif
+
+#include "config.h"
+#include "screen.h"
+#include "extern.h"
+
+extern struct win *windows; /* linked list of all windows */
+extern struct win *fore;
+extern struct display *display, *displays;
+
+extern int force_vt;
+extern int all_norefresh; /* => display */
+extern int ZombieKey_destroy, ZombieKey_resurrect;
+extern int real_uid, real_gid;
+extern time_t Now;
+extern struct NewWindow nwin_default; /* for ResetWindow() */
+extern int nversion;
+
+int Z0width, Z1width; /* widths for Z0/Z1 switching */
+
+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;
+char *printcmd = 0;
+
+char *blank; /* line filled with spaces */
+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, ... */};
+
+static void WinProcess __P((char **, int *));
+static void WinRedisplayLine __P((int, int, int, int));
+static void WinClearLine __P((int, int, int));
+static int WinRewrite __P((int, int, int, int));
+static void WinSetCursor __P((void));
+static int WinResize __P((int, int));
+static void WinRestore __P((void));
+static int Special __P((int));
+static void DoESC __P((int, int));
+static void DoCSI __P((int, int));
+static void SetChar __P((int));
+static void StartString __P((enum string_t));
+static void SaveChar __P((int));
+static void PrintStart __P((void));
+static void PrintChar __P((int));
+static void PrintFlush __P((void));
+static void DesignateCharset __P((int, int));
+static void MapCharset __P((int));
+static void MapCharsetR __P((int));
+static void SaveCursor __P((void));
+static void RestoreCursor __P((void));
+static void BackSpace __P((void));
+static void Return __P((void));
+static void LineFeed __P((int));
+static void ReverseLineFeed __P((void));
+static void InsertAChar __P((int));
+static void InsertChar __P((int));
+static void DeleteChar __P((int));
+static void DeleteLine __P((int));
+static void InsertLine __P((int));
+static void ScrollUpMap __P((int));
+static void ScrollDownMap __P((int));
+static void Scroll __P((char *, int, int, char *));
+static void ForwardTab __P((void));
+static void BackwardTab __P((void));
+static void ClearScreen __P((void));
+static void ClearFromBOS __P((void));
+static void ClearToEOS __P((void));
+static void ClearFullLine __P((void));
+static void ClearToEOL __P((void));
+static void ClearFromBOL __P((void));
+static void ClearInLine __P((int, 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 UpdateLine __P((struct mline *, int, int, int ));
+static void FindAKA __P((void));
+static void Report __P((char *, int, int));
+static void FixLine __P((void));
+static void ScrollRegion __P((int));
+static void CheckLP __P((int));
+#ifdef COPY_PASTE
+static void AddLineToHist __P((struct win *, struct mline *));
+#endif
+
+
+/*
+ * The window layer functions
+ */
+
+struct LayFuncs WinLf =
+{
+ WinProcess,
+ 0,
+ WinRedisplayLine,
+ WinClearLine,
+ WinRewrite,
+ WinSetCursor,
+ WinResize,
+ WinRestore
+};
+
+static void
+WinProcess(bufpp, lenp)
+char **bufpp;
+int *lenp;
+{
+ int addlf, l2 = 0, f, *ilen, l = *lenp;
+ char *ibuf, *p, *buf = *bufpp;
+
+ fore = D_fore;
+ /* if w_wlock is set, only one user may write, else we check acls */
+ if (fore->w_ptyfd < 0)
+ {
+ while ((*lenp)-- > 0)
+ {
+ f = *(*bufpp)++;
+ if (f == ZombieKey_destroy)
+ {
+ debug2("Turning undead: %d(%s)\n", fore->w_number, fore->w_title);
+ KillWindow(fore);
+ l2--;
+ break;
+ }
+ if (f == ZombieKey_resurrect)
+ {
+ SetCurr(fore);
+
+ debug1("Resurrecting Zombie: %d\n", fore->w_number);
+ LineFeed(2);
+ RemakeWindow(fore);
+ l2++;
+ break;
+ }
+ }
+ if (!l2)
+ {
+ char b1[10], b2[10];
+
+ b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
+ b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
+ Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
+ }
+ *bufpp += *lenp;
+ *lenp = 0;
+ return;
+ }
+#ifdef MULTIUSER
+ if ((fore->w_wlock == WLOCK_OFF) ?
+ AclCheckPermWin(D_user, ACL_WRITE, fore) :
+ (D_user != fore->w_wlockuser))
+ {
+ SetCurr(fore);
+ Special('\007');
+ *bufpp += *lenp;
+ *lenp = 0;
+ return;
+ }
+#endif /* MULTIUSER */
+#ifdef PSEUDOS
+ if (W_UWP(fore))
+ {
+ /* we send the user input to our pseudowin */
+ ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
+ f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
+ }
+ else
+#endif /* PSEUDOS */
+ {
+ /* we send the user input to the window */
+ ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
+ f = sizeof(fore->w_inbuf) - *ilen;
+ }
+
+ buf = *bufpp;
+
+ while (l)
+ {
+ l2 = l;
+ addlf = 0;
+ if (fore->w_autolf)
+ {
+ for (p = buf; l2; p++, l2--)
+ if (*p == '\r')
+ {
+ l2--;
+ addlf = 1;
+ break;
+ }
+ l2 = l - l2;
+ }
+ if (l2 + addlf > f)
+ {
+ debug1("Yuck! pty buffer full (%d chars missing). lets beep\n", l - f);
+ SetCurr(fore);
+ Special('\007');
+ l = l2 = f;
+ addlf = 0;
+ }
+ if (l2 > 0)
+ {
+ bcopy(buf, ibuf + *ilen, l2);
+ *ilen += l2;
+ f -= l2;
+ buf += l2;
+ l -= l2;
+ if (f && addlf)
+ {
+ ibuf[(*ilen)++] = '\n';
+ f--;
+ }
+ }
+ }
+ *bufpp += *lenp;
+ *lenp = 0;
+}
+
+static void
+WinRedisplayLine(y, from, to, isblank)
+int y, from, to, isblank;
+{
+ if (y < 0)
+ return;
+ fore = D_fore;
+ DisplayLine(isblank ? &mline_blank : &mline_null, &fore->w_mlines[y],
+ y, from, to);
+}
+
+static int
+WinRewrite(y, x1, x2, doit)
+int y, x1, x2, doit;
+{
+ register int cost, dx;
+ register char *p, *f, *i;
+#ifdef COLOR
+ register char *c;
+#endif
+
+ fore = D_fore;
+ dx = x2 - x1;
+ if (doit)
+ {
+ i = fore->w_mlines[y].image + x1;
+ while (dx-- > 0)
+ PUTCHAR(*i++);
+ return 0;
+ }
+ p = fore->w_mlines[y].attr + x1;
+ f = fore->w_mlines[y].font + x1;
+#ifdef COLOR
+ c = fore->w_mlines[y].color + x1;
+#endif
+
+ cost = dx = x2 - x1;
+ if (D_insert)
+ cost += D_EIcost + D_IMcost;
+ while(dx-- > 0)
+ {
+#ifdef COLOR
+ if (*p++ != D_rend.attr || *f++ != D_rend.font || *c++ != D_rend.color)
+ return EXPENSIVE;
+#else
+ if (*p++ != D_rend.attr || *f++ != D_rend.font)
+ return EXPENSIVE;
+#endif
+ }
+ return cost;
+}
+
+static void
+WinClearLine(y, xs, xe)
+int y, xs, xe;
+{
+ fore = D_fore;
+ DisplayLine(&fore->w_mlines[y], &mline_blank, y, xs, xe);
+}
+
+static void
+WinSetCursor()
+{
+ fore = D_fore;
+ GotoPos(fore->w_x, fore->w_y);
+}
+
+static int
+WinResize(wi, he)
+int wi, he;
+{
+ fore = D_fore;
+ if (fore)
+ ChangeWindowSize(fore, wi, he, fore->w_histheight);
+ return 0;
+}
+
+static void
+WinRestore()
+{
+ fore = D_fore;
+ ChangeScrollRegion(fore->w_top, fore->w_bot);
+ KeypadMode(fore->w_keypad);
+ CursorkeysMode(fore->w_cursorkeys);
+ SetFlow(fore->w_flow & FLOW_NOW);
+ InsertMode(fore->w_insert);
+ ReverseVideo(fore->w_revvid);
+ CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
+ fore->w_active = 1;
+}
+
+/*
+ * Activate - make fore window active
+ * norefresh = -1 forces a refresh, disregard all_norefresh then.
+ */
+void
+Activate(norefresh)
+int norefresh;
+{
+ debug1("Activate(%d)\n", norefresh);
+ if (display == 0)
+ return;
+ if (D_status)
+ {
+ Msg(0, "%s", ""); /* wait till mintime (keep gcc quiet) */
+ RemoveStatus();
+ }
+ fore = D_fore;
+ if (fore)
+ {
+ ASSERT(fore->w_display == display);
+ fore->w_active = D_layfn == &WinLf;
+ if (fore->w_monitor != MON_OFF)
+ fore->w_monitor = MON_ON;
+ fore->w_bell = BELL_OFF;
+ if (ResizeDisplay(fore->w_width, fore->w_height))
+ {
+ debug2("Cannot resize from (%d,%d)", D_width, D_height);
+ debug2(" to (%d,%d) -> resize window\n", fore->w_width, fore->w_height);
+ DoResize(D_width, D_height);
+ }
+ }
+ Redisplay(norefresh + all_norefresh);
+}
+
+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_curinv = 0;
+ p->w_curvvis = 0;
+ p->w_autolf = 0;
+ p->w_keypad = 0;
+ p->w_cursorkeys = 0;
+ p->w_top = 0;
+ p->w_bot = p->w_height - 1;
+ p->w_saved = 0;
+ p->w_x = p->w_y = 0;
+ p->w_state = LIT;
+ p->w_StringType = NONE;
+ bzero(p->w_tabs, p->w_width);
+ for (i = 8; i < p->w_width; i += 8)
+ p->w_tabs[i] = 1;
+ p->w_rend = mchar_null;
+ ResetCharsets(p);
+}
+
+#ifdef KANJI
+static char *kanjicharsets[3] = {
+ "BBBB02", /* jis */
+ "\002IBB01", /* euc */
+ "BIBB01" /* sjis */
+};
+#endif
+
+void
+ResetCharsets(p)
+register 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 KANJI
+ if (p->w_kanji)
+ {
+ p->w_gr = 1;
+ if (p->w_kanji == SJIS)
+ p->w_c1 = 0;
+ SetCharsets(p, kanjicharsets[p->w_kanji]);
+ }
+#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];
+}
+
+static void
+FixLine()
+{
+ struct mline *ml = &curr->w_mlines[curr->w_y];
+ if (curr->w_rend.attr && ml->attr == null)
+ {
+ if ((ml->attr = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->attr = null;
+ curr->w_rend.attr = 0;
+ Msg(0, "Warning: no space for attr - turned off");
+ }
+ bzero(ml->attr, curr->w_width + 1);
+ }
+ if ((curr->w_FontL || curr->w_FontR) && ml->font == null)
+ {
+ if ((ml->font = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->font = null;
+ curr->w_FontL = curr->w_charsets[curr->w_ss ? curr->w_ss : curr->w_Charset] = 0;
+ curr->w_FontR = curr->w_charsets[curr->w_ss ? curr->w_ss : curr->w_CharsetR] = 0;
+ curr->w_rend.font = 0;
+ Msg(0, "Warning: no space for font - turned off");
+ }
+ bzero(ml->font, curr->w_width + 1);
+ }
+#ifdef COLOR
+ if (curr->w_rend.color && ml->color == null)
+ {
+ if ((ml->color = (char *)malloc(curr->w_width + 1)) == 0)
+ {
+ ml->color = null;
+ curr->w_rend.color = 0;
+ Msg(0, "Warning: no space for color - turned off");
+ }
+ bzero(ml->color, curr->w_width + 1);
+ }
+#endif
+}
+
+
+/*
+ * Here comes the vt100 emulator
+ */
+void
+WriteString(wp, buf, len)
+struct win *wp;
+register char *buf;
+register int len;
+{
+ register int c, font;
+
+ if (!len)
+ return;
+ if (wp->w_logfp != NULL)
+ if ((int)fwrite(buf, len, 1, wp->w_logfp) < 1)
+ {
+ Msg(errno, "Error writing logfile");
+ fclose(wp->w_logfp);
+ wp->w_logfp = NULL;
+ }
+ /*
+ * SetCurr() here may prevent output, as it may set display = 0
+ */
+ SetCurr(wp);
+ if (display)
+ {
+ if (D_status && !(use_hardstatus && D_HS))
+ RemoveStatus();
+ }
+ else
+ {
+ if (curr->w_tstamp.seconds)
+ curr->w_tstamp.lastio = Now;
+
+ if (curr->w_monitor == MON_ON || curr->w_monitor == MON_DONE)
+ {
+ debug2("ACTIVITY %d %d\n", curr->w_monitor, curr->w_bell);
+ curr->w_monitor = MON_FOUND;
+ }
+ }
+
+ do
+ {
+ c = (unsigned char)*buf++;
+ curr->w_rend.font = curr->w_FontL; /* Default: GL */
+
+ /* The next part is only for speedup
+ * (therefore no mchars are used) */
+ if (curr->w_state == LIT &&
+#ifdef KANJI
+ curr->w_FontL != KANJI && curr->w_FontL != KANA && !curr->w_mbcs &&
+#endif
+ c >= ' ' &&
+ ((c & 0x80) == 0 || ((c >= 0xa0 || !curr->w_c1) && !curr->w_gr)) &&
+ !curr->w_insert && !curr->w_ss && curr->w_x < cols - 1)
+ {
+ register int currx;
+ register char *imp, *atp, *fop, at, fo;
+#ifdef COLOR
+ register char *cop, co;
+#endif
+ register char **xtable = 0;
+ register char *c0tab = 0;
+
+ if (c == '\177')
+ continue;
+ FixLine();
+ currx = curr->w_x;
+ imp = curr->w_mlines[curr->w_y].image + currx;
+ atp = curr->w_mlines[curr->w_y].attr + currx;
+ fop = curr->w_mlines[curr->w_y].font + currx;
+ at = curr->w_rend.attr;
+ fo = curr->w_rend.font;
+#ifdef COLOR
+ cop = curr->w_mlines[curr->w_y].color + currx;
+ co = curr->w_rend.color;
+#endif
+ if (display)
+ {
+ if (D_x != currx || D_y != curr->w_y)
+ GotoPos(currx, curr->w_y);
+ /* This is not SetRendition because the compiler would
+ * not use registers if at/fo/co would be an mchar */
+ if (at != D_rend.attr)
+ SetAttr(at);
+#ifdef COLOR
+ if (co != D_rend.color)
+ SetColor(co);
+#endif
+ if (fo != D_rend.font)
+ SetFont(fo);
+ if (D_insert)
+ InsertMode(0);
+ if (D_xtable)
+ xtable = D_xtable[(int)(unsigned char)D_rend.font];
+ if (D_rend.font == '0')
+ c0tab = D_c0_tab;
+ }
+ while (currx < cols - 1)
+ {
+ if (display)
+ {
+ if (xtable && xtable[c])
+ AddStr(xtable[c]);
+ else if (c0tab)
+ AddChar(c0tab[c]);
+ else
+ AddChar(c);
+ }
+ *imp++ = c;
+ *atp++ = at;
+ *fop++ = fo;
+#ifdef COLOR
+ *cop++ = co;
+#endif
+ currx++;
+skip: if (--len == 0)
+ break;
+ c = (unsigned char)*buf++;
+ if (c == '\177')
+ goto skip;
+ if (c < ' ' || ((c & 0x80) && ((c < 0xa0 && curr->w_c1) || curr->w_gr)))
+ break;
+ }
+ curr->w_x = currx;
+ if (display)
+ D_x = currx;
+ if (len == 0)
+ break;
+ }
+ /* end of speedup code */
+
+ 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! */
+ if (!(curr->w_StringType == OSC && c < ' ' && c != '\005'))
+ if (!curr->w_c1 || c != ('\\' ^ 0xc0))
+ {
+ SaveChar(c);
+ break;
+ }
+ c = '\\';
+ /* FALLTHROUGH */
+ case STRESC:
+ switch (c)
+ {
+ case '\\':
+ curr->w_state = LIT;
+ *curr->w_stringp = '\0';
+ switch (curr->w_StringType)
+ {
+ case OSC: /* special xterm compatibility hack */
+ if (curr->w_stringp - curr->w_string < 2 ||
+ curr->w_string[0] < '0' ||
+ curr->w_string[0] > '2' ||
+ curr->w_string[1] != ';')
+ break;
+ curr->w_stringp -= 2;
+ if (curr->w_stringp > curr->w_string)
+ bcopy(curr->w_string + 2, 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);
+ if (display)
+ RefreshStatus();
+ break;
+ case GM:
+ {
+ struct display *old = display;
+ for (display = displays; display; display = display->d_next)
+ if (display != old)
+ MakeStatus(curr->w_string);
+ display = old;
+ }
+ /*FALLTHROUGH*/
+ case PM:
+ if (!display)
+ break;
+ MakeStatus(curr->w_string);
+ if (D_status && !(use_hardstatus && D_HS) && len > 1)
+ {
+ curr->w_outlen = len - 1;
+ bcopy(buf, curr->w_outbuf, curr->w_outlen);
+ return;
+ }
+ break;
+ case DCS:
+ if (display)
+ AddStr(curr->w_string);
+ break;
+ case AKA:
+ if (curr->w_title == curr->w_akabuf && !*curr->w_string)
+ break;
+ ChangeAKA(curr, curr->w_string, 20);
+ if (!*curr->w_string)
+ curr->w_autoaka = curr->w_y + 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case '\033':
+ SaveChar('\033');
+ break;
+ default:
+ curr->w_state = ASTR;
+ SaveChar('\033');
+ SaveChar(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 ']':
+ StartString(OSC);
+ break;
+ case '_':
+ StartString(APC);
+ break;
+ case 'P':
+ StartString(DCS);
+ break;
+ case '^':
+ StartString(PM);
+ break;
+ case '!':
+ StartString(GM);
+ break;
+ case '"':
+ case 'k':
+ StartString(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 KANJI
+ if (curr->w_intermediate == '$')
+ c |= '$' << 8;
+ else
+#endif
+ c = -1;
+ curr->w_intermediate = c;
+ }
+ else if (c >= '0' && c <= '~')
+ {
+ DoESC(c, curr->w_intermediate);
+ curr->w_state = LIT;
+ }
+ else
+ {
+ curr->w_state = LIT;
+ goto tryagain;
+ }
+ }
+ break;
+ case CSI:
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (curr->w_NumArgs < MAXARGS)
+ {
+ curr->w_args[curr->w_NumArgs] =
+ 10 * curr->w_args[curr->w_NumArgs] + (c - '0');
+ }
+ break;
+ case ';':
+ case ':':
+ curr->w_NumArgs++;
+ break;
+ default:
+ if (Special(c))
+ break;
+ if (c >= '@' && c <= '~')
+ {
+ 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:
+ if (c < ' ')
+ {
+ if (c == '\033')
+ {
+ curr->w_intermediate = 0;
+ curr->w_state = ESC;
+ if (display && D_lp_missing && (D_CIC || D_IC || D_IM))
+ UpdateLine(&mline_blank, D_bot, cols - 2, cols - 1);
+ if (curr->w_autoaka < 0)
+ curr->w_autoaka = 0;
+ }
+ else
+ Special(c);
+ break;
+ }
+ if (c >= 0x80 && c < 0xa0 && curr->w_c1)
+ {
+ switch (c)
+ {
+ case 0xc0 ^ 'D':
+ case 0xc0 ^ 'E':
+ case 0xc0 ^ 'H':
+ case 0xc0 ^ 'M':
+ case 0xc0 ^ 'N':
+ case 0xc0 ^ 'O':
+ DoESC(c ^ 0xc0, 0);
+ break;
+ case 0xc0 ^ '[':
+ if (display && D_lp_missing && (D_CIC || D_IC || D_IM))
+ UpdateLine(&mline_blank, D_bot, cols - 2, cols - 1);
+ 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':
+ StartString(DCS);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ font = curr->w_rend.font = (c >= 0x80 ? curr->w_FontR : curr->w_FontL);
+#ifdef KANJI
+ if (font == KANA && curr->w_kanji == 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;
+ }
+ }
+ if (font == KANJI || 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);
+ }
+ c = curr->w_mbcs;
+ if (font != KANJI)
+ {
+ debug2("SJIS !! %x %x\n", c, t);
+ if (0x40 <= t && t <= 0xfc && t != 0x7f)
+ {
+ if (c <= 0x9f) c = (c - 0x81) * 2 + 0x21;
+ else c = (c - 0xc1) * 2 + 0x21;
+ if (t <= 0x7e) t -= 0x1f;
+ else if (t <= 0x9e) t -= 0x20;
+ else t -= 0x7e, c++;
+ curr->w_rend.font = KANJI;
+ }
+ else
+ {
+ /* Incomplete shift-jis - skip first byte */
+ c = t;
+ t = 0;
+ }
+ debug2("SJIS after %x %x\n", c, t);
+ }
+ curr->w_mbcs = t;
+ }
+ kanjiloop:
+#endif
+ if (curr->w_gr)
+ {
+ c &= 0x7f;
+ if (c < ' ') /* this is ugly but kanji support */
+ goto tryagain; /* prevents nicer programming */
+ }
+ if (c == '\177')
+ break;
+ if (display)
+ SetRendition(&curr->w_rend);
+ if (curr->w_x < cols - 1)
+ {
+ if (curr->w_insert)
+ InsertAChar(c);
+ else
+ {
+ if (display)
+ PUTCHAR(c);
+ SetChar(c);
+ curr->w_x++;
+ }
+ }
+ else if (curr->w_x == cols - 1)
+ {
+ if (display && curr->w_wrap && (D_CLP || !force_vt || D_COP))
+ {
+ RAW_PUTCHAR(c); /* don't care about D_insert */
+ SetChar(c);
+ curr->w_x++;
+ if (D_AM && !D_CLP)
+ {
+ SetChar(0);
+ LineFeed(0); /* terminal auto-wrapped */
+ }
+ }
+ else
+ {
+ if (display)
+ {
+ if (D_CLP || curr->w_y != D_bot)
+ {
+ RAW_PUTCHAR(c);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+ else
+ CheckLP(c);
+ }
+ SetChar(c);
+ if (curr->w_wrap)
+ curr->w_x++;
+ }
+ }
+ else /* curr->w_x > cols - 1 */
+ {
+ SetChar(0); /* we wrapped */
+ if (curr->w_insert)
+ {
+ LineFeed(2); /* cr+lf, handle LP */
+ InsertAChar(c);
+ }
+ else
+ {
+ if (display && D_AM && D_x != cols) /* write char again */
+ {
+ SetRenditionMline(&curr->w_mlines[curr->w_y], cols - 1);
+ RAW_PUTCHAR(curr->w_mlines[curr->w_y].image[cols - 1]);
+ SetRendition(&curr->w_rend);
+ if (curr->w_y == D_bot)
+ D_lp_missing = 0; /* just wrote it */
+ }
+ LineFeed((display == 0 || D_AM) ? 0 : 2);
+ if (display)
+ PUTCHAR(c);
+ SetChar(c);
+ curr->w_x = 1;
+ }
+ }
+#ifdef KANJI
+ if (curr->w_mbcs)
+ {
+ c = curr->w_mbcs;
+ curr->w_mbcs = 0;
+ goto kanjiloop; /* what a hack! */
+ }
+#endif
+ if (curr->w_ss)
+ {
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+ SetFont(curr->w_FontL);
+ curr->w_ss = 0;
+ }
+ break;
+ }
+ }
+ while (--len);
+ curr->w_outlen = 0;
+ if (curr->w_state == PRIN)
+ PrintFlush();
+}
+
+static int
+Special(c)
+register int c;
+{
+ switch (c)
+ {
+ case '\b':
+ BackSpace();
+ return 1;
+ case '\r':
+ Return();
+ return 1;
+ case '\n':
+ if (curr->w_autoaka)
+ FindAKA();
+ LineFeed(1);
+ return 1;
+ case '\007':
+ if (display == 0)
+ curr->w_bell = BELL_ON;
+ else
+ {
+ if (!visual_bell)
+ PutStr(D_BL);
+ else
+ {
+ if (!D_VB)
+ curr->w_bell = BELL_VISUAL;
+ else
+ PutStr(D_VB);
+ }
+ }
+ return 1;
+ case '\t':
+ ForwardTab();
+ return 1;
+ case '\017': /* SI */
+ MapCharset(G0);
+ return 1;
+ case '\016': /* SO */
+ MapCharset(G1);
+ return 1;
+ }
+ 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(2);
+ break;
+ case 'D':
+ LineFeed(1);
+ 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();
+ break;
+ case '8':
+ RestoreCursor();
+ break;
+ case 'c':
+ ClearScreen();
+ ResetWindow(curr);
+ SetRendition(&mchar_null);
+ InsertMode(0);
+ KeypadMode(0);
+ CursorkeysMode(0);
+ ChangeScrollRegion(0, rows - 1);
+ break;
+ case '=':
+ KeypadMode(curr->w_keypad = 1);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, 0);
+#endif /* !TIOCPKT */
+ break;
+ case '>':
+ KeypadMode(curr->w_keypad = 0);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, 1);
+#endif /* !TIOCPKT */
+ break;
+ 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;
+ case 'g': /* VBELL, private screen sequence */
+ if (display == 0)
+ curr->w_bell = BELL_ON;
+ else if (!D_VB)
+ curr->w_bell = BELL_VISUAL;
+ else
+ PutStr(D_VB);
+ break;
+ }
+ break;
+ case '#':
+ switch (c)
+ {
+ case '8':
+ FillWithEs();
+ break;
+ }
+ break;
+ case '(':
+ DesignateCharset(c, G0);
+ break;
+ case ')':
+ DesignateCharset(c, G1);
+ break;
+ case '*':
+ DesignateCharset(c, G2);
+ break;
+ case '+':
+ DesignateCharset(c, G3);
+ break;
+#ifdef KANJI
+/*
+ * 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
+ }
+}
+
+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;
+ GotoPos(--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();
+ GotoPos(curr->w_x, curr->w_y);
+ break;
+ }
+ break;
+ case 'K':
+ if (a1 < 0 || a1 > 2)
+ a1 %= 3;
+ switch (a1)
+ {
+ case 0:
+ ClearToEOL();
+ break;
+ case 1:
+ ClearFromBOL();
+ break;
+ case 2:
+ ClearFullLine();
+ break;
+ }
+ 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 '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)
+ {
+ GotoPos(0, curr->w_top);
+ curr->w_y = curr->w_top;
+ curr->w_x = 0;
+ }
+ else
+ {
+ GotoPos(0, 0);
+ curr->w_y = curr->w_x = 0;
+ }
+ break;
+ case 's':
+ SaveCursor();
+ break;
+ case 't':
+ if (a1 != 8)
+ break;
+ a1 = curr->w_args[2];
+ if (a1 < 1)
+ a1 = curr->w_width;
+ if (a2 < 1)
+ a2 = curr->w_height;
+ if (display && D_CWS == NULL)
+ {
+ a2 = curr->w_height;
+ if (D_CZ0 == NULL || (a1 != Z0width && a1 != Z1width))
+ a1 = curr->w_width;
+ }
+ if (a1 == curr->w_width && a2 == curr->w_height)
+ break;
+ ChangeWindowSize(curr, a1, a2, curr->w_histheight);
+ SetCurr(curr);
+ if (display)
+ Activate(0);
+ break;
+ case 'u':
+ RestoreCursor();
+ break;
+ case 'I':
+ if (!a1)
+ a1 = 1;
+ while (a1--)
+ ForwardTab();
+ break;
+ case 'Z':
+ if (!a1)
+ a1 = 1;
+ while (a1--)
+ BackwardTab();
+ break;
+ case 'L':
+ InsertLine(a1 ? a1 : 1);
+ break;
+ case 'M':
+ DeleteLine(a1 ? a1 : 1);
+ break;
+ case 'P':
+ DeleteChar(a1 ? a1 : 1);
+ break;
+ case '@':
+ InsertChar(a1 ? a1 : 1);
+ break;
+ case 'h':
+ ASetMode(1);
+ break;
+ case 'l':
+ ASetMode(0);
+ break;
+ case 'i':
+ if (display && 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;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ }
+ break;
+ case 'S': /* obscure code from a 97801 term */
+ ScrollRegion(a1 ? a1 : 1);
+ break;
+ case 'T': /* obscure code from a 97801 term */
+ 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 */
+ CursorkeysMode(curr->w_cursorkeys = i);
+#ifndef TIOCPKT
+ NewAutoFlow(curr, !i);
+#endif /* !TIOCPKT */
+ break;
+ case 2: /* ANM: ansi/vt52 mode */
+ if (i)
+ {
+#ifdef KANJI
+ if (curr->w_kanji)
+ break;
+#endif
+ curr->w_charsets[0] = curr->w_charsets[1] =
+ curr->w_charsets[2] = curr->w_charsets[2] =
+ curr->w_FontL = curr->w_FontR = ASCII;
+ curr->w_Charset = 0;
+ curr->w_CharsetR = 2;
+ curr->w_ss = 0;
+ }
+ break;
+ case 3: /* COLM: column mode */
+ i = (i ? Z0width : Z1width);
+ if (curr->w_width != i && (display == 0 || (D_CZ0 || D_CWS)))
+ {
+ ChangeWindowSize(curr, i, curr->w_height, curr->w_histheight);
+ SetCurr(curr); /* update rows/cols */
+ if (display)
+ Activate(0);
+ }
+ break;
+ /* case 4: SCLM: scrolling mode */
+ case 5: /* SCNM: screen mode */
+ /* This should be reverse video.
+ * Because it is used in some termcaps to emulate
+ * a visual bell we do this hack here.
+ * (screen uses \Eg as special vbell sequence)
+ */
+ if (i)
+ ReverseVideo(1);
+ else
+ {
+ if (display && D_CVR)
+ ReverseVideo(0);
+ else
+ if (curr->w_revvid)
+ {
+ if (display && D_VB)
+ PutStr(D_VB);
+ else
+ curr->w_bell = BELL_VISUAL;
+ }
+ }
+ 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;
+ if (display)
+ GotoPos(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 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 25: /* TCEM: text cursor enable mode */
+ curr->w_curinv = !i;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ /* case 40: 132 col enable */
+ /* case 42: NRCM: 7bit NRC character mode */
+ /* case 44: margin bell enable */
+ }
+ }
+ break;
+ case '>':
+ switch (c)
+ {
+ case 'c': /* secondary DA */
+ if (a1 == 0)
+ Report("\033[>%d;%d;0c", 83, nversion); /* 83 == 'S' */
+ break;
+ }
+ break;
+ }
+}
+
+
+/*
+ * Store char in mline. Be sure, that w_Font is set correctly!
+ */
+
+static void
+SetChar(c)
+register int c;
+{
+ register struct win *p = curr;
+ register struct mline *ml;
+
+ FixLine();
+ ml = &p->w_mlines[p->w_y];
+ p->w_rend.image = c;
+ copy_mchar2mline(&p->w_rend, ml, p->w_x);
+}
+
+static void
+StartString(type)
+enum string_t type;
+{
+ curr->w_StringType = type;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = ASTR;
+}
+
+static void
+SaveChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ curr->w_state = LIT;
+ else
+ *(curr->w_stringp)++ = c;
+}
+
+static void
+PrintStart()
+{
+ int pi[2];
+
+ if (printcmd == 0 && D_PO == 0)
+ return;
+ curr->w_pdisplay = display;
+ curr->w_stringp = curr->w_string;
+ curr->w_state = PRIN;
+ if (printcmd == 0 || curr->w_pdisplay->d_printfd >= 0)
+ return;
+ if (pipe(pi))
+ {
+ Msg(errno, "printing pipe");
+ return;
+ }
+ switch (fork())
+ {
+ case -1:
+ Msg(errno, "printing fork");
+ return;
+ case 0:
+ close(0);
+ dup(pi[0]);
+ closeallfiles(0);
+ if (setuid(real_uid) || setgid(real_gid))
+ _exit(1);
+#ifdef SIGPIPE
+ signal(SIGPIPE, SIG_DFL);
+#endif
+ execl("/bin/sh", "sh", "-c", printcmd, 0);
+ _exit(1);
+ default:
+ break;
+ }
+ close(pi[0]);
+ curr->w_pdisplay->d_printfd = pi[1];
+}
+
+static void
+PrintChar(c)
+int c;
+{
+ if (curr->w_stringp >= curr->w_string + MAXSTR - 1)
+ PrintFlush();
+ *(curr->w_stringp)++ = c;
+}
+
+static void
+PrintFlush()
+{
+ struct display *odisp = display;
+
+ 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)
+ {
+ Msg(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)
+ {
+ PutStr(D_PO);
+ AddStrn(curr->w_string, curr->w_stringp - curr->w_string);
+ PutStr(D_PF);
+ Flush();
+ }
+ curr->w_stringp = curr->w_string;
+ display = odisp;
+}
+
+
+void
+NewAutoFlow(win, on)
+struct win *win;
+int on;
+{
+ debug1("NewAutoFlow: %d\n", on);
+ SetCurr(win);
+ 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;
+ if (display)
+ SetFlow(win->w_flow & FLOW_NOW);
+}
+
+static void
+DesignateCharset(c, n)
+int c, n;
+{
+ curr->w_ss = 0;
+#ifdef KANJI
+ if (c == ('@' & 037))
+ c = KANJI;
+#endif
+ if (c == 'B' || c == 'J')
+ c = ASCII;
+ if (curr->w_charsets[n] != c)
+ {
+ curr->w_charsets[n] = c;
+ if (curr->w_Charset == n)
+ SetFont(curr->w_FontL = c);
+ 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;
+ SetFont(curr->w_FontL = curr->w_charsets[n]);
+ }
+}
+
+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;
+}
+
+static void
+SaveCursor()
+{
+ curr->w_saved = 1;
+ curr->w_Saved_x = curr->w_x;
+ curr->w_Saved_y = curr->w_y;
+ curr->w_SavedRend= curr->w_rend;
+ curr->w_SavedCharset = curr->w_Charset;
+ curr->w_SavedCharsetR = curr->w_CharsetR;
+ bcopy((char *) curr->w_charsets, (char *) curr->w_SavedCharsets,
+ 4 * sizeof(int));
+}
+
+static void
+RestoreCursor()
+{
+ if (curr->w_saved)
+ {
+ GotoPos(curr->w_Saved_x, curr->w_Saved_y);
+ curr->w_x = curr->w_Saved_x;
+ curr->w_y = curr->w_Saved_y;
+ curr->w_rend = curr->w_SavedRend;
+ bcopy((char *) curr->w_SavedCharsets, (char *) curr->w_charsets,
+ 4 * sizeof(int));
+ curr->w_Charset = curr->w_SavedCharset;
+ curr->w_CharsetR = curr->w_SavedCharsetR;
+ curr->w_ss = 0;
+ curr->w_FontL = curr->w_charsets[curr->w_Charset];
+ curr->w_FontR = curr->w_charsets[curr->w_CharsetR];
+ SetRendition(&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--;
+ }
+ if (display)
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+Return()
+{
+ if (curr->w_x > 0)
+ {
+ curr->w_x = 0;
+ if (display)
+ GotoPos(curr->w_x, curr->w_y);
+ }
+}
+
+static void
+LineFeed(out_mode)
+int out_mode;
+{
+ /* out_mode: 0=cr+lf no-output, 1=lf, 2=cr+lf */
+ if (out_mode != 1)
+ curr->w_x = 0;
+ if (curr->w_y != curr->w_bot) /* Don't scroll */
+ {
+ if (curr->w_y < rows-1)
+ curr->w_y++;
+ if (out_mode && display)
+ GotoPos(curr->w_x, curr->w_y);
+ return;
+ }
+ ScrollUpMap(1);
+ if (curr->w_autoaka > 1)
+ curr->w_autoaka--;
+ if (out_mode && display)
+ {
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, 1);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+}
+
+static void
+ReverseLineFeed()
+{
+ if (curr->w_y == curr->w_top)
+ {
+ ScrollDownMap(1);
+ if (!display)
+ return;
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, -1);
+ GotoPos(curr->w_x, curr->w_y);
+ }
+ else if (curr->w_y > 0)
+ CursorUp(1);
+}
+
+static void
+InsertAChar(c)
+int c;
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (x == cols)
+ x--;
+ save_mline(&curr->w_mlines[y], cols);
+ if (cols - x - 1 > 0)
+ bcopy_mline(&curr->w_mlines[y], x, x + 1, cols - x - 1);
+ SetChar(c);
+ curr->w_x = x + 1;
+ if (!display)
+ return;
+ if (D_CIC || D_IC || D_IM)
+ {
+ InsertMode(curr->w_insert);
+ INSERTCHAR(c);
+ if (y == D_bot)
+ D_lp_missing = 0;
+ }
+ else
+ UpdateLine(&mline_old, y, x, cols - 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);
+ if (n >= cols - x)
+ n = cols - x;
+ else
+ bcopy_mline(&curr->w_mlines[y], x, x + n, cols - x - n);
+
+ ClearInLine(y, x, x + n - 1);
+ if (!display)
+ return;
+ ScrollH(y, x, curr->w_width - 1, -n, &mline_old);
+ GotoPos(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);
+
+ if (n >= cols - x)
+ n = cols - x;
+ else
+ bcopy_mline(&curr->w_mlines[y], x + n, x, cols - x - n);
+ ClearInLine(y, cols - n, cols - 1);
+ if (!display)
+ return;
+ ScrollH(y, x, curr->w_width - 1, n, &mline_old);
+ GotoPos(x, y);
+}
+
+static void
+DeleteLine(n)
+int n;
+{
+ register int old = curr->w_top;
+
+ 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;
+ curr->w_top = curr->w_y;
+ ScrollUpMap(n);
+ curr->w_top = old;
+ if (!display)
+ return;
+ ScrollV(0, curr->w_y, cols - 1, curr->w_bot, n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+InsertLine(n)
+int n;
+{
+ register int old = curr->w_top;
+
+ 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;
+ curr->w_top = curr->w_y;
+ ScrollDownMap(n);
+ curr->w_top = old;
+ if (!display)
+ return;
+ ScrollV(0, curr->w_y, cols - 1, curr->w_bot, -n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ScrollRegion(n)
+int n;
+{
+ if (n > 0)
+ ScrollUpMap(n);
+ else
+ ScrollDownMap(-n);
+ if (!display)
+ return;
+ ScrollV(0, curr->w_top, cols - 1, curr->w_bot, n);
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ScrollUpMap(n)
+int n;
+{
+ char tmp[256 * sizeof(struct mline)];
+ register int i, cnt1, cnt2;
+ struct mline *ml;
+#ifdef COPY_PASTE
+ register int ii;
+#endif
+
+ i = curr->w_top + n;
+ cnt1 = n * sizeof(struct mline);
+ cnt2 = (curr->w_bot - i + 1) * sizeof(struct mline);
+#ifdef COPY_PASTE
+ for(ii = curr->w_top; ii < i; ii++)
+ AddLineToHist(curr, &curr->w_mlines[ii]);
+#endif
+ ml = curr->w_mlines + i;
+ for (i = n; i; --i)
+ {
+ --ml;
+ clear_mline(ml, 0, cols + 1);
+ }
+ Scroll((char *) ml, cnt1, cnt2, tmp);
+}
+
+static void
+ScrollDownMap(n)
+int n;
+{
+ char tmp[256 * sizeof(struct mline)];
+ register int i, cnt1, cnt2;
+ struct mline *ml;
+
+ i = curr->w_top;
+ cnt1 = (curr->w_bot - i - n + 1) * sizeof(struct mline);
+ cnt2 = n * sizeof(struct mline);
+ ml = curr->w_mlines + i;
+ Scroll((char *) ml, cnt1, cnt2, tmp);
+ for (i = n; i; --i)
+ {
+ clear_mline(ml, 0, cols + 1);
+ ml++;
+ }
+}
+
+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
+ForwardTab()
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(2);
+ x = 0;
+ }
+ if (curr->w_tabs[x] && x < cols - 1)
+ x++;
+ while (x < cols - 1 && !curr->w_tabs[x])
+ x++;
+ GotoPos(x, curr->w_y);
+ curr->w_x = x;
+}
+
+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--;
+ GotoPos(x, curr->w_y);
+ curr->w_x = x;
+}
+
+static void
+ClearScreen()
+{
+ register int i;
+ register struct mline *ml = curr->w_mlines;
+
+ for (i = 0; i < rows; ++i)
+ {
+#ifdef COPY_PASTE
+ AddLineToHist(curr, ml);
+#endif
+ clear_mline(ml, 0, cols + 1);
+ ml++;
+ }
+ if (display)
+ ClearDisplay();
+}
+
+static void
+ClearFromBOS()
+{
+ register int n, y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(0, 0, 0, cols - 1, x, y, 1);
+ for (n = 0; n < y; ++n)
+ ClearInLine(n, 0, cols - 1);
+ ClearInLine(y, 0, x);
+ RestorePosRendition();
+}
+
+static void
+ClearToEOS()
+{
+ register int n, y = curr->w_y, x = curr->w_x;
+
+ if (x == 0 && y == 0)
+ {
+ ClearScreen();
+ return;
+ }
+ if (display)
+ Clear(x, y, 0, cols - 1, cols - 1, rows - 1, 1);
+ ClearInLine(y, x, cols - 1);
+ for (n = y + 1; n < rows; n++)
+ ClearInLine(n, 0, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearFullLine()
+{
+ register int y = curr->w_y;
+
+ if (display)
+ Clear(0, y, 0, cols - 1, cols - 1, y, 1);
+ ClearInLine(y, 0, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearToEOL()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(x, y, 0, cols - 1, cols - 1, y, 1);
+ ClearInLine(y, x, cols - 1);
+ RestorePosRendition();
+}
+
+static void
+ClearFromBOL()
+{
+ register int y = curr->w_y, x = curr->w_x;
+
+ if (display)
+ Clear(0, y, 0, cols - 1, x, y, 1);
+ ClearInLine(y, 0, x);
+ RestorePosRendition();
+}
+
+static void
+ClearInLine(y, x1, x2)
+int y, x1, x2;
+{
+ register int n;
+
+ if (x1 == cols)
+ x1--;
+ if (x2 == cols - 1)
+ x2++;
+ if ((n = x2 - x1 + 1) != 0)
+ clear_mline(&curr->w_mlines[y], x1, n);
+}
+
+static void
+CursorRight(n)
+register int n;
+{
+ register int x = curr->w_x;
+
+ if (x == cols)
+ {
+ LineFeed(2);
+ x = 0;
+ }
+ if ((curr->w_x += n) >= cols)
+ curr->w_x = cols - 1;
+ GotoPos(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;
+ GotoPos(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;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+CursorLeft(n)
+register int n;
+{
+ if ((curr->w_x -= n) < 0)
+ curr->w_x = 0;
+ GotoPos(curr->w_x, curr->w_y);
+}
+
+static void
+ASetMode(on)
+int on;
+{
+ register int i;
+
+ for (i = 0; i < curr->w_NumArgs; ++i)
+ {
+ switch (curr->w_args[i])
+ {
+ case 4:
+ curr->w_insert = on;
+ InsertMode(on);
+ break;
+ case 20:
+ curr->w_autolf = on;
+ break;
+ case 34:
+ curr->w_curvvis = !on;
+ CursorVisibility(curr->w_curinv ? -1 : curr->w_curvvis);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static char rendlist[] =
+{
+ (1 << NATTR), 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()
+{
+ register int j, i = 0, a = curr->w_rend.attr;
+#ifdef COLOR
+ register int c = curr->w_rend.color;
+#endif
+
+ do
+ {
+ j = curr->w_args[i];
+#ifdef COLOR
+ if (j >= 30 && j <= 39)
+ c = (c & 0xf0) | (39 - j);
+ else if (j >= 40 && j <= 49)
+ c = (c & 0x0f) | ((49 - j) << 4);
+ if (j == 0)
+ c = 0;
+#endif
+ if (j < 0 || j >= (sizeof(rendlist)/sizeof(*rendlist)))
+ continue;
+ j = rendlist[j];
+ if (j & (1 << NATTR))
+ a &= j;
+ else
+ a |= j;
+ }
+ while (++i < curr->w_NumArgs);
+ if (curr->w_rend.attr != a)
+ SetAttr(curr->w_rend.attr = a);
+#ifdef COLOR
+ if (curr->w_rend.color != c)
+ SetColor(curr->w_rend.color = c);
+#endif
+}
+
+static void
+FillWithEs()
+{
+ register int i;
+ register char *p, *ep;
+
+ 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';
+ }
+ if (display)
+ Redisplay(0);
+}
+
+
+static void
+UpdateLine(oml, y, from, to)
+struct mline *oml;
+int from, to, y;
+{
+ ASSERT(display);
+ DisplayLine(oml, &curr->w_mlines[y], y, from, to);
+ RestorePosRendition();
+}
+
+
+static void
+CheckLP(n_ch)
+int n_ch;
+{
+ register int x;
+ register struct mline *ml;
+
+ ASSERT(display);
+ ml = &curr->w_mlines[D_bot];
+ x = cols - 1;
+
+ curr->w_rend.image = n_ch;
+
+ D_lpchar = curr->w_rend;
+ D_lp_missing = 0;
+
+ if (cmp_mchar_mline(&curr->w_rend, ml, x))
+ return;
+ if (!cmp_mchar(&mchar_blank, &curr->w_rend)) /* is new not blank */
+ D_lp_missing = 1;
+ if (!cmp_mchar_mline(&mchar_blank, ml, x)) /* is old char not blank? */
+ {
+ /* old char not blank, new blank, try to delete */
+ if (D_UT)
+ SetRendition(&mchar_null);
+ if (D_CE)
+ PutStr(D_CE);
+ else if (D_DC)
+ PutStr(D_DC);
+ else if (D_CDC)
+ CPutStr(D_CDC, 1);
+ else
+ D_lp_missing = 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;
+{
+ if (l > 20)
+ l = 20;
+ strncpy(p->w_akachange, s, l);
+ p->w_akachange[l] = 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;
+
+ /* yucc */
+ if (p->w_hstatus)
+ {
+ display = p->w_display;
+ if (display)
+ RefreshStatus();
+ }
+}
+
+static void
+FindAKA()
+{
+ register 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(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, line, cp - line);
+ }
+ else
+ wp->w_autoaka = 0;
+}
+
+void
+SetCurr(wp)
+struct win *wp;
+{
+ curr = wp;
+ if (curr == 0)
+ return;
+ cols = curr->w_width;
+ rows = curr->w_height;
+ display = curr->w_active ? curr->w_display : 0;
+}
+
+static void
+RestorePosRendition()
+{
+ if (!display)
+ return;
+ GotoPos(curr->w_x, curr->w_y);
+ SetRendition(&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];
+
+ sprintf(rbuf, fmt, n1, n2);
+ len = strlen(rbuf);
+
+ if ((unsigned)(curr->w_inlen + len) <= sizeof(curr->w_inbuf))
+ {
+ bcopy(rbuf, curr->w_inbuf + curr->w_inlen, len);
+ curr->w_inlen += len;
+ }
+}
+
+#ifdef COPY_PASTE
+static void
+AddLineToHist(wp, ml)
+struct win *wp;
+struct mline *ml;
+{
+ register 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);
+
+ q = ml->font; o = hml->font; hml->font = q; ml->font = null;
+ if (o != null)
+ free(o);
+
+#ifdef COLOR
+ q = ml->color; o = hml->color; hml->color = q; ml->color = null;
+ if (o != null)
+ free(o);
+#endif
+
+ if (++wp->w_histidx >= wp->w_histheight)
+ wp->w_histidx = 0;
+}
+#endif
+