void emulate(void) { Rune buf[BUFS+1]; int i; int n; int c; int operand[10]; int noperand; int savex, savey, saveattr, saveisgraphics; int isgraphics; int g0set, g1set; int dch; isgraphics = 0; g0set = 'B'; /* US ASCII */ g1set = 'B'; /* US ASCII */ savex = savey = 0; yscrmin = 0; yscrmax = ymax; saveattr = 0; saveisgraphics = 0; /* set initial tab stops to DEC-standard 8-column spacing */ for(c=0; (c+=8)<nelem(tabcol);) tabcol[c] = 1; for (;;) { if (y > ymax) { x = 0; newline(); } buf[0] = get_next_char(); buf[1] = '\0'; switch(buf[0]) { case '\000': case '\001': case '\002': case '\003': case '\004': case '\005': case '\006': goto Default; case '\007': /* bell */ ringbell(); break; case '\010': /* backspace */ if (x > 0) --x; break; case '\011': /* tab to next tab stop; if none, to right margin */ for(c=x+1; c<nelem(tabcol) && !tabcol[c]; c++) ; if(c < nelem(tabcol)) x = c; else x = xmax; break; case '\012': /* linefeed */ case '\013': case '\014': newline(); if (ttystate[cs->raw].nlcr) x = 0; break; case '\015': /* carriage return */ x = 0; if (ttystate[cs->raw].crnl) newline(); break; case '\016': /* SO: invoke G1 char set */ isgraphics = (isdigit(g1set)); break; case '\017': /* SI: invoke G0 char set */ isgraphics = (isdigit(g0set)); break; case '\020': /* DLE */ case '\021': /* DC1 */ case '\022': /* XON */ case '\023': /* DC3 */ case '\024': /* XOFF */ case '\025': /* NAK */ case '\026': /* SYN */ case '\027': /* ETB */ case '\030': /* CAN: cancel escape sequence, display checkerboard (not implemented) */ case '\031': /* EM */ case '\032': /* SUB: same as CAN */ goto Default; ; /* ESC, \033, is handled below */ case '\034': /* FS */ case '\035': /* GS */ case '\036': /* RS */ case '\037': /* US */ break; case '\177': /* delete: ignored */ break; case '\033': switch(dch = get_next_char()){ /* * 1 - graphic processor option on (no-op; not installed) */ case '1': break; /* * 2 - graphic processor option off (no-op; not installed) */ case '2': break; /* * 7 - save cursor position. */ case '7': //print("save\n"); savex = x; savey = y; saveattr = attr; saveisgraphics = isgraphics; break; /* * 8 - restore cursor position. */ case '8': //print("restore\n"); x = savex; y = savey; attr = saveattr; isgraphics = saveisgraphics; break; /* * c - Reset terminal. */ case 'c': print("resetterminal\n"); cursoron = 1; ttystate[cs->raw].nlcr = 0; break; /* * D - active position down a line, scroll if at bottom margin. * (Original VT100 had a bug: tracked new-line/line-feed mode.) */ case 'D': if(++y > yscrmax) { y = yscrmax; scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax); } break; /* * E - active position to start of next line, scroll if at bottom margin. */ case 'E': x = 0; if(++y > yscrmax) { y = yscrmax; scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax); } break; /* * H - set tab stop at current column. * (This is cursor home in VT52 mode (not implemented).) */ case 'H': if(x < nelem(tabcol)) tabcol[x] = 1; break; /* * M - active position up a line, scroll if at top margin.. */ case 'M': if(--y < yscrmin) { y = yscrmin; scroll(yscrmin, yscrmax, yscrmin+1, yscrmin); } break; /* * Z - identification. the terminal * emulator will return the response * code for a generic VT100. */ case 'Z': Ident: sendnchars(7, "\033[?1;2c"); /* VT100 with AVO option */ // sendnchars(5, "\033[?6c"); /* VT102 (insert/delete-char, etc.) */ break; /* * < - enter ANSI mode */ case '<': break; /* * > - set numeric keypad mode on (not implemented) */ case '>': break; /* * = - set numeric keypad mode off (not implemented) */ case '=': break; /* * # - Takes a one-digit argument */ case '#': switch(get_next_char()){ case '3': /* Top half of double-height line */ case '4': /* Bottom half of double-height line */ case '5': /* Single-width single-height line */ case '6': /* Double-width line */ case '7': /* Screen print */ case '8': /* Fill screen with E's */ break; } break; /* * ( - switch G0 character set */ case '(': g0set = get_next_char(); break; /* * - switch G1 character set */ case ')': g1set = get_next_char(); break; /* * Received left bracket. */ case '[': /* * A semi-colon or ? delimits arguments. */ memset(operand, 0, sizeof(operand)); operand[0] = number(buf, &i); noperand = 1; while(buf[0] == ';' || buf[0] == '?'){ if(noperand < nelem(operand)){ noperand++; operand[noperand-1] = number(buf, nil); } else number(buf, nil); } /* * do escape2 stuff */ switch(dch = buf[0]){ /* * c - same as ESC Z: what are you? */ case 'c': goto Ident; /* * g - various tabstop manipulation */ case 'g': switch(operand[0]){ case 0: /* clear tab at current column */ if(x < nelem(tabcol)) tabcol[x] = 0; break; case 3: /* clear all tabs */ memset(tabcol, 0, sizeof tabcol); break; } break; /* * l - clear various options. */ case 'l': if(noperand == 1){ switch(operand[0]){ case 20: /* set line feed mode */ ttystate[cs->raw].nlcr = 1; break; case 30: /* screen invisible (? not supported through VT220) */ break; } }else while(--noperand > 0){ switch(operand[noperand]){ case 1: /* set cursor keys to send ANSI functions: ESC [ A..D */ break; case 2: /* set VT52 mode (not implemented) */ break; case 3: /* set 80 columns */ setdim(-1, 80); break; case 4: /* set jump scrolling */ break; case 5: /* set normal video on screen */ break; case 6: /* set origin to absolute */ originrelative = 0; x = y = 0; break; case 7: /* reset auto-wrap mode */ wraparound = 0; break; case 8: /* reset auto-repeat mode */ break; case 9: /* reset interlacing mode */ break; case 25: /* text cursor off (VT220) */ cursoron = 0; break; } } break; /* * s - some dec private stuff. actually [ ? num s, but we can't detect it. */ case 's': break; /* * h - set various options. */ case 'h': if(noperand == 1){ switch(operand[0]){ default: break; case 20: /* set newline mode */ ttystate[cs->raw].nlcr = 0; break; case 30: /* screen visible (? not supported through VT220) */ break; } }else while(--noperand > 0){ switch(operand[noperand]){ default: break; case 1: /* set cursor keys to send application function: ESC O A..D */ break; case 2: /* set ANSI */ break; case 3: /* set 132 columns */ setdim(-1, 132); break; case 4: /* set smooth scrolling */ break; case 5: /* set screen to reverse video (not implemented) */ break; case 6: /* set origin to relative */ originrelative = 1; x = 0; y = yscrmin; break; case 7: /* set auto-wrap mode */ wraparound = 1; break; case 8: /* set auto-repeat mode */ break; case 9: /* set interlacing mode */ break; case 25: /* text cursor on (VT220) */ cursoron = 1; break; } } break; /* * m - change character attrs. */ case 'm': setattr(noperand, operand); break; /* * n - request various reports */ case 'n': switch(operand[0]){ case 5: /* status */ sendnchars(4, "\033[0n"); /* terminal ok */ break; case 6: /* cursor position */ sendnchars(sprint((char*)buf, "\033[%d;%dR", originrelative ? y+1 - yscrmin : y+1, x+1), (char*)buf); break; } break; /* * q - turn on list of LEDs; turn off others. */ case 'q': break; /* * r - change scrolling region. operand[0] is * min scrolling region and operand[1] is max * scrolling region. */ case 'r': yscrmin = 0; yscrmax = ymax; switch(noperand){ case 2: yscrmax = operand[1]-1; if(yscrmax > ymax) yscrmax = ymax; case 1: yscrmin = operand[0]-1; if(yscrmin < 0) yscrmin = 0; } x = 0; y = yscrmin; break; /* * x - report terminal parameters */ case 'x': sendnchars(20, "\033[3;1;1;120;120;1;0x"); break; /* * y - invoke confidence test */ case 'y': break; /* * z - line spacing */ case 'z': break; /* * A - cursor up. */ case 'e': case 'A': fixops(operand); y -= operand[0]; if(y < yscrmin) y = yscrmin; olines -= operand[0]; if(olines < 0) olines = 0; break; /* * B - cursor down */ case 'B': fixops(operand); y += operand[0]; if(y > yscrmax) y=yscrmax; break; /* * C - cursor right */ case 'a': case 'C': fixops(operand); x += operand[0]; /* * VT-100-UG says not to go past the * right margin. */ if(x > xmax) x = xmax; break; /* * D - cursor left */ case 'D': fixops(operand); x -= operand[0]; if(x < 0) x = 0; break; /* * G - cursor to column */ case '\'': case 'G': fixops(operand); x = operand[0] - 1; if(x > xmax) x = xmax; break; /* * H and f - cursor motion. operand[0] is row and * operand[1] is column, origin 1. */ case 'H': case 'f': fixops(operand+1); x = operand[1] - 1; if(x > xmax) x = xmax; /* fallthrough */ /* * d - cursor to line n (xterm) */ case 'd': fixops(operand); y = operand[0] - 1; if(originrelative){ y += yscrmin; if(y > yscrmax) y = yscrmax; }else{ if(y > ymax) y = ymax; } break; /* * J - clear some or all of the display. */ case 'J': switch (operand[0]) { /* * operand 2: whole screen. */ case 2: clear(Rpt(pt(0, 0), pt(xmax+1, ymax+1))); break; /* * operand 1: start of screen to active position, inclusive. */ case 1: clear(Rpt(pt(0, 0), pt(xmax+1, y))); clear(Rpt(pt(0, y), pt(x+1, y+1))); break; /* * Default: active position to end of screen, inclusive. */ default: clear(Rpt(pt(x, y), pt(xmax+1, y+1))); clear(Rpt(pt(0, y+1), pt(xmax+1, ymax+1))); break; } break; /* * K - clear some or all of the line. */ case 'K': switch (operand[0]) { /* * operand 2: whole line. */ case 2: clear(Rpt(pt(0, y), pt(xmax+1, y+1))); break; /* * operand 1: start of line to active position, inclusive. */ case 1: clear(Rpt(pt(0, y), pt(x+1, y+1))); break; /* * Default: active position to end of line, inclusive. */ default: clear(Rpt(pt(x, y), pt(xmax+1, y+1))); break; } break; /* * P - delete character(s) from right of cursor (xterm) */ case 'P': fixops(operand); i = x + operand[0]; draw(screen, Rpt(pt(x, y), pt(xmax+1, y+1)), screen, nil, pt(i, y)); clear(Rpt(pt(xmax-operand[0], y), pt(xmax+1, y+1))); break; /* * @ - insert blank(s) to right of cursor (xterm) */ case '@': fixops(operand); i = x + operand[0]; draw(screen, Rpt(pt(i, y), pt(xmax+1, y+1)), screen, nil, pt(x, y)); clear(Rpt(pt(x, y), pt(i, y+1))); break; /* * X - erase character(s) at cursor and to the right (xterm) */ case 'X': fixops(operand); i = x + operand[0]; clear(Rpt(pt(x, y), pt(i, y+1))); break; /* * L - insert a line at cursor position (VT102 and later) */ case 'L': fixops(operand); for(i = 0; i < operand[0]; ++i) scroll(y, yscrmax, y+1, y); break; /* * M - delete a line at cursor position (VT102 and later) */ case 'M': fixops(operand); for(i = 0; i < operand[0]; ++i) scroll(y+1, yscrmax+1, y, yscrmax); break; /* * S,T - scroll up/down (xterm) */ case 'T': fixops(operand); for(i = 0; i < operand[0]; ++i) scroll(yscrmin, yscrmax, yscrmin+1, yscrmin); break; case 'S': fixops(operand); for(i = 0; i < operand[0]; ++i) scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmin); break; case '=': /* ? not supported through VT220 */ number(buf, nil); switch(buf[0]) { case 'h': case 'l': break; } break; /* * Anything else we ignore for now... */ default: print("unknown escape2 '%c' (0x%x)\n", dch, dch); break; } break; /* * Collapse multiple '\033' to one. */ case '\033': peekc = '\033'; break; /* OSC escape */ case ']': osc(); break; /* * Ignore other commands. */ default: print("unknown command '%c' (0x%x)\n", dch, dch); break; } break; default: /* ordinary char */ Default: if(isgraphics && buf[0] < nelem(gmap) && gmap[buf[0]]) buf[0] = gmap[buf[0]]; /* line wrap */ if (x > xmax){ if(wraparound){ x = 0; newline(); }else{ continue; } } n = 1; c = 0; while (!cs->raw && host_avail() && x+n<=xmax && n<BUFS && (c = get_next_char())>=' ' && c<'\177') { buf[n++] = c; c = 0; } buf[n] = 0; drawstring(pt(x, y), buf, attr); x += n; peekc = c; break; } } }
int waitchar(void) { Event e; int c; char c2; int newmouse; int wasblocked; int kbdchar = -1; char echobuf[3*BSIZE]; static int lastc = -1; for(;;) { if(resize_flag) resize(); wasblocked = blocked; if(backp) return(0); if(ecanmouse() && (button2() || button3())) readmenu(); if(snarffp) { if((c = Bgetc(snarffp)) < 0) { if(lastc != '\n') write(outfd,"\n",1); Bterm(snarffp); snarffp = 0; if(lastc != '\n') { lastc = -1; return('\n'); } lastc = -1; continue; } lastc = c; c2 = c; write(outfd, &c2, 1); return(c); } if(!blocked && host_avail()) return(rcvchar()); if(kbdchar > 0) { if(blocked) resize(); if(cs->raw) { switch(kbdchar){ case Kup: sendfk("up key"); break; case Kdown: sendfk("down key"); break; case Kleft: sendfk("left key"); break; case Kright: sendfk("right key"); break; case Kpgup: sendfk("page up"); break; case Kpgdown: sendfk("page down"); break; case KF|1: sendfk("F1"); break; case KF|2: sendfk("F2"); break; case KF|3: sendfk("F3"); break; case KF|4: sendfk("F4"); break; case KF|5: sendfk("F5"); break; case KF|6: sendfk("F6"); break; case KF|7: sendfk("F7"); break; case KF|8: sendfk("F8"); break; case KF|9: sendfk("F9"); break; case KF|10: sendfk("F10"); break; case KF|11: sendfk("F11"); break; case KF|12: sendfk("F12"); break; case '\n': echobuf[0] = '\r'; sendnchars(1, echobuf); break; case '\r': echobuf[0] = '\n'; sendnchars(1, echobuf); break; default: echobuf[0] = kbdchar; sendnchars(1, echobuf); break; } } else if(canon(echobuf,kbdchar) == SCROLL) { if(!blocked) bigscroll(); } else strcat(echo_input,echobuf); blocked = 0; kbdchar = -1; continue; } curson(wasblocked); /* turn on cursor while we're waiting */ do { newmouse = 0; switch(eread(blocked ? Emouse|Ekeyboard : Emouse|Ekeyboard|Ehost, &e)) { case Emouse: mouse = e.mouse; if(button2() || button3()) readmenu(); else if(resize_flag == 0) { /* eresized() is triggered by special mouse event */ newmouse = 1; } break; case Ekeyboard: kbdchar = e.kbdc; break; case Ehost: set_host(&e); break; default: perror("protocol violation"); exits("protocol violation"); } } while(newmouse == 1); cursoff(); /* turn cursor back off */ } }
void initialize(int argc, char **argv) { int i, blkbg; char *fontname, *p; rfork(RFNAMEG|RFNOTEG); fontname = nil; term = "vt100"; fk = vt100fk; blkbg = nocolor = 0; ARGBEGIN{ case '2': term = "vt220"; fk = vt220fk; break; case 'a': term = "ansi"; fk = ansifk; break; case 'b': blkbg = 1; /* e.g., for linux colored output */ break; case 'c': nocolor = 1; break; case 'f': fontname = EARGF(usage()); break; case 'l': p = EARGF(usage()); logfd = create(p, OWRITE, 0666); if(logfd < 0) sysfatal("could not create log file: %s: %r", p); break; case 'x': fk = xtermfk; term = "xterm"; break; default: usage(); break; }ARGEND; host_buf = malloc(host_bsize); hostp = host_buf; hostlength = 0; if(initdraw(0, fontname, term) < 0){ fprint(2, "%s: initdraw failed: %r\n", term); exits("initdraw"); } werrstr(""); /* clear spurious error messages */ ebegin(Ehost); histp = hist; menu2.item = menutext2; menu3.item = menutext3; pagemode = 0; blocked = 0; NS = font->height; CW = stringwidth(font, "m"); red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed); bordercol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xCCCCCCCC); cursback = allocimage(display, Rect(0, 0, CW+1, NS+1), screen->chan, 0, DNofill); for(i=0; i<8; i++){ colors[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, rgbacolors[i]); hicolors[i] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, rgbahicolors[i]); } bgdefault = (blkbg? display->black: display->white); fgdefault = (blkbg? display->white: display->black); bgcolor = bgdefault; fgcolor = fgdefault; resize(); if(argc > 0) { sendnchars(strlen(argv[0]),argv[0]); sendnchars(1,"\n"); } }
int canon(char *ep, int c) { if(c&0200) return(SCROLL); switch(c) { case '\b': if(sendp > sendbuf) sendp--; *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; break; case 0x15: /* ^U line kill */ sendp = sendbuf; *ep++ = '^'; *ep++ = 'U'; *ep++ = '\n'; break; case 0x17: /* ^W word kill */ while(sendp > sendbuf && !alnum(*sendp)) { *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; sendp--; } while(sendp > sendbuf && alnum(*sendp)) { *ep++ = '\b'; *ep++ = ' '; *ep++ = '\b'; sendp--; } break; case '\177': /* interrupt */ sendp = sendbuf; send_interrupt(); return(NEWLINE); case '\021': /* quit */ case '\r': case '\n': if(sendp < &sendbuf[512]) *sendp++ = '\n'; sendnchars((int)(sendp-sendbuf), sendbuf); sendp = sendbuf; if(c == '\n' || c == '\r') { *ep++ = '\n'; } *ep = 0; return(NEWLINE); case '\004': /* EOT */ if(sendp == sendbuf) { sendnchars(0,sendbuf); *ep = 0; return(NEWLINE); } /* fall through */ default: if(sendp < &sendbuf[512]) *sendp++ = c; *ep++ = c; break; } *ep = 0; return(OTHER); }
jflush() { sendnchars((int)(cmdptr-cmdbuf),cmdbuf); cmdptr = cmdbuf; }