/* 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 #include #include #ifndef sun /* we want to know about TIOCPKT. */ # include #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