vt: implement /dev/cons and /dev/consctl as a fileserver, winch, incremental redraw

we used to bind a pipe to /dev/cons and /dev/consctl with some
shared segment hack to pass tty info arround. now we implement
this as a fileserver.

add support for "winchon"/"winchoff" ctl message to enable interrupt
on window size change. (used by ssh)

keep track of fullscreen scrolls, avoiding redrawing the whole
screen each time.
This commit is contained in:
cinap_lenrek 2017-08-20 19:22:30 +02:00
parent bc54898807
commit b28c3db578
6 changed files with 378 additions and 188 deletions

View file

@ -3,10 +3,17 @@ typedef struct Consstate Consstate;
struct Consstate{ struct Consstate{
int raw; int raw;
int hold; int hold;
int winch;
}; };
extern Consstate cs[];
extern Consstate* consctl(void); typedef struct Buf Buf;
extern Consstate* cs; struct Buf
{
int n;
char *s;
char b[];
};
#define INSET 2 #define INSET 2
#define BUFS 32 #define BUFS 32
@ -75,4 +82,4 @@ extern int cursoron;
extern int nocolor; extern int nocolor;
extern void setdim(int, int); extern void setdim(int, int);
extern void mountcons(void);

View file

@ -1,71 +0,0 @@
#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/consctl", MBEFORE) < 0
|| bind("/mnt/consctl/data1", "/dev/consctl", MREPL) < 0)
sysfatal("bind consctl: %r");
/* a pipe to simulate the /dev/cons */
if(bind("#|", "/mnt/cons", MREPL) < 0
|| bind("/mnt/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/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*/
}

213
sys/src/cmd/vt/fs.c Normal file
View file

@ -0,0 +1,213 @@
#include <u.h>
#include <libc.h>
#include <draw.h>
#include "cons.h"
#include <thread.h>
#include <fcall.h>
#include <9p.h>
extern Channel *hc[2];
static File *devcons, *devconsctl;
static Channel *readreq;
static Channel *flushreq;
static void
fsreader(void*)
{
Req *r, *fr;
Buf *b;
int n;
b = nil;
r = nil;
for(;;){
Alt a[] = {
{ flushreq, &fr, CHANRCV },
{ readreq, &r, r == nil ? CHANRCV : CHANNOP },
{ hc[0], &b, b == nil ? CHANRCV : CHANNOP },
{ nil, nil, b == nil || r == nil ? CHANEND : CHANNOBLK },
};
if(alt(a) == 0){
if(fr->oldreq == r){
respond(r, "interrupted");
r = nil;
}
respond(fr, nil);
}
if(b == nil || r == nil)
continue;
r->ofcall.count = 0;
while((n = r->ifcall.count - r->ofcall.count) > 0){
if(n > b->n)
n = b->n;
memmove((char*)r->ofcall.data + r->ofcall.count, b->s, n);
r->ofcall.count += n;
b->s += n, b->n -= n;
if(b->n <= 0){
free(b);
if((b = nbrecvp(hc[0])) == nil)
break;
}
}
respond(r, nil);
r = nil;
}
}
static void
fsread(Req *r)
{
if(r->fid->file == devcons){
sendp(readreq, r);
return;
}
respond(r, "not implemented");
}
typedef struct Partutf Partutf;
struct Partutf
{
int n;
char s[UTFmax];
};
static Rune*
cvtc2r(char *b, int n, Partutf *u)
{
char *cp, *ep;
Rune *rp, *rb;
cp = b, ep = b + n;
rp = rb = emalloc9p(sizeof(Rune)*(n+2));
while(u->n > 0 && cp < ep){
u->s[u->n++] = *cp++;
if(fullrune(u->s, u->n)){
chartorune(rp, u->s);
if(*rp != 0)
rp++;
u->n = 0;
break;
}
}
if(u->n == 0){
while(cp < ep && fullrune(cp, ep - cp)){
cp += chartorune(rp, cp);
if(*rp != 0)
rp++;
}
n = ep - cp;
if(n > 0){
memmove(u->s, cp, n);
u->n = n;
}
}
if(rb == rp){
free(rb);
return nil;
}
*rp = 0;
return rb;
}
static void
fswrite(Req *r)
{
if(r->fid->file == devcons){
Partutf *u;
Rune *rp;
if((u = r->fid->aux) == nil)
u = r->fid->aux = emalloc9p(sizeof(*u));
if((rp = cvtc2r((char*)r->ifcall.data, r->ifcall.count, u)) != nil)
sendp(hc[1], rp);
r->ofcall.count = r->ifcall.count;
respond(r, nil);
return;
}
if(r->fid->file == devconsctl){
char *s = r->ifcall.data;
int n = r->ifcall.count;
if(n >= 5 && strncmp(s, "rawon", 5) == 0)
cs->raw = 1;
else if(n >= 6 && strncmp(s, "rawoff", 6) == 0)
cs->raw = 0;
else if(n >= 6 && strncmp(s, "holdon", 6) == 0)
cs->hold = 1;
else if(n >= 7 && strncmp(s, "holdoff", 7) == 0)
cs->hold = 0;
else if(n >= 7 && strncmp(s, "winchon", 7) == 0)
cs->winch = 1;
else if(n >= 8 && strncmp(s, "winchoff", 8) == 0)
cs->winch = 0;
r->ofcall.count = r->ifcall.count;
respond(r, nil);
return;
}
respond(r, "not implemented");
}
static void
fsflush(Req *r)
{
sendp(flushreq, r);
}
static void
fsdestroyfid(Fid *f)
{
if(f->file == devconsctl && f->omode >= 0){
cs->raw = 0;
cs->hold = 0;
cs->winch = 0;
}
if(f->aux != nil){
free(f->aux);
f->aux = nil;
}
}
static void
fsstart(Srv*)
{
flushreq = chancreate(sizeof(Req*), 4);
readreq = chancreate(sizeof(Req*), 4);
proccreate(fsreader, nil, 16*1024);
}
static void
fsend(Srv*)
{
sendp(hc[1], nil);
}
Srv fs = {
.read=fsread,
.write=fswrite,
.flush=fsflush,
.destroyfid=fsdestroyfid,
.start=fsstart,
.end=fsend,
};
void
mountcons(void)
{
fs.tree = alloctree("vt", "vt", DMDIR|0555, nil);
devcons = createfile(fs.tree->root, "cons", "vt", 0666, nil);
if(devcons == nil)
sysfatal("creating /dev/cons: %r");
devconsctl = createfile(fs.tree->root, "consctl", "vt", 0666, nil);
if(devconsctl == nil)
sysfatal("creating /dev/consctl: %r");
threadpostmountsrv(&fs, nil, "/dev", MBEFORE);
}

View file

@ -1,11 +1,16 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include "cons.h"
#include <thread.h> #include <thread.h>
#include <fcall.h>
#include <9p.h>
#include <bio.h>
#include <mouse.h> #include <mouse.h>
#include <keyboard.h> #include <keyboard.h>
#include <bio.h>
#include "cons.h"
char *menutext2[] = { char *menutext2[] = {
"backup", "backup",
@ -40,6 +45,7 @@ int pagemode;
int olines; int olines;
int peekc; int peekc;
int cursoron = 1; int cursoron = 1;
int hostclosed = 0;
Menu menu2; Menu menu2;
Menu menu3; Menu menu3;
Rune *histp; Rune *histp;
@ -52,9 +58,15 @@ uchar *onscreencbuf;
#define onscreena(x, y) &onscreenabuf[((y)*(xmax+2) + (x))] #define onscreena(x, y) &onscreenabuf[((y)*(xmax+2) + (x))]
#define onscreenc(x, y) &onscreencbuf[((y)*(xmax+2) + (x))] #define onscreenc(x, y) &onscreencbuf[((y)*(xmax+2) + (x))]
uchar *screenchangebuf;
uint scrolloff;
#define screenchange(y) screenchangebuf[((y)+scrolloff) % (ymax+1)]
int yscrmin, yscrmax; int yscrmin, yscrmax;
int attr, defattr; int attr, defattr;
Image *cursorsave;
Image *bordercol; Image *bordercol;
Image *colors[8]; Image *colors[8];
Image *hicolors[8]; Image *hicolors[8];
@ -100,13 +112,12 @@ Rune kbdchar;
Mousectl *mc; Mousectl *mc;
Keyboardctl *kc; Keyboardctl *kc;
Channel *hc; Channel *hc[2];
Consstate *cs; Consstate cs[1];
int nocolor; int nocolor;
int logfd = -1; int logfd = -1;
int hostfd = -1; int hostpid = -1;
int hostpid;
Biobuf *snarffp = 0; Biobuf *snarffp = 0;
Rune *hostbuf, *hostbufp; Rune *hostbuf, *hostbufp;
char echo_input[BSIZE]; char echo_input[BSIZE];
@ -118,7 +129,6 @@ char *term;
struct funckey *fk, *appfk; struct funckey *fk, *appfk;
/* functions */ /* functions */
void initialize(int, char **);
int waitchar(void); int waitchar(void);
void waitio(void); void waitio(void);
int rcvchar(void); int rcvchar(void);
@ -130,78 +140,62 @@ void send_interrupt(void);
int alnum(int); int alnum(int);
void escapedump(int,uchar *,int); void escapedump(int,uchar *,int);
int static Channel *pidchan;
start_host(void)
static void
runcmd(void *args)
{ {
switch((hostpid = rfork(RFPROC|RFNAMEG|RFFDG|RFNOTEG))) { char **argv = args;
case 0: char *cmd;
close(0);
open("/dev/cons", OREAD); rfork(RFNAMEG);
close(1); mountcons();
open("/dev/cons", OWRITE);
dup(1, 2); rfork(RFFDG);
execl("/bin/rc","rcX",nil); close(0);
fprint(2, "failed to start up rc: %r\n"); open("/dev/cons", OREAD);
_exits("rc"); close(1);
case -1: open("/dev/cons", OWRITE);
fprint(2,"rc startup: fork: %r\n"); dup(1, 2);
_exits("rc_fork");
cmd = nil;
while(*argv != nil){
if(cmd == nil)
cmd = strdup(*argv);
else
cmd = smprint("%s %q", cmd, *argv);
argv++;
} }
return open("/mnt/cons/data", ORDWR);
procexecl(pidchan, "/bin/rc", "rcX", cmd == nil ? nil : "-c", cmd, nil);
sysfatal("%r");
} }
void void
send_interrupt(void) send_interrupt(void)
{ {
postnote(PNGROUP, hostpid, "interrupt"); if(hostpid > 0)
postnote(PNGROUP, hostpid, "interrupt");
} }
void void
hostreader(void*) sendnchars(int n, char *p)
{ {
char cb[BSIZE+1], *cp; Buf *b;
Rune *rb, *rp;
int n, r;
n = 0; b = emalloc9p(sizeof(Buf)+n);
while((r = read(hostfd, cb+n, BSIZE-n)) > 0){ memmove(b->s = b->b, p, b->n = n);
n += r; if(nbsendp(hc[0], b) < 0)
rb = mallocz((n+1)*sizeof(Rune), 0); free(b);
for(rp = rb, cp = cb; n > 0; n -= r, cp += r){
if(!fullrune(cp, n))
break;
r = chartorune(rp, cp);
if(*rp != 0)
rp++;
}
if(rp > rb){
*rp = 0;
sendp(hc, rb);
} else {
free(rb);
}
if(n > 0) memmove(cb, cp, n);
}
sendp(hc, nil);
} }
static void static void
shutdown(void) shutdown(void)
{ {
send_interrupt(); send_interrupt();
postnote(PNGROUP, getpid(), "exit");
threadexitsall(nil); threadexitsall(nil);
} }
void
threadmain(int argc, char **argv)
{
rfork(RFNAMEG|RFNOTEG|RFENVG);
atexit(shutdown);
initialize(argc, argv);
emulate();
}
void void
usage(void) usage(void)
{ {
@ -210,7 +204,7 @@ usage(void)
} }
void void
initialize(int argc, char **argv) threadmain(int argc, char **argv)
{ {
int rflag; int rflag;
int i, blkbg; int i, blkbg;
@ -257,14 +251,19 @@ initialize(int argc, char **argv)
break; break;
}ARGEND; }ARGEND;
quotefmtinstall();
atexit(shutdown);
if(initdraw(0, fontname, term) < 0) if(initdraw(0, fontname, term) < 0)
sysfatal("inidraw failed: %r"); sysfatal("inidraw failed: %r");
if((mc = initmouse("/dev/mouse", screen)) == nil) if((mc = initmouse("/dev/mouse", screen)) == nil)
sysfatal("initmouse failed: %r"); sysfatal("initmouse failed: %r");
if((kc = initkeyboard("/dev/cons")) == nil) if((kc = initkeyboard("/dev/cons")) == nil)
sysfatal("initkeyboard failed: %r"); sysfatal("initkeyboard failed: %r");
if((cs = consctl()) == nil)
sysfatal("consctl failed: %r"); hc[0] = chancreate(sizeof(Buf*), 8); /* input to host */
hc[1] = chancreate(sizeof(Rune*), 8); /* output from host */
cs->raw = rflag; cs->raw = rflag;
histp = hist; histp = hist;
@ -290,19 +289,11 @@ initialize(int argc, char **argv)
fgcolor = (blkbg? display->white: display->black); fgcolor = (blkbg? display->white: display->black);
resize(); resize();
hc = chancreate(sizeof(Rune*), 5); pidchan = chancreate(sizeof(int), 0);
if((hostfd = start_host()) >= 0) proccreate(runcmd, argv, 16*1024);
proccreate(hostreader, nil, BSIZE+1024); hostpid = recvul(pidchan);
while(*argv != nil){ emulate();
sendnchars(strlen(*argv), *argv);
if(argv[1] == nil){
sendnchars(1, "\n");
break;
}
sendnchars(1, " ");
argv++;
}
} }
Image* Image*
@ -333,6 +324,16 @@ fgcol(int a, int c)
return colors[(c>>1)&7]; return colors[(c>>1)&7];
} }
void
hidecursor(void)
{
if(cursorsave == nil)
return;
draw(screen, cursorsave->r, cursorsave, nil, cursorsave->r.min);
freeimage(cursorsave);
cursorsave = nil;
}
void void
drawscreen(void) drawscreen(void)
{ {
@ -342,26 +343,28 @@ drawscreen(void)
Rune *rp; Rune *rp;
Point p, q; Point p, q;
draw(screen, screen->r, bgcolor, nil, ZP); hidecursor();
if(scrolloff != 0){
n = scrolloff % (ymax+1);
draw(screen, Rpt(pt(0,0), pt(xmax+2, ymax+1-n)), screen, nil, pt(0, n));
}
/* draw background */
for(y = 0; y <= ymax; y++){ for(y = 0; y <= ymax; y++){
if(!screenchange(y))
continue;
screenchange(y) = 0;
for(x = 0; x <= xmax; x += n){ for(x = 0; x <= xmax; x += n){
cp = onscreenc(x, y); cp = onscreenc(x, y);
ap = onscreena(x, y); ap = onscreena(x, y);
c = bgcol(*ap, *cp); c = bgcol(*ap, *cp);
if(c == bgcolor){
n = 1;
continue;
}
for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n]) == c; n++) for(n = 1; x+n <= xmax && bgcol(ap[n], cp[n]) == c; n++)
; ;
draw(screen, Rpt(pt(x, y), pt(x+n, y+1)), c, nil, ZP); draw(screen, Rpt(pt(x, y), pt(x+n, y+1)), c, nil, ZP);
} }
} draw(screen, Rpt(pt(x, y), pt(x+1, y+1)), bgcolor, nil, ZP);
/* draw foreground */
for(y = 0; y <= ymax; y++){
for(x = 0; x <= xmax; x += n){ for(x = 0; x <= xmax; x += n){
rp = onscreenr(x, y); rp = onscreenr(x, y);
if(*rp == 0){ if(*rp == 0){
@ -387,25 +390,40 @@ drawscreen(void)
bordercol, bordercol,
ZP, font, L">", 1); ZP, font, L">", 1);
} }
scrolloff = 0;
} }
void void
drawcursor(void) drawcursor(void)
{ {
Image *col; Image *col;
Rectangle r;
hidecursor();
if(cursoron == 0) if(cursoron == 0)
return; return;
col = (blocked || hostfd < 0) ? red : bordercol;
border(screen, Rpt(pt(x, y), pt(x+1, y+1)), 2, col, ZP); col = (blocked || hostclosed) ? red : bordercol;
r = Rpt(pt(x, y), pt(x+1, y+1));
cursorsave = allocimage(display, r, screen->chan, 0, DNofill);
draw(cursorsave, r, screen, nil, r.min);
border(screen, r, 2, col, ZP);
} }
void void
clear(int x1, int y1, int x2, int y2) clear(int x1, int y1, int x2, int y2)
{ {
int c = (attr & 0x0F00)>>8; /* bgcolor */ int c = (attr & 0x0F00)>>8; /* bgcolor */
if(y1 < 0 || y1 > ymax || x1 < 0 || x1 > xmax || y2 <= y1 || x2 <= x1)
return;
while(y1 < y2){ while(y1 < y2){
screenchange(y1) = 1;
if(x1 < x2){ if(x1 < x2){
memset(onscreenr(x1, y1), 0, (x2-x1)*sizeof(Rune)); memset(onscreenr(x1, y1), 0, (x2-x1)*sizeof(Rune));
memset(onscreena(x1, y1), 0, x2-x1); memset(onscreena(x1, y1), 0, x2-x1);
@ -713,8 +731,8 @@ waitchar(void)
if(host_avail()) if(host_avail())
return(rcvchar()); return(rcvchar());
free(hostbuf); free(hostbuf);
hostbufp = hostbuf = nbrecvp(hc); hostbufp = hostbuf = nbrecvp(hc[1]);
if(host_avail() && nrand(8)) if(host_avail() && nrand(32))
return(rcvchar()); return(rcvchar());
} }
drawscreen(); drawscreen();
@ -731,7 +749,7 @@ waitio(void)
{ mc->c, &mc->Mouse, CHANRCV }, { mc->c, &mc->Mouse, CHANRCV },
{ mc->resizec, nil, CHANRCV }, { mc->resizec, nil, CHANRCV },
{ kc->c, &kbdchar, CHANRCV }, { kc->c, &kbdchar, CHANRCV },
{ hc, &hostbuf, CHANRCV }, { hc[1], &hostbuf, CHANRCV },
{ nil, nil, CHANEND }, { nil, nil, CHANEND },
}; };
if(blocked) if(blocked)
@ -755,10 +773,8 @@ Next:
break; break;
case AHOST: case AHOST:
hostbufp = hostbuf; hostbufp = hostbuf;
if(hostbuf == nil){ if(hostbuf == nil)
close(hostfd); hostclosed = 1;
hostfd = -1;
}
break; break;
} }
} }
@ -780,6 +796,8 @@ exportsize(void)
putenvint("LINES", ymax+1); putenvint("LINES", ymax+1);
putenvint("COLS", xmax+1); putenvint("COLS", xmax+1);
putenv("TERM", term); putenv("TERM", term);
if(cs->winch)
send_interrupt();
} }
void void
@ -799,14 +817,20 @@ setdim(int ht, int wid)
margin.x = (Dx(screen->r) - (xmax+1)*ftsize.x) / 2; margin.x = (Dx(screen->r) - (xmax+1)*ftsize.x) / 2;
margin.y = (Dy(screen->r) - (ymax+1)*ftsize.y) / 2; margin.y = (Dy(screen->r) - (ymax+1)*ftsize.y) / 2;
free(screenchangebuf);
screenchangebuf = emalloc9p(ymax+1);
scrolloff = 0;
free(onscreenrbuf); free(onscreenrbuf);
onscreenrbuf = mallocz((ymax+1)*(xmax+2)*sizeof(Rune), 1); onscreenrbuf = emalloc9p((ymax+1)*(xmax+2)*sizeof(Rune));
free(onscreenabuf); free(onscreenabuf);
onscreenabuf = mallocz((ymax+1)*(xmax+2), 1); onscreenabuf = emalloc9p((ymax+1)*(xmax+2));
free(onscreencbuf); free(onscreencbuf);
onscreencbuf = mallocz((ymax+1)*(xmax+2), 1); onscreencbuf = emalloc9p((ymax+1)*(xmax+2));
clear(0,0,xmax+1,ymax+1); clear(0,0,xmax+1,ymax+1);
draw(screen, screen->r, bgcolor, nil, ZP);
if(resize_flag || backc) if(resize_flag || backc)
return; return;
@ -1052,10 +1076,15 @@ pos(Point pt)
void void
shift(int x1, int y, int x2, int w) shift(int x1, int y, int x2, int w)
{ {
if(y < 0 || y > ymax || x1 < 0 || x2 < 0 || w <= 0)
return;
if(x1+w > xmax+1) if(x1+w > xmax+1)
w = xmax+1 - x1; w = xmax+1 - x1;
if(x2+w > xmax+1) if(x2+w > xmax+1)
w = xmax+1 - x2; w = xmax+1 - x2;
screenchange(y) = 1;
memmove(onscreenr(x1, y), onscreenr(x2, y), w*sizeof(Rune)); memmove(onscreenr(x1, y), onscreenr(x2, y), w*sizeof(Rune));
memmove(onscreena(x1, y), onscreena(x2, y), w); memmove(onscreena(x1, y), onscreena(x2, y), w);
memmove(onscreenc(x1, y), onscreenc(x2, y), w); memmove(onscreenc(x1, y), onscreenc(x2, y), w);
@ -1064,9 +1093,30 @@ shift(int x1, int y, int x2, int w)
void void
scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */ scroll(int sy, int ly, int dy, int cy) /* source, limit, dest, which line to clear */
{ {
memmove(onscreenr(0, dy), onscreenr(0, sy), (ly-sy)*(xmax+2)*sizeof(Rune)); int n, d, i;
memmove(onscreena(0, dy), onscreena(0, sy), (ly-sy)*(xmax+2));
memmove(onscreenc(0, dy), onscreenc(0, sy), (ly-sy)*(xmax+2)); if(sy < 0 || sy > ymax || dy < 0 || dy > ymax)
return;
n = ly - sy;
if(sy + n > ymax+1)
n = ymax+1 - sy;
if(dy + n > ymax+1)
n = ymax+1 - dy;
d = sy - dy;
if(n > 0 && d != 0){
if(d > 0 && dy == 0 && n >= ymax){
scrolloff += d;
} else {
for(i = 0; i < n; i++)
screenchange(dy+i) = 1;
}
memmove(onscreenr(0, dy), onscreenr(0, sy), n*(xmax+2)*sizeof(Rune));
memmove(onscreena(0, dy), onscreena(0, sy), n*(xmax+2));
memmove(onscreenc(0, dy), onscreenc(0, sy), n*(xmax+2));
}
clear(0, cy, xmax+1, cy+1); clear(0, cy, xmax+1, cy+1);
} }
@ -1079,13 +1129,13 @@ bigscroll(void) /* scroll up half a page */
return; return;
if(y < half) { if(y < half) {
clear(0, 0, xmax+1, ymax+1); clear(0, 0, xmax+1, ymax+1);
scrolloff = 0;
x = y = 0; x = y = 0;
return; return;
} }
memmove(onscreenr(0, 0), onscreenr(0, half), (ymax-half+1)*(xmax+2)*sizeof(Rune)); scroll(half, ymax+1, 0, ymax);
memmove(onscreena(0, 0), onscreena(0, half), (ymax-half+1)*(xmax+2));
memmove(onscreenc(0, 0), onscreenc(0, half), (ymax-half+1)*(xmax+2));
clear(0, y-half+1, xmax+1, ymax+1); clear(0, y-half+1, xmax+1, ymax+1);
y -= half; y -= half;
if(olines) if(olines)
olines -= half; olines -= half;
@ -1109,17 +1159,6 @@ number(Rune *p, int *got)
/* stubs */ /* stubs */
void
sendnchars(int n,char *p)
{
if(hostfd < 0)
return;
if(write(hostfd,p,n) < 0){
close(hostfd);
hostfd = -1;
}
}
int int
host_avail(void) host_avail(void)
{ {
@ -1179,6 +1218,7 @@ escapedump(int fd,uchar *str,int len)
void void
drawstring(Rune *str, int n) drawstring(Rune *str, int n)
{ {
screenchange(y) = 1;
memmove(onscreenr(x, y), str, n*sizeof(Rune)); memmove(onscreenr(x, y), str, n*sizeof(Rune));
memset(onscreena(x, y), attr & 0xFF, n); memset(onscreena(x, y), attr & 0xFF, n);
memset(onscreenc(x, y), attr >> 8, n); memset(onscreenc(x, y), attr >> 8, n);

View file

@ -3,9 +3,9 @@
TARG=vt TARG=vt
OFILES=\ OFILES=\
consctl.$O\
main.$O\ main.$O\
vt.$O\ vt.$O\
fs.$O\
HFILES=cons.h HFILES=cons.h

View file

@ -23,10 +23,11 @@
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <draw.h> #include <draw.h>
#include <bio.h>
#include <ctype.h>
#include "cons.h" #include "cons.h"
#include <ctype.h>
int wraparound = 1; int wraparound = 1;
int originrelative = 0; int originrelative = 0;