#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;
int attribute;
Image *bordercol;
Image *cursback;
Image *black;
Image *white;
Image *red;
Image *green;
Image *blue;
Image *cyan;
Image *magenta;
Image *yellow;
Image *grey;
Image *colortab[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;
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;
rfork(RFENVG|RFNAMEG|RFNOTEG);
term = "vt100";
fk = vt100fk;
ARGBEGIN{
case 'a':
term = "ansi";
fk = ansifk;
break;
case '2':
term = "vt220";
fk = vt220fk;
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;
}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);
histp = hist;
menu2.item = menutext2;
menu3.item = menutext3;
pagemode = 0;
blocked = 0;
NS = font->height ;
CW = stringwidth(font, "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, DBlack);
white = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DWhite);
red = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DRed);
green = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DGreen);
yellow = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DYellow);
blue = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DBlue);
magenta = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DMagenta);
cyan = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DCyan);
grey = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, DPalegreygreen);
colortab[0] = black;
colortab[1] = red;
colortab[2] = green;
colortab[3] = yellow;
colortab[4] = blue;
colortab[5] = magenta;
colortab[6] = cyan;
colortab[7] = grey;
if(dayglo) {
bckcolor = 0;
frgcolor = 7;
} else {
bckcolor = 7;
frgcolor = 0;
colortab[7] = white;
}
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;
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 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)
{
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;
}
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)));
}
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;
}
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;
if(!(attribute & TReverse)) {
txt = colortab[frgcolor];
bg = colortab[bckcolor];
} else {
txt = colortab[bckcolor];
bg = colortab[frgcolor];
}
if(attribute & THighIntensity)
txt = white;
draw(screen, Rpt(p, addpt(p, stringsize(font, str))), bg, nil, p);
string(screen, p, txt, ZP, font, str);
}
|