Today's changes.
More changes.
This commit is contained in:
parent
cb27443abf
commit
8ad517944e
73 changed files with 2865 additions and 1293 deletions
|
|
@ -1,15 +1,24 @@
|
|||
#include "9term.h"
|
||||
|
||||
#define fatal sysfatal
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <draw.h>
|
||||
#include <thread.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include <plumb.h>
|
||||
#include <complete.h>
|
||||
#include "term.h"
|
||||
|
||||
typedef struct Text Text;
|
||||
typedef struct Readbuf Readbuf;
|
||||
|
||||
enum
|
||||
{
|
||||
/* these are chosen to use malloc()'s properties well */
|
||||
HiWater = 640000, /* max size of history */
|
||||
LoWater = 330000, /* min size of history after max'ed */
|
||||
LoWater = 400000, /* min size of history after max'ed */
|
||||
MinWater = 20000,
|
||||
};
|
||||
|
||||
/* various geometric paramters */
|
||||
|
|
@ -30,21 +39,22 @@ enum
|
|||
Scroll,
|
||||
};
|
||||
|
||||
|
||||
#define SCROLLKEY Kdown
|
||||
#define ESC 0x1B
|
||||
#define CUT 0x18 /* ctrl-x */
|
||||
#define COPY 0x03 /* crtl-c */
|
||||
#define PASTE 0x16 /* crtl-v */
|
||||
#define BACKSCROLLKEY Kup
|
||||
#define CUT 0x18 /* ctrl-x */
|
||||
#define COPY 0x03 /* crtl-c */
|
||||
#define PASTE 0x16 /* crtl-v */
|
||||
|
||||
#define READBUFSIZE 8192
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
|
||||
struct Text
|
||||
{
|
||||
Frame *f; /* frame ofr terminal */
|
||||
Mouse m;
|
||||
uint nr; /* num of runes in term */
|
||||
uint maxr; /* max num of runes in r */
|
||||
Rune *r; /* runes for term */
|
||||
uint nraw; /* num of runes in raw buffer */
|
||||
Rune *raw; /* raw buffer */
|
||||
|
|
@ -72,7 +82,6 @@ void fill(void);
|
|||
void tcheck(void);
|
||||
void updatesel(void);
|
||||
void doreshape(void);
|
||||
void rcstart(int fd[2], int, char**);
|
||||
void runewrite(Rune*, int);
|
||||
void consread(void);
|
||||
void conswrite(char*, int);
|
||||
|
|
@ -99,11 +108,10 @@ void scrdraw(void);
|
|||
void scroll(int);
|
||||
void hostproc(void *arg);
|
||||
void hoststart(void);
|
||||
int getchildwd(int, char*, int);
|
||||
void plumbstart(void);
|
||||
void plumb(uint, uint);
|
||||
void plumbclick(uint*, uint*);
|
||||
int getpts(int fd[], char *slave);
|
||||
uint insert(Rune*, int, uint, int);
|
||||
|
||||
#define runemalloc(n) malloc((n)*sizeof(Rune))
|
||||
#define runerealloc(a, n) realloc(a, (n)*sizeof(Rune))
|
||||
|
|
@ -115,7 +123,7 @@ int rawon; /* raw mode */
|
|||
int scrolling; /* window scrolls */
|
||||
int clickmsec; /* time of last click */
|
||||
uint clickq0; /* point of last click */
|
||||
int rcfd[2];
|
||||
int rcfd;
|
||||
int rcpid;
|
||||
int maxtab;
|
||||
int use9wm;
|
||||
|
|
@ -211,7 +219,7 @@ threadmain(int argc, char *argv[])
|
|||
|
||||
mc = initmouse(nil, screen);
|
||||
kc = initkeyboard(nil);
|
||||
rcstart(rcfd, argc, argv);
|
||||
rcpid = rcstart(argc, argv, &rcfd);
|
||||
hoststart();
|
||||
plumbstart();
|
||||
|
||||
|
|
@ -265,8 +273,9 @@ hostproc(void *arg)
|
|||
|
||||
i = 0;
|
||||
for(;;){
|
||||
/* Let typing have a go -- maybe there's a rubout waiting. */
|
||||
i = 1-i; /* toggle */
|
||||
n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
|
||||
n = threadread(rcfd, rcbuf[i].data, sizeof rcbuf[i].data);
|
||||
if(n <= 0){
|
||||
if(n < 0)
|
||||
fprint(2, "9term: host read error: %r\n");
|
||||
|
|
@ -308,7 +317,7 @@ loop(void)
|
|||
a[2].op = CHANNOP;;
|
||||
switch(alt(a)) {
|
||||
default:
|
||||
fatal("impossible");
|
||||
sysfatal("impossible");
|
||||
case 0:
|
||||
t.m = mc->m;
|
||||
mouse();
|
||||
|
|
@ -330,23 +339,23 @@ void
|
|||
doreshape(void)
|
||||
{
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
fatal("can't reattach to window");
|
||||
sysfatal("can't reattach to window");
|
||||
draw(screen, screen->r, cols[BACK], nil, ZP);
|
||||
geom();
|
||||
scrdraw();
|
||||
}
|
||||
|
||||
struct winsize ows;
|
||||
|
||||
void
|
||||
geom(void)
|
||||
{
|
||||
struct winsize ws;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
|
||||
r = screen->r;
|
||||
scrollr = screen->r;
|
||||
r.min.y++;
|
||||
r.max.y--;
|
||||
|
||||
scrollr = r;
|
||||
scrollr.max.x = r.min.x+Scrollwid;
|
||||
lastsr = Rect(0,0,0,0);
|
||||
|
||||
|
|
@ -362,13 +371,7 @@ geom(void)
|
|||
if(p.x == 0 || p.y == 0)
|
||||
return;
|
||||
|
||||
ws.ws_row = Dy(r)/p.y;
|
||||
ws.ws_col = Dx(r)/p.x;
|
||||
ws.ws_xpixel = Dx(r);
|
||||
ws.ws_ypixel = Dy(r);
|
||||
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
|
||||
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
|
||||
fprint(2, "ioctl: %r\n");
|
||||
updatewinsize(Dy(r)/p.y, Dx(r)/p.x, Dx(r), Dy(r));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -585,7 +588,10 @@ domenu2(int but)
|
|||
show(t.q0);
|
||||
break;
|
||||
case Send:
|
||||
snarf();
|
||||
if(t.q0 != t.q1)
|
||||
snarf();
|
||||
else
|
||||
snarfupdate();
|
||||
t.q0 = t.q1 = t.nr;
|
||||
updatesel();
|
||||
paste(t.snarf, t.nsnarf, 1);
|
||||
|
|
@ -605,37 +611,182 @@ domenu2(int but)
|
|||
plumb(t.q0, t.q1);
|
||||
break;
|
||||
default:
|
||||
fatal("bad menu item");
|
||||
sysfatal("bad menu item");
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
windfilewidth(uint q0, int oneelement)
|
||||
{
|
||||
uint q;
|
||||
Rune r;
|
||||
|
||||
q = q0;
|
||||
while(q > 0){
|
||||
r = t.r[q-1];
|
||||
if(r<=' ')
|
||||
break;
|
||||
if(oneelement && r=='/')
|
||||
break;
|
||||
--q;
|
||||
}
|
||||
return q0-q;
|
||||
}
|
||||
|
||||
void
|
||||
showcandidates(Completion *c)
|
||||
{
|
||||
int i;
|
||||
Fmt f;
|
||||
Rune *rp;
|
||||
uint nr, qline, q0;
|
||||
char *s;
|
||||
|
||||
runefmtstrinit(&f);
|
||||
if (c->nmatch == 0)
|
||||
s = "[no matches in ";
|
||||
else
|
||||
s = "[";
|
||||
if(c->nfile > 32)
|
||||
fmtprint(&f, "%s%d files]\n", s, c->nfile);
|
||||
else{
|
||||
fmtprint(&f, "%s", s);
|
||||
for(i=0; i<c->nfile; i++){
|
||||
if(i > 0)
|
||||
fmtprint(&f, " ");
|
||||
fmtprint(&f, "%s", c->filename[i]);
|
||||
}
|
||||
fmtprint(&f, "]\n");
|
||||
}
|
||||
/* place text at beginning of line before host point */
|
||||
qline = t.qh;
|
||||
while(qline>0 && t.r[qline-1] != '\n')
|
||||
qline--;
|
||||
|
||||
rp = runefmtstrflush(&f);
|
||||
nr = runestrlen(rp);
|
||||
|
||||
q0 = t.q0;
|
||||
q0 += insert(rp, nr, qline, 0) - qline;
|
||||
free(rp);
|
||||
t.q0 = q0+nr;
|
||||
t.q1 = q0+nr;
|
||||
updatesel();
|
||||
}
|
||||
|
||||
Rune*
|
||||
namecomplete(void)
|
||||
{
|
||||
int nstr, npath;
|
||||
Rune *rp, *path, *str;
|
||||
Completion *c;
|
||||
char *s, *dir, *root;
|
||||
|
||||
/* control-f: filename completion; works back to white space or / */
|
||||
if(t.q0<t.nr && t.r[t.q0]>' ') /* must be at end of word */
|
||||
return nil;
|
||||
nstr = windfilewidth(t.q0, TRUE);
|
||||
str = runemalloc(nstr);
|
||||
runemove(str, t.r+(t.q0-nstr), nstr);
|
||||
npath = windfilewidth(t.q0-nstr, FALSE);
|
||||
path = runemalloc(npath);
|
||||
runemove(path, t.r+(t.q0-nstr-npath), npath);
|
||||
rp = nil;
|
||||
|
||||
/* is path rooted? if not, we need to make it relative to window path */
|
||||
if(npath>0 && path[0]=='/'){
|
||||
dir = malloc(UTFmax*npath+1);
|
||||
sprint(dir, "%.*S", npath, path);
|
||||
}else{
|
||||
if(strcmp(wdir, "") == 0)
|
||||
root = ".";
|
||||
else
|
||||
root = wdir;
|
||||
dir = malloc(strlen(root)+1+UTFmax*npath+1);
|
||||
sprint(dir, "%s/%.*S", root, npath, path);
|
||||
}
|
||||
dir = cleanname(dir);
|
||||
|
||||
s = smprint("%.*S", nstr, str);
|
||||
c = complete(dir, s);
|
||||
free(s);
|
||||
if(c == nil)
|
||||
goto Return;
|
||||
|
||||
if(!c->advance)
|
||||
showcandidates(c);
|
||||
|
||||
if(c->advance)
|
||||
rp = runesmprint("%s", c->string);
|
||||
|
||||
Return:
|
||||
freecompletion(c);
|
||||
free(dir);
|
||||
free(path);
|
||||
free(str);
|
||||
return rp;
|
||||
}
|
||||
|
||||
void
|
||||
key(Rune r)
|
||||
{
|
||||
uint sig;
|
||||
Rune *rp;
|
||||
int nr;
|
||||
|
||||
if(r == 0)
|
||||
return;
|
||||
if(r==SCROLLKEY){ /* scroll key */
|
||||
switch(r){
|
||||
case Kpgup:
|
||||
setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
|
||||
return;
|
||||
case Kpgdown:
|
||||
setorigin(line2q(t.f->maxlines*2/3), 1);
|
||||
if(t.qh<=t.org+t.f->nchars)
|
||||
consread();
|
||||
return;
|
||||
}else if(r == BACKSCROLLKEY){
|
||||
setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
|
||||
case Kup:
|
||||
setorigin(backnl(t.org, t.f->maxlines/3), 1);
|
||||
return;
|
||||
}else if(r == CUT){
|
||||
case Kdown:
|
||||
setorigin(line2q(t.f->maxlines/3), 1);
|
||||
if(t.qh<=t.org+t.f->nchars)
|
||||
consread();
|
||||
return;
|
||||
case Kleft:
|
||||
if(t.q0 > 0){
|
||||
t.q0--;
|
||||
t.q1 = t.q0;
|
||||
updatesel();
|
||||
show(t.q0);
|
||||
}
|
||||
return;
|
||||
case Kright:
|
||||
if(t.q1 < t.nr){
|
||||
t.q1++;
|
||||
t.q0 = t.q1;
|
||||
updatesel();
|
||||
show(t.q1);
|
||||
}
|
||||
return;
|
||||
case Khome:
|
||||
show(0);
|
||||
return;
|
||||
case Kend:
|
||||
case 0x05:
|
||||
show(t.nr);
|
||||
return;
|
||||
case CUT:
|
||||
snarf();
|
||||
cut();
|
||||
if(scrolling)
|
||||
show(t.q0);
|
||||
return;
|
||||
}else if(r == COPY){
|
||||
case COPY:
|
||||
snarf();
|
||||
if(scrolling)
|
||||
show(t.q0);
|
||||
return;
|
||||
}else if(r == PASTE){
|
||||
case PASTE:
|
||||
snarfupdate();
|
||||
paste(t.snarf, t.nsnarf, 0);
|
||||
if(scrolling)
|
||||
|
|
@ -661,19 +812,21 @@ key(Rune r)
|
|||
snarf();
|
||||
|
||||
switch(r) {
|
||||
case 0x03: /* ^C: send interrupt */
|
||||
case 0x7F: /* DEL: send interrupt */
|
||||
t.qh = t.q0 = t.q1 = t.nr;
|
||||
show(t.q0);
|
||||
goto Default;
|
||||
fprint(2, "send interrupt to %d group\n", rcpid);
|
||||
#ifdef TIOCSIG
|
||||
sig = 2; /* SIGINT */
|
||||
if(ioctl(rcfd[0], TIOCSIG, &sig) < 0)
|
||||
fprint(2, "sending interrupt: %r\n");
|
||||
#else
|
||||
postnote(PNGROUP, rcpid, "interrupt");
|
||||
#endif
|
||||
write(rcfd, "\x7F", 1);
|
||||
break;
|
||||
case 0x06: /* ^F: file name completion */
|
||||
case Kins: /* Insert: file name completion */
|
||||
rp = namecomplete();
|
||||
if(rp == nil)
|
||||
return;
|
||||
nr = runestrlen(rp);
|
||||
paste(rp, nr, 1);
|
||||
free(rp);
|
||||
return;
|
||||
case 0x08: /* ^H: erase character */
|
||||
case 0x15: /* ^U: erase line */
|
||||
case 0x17: /* ^W: erase word */
|
||||
|
|
@ -682,7 +835,6 @@ fprint(2, "send interrupt to %d group\n", rcpid);
|
|||
cut();
|
||||
break;
|
||||
default:
|
||||
Default:
|
||||
paste(&r, 1, 1);
|
||||
break;
|
||||
}
|
||||
|
|
@ -773,7 +925,7 @@ consread(void)
|
|||
}
|
||||
/* take out control-d when not doing a zero length write */
|
||||
n = p-buf;
|
||||
if(write(rcfd[1], buf, n) < 0)
|
||||
if(write(rcfd, buf, n) < 0)
|
||||
exits(0);
|
||||
/* mallocstats(); */
|
||||
}
|
||||
|
|
@ -833,7 +985,6 @@ conswrite(char *p, int n)
|
|||
void
|
||||
runewrite(Rune *r, int n)
|
||||
{
|
||||
uint m;
|
||||
int i;
|
||||
uint initial;
|
||||
uint q0, q1;
|
||||
|
|
@ -896,37 +1047,7 @@ runewrite(Rune *r, int n)
|
|||
updatesel();
|
||||
}
|
||||
|
||||
if(t.nr>HiWater && t.qh>=t.org){
|
||||
m = HiWater-LoWater;
|
||||
if(m > t.org);
|
||||
m = t.org;
|
||||
t.org -= m;
|
||||
t.qh -= m;
|
||||
if(t.q0 > m)
|
||||
t.q0 -= m;
|
||||
else
|
||||
t.q0 = 0;
|
||||
if(t.q1 > m)
|
||||
t.q1 -= m;
|
||||
else
|
||||
t.q1 = 0;
|
||||
t.nr -= m;
|
||||
runemove(t.r, t.r+m, t.nr);
|
||||
}
|
||||
t.r = runerealloc(t.r, t.nr+n);
|
||||
runemove(t.r+t.qh+n, t.r+t.qh, t.nr-t.qh);
|
||||
runemove(t.r+t.qh, r, n);
|
||||
t.nr += n;
|
||||
if(t.qh < t.org)
|
||||
t.org += n;
|
||||
else if(t.qh <= t.f->nchars+t.org)
|
||||
frinsert(t.f, r, r+n, t.qh-t.org);
|
||||
if (t.qh <= t.q0)
|
||||
t.q0 += n;
|
||||
if (t.qh <= t.q1)
|
||||
t.q1 += n;
|
||||
t.qh += n;
|
||||
updatesel();
|
||||
insert(r, n, t.qh, 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1009,12 +1130,83 @@ snarf(void)
|
|||
putsnarf(sbuf);
|
||||
}
|
||||
|
||||
uint
|
||||
min(uint x, uint y)
|
||||
{
|
||||
if(x < y)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint
|
||||
max(uint x, uint y)
|
||||
{
|
||||
if(x > y)
|
||||
return x;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint
|
||||
insert(Rune *r, int n, uint q0, int hostwrite)
|
||||
{
|
||||
uint m;
|
||||
|
||||
if(n == 0)
|
||||
return q0;
|
||||
if(t.nr+n>HiWater && q0>=t.org && q0>=t.qh){
|
||||
m = min(HiWater-LoWater, min(t.org, t.qh));
|
||||
t.org -= m;
|
||||
t.qh -= m;
|
||||
if(t.q0 > m)
|
||||
t.q0 -= m;
|
||||
else
|
||||
t.q0 = 0;
|
||||
if(t.q1 > m)
|
||||
t.q1 -= m;
|
||||
else
|
||||
t.q1 = 0;
|
||||
t.nr -= m;
|
||||
runemove(t.r, t.r+m, t.nr);
|
||||
q0 -= m;
|
||||
}
|
||||
if(t.nr+n > t.maxr){
|
||||
/*
|
||||
* Minimize realloc breakage:
|
||||
* Allocate at least MinWater
|
||||
* Double allocation size each time
|
||||
* But don't go much above HiWater
|
||||
*/
|
||||
m = max(min(2*(t.nr+n), HiWater), t.nr+n)+MinWater;
|
||||
if(m > HiWater)
|
||||
m = max(HiWater+MinWater, t.nr+n);
|
||||
if(m > t.maxr){
|
||||
t.r = runerealloc(t.r, m);
|
||||
t.maxr = m;
|
||||
}
|
||||
}
|
||||
runemove(t.r+q0+n, t.r+q0, t.nr-q0);
|
||||
runemove(t.r+q0, r, n);
|
||||
t.nr += n;
|
||||
/* if output touches, advance selection, not qh; works best for keyboard and output */
|
||||
if(q0 <= t.q1)
|
||||
t.q1 += n;
|
||||
if(q0 <= t.q0)
|
||||
t.q0 += n;
|
||||
if(q0 < t.qh || (q0==t.qh && hostwrite))
|
||||
t.qh += n;
|
||||
else
|
||||
consread();
|
||||
if(q0 < t.org)
|
||||
t.org += n;
|
||||
else if(q0 <= t.org+t.f->nchars)
|
||||
frinsert(t.f, r, r+n, q0-t.org);
|
||||
return q0;
|
||||
}
|
||||
|
||||
void
|
||||
paste(Rune *r, int n, int advance)
|
||||
{
|
||||
Rune *rbuf;
|
||||
uint m;
|
||||
uint q0;
|
||||
|
||||
if(rawon && t.q0==t.nr){
|
||||
addraw(r, n);
|
||||
|
|
@ -1024,6 +1216,7 @@ paste(Rune *r, int n, int advance)
|
|||
cut();
|
||||
if(n == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* if this is a button2 execute then we might have been passed
|
||||
* runes inside the buffer. must save them before realloc.
|
||||
|
|
@ -1035,36 +1228,7 @@ paste(Rune *r, int n, int advance)
|
|||
r = rbuf;
|
||||
}
|
||||
|
||||
if(t.nr>HiWater && t.q0>=t.org && t.q0>=t.qh){
|
||||
m = HiWater-LoWater;
|
||||
if(m > t.org)
|
||||
m = t.org;
|
||||
if(m > t.qh);
|
||||
m = t.qh;
|
||||
t.org -= m;
|
||||
t.qh -= m;
|
||||
t.q0 -= m;
|
||||
t.q1 -= m;
|
||||
t.nr -= m;
|
||||
runemove(t.r, t.r+m, t.nr);
|
||||
}
|
||||
|
||||
t.r = runerealloc(t.r, t.nr+n);
|
||||
q0 = t.q0;
|
||||
runemove(t.r+q0+n, t.r+q0, t.nr-q0);
|
||||
runemove(t.r+q0, r, n);
|
||||
t.nr += n;
|
||||
if(q0 < t.qh)
|
||||
t.qh += n;
|
||||
else
|
||||
consread();
|
||||
if(q0 < t.org)
|
||||
t.org += n;
|
||||
else if(q0 <= t.f->nchars+t.org)
|
||||
frinsert(t.f, r, r+n, q0-t.org);
|
||||
if(advance)
|
||||
t.q0 += n;
|
||||
t.q1 += n;
|
||||
insert(r, n, t.q0, 0);
|
||||
updatesel();
|
||||
free(rbuf);
|
||||
}
|
||||
|
|
@ -1321,61 +1485,6 @@ clickmatch(int cl, int cr, int dir, uint *q)
|
|||
return cl=='\n' && nest==1;
|
||||
}
|
||||
|
||||
void
|
||||
rcstart(int fd[2], int argc, char **argv)
|
||||
{
|
||||
int pid;
|
||||
char *xargv[3];
|
||||
char slave[256];
|
||||
int sfd;
|
||||
|
||||
if(argc == 0){
|
||||
argc = 2;
|
||||
argv = xargv;
|
||||
argv[0] = getenv("SHELL");
|
||||
if(argv[0] == 0)
|
||||
argv[0] = "rc";
|
||||
argv[1] = "-i";
|
||||
argv[2] = 0;
|
||||
}
|
||||
/*
|
||||
* fd0 is slave (tty), fd1 is master (pty)
|
||||
*/
|
||||
fd[0] = fd[1] = -1;
|
||||
if(getpts(fd, slave) < 0)
|
||||
fprint(2, "getpts: %r\n");
|
||||
|
||||
switch(pid = fork()) {
|
||||
case 0:
|
||||
putenv("TERM", "9term");
|
||||
close(fd[1]);
|
||||
setsid();
|
||||
// tcsetpgrp(0, pid);
|
||||
sfd = open(slave, ORDWR);
|
||||
if(sfd < 0)
|
||||
fprint(2, "open %s: %r\n", slave);
|
||||
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
|
||||
fprint(2, "ioctl TIOCSCTTY: %r\n");
|
||||
// ioctl(sfd, I_PUSH, "ptem");
|
||||
// ioctl(sfd, I_PUSH, "ldterm");
|
||||
dup(sfd, 0);
|
||||
dup(sfd, 1);
|
||||
dup(sfd, 2);
|
||||
system("stty tabs -onlcr -echo erase ^h intr ^?");
|
||||
execvp(argv[0], argv);
|
||||
fprint(2, "exec %s failed: %r\n", argv[0]);
|
||||
_exits("oops");
|
||||
break;
|
||||
case -1:
|
||||
fatal("proc failed: %r");
|
||||
break;
|
||||
}
|
||||
close(fd[0]);
|
||||
fd[0] = fd[1];
|
||||
|
||||
rcpid = pid;
|
||||
}
|
||||
|
||||
void
|
||||
tcheck(void)
|
||||
{
|
||||
|
|
@ -1421,7 +1530,7 @@ scrdraw(void)
|
|||
freeimage(scrx);
|
||||
scrx = allocimage(display, Rect(0, 0, 32, r.max.y), screen->chan, 1, DPaleyellow);
|
||||
if(scrx == 0)
|
||||
fatal("scroll balloc");
|
||||
sysfatal("scroll balloc");
|
||||
}
|
||||
r1.min.x = 0;
|
||||
r1.max.x = Dx(r);
|
||||
|
|
@ -1525,16 +1634,11 @@ plumb(uint q0, uint q1)
|
|||
char *p;
|
||||
int i, p0, n;
|
||||
char cbuf[100];
|
||||
char *w;
|
||||
|
||||
if(getchildwd(rcpid, childwdir, sizeof childwdir) == 0)
|
||||
w = childwdir;
|
||||
else
|
||||
w = wdir;
|
||||
pm = malloc(sizeof(Plumbmsg));
|
||||
pm->src = strdup("9term");
|
||||
pm->dst = 0;
|
||||
pm->wdir = strdup(w);
|
||||
pm->wdir = strdup(wdir);
|
||||
pm->type = strdup("text");
|
||||
pm->data = nil;
|
||||
if(q1 > q0)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,4 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <ctype.h>
|
||||
#include <draw.h>
|
||||
#include <thread.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <keyboard.h>
|
||||
#include <frame.h>
|
||||
#include <plumb.h>
|
||||
#include <termios.h>
|
||||
#include <sys/termios.h>
|
||||
#ifdef __linux__
|
||||
#include <pty.h>
|
||||
#endif
|
||||
|
||||
extern int getchildwd(int, char*, int);
|
||||
extern int getpts(int[], char*);
|
||||
|
||||
extern int childpty(int[], char*);
|
||||
extern void updatewinsize(int, int, int, int);
|
||||
extern int rcfd[];
|
||||
|
|
|
|||
|
|
@ -1,17 +1,43 @@
|
|||
#include "9term.h"
|
||||
#include <termios.h>
|
||||
#include <sys/termios.h>
|
||||
#include <libutil.h>
|
||||
|
||||
int
|
||||
getchildwd(int pid, char *wdir, int bufn)
|
||||
{
|
||||
USED(pid);
|
||||
USED(wdir);
|
||||
USED(bufn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
getpts(int fd[], char *slave)
|
||||
{
|
||||
return openpty(&fd[1], &fd[0], slave, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
childpty(int fd[], char *slave)
|
||||
{
|
||||
int sfd;
|
||||
|
||||
close(fd[1]);
|
||||
setsid();
|
||||
sfd = open(slave, ORDWR);
|
||||
if(sfd < 0)
|
||||
sysfatal("open %s: %r\n", slave);
|
||||
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
|
||||
fprint(2, "ioctl TIOCSCTTY: %r\n");
|
||||
return sfd;
|
||||
}
|
||||
|
||||
struct winsize ows;
|
||||
|
||||
void
|
||||
updatewinsize(int row, int col, int dx, int dy)
|
||||
{
|
||||
struct winsize ws;
|
||||
|
||||
ws.ws_row = row;
|
||||
ws.ws_col = col;
|
||||
ws.ws_xpixel = dx;
|
||||
ws.ws_ypixel = dy;
|
||||
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
|
||||
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
|
||||
fprint(2, "ioctl: %r\n");
|
||||
ows = ws;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,46 @@
|
|||
#include <u.h>
|
||||
#include <termios.h>
|
||||
#include <sys/termios.h>
|
||||
#include <pty.h>
|
||||
#include <libc.h>
|
||||
#include "9term.h"
|
||||
|
||||
int
|
||||
getchildwd(int pid, char *wdir, int bufn)
|
||||
{
|
||||
char path[256];
|
||||
int n;
|
||||
|
||||
snprint(path, sizeof path, "/proc/%d/cwd", pid);
|
||||
n = readlink(path, wdir, bufn);
|
||||
if(n < 0)
|
||||
return -1;
|
||||
wdir[n] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
getpts(int fd[], char *slave)
|
||||
{
|
||||
openpty(&fd[1], &fd[0], slave, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
childpty(int fd[], char *slave)
|
||||
{
|
||||
int sfd;
|
||||
|
||||
close(fd[1]);
|
||||
setsid();
|
||||
sfd = open(slave, ORDWR);
|
||||
if(sfd < 0)
|
||||
sysfatal("open %s: %r\n", slave);
|
||||
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
|
||||
fprint(2, "ioctl TIOCSCTTY: %r\n");
|
||||
return sfd;
|
||||
}
|
||||
|
||||
struct winsize ows;
|
||||
|
||||
void
|
||||
updatewinsize(int row, int col, int dx, int dy)
|
||||
{
|
||||
struct winsize ws;
|
||||
|
||||
ws.ws_row = row;
|
||||
ws.ws_col = col;
|
||||
ws.ws_xpixel = dx;
|
||||
ws.ws_ypixel = dy;
|
||||
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
|
||||
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
|
||||
fprint(2, "ioctl: %r\n");
|
||||
ows = ws;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,21 +1,6 @@
|
|||
#include "9term.h"
|
||||
|
||||
int
|
||||
getchildwd(int pid, char *wdir, int bufn)
|
||||
{
|
||||
char path[256];
|
||||
char cwd[256];
|
||||
|
||||
if(getcwd(cwd, sizeof cwd) < 0)
|
||||
return -1;
|
||||
snprint(path, sizeof path, "/proc/%d/cwd", pid);
|
||||
if(chdir(path) < 0)
|
||||
return -1;
|
||||
if(getcwd(wdir, bufn) < 0)
|
||||
return -1;
|
||||
chdir(cwd);
|
||||
return 0;
|
||||
}
|
||||
#include <termios.h>
|
||||
#include <sys/termios.h>
|
||||
|
||||
int
|
||||
getpts(int fd[], char *slave)
|
||||
|
|
@ -28,3 +13,21 @@ getpts(int fd[], char *slave)
|
|||
fd[0] = open(slave, OREAD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct winsize ows;
|
||||
|
||||
void
|
||||
updatewinsize(int row, int col, int dx, int dy)
|
||||
{
|
||||
struct winsize ws;
|
||||
|
||||
ws.ws_row = row;
|
||||
ws.ws_col = col;
|
||||
ws.ws_xpixel = dx;
|
||||
ws.ws_ypixel = dy;
|
||||
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
|
||||
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
|
||||
fprint(2, "ioctl: %r\n");
|
||||
ows = ws;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
PLAN9=../../..
|
||||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=9term
|
||||
TARG=9term win
|
||||
|
||||
OFILES=\
|
||||
9term.$O\
|
||||
rcstart.$O\
|
||||
$SYSNAME.$O\
|
||||
|
||||
SHORTLIB=frame draw plumb fs mux thread 9
|
||||
SHORTLIB=complete frame draw plumb fs mux thread 9
|
||||
|
||||
<$PLAN9/src/mkone
|
||||
<$PLAN9/src/mkmany
|
||||
|
||||
LDFLAGS=-L$X11/lib -lX11 -lutil
|
||||
|
||||
|
|
|
|||
51
src/cmd/9term/rcstart.c
Normal file
51
src/cmd/9term/rcstart.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "term.h"
|
||||
|
||||
int
|
||||
rcstart(int argc, char **argv, int *pfd)
|
||||
{
|
||||
int pid;
|
||||
int fd[2];
|
||||
char *xargv[3];
|
||||
char slave[256];
|
||||
int sfd;
|
||||
|
||||
if(argc == 0){
|
||||
argc = 2;
|
||||
argv = xargv;
|
||||
argv[0] = getenv("SHELL");
|
||||
if(argv[0] == 0)
|
||||
argv[0] = "rc";
|
||||
argv[1] = "-i";
|
||||
argv[2] = 0;
|
||||
}
|
||||
/*
|
||||
* fd0 is slave (tty), fd1 is master (pty)
|
||||
*/
|
||||
fd[0] = fd[1] = -1;
|
||||
if(getpts(fd, slave) < 0)
|
||||
fprint(2, "getpts: %r\n");
|
||||
|
||||
|
||||
switch(pid = fork()) {
|
||||
case 0:
|
||||
putenv("TERM", "9term");
|
||||
sfd = childpty(fd, slave);
|
||||
dup(sfd, 0);
|
||||
dup(sfd, 1);
|
||||
dup(sfd, 2);
|
||||
system("stty tabs -onlcr -echo erase ^h intr ^?");
|
||||
execvp(argv[0], argv);
|
||||
fprint(2, "exec %s failed: %r\n", argv[0]);
|
||||
_exits("oops");
|
||||
break;
|
||||
case -1:
|
||||
sysfatal("proc failed: %r");
|
||||
break;
|
||||
}
|
||||
close(fd[0]);
|
||||
*pfd = fd[1];
|
||||
return pid;
|
||||
}
|
||||
|
||||
5
src/cmd/9term/term.h
Normal file
5
src/cmd/9term/term.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extern int getpts(int[], char*);
|
||||
extern int childpty(int[], char*);
|
||||
extern void updatewinsize(int, int, int, int);
|
||||
extern int rcfd;
|
||||
extern int rcstart(int, char*[], int*);
|
||||
693
src/cmd/9term/win.c
Normal file
693
src/cmd/9term/win.c
Normal file
|
|
@ -0,0 +1,693 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <fcall.h>
|
||||
#include <fs.h>
|
||||
#include "term.h"
|
||||
|
||||
#define EVENTSIZE 256
|
||||
#define STACK 32768
|
||||
|
||||
typedef struct Event Event;
|
||||
typedef struct Q Q;
|
||||
|
||||
struct Event
|
||||
{
|
||||
int c1;
|
||||
int c2;
|
||||
int q0;
|
||||
int q1;
|
||||
int flag;
|
||||
int nb;
|
||||
int nr;
|
||||
char b[EVENTSIZE*UTFmax+1];
|
||||
Rune r[EVENTSIZE+1];
|
||||
};
|
||||
|
||||
Event blank = {
|
||||
'M',
|
||||
'X',
|
||||
0, 0, 0, 1, 1,
|
||||
{ ' ', 0 },
|
||||
{ ' ', 0 },
|
||||
};
|
||||
|
||||
struct Q
|
||||
{
|
||||
QLock lk;
|
||||
int p;
|
||||
int k;
|
||||
};
|
||||
|
||||
Q q;
|
||||
|
||||
Fid *eventfd;
|
||||
Fid *addrfd;
|
||||
Fid *datafd;
|
||||
Fid *ctlfd;
|
||||
// int bodyfd;
|
||||
|
||||
char *typing;
|
||||
int ntypeb;
|
||||
int ntyper;
|
||||
int ntypebreak;
|
||||
int debug;
|
||||
int rcfd;
|
||||
|
||||
char *name;
|
||||
|
||||
char **prog;
|
||||
Channel *cwait;
|
||||
int pid = -1;
|
||||
|
||||
int label(char*, int);
|
||||
void error(char*);
|
||||
void stdinproc(void*);
|
||||
void stdoutproc(void*);
|
||||
void type(Event*, int, Fid*, Fid*);
|
||||
void sende(Event*, int, Fid*, Fid*, Fid*, int);
|
||||
char *onestring(int, char**);
|
||||
int delete(Event*);
|
||||
void deltype(uint, uint);
|
||||
void runproc(void*);
|
||||
|
||||
int
|
||||
fsfidprint(Fid *fid, char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list arg;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
n = vsnprint(buf, sizeof buf, fmt, arg);
|
||||
va_end(arg);
|
||||
return fswrite(fid, buf, n);
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: win cmd args...\n");
|
||||
threadexitsall("usage");
|
||||
}
|
||||
|
||||
int
|
||||
nopipes(void *v, char *msg)
|
||||
{
|
||||
USED(v);
|
||||
if(strcmp(msg, "sys: write on closed pipe") == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
waitthread(void *v)
|
||||
{
|
||||
recvp(cwait);
|
||||
threadexitsall(nil);
|
||||
}
|
||||
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
int fd, id;
|
||||
char buf[256];
|
||||
char buf1[128];
|
||||
Fsys *fs;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
prog = argv;
|
||||
|
||||
if(argc > 0){
|
||||
name = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
}else
|
||||
name = "gnot";
|
||||
|
||||
threadnotify(nopipes, 1);
|
||||
if((fs = nsmount("acme", "")) < 0)
|
||||
sysfatal("nsmount acme: %r");
|
||||
ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
|
||||
if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
|
||||
sysfatal("ctl: %r");
|
||||
id = atoi(buf);
|
||||
sprint(buf, "%d/tag", id);
|
||||
fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
|
||||
write(fd, " Send Delete", 12);
|
||||
close(fd);
|
||||
sprint(buf, "%d/event", id);
|
||||
eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
|
||||
sprint(buf, "%d/addr", id);
|
||||
addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
|
||||
sprint(buf, "%d/data", id);
|
||||
datafd = fsopen(fs, buf, ORDWR|OCEXEC);
|
||||
sprint(buf, "%d/body", id);
|
||||
/* bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
|
||||
if(eventfd==nil || addrfd==nil || datafd==nil)
|
||||
sysfatal("data files: %r");
|
||||
/*
|
||||
if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
|
||||
sysfatal("data files: %r");
|
||||
*/
|
||||
fsunmount(fs);
|
||||
|
||||
cwait = threadwaitchan();
|
||||
threadcreate(waitthread, nil, STACK);
|
||||
pid = rcstart(argc, argv, &rcfd);
|
||||
if(pid == -1)
|
||||
sysfatal("exec failed");
|
||||
|
||||
getwd(buf1, sizeof buf1);
|
||||
sprint(buf, "name %s/-%s\n0\n", buf1, name);
|
||||
fswrite(ctlfd, buf, strlen(buf));
|
||||
sprint(buf, "dumpdir %s/\n", buf1);
|
||||
fswrite(ctlfd, buf, strlen(buf));
|
||||
sprint(buf, "dump %s\n", onestring(argc, argv));
|
||||
fswrite(ctlfd, buf, strlen(buf));
|
||||
|
||||
threadcreate(stdoutproc, nil, STACK);
|
||||
stdinproc(nil);
|
||||
}
|
||||
|
||||
void
|
||||
error(char *s)
|
||||
{
|
||||
if(s)
|
||||
fprint(2, "win: %s: %r\n", s);
|
||||
else
|
||||
s = "kill";
|
||||
if(pid != -1)
|
||||
postnote(PNGROUP, pid, "hangup");
|
||||
threadexitsall(s);
|
||||
}
|
||||
|
||||
char*
|
||||
onestring(int argc, char **argv)
|
||||
{
|
||||
char *p;
|
||||
int i, n;
|
||||
static char buf[1024];
|
||||
|
||||
if(argc == 0)
|
||||
return "";
|
||||
p = buf;
|
||||
for(i=0; i<argc; i++){
|
||||
n = strlen(argv[i]);
|
||||
if(p+n+1 >= buf+sizeof buf)
|
||||
break;
|
||||
memmove(p, argv[i], n);
|
||||
p += n;
|
||||
*p++ = ' ';
|
||||
}
|
||||
p[-1] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
getec(Fid *efd)
|
||||
{
|
||||
static char buf[8192];
|
||||
static char *bufp;
|
||||
static int nbuf;
|
||||
|
||||
if(nbuf == 0){
|
||||
nbuf = fsread(efd, buf, sizeof buf);
|
||||
if(nbuf <= 0)
|
||||
error(nil);
|
||||
bufp = buf;
|
||||
}
|
||||
--nbuf;
|
||||
return *bufp++;
|
||||
}
|
||||
|
||||
int
|
||||
geten(Fid *efd)
|
||||
{
|
||||
int n, c;
|
||||
|
||||
n = 0;
|
||||
while('0'<=(c=getec(efd)) && c<='9')
|
||||
n = n*10+(c-'0');
|
||||
if(c != ' ')
|
||||
error("event number syntax");
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
geter(Fid *efd, char *buf, int *nb)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
r = getec(efd);
|
||||
buf[0] = r;
|
||||
n = 1;
|
||||
if(r < Runeself)
|
||||
goto Return;
|
||||
while(!fullrune(buf, n))
|
||||
buf[n++] = getec(efd);
|
||||
chartorune(&r, buf);
|
||||
Return:
|
||||
*nb = n;
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
gete(Fid *efd, Event *e)
|
||||
{
|
||||
int i, nb;
|
||||
|
||||
e->c1 = getec(efd);
|
||||
e->c2 = getec(efd);
|
||||
e->q0 = geten(efd);
|
||||
e->q1 = geten(efd);
|
||||
e->flag = geten(efd);
|
||||
e->nr = geten(efd);
|
||||
if(e->nr > EVENTSIZE)
|
||||
error("event string too long");
|
||||
e->nb = 0;
|
||||
for(i=0; i<e->nr; i++){
|
||||
e->r[i] = geter(efd, e->b+e->nb, &nb);
|
||||
e->nb += nb;
|
||||
}
|
||||
e->r[e->nr] = 0;
|
||||
e->b[e->nb] = 0;
|
||||
if(getec(efd) != '\n')
|
||||
error("event syntax 2");
|
||||
}
|
||||
|
||||
int
|
||||
nrunes(char *s, int nb)
|
||||
{
|
||||
int i, n;
|
||||
Rune r;
|
||||
|
||||
n = 0;
|
||||
for(i=0; i<nb; n++)
|
||||
i += chartorune(&r, s+i);
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
stdinproc(void *v)
|
||||
{
|
||||
Fid *cfd = ctlfd;
|
||||
Fid *efd = eventfd;
|
||||
Fid *dfd = datafd;
|
||||
Fid *afd = addrfd;
|
||||
int fd0 = rcfd;
|
||||
Event e, e2, e3, e4;
|
||||
|
||||
USED(v);
|
||||
|
||||
for(;;){
|
||||
if(debug)
|
||||
fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
|
||||
gete(efd, &e);
|
||||
if(debug)
|
||||
fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
|
||||
qlock(&q.lk);
|
||||
switch(e.c1){
|
||||
default:
|
||||
Unknown:
|
||||
print("unknown message %c%c\n", e.c1, e.c2);
|
||||
break;
|
||||
|
||||
case 'E': /* write to body; can't affect us */
|
||||
if(debug)
|
||||
fprint(2, "shift typing %d... ", e.q1-e.q0);
|
||||
q.p += e.q1-e.q0;
|
||||
break;
|
||||
|
||||
case 'F': /* generated by our actions; ignore */
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
case 'M':
|
||||
switch(e.c2){
|
||||
case 'I':
|
||||
if(e.q0 < q.p){
|
||||
if(debug)
|
||||
fprint(2, "shift typing %d... ", e.q1-e.q0);
|
||||
q.p += e.q1-e.q0;
|
||||
}
|
||||
else if(e.q0 <= q.p+ntyper){
|
||||
if(debug)
|
||||
fprint(2, "type... ");
|
||||
type(&e, fd0, afd, dfd);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
q.p -= delete(&e);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
if(e.flag & 2)
|
||||
gete(efd, &e2);
|
||||
if(e.flag & 8){
|
||||
gete(efd, &e3);
|
||||
gete(efd, &e4);
|
||||
}
|
||||
if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
|
||||
/* send it straight back */
|
||||
fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
|
||||
break;
|
||||
}
|
||||
if(e.q0==e.q1 && (e.flag&2)){
|
||||
e2.flag = e.flag;
|
||||
e = e2;
|
||||
}
|
||||
if(e.flag & 8){
|
||||
if(e.q1 != e.q0){
|
||||
sende(&e, fd0, cfd, afd, dfd, 0);
|
||||
sende(&blank, fd0, cfd, afd, dfd, 0);
|
||||
}
|
||||
sende(&e3, fd0, cfd, afd, dfd, 1);
|
||||
}else if(e.q1 != e.q0)
|
||||
sende(&e, fd0, cfd, afd, dfd, 1);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
case 'L':
|
||||
/* just send it back */
|
||||
if(e.flag & 2)
|
||||
gete(efd, &e2);
|
||||
fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
break;
|
||||
|
||||
default:
|
||||
goto Unknown;
|
||||
}
|
||||
}
|
||||
qunlock(&q.lk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stdoutproc(void *v)
|
||||
{
|
||||
int fd1 = rcfd;
|
||||
Fid *afd = addrfd;
|
||||
Fid *dfd = datafd;
|
||||
int n, m, w, npart;
|
||||
char *buf, *s, *t;
|
||||
Rune r;
|
||||
char x[16], hold[UTFmax];
|
||||
|
||||
USED(v);
|
||||
threadnotify(nopipes, 1);
|
||||
buf = malloc(8192+UTFmax+1);
|
||||
npart = 0;
|
||||
for(;;){
|
||||
/* Let typing have a go -- maybe there's a rubout waiting. */
|
||||
yield();
|
||||
n = threadread(fd1, buf+npart, 8192);
|
||||
if(n < 0)
|
||||
error(nil);
|
||||
if(n == 0)
|
||||
continue;
|
||||
|
||||
/* squash NULs */
|
||||
s = memchr(buf+npart, 0, n);
|
||||
if(s){
|
||||
for(t=s; s<buf+npart+n; s++)
|
||||
if(*t = *s) /* assign = */
|
||||
t++;
|
||||
n = t-(buf+npart);
|
||||
}
|
||||
|
||||
n += npart;
|
||||
|
||||
/* hold on to final partial rune */
|
||||
npart = 0;
|
||||
while(n>0 && (buf[n-1]&0xC0)){
|
||||
--n;
|
||||
npart++;
|
||||
if((buf[n]&0xC0)!=0x80){
|
||||
if(fullrune(buf+n, npart)){
|
||||
w = chartorune(&r, buf+n);
|
||||
n += w;
|
||||
npart -= w;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(n > 0){
|
||||
memmove(hold, buf+n, npart);
|
||||
buf[n] = 0;
|
||||
n = label(buf, n);
|
||||
buf[n] = 0;
|
||||
qlock(&q.lk);
|
||||
m = sprint(x, "#%d", q.p);
|
||||
if(fswrite(afd, x, m) != m)
|
||||
error("stdout writing address");
|
||||
if(fswrite(dfd, buf, n) != n)
|
||||
error("stdout writing body");
|
||||
q.p += nrunes(buf, n);
|
||||
qunlock(&q.lk);
|
||||
memmove(buf, hold, npart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char wdir[256];
|
||||
int
|
||||
label(char *sr, int n)
|
||||
{
|
||||
char *sl, *el, *er, *r;
|
||||
|
||||
er = sr+n;
|
||||
for(r=er-1; r>=sr; r--)
|
||||
if(*r == '\007')
|
||||
break;
|
||||
if(r < sr)
|
||||
return n;
|
||||
|
||||
el = r+1;
|
||||
if(el-sr > sizeof wdir)
|
||||
sr = el - sizeof wdir;
|
||||
for(sl=el-3; sl>=sr; sl--)
|
||||
if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
|
||||
break;
|
||||
if(sl < sr)
|
||||
return n;
|
||||
|
||||
*r = 0;
|
||||
snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
|
||||
fswrite(ctlfd, wdir, strlen(wdir));
|
||||
|
||||
memmove(sl, el, er-el);
|
||||
n -= (el-sl);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
delete(Event *e)
|
||||
{
|
||||
uint q0, q1;
|
||||
int deltap;
|
||||
|
||||
q0 = e->q0;
|
||||
q1 = e->q1;
|
||||
if(q1 <= q.p)
|
||||
return e->q1-e->q0;
|
||||
if(q0 >= q.p+ntyper)
|
||||
return 0;
|
||||
deltap = 0;
|
||||
if(q0 < q.p){
|
||||
deltap = q.p-q0;
|
||||
q0 = 0;
|
||||
}else
|
||||
q0 -= q.p;
|
||||
if(q1 > q.p+ntyper)
|
||||
q1 = ntyper;
|
||||
else
|
||||
q1 -= q.p;
|
||||
deltype(q0, q1);
|
||||
return deltap;
|
||||
}
|
||||
|
||||
void
|
||||
addtype(int c, uint p0, char *b, int nb, int nr)
|
||||
{
|
||||
int i, w;
|
||||
Rune r;
|
||||
uint p;
|
||||
char *b0;
|
||||
|
||||
for(i=0; i<nb; i+=w){
|
||||
w = chartorune(&r, b+i);
|
||||
if((r==0x7F||r==3) && c=='K'){
|
||||
write(rcfd, "\x7F", 1);
|
||||
/* toss all typing */
|
||||
q.p += ntyper+nr;
|
||||
ntypebreak = 0;
|
||||
ntypeb = 0;
|
||||
ntyper = 0;
|
||||
/* buglet: more than one delete ignored */
|
||||
return;
|
||||
}
|
||||
if(r=='\n' || r==0x04)
|
||||
ntypebreak++;
|
||||
}
|
||||
typing = realloc(typing, ntypeb+nb);
|
||||
if(typing == nil)
|
||||
error("realloc");
|
||||
if(p0 == ntyper)
|
||||
memmove(typing+ntypeb, b, nb);
|
||||
else{
|
||||
b0 = typing;
|
||||
for(p=0; p<p0 && b0<typing+ntypeb; p++){
|
||||
w = chartorune(&r, b0+i);
|
||||
b0 += w;
|
||||
}
|
||||
if(p != p0)
|
||||
error("typing: findrune");
|
||||
memmove(b0+nb, b0, (typing+ntypeb)-b0);
|
||||
memmove(b0, b, nb);
|
||||
}
|
||||
ntypeb += nb;
|
||||
ntyper += nr;
|
||||
}
|
||||
|
||||
void
|
||||
sendtype(int fd0)
|
||||
{
|
||||
int i, n, nr;
|
||||
|
||||
while(ntypebreak){
|
||||
for(i=0; i<ntypeb; i++)
|
||||
if(typing[i]=='\n' || typing[i]==0x04){
|
||||
n = i + (typing[i] == '\n');
|
||||
i++;
|
||||
if(write(fd0, typing, n) != n)
|
||||
error("sending to program");
|
||||
nr = nrunes(typing, i);
|
||||
q.p += nr;
|
||||
ntyper -= nr;
|
||||
ntypeb -= i;
|
||||
memmove(typing, typing+i, ntypeb);
|
||||
ntypebreak--;
|
||||
goto cont2;
|
||||
}
|
||||
print("no breakchar\n");
|
||||
ntypebreak = 0;
|
||||
cont2:;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
deltype(uint p0, uint p1)
|
||||
{
|
||||
int w;
|
||||
uint p, b0, b1;
|
||||
Rune r;
|
||||
|
||||
/* advance to p0 */
|
||||
b0 = 0;
|
||||
for(p=0; p<p0 && b0<ntypeb; p++){
|
||||
w = chartorune(&r, typing+b0);
|
||||
b0 += w;
|
||||
}
|
||||
if(p != p0)
|
||||
error("deltype 1");
|
||||
/* advance to p1 */
|
||||
b1 = b0;
|
||||
for(; p<p1 && b1<ntypeb; p++){
|
||||
w = chartorune(&r, typing+b1);
|
||||
b1 += w;
|
||||
if(r=='\n' || r==0x04)
|
||||
ntypebreak--;
|
||||
}
|
||||
if(p != p1)
|
||||
error("deltype 2");
|
||||
memmove(typing+b0, typing+b1, ntypeb-b1);
|
||||
ntypeb -= b1-b0;
|
||||
ntyper -= p1-p0;
|
||||
}
|
||||
|
||||
void
|
||||
type(Event *e, int fd0, Fid *afd, Fid *dfd)
|
||||
{
|
||||
int m, n, nr;
|
||||
char buf[128];
|
||||
|
||||
if(e->nr > 0)
|
||||
addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
|
||||
else{
|
||||
m = e->q0;
|
||||
while(m < e->q1){
|
||||
n = sprint(buf, "#%d", m);
|
||||
fswrite(afd, buf, n);
|
||||
n = fsread(dfd, buf, sizeof buf);
|
||||
nr = nrunes(buf, n);
|
||||
while(m+nr > e->q1){
|
||||
do; while(n>0 && (buf[--n]&0xC0)==0x80);
|
||||
--nr;
|
||||
}
|
||||
if(n == 0)
|
||||
break;
|
||||
addtype(e->c1, m-q.p, buf, n, nr);
|
||||
m += nr;
|
||||
}
|
||||
}
|
||||
sendtype(fd0);
|
||||
}
|
||||
|
||||
void
|
||||
sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
|
||||
{
|
||||
int l, m, n, nr, lastc, end;
|
||||
char abuf[16], buf[128];
|
||||
|
||||
end = q.p+ntyper;
|
||||
l = sprint(abuf, "#%d", end);
|
||||
fswrite(afd, abuf, l);
|
||||
if(e->nr > 0){
|
||||
fswrite(dfd, e->b, e->nb);
|
||||
addtype(e->c1, ntyper, e->b, e->nb, e->nr);
|
||||
lastc = e->r[e->nr-1];
|
||||
}else{
|
||||
m = e->q0;
|
||||
lastc = 0;
|
||||
while(m < e->q1){
|
||||
n = sprint(buf, "#%d", m);
|
||||
fswrite(afd, buf, n);
|
||||
n = fsread(dfd, buf, sizeof buf);
|
||||
nr = nrunes(buf, n);
|
||||
while(m+nr > e->q1){
|
||||
do; while(n>0 && (buf[--n]&0xC0)==0x80);
|
||||
--nr;
|
||||
}
|
||||
if(n == 0)
|
||||
break;
|
||||
l = sprint(abuf, "#%d", end);
|
||||
fswrite(afd, abuf, l);
|
||||
fswrite(dfd, buf, n);
|
||||
addtype(e->c1, ntyper, buf, n, nr);
|
||||
lastc = buf[n-1];
|
||||
m += nr;
|
||||
end += nr;
|
||||
}
|
||||
}
|
||||
if(donl && lastc!='\n'){
|
||||
fswrite(dfd, "\n", 1);
|
||||
addtype(e->c1, ntyper, "\n", 1, 1);
|
||||
}
|
||||
fswrite(cfd, "dot=addr", 8);
|
||||
sendtype(fd0);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue