/* * KON - Kanji ON Linux Console - Copyright (C) 1992, 1993, 1994 Takashi * MANABE (manabe@Roy.dsl.tutics.tut.ac.jp) * * KON 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 of the License, or (at your option) any later * version. * * KON 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; if not, write to the Free Software Foundation, Inc., 675 * Mass Ave, Cambridge, MA 02139, USA. */ #include "big5con.h" struct _con_info con; #define CHAR_NUL '\x00' #define CHAR_BEL '\x07' #define CHAR_BS '\x08' #define CHAR_HT '\x09' #define CHAR_LF '\x0A' #define CHAR_VT '\x0B' #define CHAR_FF '\x0C' #define CHAR_CR '\x0D' #define CHAR_SO '\x0E' #define CHAR_SI '\x0F' #define CHAR_XON '\x11' #define CHAR_XOFF '\x12' #define CHAR_CAN '\x18' #define CHAR_SUB '\x1A' #define CHAR_ESC '\x1B' #define CHAR_DEL '\x7F' #define CHAR_CSI '\x9B' #define CHAR_SS2 '\x8E' #define LEN_REPORT 9 struct attrStack { struct attrStack *prev; u_char x, y, attr, bcol, fcol; }; static struct attrStack *saveAttr; static int scroll; struct langInfo lInfo; static void SaveAttr() { struct attrStack *tmp; tmp = (struct attrStack *) malloc(sizeof(struct attrStack)); if (saveAttr) tmp->prev = saveAttr; else tmp->prev = NULL; saveAttr = tmp; saveAttr->x = con.x; saveAttr->y = con.y; saveAttr->attr = con.attr; saveAttr->fcol = con.fcol; saveAttr->bcol = con.bcol; } static void RestoreAttr() { struct attrStack *tmp; if (saveAttr) { con.x = saveAttr->x; con.y = saveAttr->y; con.attr = saveAttr->attr; con.fcol = saveAttr->fcol; con.bcol = saveAttr->bcol; tmp = saveAttr; saveAttr = tmp->prev; free(tmp); } } static void EscSetAttr(int col) { static u_char table[] = {0, 4, 2, 6, 1, 5, 3, 7}; u_char swp; switch (col) { case 0: /* off all attributes */ con.bcol = 0; con.fcol = 7; con.attr = 0; break; case 1: con.attr |= ATTR_HIGH; if (con.fcol) con.fcol |= 8; break; case 21: con.attr &= ~ATTR_HIGH; con.fcol &= ~8; break; case 4: con.attr |= ATTR_ULINE; con.bcol |= 8; break; case 24: con.attr &= ~ATTR_ULINE; con.bcol &= ~8; break; case 7: if (!(con.attr & ATTR_REVERSE)) { con.attr |= ATTR_REVERSE; swp = con.fcol & 7; if (con.attr & ATTR_ULINE) swp |= 8; con.fcol = con.bcol & 7; if (con.attr & ATTR_HIGH && con.fcol) con.fcol |= 8; con.bcol = swp; } break; case 27: if (con.attr & ATTR_REVERSE) { con.attr &= ~ATTR_REVERSE; swp = con.fcol & 7; if (con.attr & ATTR_ULINE) swp |= 8; con.fcol = con.bcol & 7; if (con.attr & ATTR_HIGH && con.fcol) con.fcol |= 8; con.bcol = swp; } break; default: if (col >= 30 && col <= 37) { swp = table[col - 30]; if (con.attr & ATTR_REVERSE) { if (con.attr & ATTR_ULINE) swp |= 8; con.bcol = swp; } else { if (con.attr & ATTR_HIGH) swp |= 8; con.fcol = swp; } } else if (col >= 40 && col <= 47) { swp = table[col - 40]; if (con.attr & ATTR_REVERSE) { if (con.attr & ATTR_HIGH) swp |= 8; con.fcol = swp; } else { if (con.attr & ATTR_ULINE) swp |= 8; con.bcol = swp; } } break; } } static void VtSetMode(u_char mode, bool sw) { switch (mode) { case 4: con.ins = sw; break; case 25: cInfo.sw = sw; break; } } static void EscReport(u_char mode, u_char arg) { static char report[LEN_REPORT]; switch (mode) { case 'n': if (arg == 6) { int x = (con.x < con.xmax) ? con.x : con.xmax; int y = (con.y < con.ymax) ? con.y : con.ymax; sprintf(report, "\x1B[%d;%dR", y + 1, x + 1); } else if (arg == 5) strcpy(report, "\x1B[0n\0"); break; case 'c': if (arg == 0) strcpy(report, "\x1B[?6c\0"); break; } write(masterPty, report, strlen(report)); } #define MAX_NARG 8 static void EscBracket(u_char ch) { u_char n; static u_short varg[MAX_NARG], narg, question; if (ch >= '0' && ch <= '9') { varg[narg] = (varg[narg] * 10) + (ch - '0'); } else if (ch == ';') { if (narg < MAX_NARG) narg++; else con.esc = NULL; } else { con.esc = NULL; switch (ch) { case 'K': TextClearEol(varg[0]); break; case 'J': TextClearEos(varg[0]); break; case 'A': con.y -= varg[0] ? varg[0] : 1; if (con.y < con.ymin) { scroll -= con.y - con.ymin; con.y = con.ymin; } break; case 'B': con.y += varg[0] ? varg[0] : 1; if (con.y > con.ymax - 1) { scroll += con.y - con.ymax + 1; con.y = con.ymax - 1; } break; case 'C': con.x += varg[0] ? varg[0] : 1; break; case 'D': con.x -= varg[0] ? varg[0] : 1; break; case 'G': con.x = varg[0] ? varg[0] - 1 : 0; break; case 'P': TextDeleteChar(varg[0] ? varg[0] : 1); break; case '@': TextInsertChar(varg[0] ? varg[0] : 1); break; case 'L': TextMoveDown(con.y, con.ymax - 1, varg[0] ? varg[0] : 1); break; case 'M': TextMoveUp(con.y, con.ymax - 1, varg[0] ? varg[0] : 1); break; case 'H': case 'f': if (varg[1]) con.x = varg[1] - 1; else con.x = 0; case 'd': con.y = varg[0] ? varg[0] - 1 : 0; break; case 'm': for (n = 0; n <= narg; n++) EscSetAttr(varg[n]); break; case 'r': con.ymin = varg[0] ? (varg[0] - 1) : 0; con.ymax = varg[1] ? varg[1] : dInfo.tymax; con.x = 0; con.y = con.ymin; if (con.ymin || con.ymax != dInfo.tymax) con.soft = TRUE; else con.soft = FALSE; break; case 'l': for (n = 0; n <= narg; n++) VtSetMode(varg[n], FALSE); break; case 'h': for (n = 0; n <= narg; n++) VtSetMode(varg[n], TRUE); break; case '?': question = TRUE; con.esc = EscBracket; break; case 's': SaveAttr(); break; case 'u': RestoreAttr(); break; case 'n': case 'c': if (question != TRUE) EscReport(ch, varg[0]); break; case 'R': break; } if (con.esc == NULL) question = narg = varg[0] = varg[1] = 0; } } static void EscSetDCodeG0(u_char ch) { int i; switch (ch) { case '(': /* EscSetDCodeG0 */ case ')': /* EscSetDCodeG1 */ return; case '@': ch = 'B'; default: i = 0; while (fDRegs[i].sign0) { if (fDRegs[i].sign0 == ch) { con.db = (u_char) i | LATCH_1; break; } i++; } con.trans = CS_DBCS; break; } con.esc = NULL; } static void EscSetSCodeG0(u_char ch) { int i = 0; switch (ch) { case 'U': con.g[0] = CS_GRAPH; break; /* * Thank zmx@bbs.ee.ntu.edu.tw Fix text-table display (sysinstall * under b5c+screen) */ case '0': con.g[0] = CS_GRAPH; case 'B': con.g[0] = CS_LEFT; default: while (fSRegs[i].sign0) { if (fSRegs[i].sign0 == ch) { con.sb = (u_char) i; con.g[0] = CS_LEFT; break; } else if (fSRegs[i].sign1 == ch) { con.sb = (u_char) i; con.g[0] = CS_RIGHT; break; } i++; } } con.trans = con.g[0]; con.esc = NULL; } static void EscSetSCodeG1(u_char ch) { switch (ch) { case 'U': con.g[1] = CS_LEFT; break; case '0': con.g[1] = CS_GRAPH; break; case 'A': case 'J': case 'B': break; } con.trans = con.g[1]; con.esc = NULL; } static void EscStart(u_char ch) { con.esc = NULL; switch (ch) { case '[': con.esc = EscBracket; break; case '$': /* Set Double Byte Code */ con.esc = EscSetDCodeG0; break; case '(': /* Set 94 to G0 */ case ',': /* Set 96 to G0 */ con.esc = EscSetSCodeG0; break; case ')': /* Set G1 */ con.esc = EscSetSCodeG1; break; case 'E': con.x = 0; case 'D': if (con.y == con.ymax - 1) /* by b5c */ scroll++; else con.y++; break; case 'M': if (con.y == con.ymin) scroll--; else con.y--; break; case 'c': con.fcol = 7; con.attr = 0; con.bcol = 0; con.trans = CS_LEFT; con.sb = lInfo.sb; con.db = lInfo.db | LATCH_1; case '*': con.x = con.y = 0; TextClearAll(); break; case '7': SaveAttr(); break; case '8': RestoreAttr(); break; } } static inline bool isdb1(u_char c) { switch (lInfo.sc) { case CODE_SJIS: return (c >= 0x81 && c <= 0x9F) || (c >= 0xE0 && c <= 0xFC); case CODE_BIG5: return (c >= 0xa1 && c <= 0xfe); default: return (c & 0x80); } } static inline bool isdb2(u_char c) { switch (lInfo.sc) { case CODE_BIG5: return ((c >= 0x40 && c <= 0x7e) || (c >= 0xa1 && c <= 0xfe)); default: return (1); } } void VtEmu(const char *buff, int nchars) { u_char ch; int addr; while (nchars-- > 0) { ch = *buff; buff++; if (!ch) continue; if (con.esc) { con.esc(ch); } else switch (ch) { case CHAR_BEL: Beep(); break; case CHAR_DEL: break; case CHAR_BS: if (con.x) con.x--; break; case CHAR_HT: con.x += con.tab - (con.x % con.tab); if (con.x > con.xmax) con.x -= con.xmax + 1; else break; case CHAR_VT: case CHAR_FF: #if 1 con.trans = CS_LEFT; con.sb = lInfo.sb; con.db = lInfo.db | LATCH_1; #endif case CHAR_LF: if (con.y == con.ymax - 1) scroll++; else con.y++; break; case CHAR_CR: con.x = 0; break; case CHAR_ESC: con.esc = EscStart; continue; case CHAR_SO: con.trans = con.g[1] | G1_SET; continue; case CHAR_SI: con.trans = con.g[0]; continue; /* case ' ': con.trans = CS_LEFT; */ default: if (con.x == con.xmax + 1) { con.x = 0; if (con.y == con.ymax - 1) scroll++; else con.y++; buff--; nchars++; break; } if (isPrevWT1() && isdb2(ch)) { if (con.ins) TextInsertChar(1); TextWput2(ch); con.x++; continue; } else if (con.x < con.xmax && (con.trans == CS_DBCS || (isdb1(ch) && con.trans == CS_LEFT))) { if (con.ins) TextInsertChar(1); TextWput1(ch); con.x++; continue; } else { if (con.ins) TextInsertChar(1); TextSput(con.trans == CS_RIGHT ? ch | 0x80 : ch); con.x++; continue; } } if (scroll > 0) { ScrollUp(scroll); } else if (scroll < 0) { ScrollDown(-scroll); } scroll = 0; } } static int ConfigCoding(const char *confstr) { char reg[3][MAX_COLS]; int n, i; *reg[0] = *reg[1] = *reg[2] = '\0'; sscanf(confstr, "%s %s %s", reg[0], reg[1], reg[2]); for (i = 0; i < 3 && *reg[i]; i++) { n = (int)CodingByRegistry(reg[i]); if (n < 0) { if (!strcasecmp(reg[i], "EUC")) lInfo.sc = CODE_EUC; else if (!strcasecmp(reg[i], "SJIS")) lInfo.sc = CODE_SJIS; else if (!strcasecmp(reg[i], "BIG5")) lInfo.sc = CODE_BIG5; else lInfo.sc = 0; } else if (n & CHR_DBC) lInfo.db = n & ~CHR_DFLD; else lInfo.sb = n & ~CHR_SFLD; } return SUCCESS; } void VtInit(void) { con.text_mode = TRUE; DefineCap("Coding", ConfigCoding, "ISO8859-1 BIG5-0 BIG5"); } void VtStart(void) { con.x = con.y = 0; con.xmax = dInfo.txmax; con.ymax = dInfo.tymax; con.tab = 8; con.fcol = 7; con.attr = 0; con.esc = NULL; con.g[0] = con.g[1] = CS_LEFT; con.trans = con.soft = con.ins = FALSE; con.sb = lInfo.sb; con.db = lInfo.db | LATCH_1; con.active = cInfo.sw = TRUE; }