summaryrefslogtreecommitdiff
path: root/sys/src/cmd/vt/main.c
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/main.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/vt/main.c')
-rwxr-xr-xsys/src/cmd/vt/main.c875
1 files changed, 875 insertions, 0 deletions
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);
+}