#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 bckcolor, frgcolor, bckdefault, frgdefault;
int attribute, attdefault;
int wctlout;
int wflag;
Image *bordercol;
Image *cursback;
Image *black;
Image *red;
Image *green;
Image *blue;
Image *cyan;
Image *purple;
Image *brown;
Image *grey;
Image *hiblack;
Image *hired;
Image *higreen;
Image *hiblue;
Image *hicyan;
Image *hipurple;
Image *hibrown;
Image *higrey;
Image *colortab[8];
Image *hicolortab[8];
/* terminal control */
struct ttystate ttystate[2] = { {0, 1}, {0, 1} };
int NS;
int CW;
Consstate *cs;
Mouse mouse;
int outfd = -1;
Biobuf *snarffp = 0;
Font *fnt;
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;
/* 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);
char *term;
struct funckey *fk;
int debug;
int logfd = -1;
void
main(int argc, char **argv)
{
initialize(argc, argv);
emulate();
}
void
useage(void)
{
fprint(2, "usage: %s [-2s] [-l logfile]\n", argv0);
exits("usage");
}
void
initialize(int argc, char **argv)
{
int dayglo = 1;
char *p;
char *fname = 0;
rfork(RFENVG|RFNAMEG|RFNOTEG);
term = "vt100";
fk = vt100fk;
ARGBEGIN{
case 'f':
fname = EARGF(useage());
break;
case 'a':
term = "ansi";
fk = ansifk;
break;
case '2':
term = "vt220";
fk = vt220fk;
break;
case 'x':
fk = xtermfk;
term = "xterm";
break;
case 's': /* for sape */
dayglo = 0;
break;
case 'l':
p = ARGF();
if(p == 0)
useage();
logfd = create(p, OWRITE, 0666);
if(logfd < 0)
sysfatal("could not create log file: %s: %r", p);
break;
case 'w':
wflag = 1;
break;
}ARGEND;
host_buf = malloc(host_bsize);
hostp = host_buf;
hostlength = 0;
if(initdraw(0,0,term) < 0){
fprint(2, "%s: initdraw failed: %r\n", term);
exits("initdraw");
}
ebegin(Ehost);
if(fname)
fnt = openfont(display, fname);
if(fnt == nil)
fnt = font;
histp = hist;
menu2.item = menutext2;
menu3.item = menutext3;
pagemode = 0;
blocked = 0;
NS = fnt->height;
CW = stringwidth(fnt, "m");
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);
black = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x000000FF);
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xAA0000FF);
green = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x00AA00FF);
blue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x0000FFFF);
cyan = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x00AAAAFF);
purple = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xAA00AAFF);
brown = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xFF5500FF);
grey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x7F7F7FFF);
hiblack = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x555555FF);
hired = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xff5555FF);
higreen = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x55ff55FF);
hiblue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x5555ffFF);
hicyan = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x55ffffFF);
hipurple = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xff55ffFF);
hibrown = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xffff55FF);
higrey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xffffffFF);
bckdefault = bckcolor = 0;
frgdefault = frgcolor = 7;
if(dayglo){
colortab[0] = black;
colortab[1] = red;
colortab[2] = green;
colortab[3] = brown;
colortab[4] = blue;
colortab[5] = purple;
colortab[6] = cyan;
colortab[7] = grey;
hicolortab[0] = hiblack;
hicolortab[1] = hired;
hicolortab[2] = higreen;
hicolortab[3] = hibrown;
hicolortab[4] = hiblue;
hicolortab[5] = hipurple;
hicolortab[6] = hicyan;
hicolortab[7] = higrey;
} else {
hicolortab[0] = grey;
hicolortab[1] = red;
hicolortab[2] = green;
hicolortab[3] = brown;
hicolortab[4] = blue;
hicolortab[5] = purple;
hicolortab[6] = cyan;
hicolortab[7] = black;
colortab[0] = higrey;
colortab[1] = hired;
colortab[2] = higreen;
colortab[3] = hibrown;
colortab[4] = hiblue;
colortab[5] = hipurple;
colortab[6] = hicyan;
colortab[7] = hiblack;
}
eresized(0);
if(argc > 0) {
sendnchars(strlen(argv[0]),argv[0]);
sendnchars(1,"\n");
}
}
void
clear(Rectangle r)
{
draw(screen, r, colortab[bckcolor], 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;
draw(cursback, cursback->r, screen, nil, pt(x, y));
if(!cursoron)
return;
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 */
}
return 1; /* to shut up compiler */
}
void
eresized(int new)
{
resize_flag = 1+new;
}
void
exportsize(void)
{
int fd;
char buf[10];
if((fd = create("/env/LINES", OWRITE, 0644)) > 0) {
sprint(buf,"%d",ymax+1);
write(fd,buf,strlen(buf));
close(fd);
}
if((fd = create("/env/COLS", OWRITE, 0644)) > 0) {
sprint(buf,"%d",xmax+1);
write(fd,buf,strlen(buf));
close(fd);
}
if((fd = create("/env/TERM", OWRITE, 0644)) > 0) {
fprint(fd, "%s", term);
close(fd);
}
}
void
resize(void)
{
static int oldwt;
static int oldht;
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);
fprint(wctlout, " %11d %11d %11d %11d",
screen->r.min.x, screen->r.min.y,
screen->r.max.x, screen->r.max.y);
oldwt = Dx(screen->r);
oldht = Dy(screen->r);
resize_flag = 0;
}
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 attribute)
{
Image *txt, *bg;
Rune *rstr;
int i, n;
if(!(attribute & TReverse)) {
if(attribute & THighIntensity || bckcolor){
txt = hicolortab[frgcolor];
bg = colortab[bckcolor];
}else{
txt = colortab[frgcolor];
bg = colortab[bckcolor];
}
} else {
if(attribute & THighIntensity || bckcolor){
txt = colortab[bckcolor];
bg = colortab[frgcolor];
}else{
txt = colortab[bckcolor];
bg = colortab[frgcolor];
}
}
n = strlen(str) + 1;
rstr = malloc(n * sizeof(rstr[0]));
for(i = 0; i < n; ++i)
rstr[i] = (uchar)str[i];
draw(screen, Rpt(p, addpt(p, runestringsize(fnt, rstr))), bg, nil, p);
runestring(screen, p, txt, ZP, fnt, rstr);
free(rstr);
}
|