summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vt
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/vt
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/vt')
-rwxr-xr-xsys/src/cmd/vt/cons.h89
-rwxr-xr-xsys/src/cmd/vt/consctl.c71
-rwxr-xr-xsys/src/cmd/vt/event.c70
-rwxr-xr-xsys/src/cmd/vt/event.h13
-rwxr-xr-xsys/src/cmd/vt/hp.c212
-rwxr-xr-xsys/src/cmd/vt/main.c875
-rwxr-xr-xsys/src/cmd/vt/mkfile18
-rwxr-xr-xsys/src/cmd/vt/termcap5
-rwxr-xr-xsys/src/cmd/vt/vt.c943
9 files changed, 2296 insertions, 0 deletions
diff --git a/sys/src/cmd/vt/cons.h b/sys/src/cmd/vt/cons.h
new file mode 100755
index 000000000..436ef6366
--- /dev/null
+++ b/sys/src/cmd/vt/cons.h
@@ -0,0 +1,89 @@
+/* console state (for consctl) */
+typedef struct Consstate Consstate;
+struct Consstate{
+ int raw;
+ int hold;
+};
+
+extern Consstate* consctl(void);
+extern Consstate* cs;
+
+#define XMARGIN 5 /* inset from border of layer */
+#define YMARGIN 5
+#define INSET 3
+#define BUFS 32
+#define HISTSIZ 4096 /* number of history characters */
+#define BSIZE 1000
+
+#define SCROLL 2
+#define NEWLINE 1
+#define OTHER 0
+
+#define COOKED 0
+#define RAW 1
+
+/* text attributes */
+enum {
+ THighIntensity = (1<<0),
+ TUnderline = (1<<1),
+ TBlink = (1<<2),
+ TReverse = (1<<3),
+ TInvisible = (1<<4),
+};
+
+
+#define button2() ((mouse.buttons & 07)==2)
+#define button3() ((mouse.buttons & 07)==4)
+
+struct ttystate {
+ int crnl;
+ int nlcr;
+};
+extern struct ttystate ttystate[];
+
+#define NKEYS 32 /* max key definitions */
+struct funckey {
+ char *name;
+ char *sequence;
+};
+extern struct funckey *fk;
+extern struct funckey vt100fk[], vt220fk[], ansifk[], xtermfk[];
+
+extern int x, y, xmax, ymax, olines;
+extern int peekc, attribute;
+extern char* term;
+
+extern void emulate(void);
+extern int host_avail(void);
+extern void clear(Rectangle);
+extern void newline(void);
+extern int get_next_char(void);
+extern void ringbell(void);
+extern int number(char *, int *);
+extern void scroll(int,int,int,int);
+extern void backup(int);
+extern void sendnchars(int, char *);
+extern void sendnchars2(int, char *);
+extern Point pt(int, int);
+extern void funckey(int);
+extern void drawstring(Point, char*, int);
+
+extern int debug;
+extern int yscrmin, yscrmax;
+extern int attr;
+extern int defattr;
+
+extern Image *fgcolor;
+extern Image *bgcolor;
+extern Image *colors[];
+extern Image *hicolors[];
+extern Image *bgdefault;
+extern Image *fgdefault;
+
+extern int cursoron;
+extern int nocolor;
+
+extern void curson(int);
+extern void cursoff(void);
+extern void setdim(int, int);
+
diff --git a/sys/src/cmd/vt/consctl.c b/sys/src/cmd/vt/consctl.c
new file mode 100755
index 000000000..525bbb664
--- /dev/null
+++ b/sys/src/cmd/vt/consctl.c
@@ -0,0 +1,71 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include "cons.h"
+
+/*
+ * bind a pipe onto consctl and keep reading it to
+ * get changes to console state.
+ */
+Consstate*
+consctl(void)
+{
+ int i, n, fd, tries;
+ char buf[128];
+ Consstate *x;
+ char *field[10];
+
+ x = segattach(0, "shared", 0, sizeof *x);
+ if(x == (void*)-1)
+ sysfatal("segattach: %r");
+
+ /* a pipe to simulate consctl */
+ if(bind("#|", "/mnt/cons/consctl", MBEFORE) < 0
+ || bind("/mnt/cons/consctl/data1", "/dev/consctl", MREPL) < 0)
+ sysfatal("bind consctl: %r");
+
+ /* a pipe to simulate the /dev/cons */
+ if(bind("#|", "/mnt/cons/cons", MREPL) < 0
+ || bind("/mnt/cons/cons/data1", "/dev/cons", MREPL) < 0)
+ sysfatal("bind cons: %r");
+
+ switch(fork()){
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ break;
+ default:
+ return x;
+ }
+
+ notify(0);
+
+ for(tries = 0; tries < 100; tries++){
+ x->raw = 0;
+ x->hold = 0;
+ fd = open("/mnt/cons/consctl/data", OREAD);
+ if(fd < 0)
+ break;
+ tries = 0;
+ for(;;){
+ n = read(fd, buf, sizeof(buf)-1);
+ if(n <= 0)
+ break;
+ buf[n] = 0;
+ n = getfields(buf, field, 10, 1, " ");
+ for(i = 0; i < n; i++){
+ if(strcmp(field[i], "rawon") == 0)
+ x->raw = 1;
+ else if(strcmp(field[i], "rawoff") == 0)
+ x->raw = 0;
+ else if(strcmp(field[i], "holdon") == 0)
+ x->hold = 1;
+ else if(strcmp(field[i], "holdoff") == 0)
+ x->hold = 0;
+ }
+ }
+ close(fd);
+ }
+ exits(0);
+ return 0; /* dummy to keep compiler quiet*/
+}
diff --git a/sys/src/cmd/vt/event.c b/sys/src/cmd/vt/event.c
new file mode 100755
index 000000000..12f1f0e43
--- /dev/null
+++ b/sys/src/cmd/vt/event.c
@@ -0,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include "cons.h"
+
+#define BUFSIZ 4000
+
+extern int outfd;
+
+int hostpid;
+
+void
+edie(void)
+{
+ static int dead = 0;
+
+ if(dead++ > 0) return;
+ close(outfd);
+ postnote(PNGROUP, getpid(), "exit");
+}
+
+static int
+start_host(void)
+{
+ int fd;
+
+ cs = consctl();
+
+ switch((hostpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG))) {
+ case 0:
+ fd = open("/dev/cons", OREAD);
+ dup(fd,0);
+ if(fd != 0)
+ close(fd);
+ fd = open("/dev/cons", OWRITE);
+ dup(fd,1);
+ dup(fd,2);
+ if(fd != 1 && fd !=2)
+ close(fd);
+ execl("/bin/rc","rcX",nil);
+ fprint(2,"failed to start up rc\n");
+ _exits("rc");
+ case -1:
+ fprint(2,"rc startup: fork error\n");
+ _exits("rc_fork");
+ }
+
+ return open("/mnt/cons/cons/data", ORDWR);
+}
+
+void
+ebegin(int Ehost)
+{
+
+ atexit(edie);
+
+ einit(Emouse|Ekeyboard);
+
+ outfd = start_host();
+ if( estart(Ehost, outfd, BUFSIZ) != Ehost) {
+ exits("event init error");
+ }
+}
+
+void
+send_interrupt(void)
+{
+ postnote(PNGROUP, hostpid,"interrupt");
+}
diff --git a/sys/src/cmd/vt/event.h b/sys/src/cmd/vt/event.h
new file mode 100755
index 000000000..baa108623
--- /dev/null
+++ b/sys/src/cmd/vt/event.h
@@ -0,0 +1,13 @@
+#define BSIZE 4000
+#define MOUSE 0
+#define KBD 1
+#define HOST 2
+#define HOST_BLOCKED 1
+#define KBD_BLOCKED 2
+
+typedef struct IOEvent {
+ short key;
+ short size;
+ uchar data[BSIZE];
+} IOEvent;
+
diff --git a/sys/src/cmd/vt/hp.c b/sys/src/cmd/vt/hp.c
new file mode 100755
index 000000000..cfca3033e
--- /dev/null
+++ b/sys/src/cmd/vt/hp.c
@@ -0,0 +1,212 @@
+#include <u.h>
+#include <libc.h>
+#include <ndraw.h>
+#include <bio.h>
+#include "cons.h"
+
+char *term = "2621";
+
+struct funckey fk[32];
+
+void
+emulate(void)
+{
+ char buf[BUFS+1];
+ int n;
+ int c;
+ int standout = 0;
+ int insmode = 0;
+
+ for (;;) {
+ if (x > xmax || y > ymax) {
+ x = 0;
+ newline();
+ }
+ buf[0] = get_next_char();
+ buf[1] = '\0';
+ switch(buf[0]) {
+
+ case '\000': /* nulls, just ignore 'em */
+ break;
+
+ case '\007': /* bell */
+ ringbell();
+ break;
+
+ case '\t': /* tab modulo 8 */
+ x = (x|7)+1;
+ break;
+
+ case '\033':
+ switch(get_next_char()) {
+
+ case 'j':
+ get_next_char();
+ break;
+
+ case '&': /* position cursor &c */
+ switch(get_next_char()) {
+
+ case 'a':
+ for (;;) {
+ n = number(buf, nil);
+ switch(buf[0]) {
+
+ case 'r':
+ case 'y':
+ y = n;
+ continue;
+
+ case 'c':
+ x = n;
+ continue;
+
+ case 'R':
+ case 'Y':
+ y = n;
+ break;
+
+ case 'C':
+ x = n;
+ break;
+ }
+ break;
+ }
+ break;
+
+ case 'd': /* underline stuff */
+ if ((n=get_next_char())>='A' && n <= 'O')
+ standout++;
+ else if (n == '@')
+ standout = 0;
+ break;
+
+ default:
+ get_next_char();
+ break;
+
+ }
+ break;
+
+ case 'i': /* back tab */
+ if (x>0)
+ x = (x-1) & ~07;
+ break;
+
+ case 'H': /* home cursor */
+ case 'h':
+ x = 0;
+ y = 0;
+ break;
+
+ case 'L': /* insert blank line */
+ scroll(y, ymax, y+1, y);
+ break;
+
+ case 'M': /* delete line */
+ scroll(y+1, ymax+1, y, ymax);
+ break;
+
+ case 'J': /* clear to end of display */
+ xtipple(Rpt(pt(0, y+1),
+ pt(xmax+1, ymax+1)));
+ /* flow */
+ case 'K': /* clear to EOL */
+ xtipple(Rpt(pt(x, y),
+ pt(xmax+1, y+1)));
+ break;
+
+ case 'P': /* delete char */
+ bitblt(&screen, pt(x, y),
+ &screen, Rpt(pt(x+1, y),
+ pt(xmax+1, y+1)),
+ S);
+ xtipple(Rpt(pt(xmax, y),
+ pt(xmax+1, y+1)));
+ break;
+
+ case 'Q': /* enter insert mode */
+ insmode++;
+ break;
+
+ case 'R': /* leave insert mode */
+ insmode = 0;
+ break;
+
+ case 'S': /* roll up */
+ scroll(1, ymax+1, 0, ymax);
+ break;
+
+ case 'T':
+ scroll(0, ymax, 1, 0);
+ break;
+
+ case 'A': /* upline */
+ case 't':
+ if (y>0)
+ y--;
+ if (olines > 0)
+ olines--;
+ break;
+
+ case 'B':
+ case 'w':
+ y++; /* downline */
+ break;
+
+ case 'C': /* right */
+ case 'v':
+ x++;
+ break;
+
+ case 'D': /* left */
+ case 'u':
+ x--;
+
+ }
+ break;
+
+ case '\b': /* backspace */
+ if(x > 0)
+ --x;
+ break;
+
+ case '\n': /* linefeed */
+ newline();
+ standout = 0;
+ if( ttystate[cs->raw].nlcr )
+ x = 0;
+ break;
+
+ case '\r': /* carriage return */
+ x = 0;
+ standout = 0;
+ if( ttystate[cs->raw].crnl )
+ newline();
+ break;
+
+ default: /* ordinary char */
+ 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;
+ if (insmode) {
+ bitblt(&screen, pt(x+n, y), &screen,
+ Rpt(pt(x, y), pt(xmax-n+1, y+1)), S);
+ }
+ xtipple(Rpt(pt(x,y), pt(x+n, y+1)));
+ string(&screen, pt(x, y), font, buf, DxorS);
+ if (standout)
+ rectf(&screen,
+ Rpt(pt(x,y),pt(x+n,y+1)),
+ DxorS);
+ x += n;
+ peekc = c;
+ break;
+ }
+ }
+}
diff --git a/sys/src/cmd/vt/main.c b/sys/src/cmd/vt/main.c
new file mode 100755
index 000000000..a342a8984
--- /dev/null
+++ b/sys/src/cmd/vt/main.c
@@ -0,0 +1,875 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+#include <bio.h>
+#include <keyboard.h>
+#include "cons.h"
+
+enum{
+ Ehost = 4,
+};
+
+char *menutext2[] = {
+ "backup",
+ "forward",
+ "reset",
+ "clear",
+ "send",
+ "page",
+ 0
+};
+
+char *menutext3[] = {
+ "24x80",
+ "crnl",
+ "nl",
+ "raw",
+ "exit",
+ 0
+};
+
+/* variables associated with the screen */
+
+int x, y; /* character positions */
+char *backp;
+int backc;
+int atend;
+int nbacklines;
+int xmax, ymax;
+int blocked;
+int resize_flag;
+int pagemode;
+int olines;
+int peekc;
+int cursoron = 1;
+Menu menu2;
+Menu menu3;
+char *histp;
+char hist[HISTSIZ];
+int yscrmin, yscrmax;
+int attr, defattr;
+int wctlout;
+
+Image *bordercol;
+Image *cursback;
+Image *colors[8];
+Image *hicolors[8];
+Image *red;
+Image *fgcolor;
+Image *bgcolor;
+Image *fgdefault;
+Image *bgdefault;
+
+uint rgbacolors[8] = {
+ 0x000000FF, /* black */
+ 0xAA0000FF, /* red */
+ 0x00AA00FF, /* green */
+ 0xFF5500FF, /* brown */
+ 0x0000FFFF, /* blue */
+ 0xAA00AAFF, /* purple */
+ 0x00AAAAFF, /* cyan */
+ 0x7F7F7FFF, /* white */
+};
+
+ulong rgbahicolors[8] = {
+ 0x555555FF, /* light black aka grey */
+ 0xFF5555FF, /* light red */
+ 0x55FF55FF, /* light green */
+ 0xFFFF55FF, /* light brown aka yellow */
+ 0x5555FFFF, /* light blue */
+ 0xFF55FFFF, /* light purple */
+ 0x55FFFFFF, /* light cyan */
+ 0xFFFFFFFF, /* light grey aka white */
+};
+
+/* terminal control */
+struct ttystate ttystate[2] = { {0, 1}, {0, 1} };
+
+int NS;
+int CW;
+Consstate *cs;
+Mouse mouse;
+
+int debug;
+int nocolor;
+int logfd = -1;
+int outfd = -1;
+Biobuf *snarffp = 0;
+
+char *host_buf;
+char *hostp; /* input from host */
+int host_bsize = 2*BSIZE;
+int hostlength; /* amount of input from host */
+char echo_input[BSIZE];
+char *echop = echo_input; /* characters to echo, after canon */
+char sendbuf[BSIZE]; /* hope you can't type ahead more than BSIZE chars */
+char *sendp = sendbuf;
+
+char *term;
+struct funckey *fk;
+
+/* functions */
+void initialize(int, char **);
+void ebegin(int);
+int waitchar(void);
+int rcvchar(void);
+void set_input(char *);
+void set_host(Event *);
+void bigscroll(void);
+void readmenu(void);
+void eresized(int);
+void resize(void);
+void send_interrupt(void);
+int alnum(int);
+void escapedump(int,uchar *,int);
+
+void
+main(int argc, char **argv)
+{
+ initialize(argc, argv);
+ emulate();
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-2abcx] [-f font] [-l logfile]\n", argv0);
+ exits("usage");
+}
+
+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");
+ }
+}
+
+void
+clear(Rectangle r)
+{
+ draw(screen, r, bgcolor, nil, ZP);
+}
+
+void
+newline(void)
+{
+ nbacklines--;
+ if(y >= yscrmax) {
+ y = yscrmax;
+ if(pagemode && olines >= yscrmax) {
+ blocked = 1;
+ return;
+ }
+ scroll(yscrmin+1, yscrmax+1, yscrmin, yscrmax);
+ } else
+ y++;
+ olines++;
+}
+
+void
+cursoff(void)
+{
+ draw(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))),
+ cursback, nil, cursback->r.min);
+}
+
+void
+curson(int bl)
+{
+ Image *col;
+
+ if(!cursoron){
+ cursoff();
+ return;
+ }
+
+ draw(cursback, cursback->r, screen, nil, pt(x, y));
+ if(bl)
+ col = red;
+ else
+ col = bordercol;
+ border(screen, Rpt(pt(x, y), addpt(pt(x, y), Pt(CW,NS))), 2, col, ZP);
+}
+
+int
+get_next_char(void)
+{
+ int c = peekc;
+ uchar buf[1];
+ peekc = 0;
+ if(c > 0)
+ return(c);
+ while(c <= 0) {
+ if(backp) {
+ c = *backp;
+ if(c && nbacklines >= 0) {
+ backp++;
+ if(backp >= &hist[HISTSIZ])
+ backp = hist;
+ return(c);
+ }
+ backp = 0;
+ }
+ c = (uchar)waitchar();
+ if(c > 0 && logfd >= 0) {
+ buf[0] = c;
+ write(logfd, buf, 1);
+ }
+ }
+ *histp++ = c;
+ if(histp >= &hist[HISTSIZ])
+ histp = hist;
+ *histp = '\0';
+ return(c);
+}
+
+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);
+}
+
+void
+sendfk(char *name)
+{
+ int i;
+ static int fd;
+
+ for(i=0; fk[i].name; i++)
+ if(strcmp(name, fk[i].name)==0){
+ sendnchars2(strlen(fk[i].sequence), fk[i].sequence);
+ return;
+ }
+}
+
+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
+eresized(int new)
+{
+ resize_flag = 1+new;
+}
+
+void
+putenvint(char *name, int x)
+{
+ char buf[20];
+
+ snprint(buf, sizeof buf, "%d", x);
+ putenv(name, buf);
+}
+
+void
+exportsize(void)
+{
+ putenvint("XPIXELS", Dx(screen->r)-2*XMARGIN);
+ putenvint("YPIXELS", Dy(screen->r)-2*XMARGIN);
+ putenvint("LINES", ymax+1);
+ putenvint("COLS", xmax+1);
+ putenv("TERM", term);
+}
+
+void
+resize(void)
+{
+ if(resize_flag > 1 && getwindow(display, Refnone) < 0){
+ fprint(2, "can't reattach to window: %r\n");
+ exits("can't reattach to window");
+ }
+ xmax = (Dx(screen->r)-2*XMARGIN)/CW-1;
+ ymax = (Dy(screen->r)-2*YMARGIN)/NS-1;
+ if(xmax == 0 || ymax == 0)
+ exits("window gone");
+ x = 0;
+ y = 0;
+ yscrmin = 0;
+ yscrmax = ymax;
+ olines = 0;
+ exportsize();
+ clear(screen->r);
+ resize_flag = 0;
+ werrstr(""); /* clear spurious error messages */
+}
+
+void
+setdim(int ht, int wid)
+{
+ int fd;
+ Rectangle r;
+
+ if(ht != -1)
+ ymax = ht-1;
+ if(wid != -1)
+ xmax = wid-1;
+
+ r.min = screen->r.min;
+ r.max = addpt(screen->r.min,
+ Pt((xmax+1)*CW+2*XMARGIN+2*INSET,
+ (ymax+1)*NS+2*YMARGIN+2*INSET));
+ fd = open("/dev/wctl", OWRITE);
+ if(fd < 0 || fprint(fd, "resize -dx %d -dy %d\n", Dx(r)+2*Borderwidth,
+ Dy(r)+2*Borderwidth) < 0){
+ border(screen, r, INSET, bordercol, ZP);
+ exportsize();
+ }
+ if(fd >= 0)
+ close(fd);
+}
+
+void
+readmenu(void)
+{
+ if(button3()) {
+ menu3.item[1] = ttystate[cs->raw].crnl ? "cr" : "crnl";
+ menu3.item[2] = ttystate[cs->raw].nlcr ? "nl" : "nlcr";
+ menu3.item[3] = cs->raw ? "cooked" : "raw";
+
+ switch(emenuhit(3, &mouse, &menu3)) {
+ case 0: /* 24x80 */
+ setdim(24, 80);
+ return;
+ case 1: /* newline after cr? */
+ ttystate[cs->raw].crnl = !ttystate[cs->raw].crnl;
+ return;
+ case 2: /* cr after newline? */
+ ttystate[cs->raw].nlcr = !ttystate[cs->raw].nlcr;
+ return;
+ case 3: /* switch raw mode */
+ cs->raw = !cs->raw;
+ return;
+ case 4:
+ exits(0);
+ }
+ return;
+ }
+
+ menu2.item[5] = pagemode? "scroll": "page";
+
+ switch(emenuhit(2, &mouse, &menu2)) {
+
+ case 0: /* back up */
+ if(atend == 0) {
+ backc++;
+ backup(backc);
+ }
+ return;
+
+ case 1: /* move forward */
+ backc--;
+ if(backc >= 0)
+ backup(backc);
+ else
+ backc = 0;
+ return;
+
+ case 2: /* reset */
+ backc = 0;
+ backup(0);
+ return;
+
+ case 3: /* clear screen */
+ eresized(0);
+ return;
+
+ case 4: /* send the snarf buffer */
+ snarffp = Bopen("/dev/snarf",OREAD);
+ return;
+
+ case 5: /* pause and clear at end of screen */
+ pagemode = 1-pagemode;
+ if(blocked && !pagemode) {
+ eresized(0);
+ blocked = 0;
+ }
+ return;
+ }
+}
+
+void
+backup(int count)
+{
+ register n;
+ register char *cp;
+
+ eresized(0);
+ n = 3*(count+1)*ymax/4;
+ cp = histp;
+ atend = 0;
+ while (n >= 0) {
+ cp--;
+ if(cp < hist)
+ cp = &hist[HISTSIZ-1];
+ if(*cp == '\0') {
+ atend = 1;
+ break;
+ }
+ if(*cp == '\n')
+ n--;
+ }
+ cp++;
+ if(cp >= &hist[HISTSIZ])
+ cp = hist;
+ backp = cp;
+ nbacklines = ymax-2;
+}
+
+Point
+pt(int x, int y)
+{
+ return addpt(screen->r.min, Pt(x*CW+XMARGIN,y*NS+YMARGIN));
+}
+
+void
+scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */
+{
+ draw(screen, Rpt(pt(0, dy), pt(xmax+1, dy+ly-sy)), screen, nil, pt(0, sy));
+ clear(Rpt(pt(0, cy), pt(xmax+1, cy+1)));
+ flushimage(display, 1);
+}
+
+void
+bigscroll(void) /* scroll up half a page */
+{
+ int half = ymax/3;
+
+ if(x == 0 && y == 0)
+ return;
+ if(y < half) {
+ clear(Rpt(pt(0,0),pt(xmax+1,ymax+1)));
+ x = y = 0;
+ return;
+ }
+ draw(screen, Rpt(pt(0, 0), pt(xmax+1, ymax+1)), screen, nil, pt(0, half));
+ clear(Rpt(pt(0,y-half+1),pt(xmax+1,ymax+1)));
+ y -= half;
+ if(olines)
+ olines -= half;
+ flushimage(display, 1);
+}
+
+int
+number(char *p, int *got)
+{
+ int c, n = 0;
+
+ if(got)
+ *got = 0;
+ while ((c = get_next_char()) >= '0' && c <= '9'){
+ if(got)
+ *got = 1;
+ n = n*10 + c - '0';
+ }
+ *p = c;
+ return(n);
+}
+
+/* stubs */
+
+void
+sendnchars(int n,char *p)
+{
+ sendnchars2(n, p);
+ p[n+1] = 0;
+}
+
+void
+sendnchars2(int n,char *p)
+{
+ if(write(outfd,p,n) < 0) {
+ close(outfd);
+ close(0);
+ close(1);
+ close(2);
+ exits("write");
+ }
+}
+
+int
+host_avail(void)
+{
+ return(*echop || ((hostp - host_buf) < hostlength));
+}
+
+int
+rcvchar(void)
+{
+ int c;
+ if(*echop) {
+ c = *echop++;
+ if(!*echop) {
+ echop = echo_input;
+ *echop = 0;
+ }
+ return c;
+ }
+ return *hostp++;
+}
+
+void
+set_host(Event *e)
+{
+ hostlength = e->n;
+ if(hostlength > host_bsize) {
+ host_bsize *= 2;
+ host_buf = realloc(host_buf,host_bsize);
+ }
+ hostp = host_buf;
+ memmove(host_buf,e->data,hostlength);
+ host_buf[hostlength]=0;
+}
+
+void
+ringbell(void){
+}
+
+int
+alnum(int c)
+{
+ if(c >= 'a' && c <= 'z')
+ return 1;
+ if(c >= 'A' && c <= 'Z')
+ return 1;
+ if(c >= '0' && c <= '9')
+ return 1;
+ return 0;
+}
+
+void
+escapedump(int fd,uchar *str,int len)
+{
+ int i;
+
+ for(i = 0; i < len; i++) {
+ if((str[i] < ' ' || str[i] > '\177') &&
+ str[i] != '\n' && str[i] != '\t') fprint(fd,"^%c",str[i]+64);
+ else if(str[i] == '\177') fprint(fd,"^$");
+ else if(str[i] == '\n') fprint(fd,"^J\n");
+ else fprint(fd,"%c",str[i]);
+ }
+}
+
+void
+funckey(int key)
+{
+ if(key >= NKEYS)
+ return;
+ if(fk[key].name == 0)
+ return;
+ sendnchars2(strlen(fk[key].sequence), fk[key].sequence);
+}
+
+
+void
+drawstring(Point p, char *str, int attr)
+{
+ int i;
+ Image *txt, *bg, *tmp;
+
+ txt = fgcolor;
+ bg = bgcolor;
+ if(attr & TReverse){
+ tmp = txt;
+ txt = bg;
+ bg = tmp;
+ }
+ if(attr & THighIntensity){
+ for(i=0; i<8; i++)
+ if(txt == colors[i])
+ txt = hicolors[i];
+ }
+
+ draw(screen, Rpt(p, addpt(p, stringsize(font, str))), bg, nil, p);
+ string(screen, p, txt, ZP, font, str);
+}
diff --git a/sys/src/cmd/vt/mkfile b/sys/src/cmd/vt/mkfile
new file mode 100755
index 000000000..b4cad99d7
--- /dev/null
+++ b/sys/src/cmd/vt/mkfile
@@ -0,0 +1,18 @@
+</$objtype/mkfile
+
+#TARG=hp\
+# vt\
+# vt220\
+
+TARG=vt
+
+OFILES=\
+ consctl.$O\
+ event.$O\
+ main.$O\
+ vt.$O\
+
+HFILES=cons.h
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
diff --git a/sys/src/cmd/vt/termcap b/sys/src/cmd/vt/termcap
new file mode 100755
index 000000000..b1c6ef1aa
--- /dev/null
+++ b/sys/src/cmd/vt/termcap
@@ -0,0 +1,5 @@
+h2|2621|hp2621|hp2621a|hp2621p|2621|2621a|2621p|hp 2621:\
+ :is=\E&j@\r\E3\r:bt=\Ei:cm=\E&a%r%dc%dY:dc=2\EP:ip=2:\
+ :kh=\Ep\r:ku=\Et\r:kl=\Eu\r:kr=\Ev\r:kd=\Ew\r:\
+ :kn#8:k1=\Ep\r:k2=\Eq\r:k3=\Er\r:k4=\Es\r:k5=\Et\r:k6=\Eu\r:k7=\Ev\r:\
+ :k8=\Ew\r:ks=\E&jB:ke=\E&j@:ta=2^I:tc=hp:
diff --git a/sys/src/cmd/vt/vt.c b/sys/src/cmd/vt/vt.c
new file mode 100755
index 000000000..999ead350
--- /dev/null
+++ b/sys/src/cmd/vt/vt.c
@@ -0,0 +1,943 @@
+/*
+ * Known bugs:
+ *
+ * 1. We don't handle cursor movement characters inside escape sequences.
+ * That is, ESC[2C moves two to the right, so ESC[2\bC is supposed to back
+ * up one and then move two to the right.
+ *
+ * 2. We don't handle tabstops past nelem(tabcol) columns.
+ *
+ * 3. We don't respect requests to do reverse video for the whole screen.
+ *
+ * 4. We ignore the ESC#n codes, so that we don't do double-width nor
+ * double-height lines, nor the ``fill the screen with E's'' confidence check.
+ *
+ * 5. Cursor key sequences aren't selected by keypad application mode.
+ *
+ * 6. "VT220" mode (-2) currently just switches the default cursor key
+ * functions (same as -a); it's still just a VT100 emulation.
+ *
+ * 7. VT52 mode and a few other rarely used features are not implemented.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <bio.h>
+#include <ctype.h>
+#include "cons.h"
+
+int wraparound = 1;
+int originrelative = 0;
+
+int tabcol[200];
+
+struct funckey vt100fk[NKEYS] = {
+ { "up key", "\033OA", },
+ { "down key", "\033OB", },
+ { "left key", "\033OD", },
+ { "right key", "\033OC", },
+};
+
+struct funckey ansifk[NKEYS] = {
+ { "up key", "\033[A", },
+ { "down key", "\033[B", },
+ { "left key", "\033[D", },
+ { "right key", "\033[C", },
+ { "F1", "\033OP", },
+ { "F2", "\033OQ", },
+ { "F3", "\033OR", },
+ { "F4", "\033OS", },
+ { "F5", "\033OT", },
+ { "F6", "\033OU", },
+ { "F7", "\033OV", },
+ { "F8", "\033OW", },
+ { "F9", "\033OX", },
+ { "F10", "\033OY", },
+ { "F11", "\033OZ", },
+ { "F12", "\033O1", },
+};
+
+struct funckey vt220fk[NKEYS] = {
+ { "up key", "\033[A", },
+ { "down key", "\033[B", },
+ { "left key", "\033[D", },
+ { "right key", "\033[C", },
+};
+
+struct funckey xtermfk[NKEYS] = {
+ { "page up", "\033[5~", },
+ { "page down", "\033[6~", },
+ { "up key", "\033[A", },
+ { "down key", "\033[B", },
+ { "left key", "\033[D", },
+ { "right key", "\033[C", },
+ { "F1", "\033[11~", },
+ { "F2", "\033[12~", },
+ { "F3", "\033[13~", },
+ { "F4", "\033[14~", },
+ { "F5", "\033[15~", },
+ { "F6", "\033[17~", },
+ { "F7", "\033[18~", },
+ { "F8", "\033[19~", },
+ { "F9", "\033[20~", },
+ { "F10", "\033[21~", },
+ { "F11", "\033[22~", },
+ { "F12", "\033[23~", },
+};
+
+char gmap[256] = {
+ ['_'] ' ', /* blank */
+ ['\\'] '*', /* diamond */
+ ['a'] 'X', /* checkerboard */
+ ['b'] '\t', /* HT */
+ ['c'] '\x0C', /* FF */
+ ['d'] '\r', /* CR */
+ ['e'] '\n', /* LF */
+ ['f'] 'o', /* degree */
+ ['g'] '+', /* plus/minus */
+ ['h'] '\n', /* NL, but close enough */
+ ['i'] '\v', /* VT */
+ ['j'] '+', /* lower right corner */
+ ['k'] '+', /* upper right corner */
+ ['l'] '+', /* upper left corner */
+ ['m'] '+', /* lower left corner */
+ ['n'] '+', /* crossing lines */
+ ['o'] '-', /* horiz line - scan 1 */
+ ['p'] '-', /* horiz line - scan 3 */
+ ['q'] '-', /* horiz line - scan 5 */
+ ['r'] '-', /* horiz line - scan 7 */
+ ['s'] '-', /* horiz line - scan 9 */
+ ['t'] '+', /* |- */
+ ['u'] '+', /* -| */
+ ['v'] '+', /* upside down T */
+ ['w'] '+', /* rightside up T */
+ ['x'] '|', /* vertical bar */
+ ['y'] '<', /* less/equal */
+ ['z'] '>', /* gtr/equal */
+ ['{'] 'p', /* pi */
+ ['|'] '!', /* not equal */
+ ['}'] 'L', /* pound symbol */
+ ['~'] '.', /* centered dot: ยท */
+};
+
+static void setattr(int argc, int *argv);
+
+void
+fixops(int *operand)
+{
+ if(operand[0] < 1)
+ operand[0] = 1;
+}
+
+void
+emulate(void)
+{
+ char 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:
+ sendnchars2(7, "\033[?1;2c"); /* VT100 with AVO option */
+// sendnchars2(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 */
+ sendnchars2(4, "\033[0n"); /* terminal ok */
+ break;
+ case 6: /* cursor position */
+ sendnchars2(sprint(buf, "\033[%d;%dR",
+ originrelative ? y+1 - yscrmin : y+1, x+1), 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':
+ sendnchars2(20, "\033[3;1;1;120;120;1;0x");
+ break;
+
+ /*
+ * y - invoke confidence test
+ */
+ case 'y':
+ 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;
+
+ /* set title */
+ case ']': /* it's actually <esc> ] num ; title <bel> */
+ {
+ int ch, fd;
+ number(buf, nil);
+ i = 0;
+ while((ch = get_next_char()) != '\a')
+ if(i < sizeof buf)
+ buf[i++] = ch;
+ fd = open("/dev/label", OWRITE);
+ write(fd, buf, i);
+ close(fd);
+ }
+ break;
+
+ /*
+ * Ignore other commands.
+ */
+ default:
+print("unknown command '%c' (0x%x)\n", dch, dch);
+ break;
+
+ }
+ break;
+
+ default: /* ordinary char */
+Default:
+ if(isgraphics && gmap[(uchar) buf[0]])
+ buf[0] = gmap[(uchar) 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;
+// clear(Rpt(pt(x,y), pt(x+n, y+1)));
+ drawstring(pt(x, y), buf, attr);
+ x += n;
+ peekc = c;
+ break;
+ }
+ }
+}
+
+static void
+setattr(int argc, int *argv)
+{
+ int i;
+
+ for(i=0; i<argc; i++) {
+ switch(argv[i]) {
+ case 0:
+ attr = defattr;
+ fgcolor = fgdefault;
+ bgcolor = bgdefault;
+ break;
+ case 1:
+ attr |= THighIntensity;
+ break;
+ case 4:
+ attr |= TUnderline;
+ break;
+ case 5:
+ attr |= TBlink;
+ break;
+ case 7:
+ attr |= TReverse;
+ break;
+ case 8:
+ attr |= TInvisible;
+ break;
+ case 22:
+ attr &= ~THighIntensity;
+ break;
+ case 24:
+ attr &= ~TUnderline;
+ break;
+ case 25:
+ attr &= ~TBlink;
+ break;
+ case 27:
+ attr &= ~TReverse;
+ break;
+ case 28:
+ attr &= ~TInvisible;
+ break;
+ case 30: /* black */
+ case 31: /* red */
+ case 32: /* green */
+ case 33: /* brown */
+ case 34: /* blue */
+ case 35: /* purple */
+ case 36: /* cyan */
+ case 37: /* white */
+ fgcolor = (nocolor? fgdefault: colors[argv[i]-30]);
+ break;
+ case 39:
+ fgcolor = fgdefault;
+ break;
+ case 40: /* black */
+ case 41: /* red */
+ case 42: /* green */
+ case 43: /* brown */
+ case 44: /* blue */
+ case 45: /* purple */
+ case 46: /* cyan */
+ case 47: /* white */
+ bgcolor = (nocolor? bgdefault: colors[argv[i]-40]);
+ break;
+ case 49:
+ bgcolor = bgdefault;
+ break;
+ }
+ }
+}