Fighting the good fight.

Move libfmt, libutf into subdirectories of lib9.

Add poll-based socket i/o to libthread, so that we can
avoid using multiple procs when possible, thus removing
dependence on crappy pthreads implementations.

Convert samterm, acme to the single-proc libthread.

Bring libcomplete, acme up-to-date w.r.t. Plan 9 distribution.
This commit is contained in:
rsc 2004-02-29 22:10:26 +00:00
parent d51419bf43
commit 5a8e63b2f0
107 changed files with 665 additions and 6637 deletions

View file

@ -76,6 +76,7 @@ int isunix;
Queue *outq;
Queue *inq;
int verbose;
int msize = 8192;
void *gethash(Hash**, uint);
int puthash(Hash**, uint, void*);
@ -94,7 +95,6 @@ void *erealloc(void*, int);
Queue *qalloc(void);
int sendq(Queue*, void*);
void *recvq(Queue*);
void pollthread(void*);
void connthread(void*);
void connoutthread(void*);
void listenthread(void*);
@ -125,7 +125,6 @@ threadmain(int argc, char **argv)
{
char *file;
if(verbose) fprint(2, "9pserve running\n");
ARGBEGIN{
default:
usage();
@ -143,6 +142,7 @@ threadmain(int argc, char **argv)
break;
}ARGEND
if(verbose) fprint(2, "9pserve running\n");
if(argc != 1)
usage();
addr = argv[0];
@ -150,8 +150,19 @@ threadmain(int argc, char **argv)
if((afd = announce(addr, adir)) < 0)
sysfatal("announce %s: %r", addr);
proccreate(mainproc, nil, STACK);
threadexits(0);
if(verbose) fprint(2, "9pserve forking\n");
switch(fork()){
case -1:
sysfatal("fork: %r");
case 0:
if(verbose) fprint(2, "running mainproc\n");
mainproc(nil);
if(verbose) fprint(2, "mainproc finished\n");
_exits(0);
default:
if(verbose) fprint(2, "9pserve exiting\n");
_exits(0);
}
}
void
@ -161,8 +172,6 @@ mainproc(void *v)
Fcall f;
USED(v);
yield(); /* let threadmain exit */
atnotify(ignorepipe, 1);
fmtinstall('D', dirfmt);
fmtinstall('M', dirmodefmt);
@ -174,7 +183,7 @@ mainproc(void *v)
f.type = Tversion;
f.version = "9P2000";
f.msize = 8192;
f.msize = msize;
f.tag = NOTAG;
n = convS2M(&f, vbuf, sizeof vbuf);
if(verbose > 1) fprint(2, "* <- %F\n", &f);
@ -182,12 +191,13 @@ mainproc(void *v)
n = read9pmsg(0, vbuf, sizeof vbuf);
if(convM2S(vbuf, n, &f) != n)
sysfatal("convM2S failure");
if(f.msize < msize)
msize = f.msize;
if(verbose > 1) fprint(2, "* -> %F\n", &f);
threadcreate(inputthread, nil, STACK);
threadcreate(outputthread, nil, STACK);
threadcreate(listenthread, nil, STACK);
threadcreateidle(pollthread, nil, STACK);
threadexits(0);
}
@ -296,8 +306,8 @@ connthread(void *arg)
case Tversion:
m->rx.tag = m->tx.tag;
m->rx.msize = m->tx.msize;
if(m->rx.msize > 8192)
m->rx.msize = 8192;
if(m->rx.msize > msize)
m->rx.msize = msize;
m->rx.version = "9P2000";
m->rx.type = Rversion;
send9pmsg(m);
@ -480,7 +490,7 @@ openfdthread(void *v)
m->internal = 1;
m->c = c;
m->tx.type = Tread;
m->tx.count = 8192;
m->tx.count = msize - IOHDRSZ;
m->tx.fid = fid->fid;
m->tx.tag = m->tag;
m->tx.offset = tot;
@ -506,7 +516,10 @@ openfdthread(void *v)
}else{
for(;;){
if(verbose) fprint(2, "twrite...");
if((n=ioread(io, c->fd, buf, sizeof buf)) <= 0){
n = sizeof buf;
if(n > msize)
n = msize;
if((n=ioread(io, c->fd, buf, n)) <= 0){
if(n < 0)
fprint(2, "pipe read error: %r\n");
m = nil;
@ -1122,106 +1135,23 @@ struct Ioproc
int index;
};
static struct Ioproc **pio;
static struct pollfd *pfd;
static int npfd;
static struct Ioproc *iofree;
Ioproc*
ioproc(void)
{
Ioproc *io;
if(iofree == nil){
pfd = erealloc(pfd, (npfd+1)*sizeof(pfd[0]));
pfd[npfd].events = 0;
pfd[npfd].fd = -1;
iofree = emalloc(sizeof(Ioproc));
iofree->index = npfd;
iofree->c = chancreate(sizeof(ulong), 1);
pio = erealloc(pio, (npfd+1)*sizeof(pio[0]));
pio[npfd] = iofree;
npfd++;
}
io = iofree;
iofree = io->next;
return io;
return (Ioproc*)-1;
}
void
closeioproc(Ioproc *io)
{
io->next = iofree;
iofree = io;
}
void
pollthread(void *v)
{
int i, n;
for(;;){
yield();
for(i=0; i<npfd; i++)
pfd[i].revents = 0;
if(verbose){
fprint(2, "poll:");
for(i=0; i<npfd; i++)
if(pfd[i].events)
fprint(2, " %d%c", pfd[i].fd, pfd[i].events==POLLIN ? 'r' : pfd[i].events==POLLOUT ? 'w' : '?');
fprint(2, "\n");
}
n = poll(pfd, npfd, -1);
if(n <= 0)
continue;
for(i=0; i<npfd; i++)
if(pfd[i].fd != -1 && pfd[i].revents){
pfd[i].fd = -1;
pfd[i].events = 0;
pfd[i].revents = 0;
nbsendul(pio[i]->c, 1);
}
}
}
static void
noblock(int fd)
{
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
}
static void
xwait(Ioproc *io, int fd, int e)
{
if(verbose) fprint(2, "wait for %d%c\n", fd, e==POLLIN ? 'r' : 'w');
pfd[io->index].fd = fd;
pfd[io->index].events = e;
recvul(io->c);
if(verbose) fprint(2, "got %d\n", fd);
}
static void
rwait(Ioproc *io, int fd)
{
xwait(io, fd, POLLIN);
}
static void
wwait(Ioproc *io, int fd)
{
xwait(io, fd, POLLOUT);
}
long
ioread(Ioproc *io, int fd, void *v, long n)
{
long r;
USED(io);
noblock(fd);
while((r=read(fd, v, n)) < 0 && errno == EWOULDBLOCK)
rwait(io, fd);
return r;
return threadread(fd, v, n);
}
long
@ -1247,9 +1177,16 @@ iorecvfd(Ioproc *io, int fd)
{
int r;
noblock(fd);
while((r=recvfd(fd)) < 0 && errno == EWOULDBLOCK)
rwait(io, fd);
threadfdnoblock(fd);
while((r=recvfd(fd)) < 0){
if(errno == EINTR)
continue;
if(errno == EWOULDBLOCK || errno == EAGAIN){
threadfdwait(fd, 'r');
continue;
}
break;
}
return r;
}
@ -1258,23 +1195,24 @@ iosendfd(Ioproc *io, int s, int fd)
{
int r;
noblock(s);
while((r=sendfd(s, fd)) < 0 && errno == EWOULDBLOCK)
wwait(io, s);
if(r < 0) fprint(2, "sent %d, %d\n", s, fd);
threadfdnoblock(s);
while((r=sendfd(s, fd)) < 0){
if(errno == EINTR)
continue;
if(errno == EWOULDBLOCK || errno == EAGAIN){
threadfdwait(fd, 'w');
continue;
}
break;
}
return r;
}
static long
_iowrite(Ioproc *io, int fd, void *v, long n)
{
long r;
USED(io);
noblock(fd);
while((r=write(fd, v, n)) < 0 && errno == EWOULDBLOCK)
wwait(io, fd);
return r;
return threadwrite(fd, v, n);
}
long
@ -1305,9 +1243,16 @@ iolisten(Ioproc *io, char *dir, char *ndir)
if((fd = _p9netfd(dir)) < 0)
return -1;
noblock(fd);
while((r=listen(dir, ndir)) < 0 && errno == EWOULDBLOCK)
rwait(io, fd);
threadfdnoblock(fd);
while((r=listen(dir, ndir)) < 0){
if(errno == EINTR)
continue;
if(errno == EWOULDBLOCK || errno == EAGAIN){
threadfdwait(fd, 'r');
continue;
}
break;
}
return r;
}
@ -1317,9 +1262,16 @@ ioaccept(Ioproc *io, int fd, char *dir)
int r;
USED(io);
noblock(fd);
while((r=accept(fd, dir)) < 0 && errno == EWOULDBLOCK)
rwait(io, fd);
threadfdnoblock(fd);
while((r=accept(fd, dir)) < 0){
if(errno == EINTR)
continue;
if(errno == EWOULDBLOCK || errno == EAGAIN){
threadfdwait(fd, 'r');
continue;
}
break;
}
return r;
}

View file

@ -59,7 +59,6 @@ threadmain(int argc, char *argv[])
{
int i;
char *p, *loadfile;
char buf[256];
Column *c;
int ncol;
Display *d;
@ -70,6 +69,9 @@ threadmain(int argc, char *argv[])
loadfile = nil;
ARGBEGIN{
case 'a':
globalautoindent = TRUE;
break;
case 'b':
bartflag = TRUE;
break;
@ -98,7 +100,7 @@ threadmain(int argc, char *argv[])
break;
default:
Usage:
fprint(2, "usage: acme -c ncol -f fontname -F fixedwidthfontname -l loadfile\n");
fprint(2, "usage: acme -a -c ncol -f fontname -F fixedwidthfontname -l loadfile\n");
exits("usage");
}ARGEND
@ -183,7 +185,7 @@ threadmain(int argc, char *argv[])
fprint(2, "acme: can't initialize plumber: %r\n");
else{
cplumb = chancreate(sizeof(Plumbmsg*), 0);
proccreate(plumbproc, nil, STACK);
threadcreate(plumbproc, nil, STACK);
}
plumbsendfd = plumbopen("send", OWRITE|OCEXEC);
@ -315,7 +317,7 @@ acmeerrorproc(void *v)
USED(v);
threadsetname("acmeerrorproc");
buf = emalloc(8192+1);
while((n=read(errorfd, buf, 8192)) >= 0){
while((n=threadread(errorfd, buf, 8192)) >= 0){
buf[n] = '\0';
sendp(cerr, estrdup(buf));
}
@ -324,8 +326,7 @@ acmeerrorproc(void *v)
void
acmeerrorinit(void)
{
int fd, pfd[2];
char buf[64];
int pfd[2];
if(pipe(pfd) < 0)
error("can't create pipe");
@ -351,7 +352,7 @@ acmeerrorinit(void)
errorfd = pfd[1];
if(errorfd < 0)
error("can't re-open acmeerror file");
proccreate(acmeerrorproc, nil, STACK);
threadcreate(acmeerrorproc, nil, STACK);
}
void
@ -362,7 +363,7 @@ plumbproc(void *v)
USED(v);
threadsetname("plumbproc");
for(;;){
m = plumbrecv(plumbeditfd);
m = threadplumbrecv(plumbeditfd);
if(m == nil)
threadexits(nil);
sendp(cplumb, m);
@ -399,6 +400,7 @@ keyboardthread(void *v)
winlock(t->w, 'K');
wincommit(t->w, t);
winunlock(t->w);
flushwarnings(1);
flushimage(display, 1);
}
alts[KTimer].c = nil;
@ -425,6 +427,7 @@ keyboardthread(void *v)
}
if(nbrecv(keyboardctl->c, &r) > 0)
goto casekeyboard;
flushwarnings(1);
flushimage(display, 1);
break;
}
@ -467,6 +470,7 @@ mousethread(void *v)
draw(screen, screen->r, display->white, nil, ZP);
scrlresize();
rowresize(&row, screen->clipr);
flushwarnings(1);
flushimage(display, 1);
break;
case MPlumb:
@ -477,6 +481,7 @@ mousethread(void *v)
else if(strcmp(act, "showdata")==0)
plumbshow(pm);
}
flushwarnings(1);
flushimage(display, 1);
plumbfree(pm);
break;
@ -562,6 +567,7 @@ mousethread(void *v)
goto Continue;
}
Continue:
flushwarnings(0);
flushimage(display, 1);
qunlock(&row.lk);
break;
@ -916,36 +922,48 @@ iconinit(void)
void
acmeputsnarf(void)
{
int fd, i, n;
int i, n;
Fmt f;
char *s;
if(snarffd<0 || snarfbuf.nc==0)
if(snarfbuf.nc==0)
return;
if(snarfbuf.nc > MAXSNARF)
return;
fd = open("/dev/snarf", OWRITE);
if(fd < 0)
return;
fmtstrinit(&f);
for(i=0; i<snarfbuf.nc; i+=n){
n = snarfbuf.nc-i;
if(n >= NSnarf)
n = NSnarf;
bufread(&snarfbuf, i, snarfrune, n);
if(fprint(fd, "%.*S", n, snarfrune) < 0)
if(fmtprint(&f, "%.*S", n, snarfrune) < 0)
break;
}
close(fd);
s = fmtstrflush(&f);
if(s && s[0])
putsnarf(s);
free(s);
}
void
acmegetsnarf()
acmegetsnarf(void)
{
int nulls;
char *s;
int nb, nr, nulls, len;
Rune *r;
if(snarfbuf.nc > MAXSNARF)
s = getsnarf();
if(s == nil || s[0]==0){
free(s);
return;
if(snarffd < 0)
return;
seek(snarffd, 0, 0);
}
len = strlen(s);
r = runemalloc(len+1);
cvttorunes(s, len, r, &nb, &nr, &nulls);
bufreset(&snarfbuf);
bufload(&snarfbuf, 0, snarffd, &nulls);
bufinsert(&snarfbuf, 0, r, nr);
free(r);
free(s);
}

View file

@ -232,6 +232,7 @@ struct Window
uchar isscratch;
uchar filemenu;
uchar dirty;
uchar autoindent;
int id;
Range addr;
Range limit;
@ -486,6 +487,7 @@ enum /* editing */
Collecting,
};
uint globalincref;
uint seq;
uint maxtab; /* size of a tab, in units of the '0' character */
@ -524,10 +526,11 @@ Image *tagcols[NCOL];
Image *textcols[NCOL];
int plumbsendfd;
int plumbeditfd;
extern char wdir[];
extern char wdir[]; /* must use extern because no dimension given */
int editing;
int erroutfd;
int messagesize; /* negotiated in 9P version setup */
int globalautoindent;
Channel *ckeyboard; /* chan(Rune)[10] */
Channel *cplumb; /* chan(Plumbmsg*) */

View file

@ -596,7 +596,7 @@ runpipe(Text *t, int cmd, Rune *cr, int ncr, int state)
r = skipbl(cr, ncr, &n);
if(n == 0)
editerror("no command specified for >");
editerror("no command specified for %c", cmd);
w = nil;
if(state == Inserting){
w = t->w;
@ -949,12 +949,15 @@ filelooper(Cmd *cp, int XY)
/*
* add a ref to all windows to keep safe windows accessed by X
* that would not otherwise have a ref to hold them up during
* the shenanigans.
* the shenanigans. note this with globalincref so that any
* newly created windows start with an extra reference.
*/
allwindows(alllocker, (void*)1);
globalincref = 1;
for(i=0; i<loopstruct.nw; i++)
cmdexec(&loopstruct.w[i]->body, cp->u.cmd);
allwindows(alllocker, (void*)0);
globalincref = 0;
free(loopstruct.w);
loopstruct.w = nil;

View file

@ -462,7 +462,7 @@ getname(Text *t, Text *argt, Rune *arg, int narg, int isput)
dir.nr = 0;
if(n>0 && arg[0]!='/'){
dir = dirname(t, nil, 0);
if(n==1 && dir.r[0]=='.'){ /* sigh */
if(dir.nr==1 && dir.r[0]=='.'){ /* sigh */
free(dir.r);
dir.r = nil;
dir.nr = 0;
@ -606,15 +606,15 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
f->qidpath = d->qid.path;
f->mtime = d->mtime;
if(f->unread)
warningew(w, nil, "%s not written; file already exists\n", name);
warning(nil, "%s not written; file already exists\n", name);
else
warningew(w, nil, "%s modified%s%s since last read\n", name, d->muid[0]?" by ":"", d->muid);
warning(nil, "%s modified%s%s since last read\n", name, d->muid[0]?" by ":"", d->muid);
goto Rescue1;
}
}
fd = create(name, OWRITE, 0666);
if(fd < 0){
warningew(w, nil, "can't create file %s: %r\n", name);
warning(nil, "can't create file %s: %r\n", name);
goto Rescue1;
}
r = fbufalloc();
@ -623,7 +623,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
d = dirfstat(fd);
isapp = (d!=nil && d->length>0 && (d->qid.type&QTAPPEND));
if(isapp){
warningew(w, nil, "%s not written; file is append only\n", name);
warning(nil, "%s not written; file is append only\n", name);
goto Rescue2;
}
@ -634,7 +634,7 @@ putfile(File *f, int q0, int q1, Rune *namer, int nname)
bufread(&f->b, q, r, n);
m = snprint(s, BUFSIZE+1, "%.*S", n, r);
if(write(fd, s, m) != m){
warningew(w, nil, "can't write file %s: %r\n", name);
warning(nil, "can't write file %s: %r\n", name);
goto Rescue2;
}
}
@ -701,7 +701,7 @@ put(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
f = w->body.file;
name = getname(&w->body, argt, arg, narg, TRUE);
if(name == nil){
warningew(w, nil, "no file name\n");
warning(nil, "no file name\n");
return;
}
namer = bytetorune(name, &nname);
@ -1163,6 +1163,58 @@ incl(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
}
}
static Rune LON[] = { 'O', 'N', 0 };
static Rune LOFF[] = { 'O', 'F', 'F', 0 };
static Rune Lon[] = { 'o', 'n', 0 };
static int
indentval(Rune *s, int n)
{
if(n < 2)
return -1;
if(runestrncmp(s, LON, n) == 0){
globalautoindent = TRUE;
warning(nil, "Indent ON\n");
return -2;
}
if(runestrncmp(s, LOFF, n) == 0){
globalautoindent = FALSE;
warning(nil, "Indent OFF\n");
return -2;
}
return runestrncmp(s, Lon, n) == 0;
}
void
indent(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
{
Rune *a, *r;
Window *w;
int na, len, autoindent;
USED(_0);
USED(_1);
USED(_2);
if(et==nil || et->w==nil)
return;
w = et->w;
autoindent = -1;
getarg(argt, FALSE, TRUE, &r, &len);
if(r!=nil && len>0)
autoindent = indentval(r, len);
else{
a = findbl(arg, narg, &na);
if(a != arg)
autoindent = indentval(arg, narg-na);
}
if(autoindent >= 0)
w->autoindent = autoindent;
if(autoindent != 2)
warning(nil, "%.*S: Indent %s\n", w->body.file->nname, w->body.file->name,
w->autoindent ? "on" : "off");
}
void
tab(Text *et, Text *_0, Text *argt, int _1, int _2, Rune *arg, int narg)
{
@ -1375,7 +1427,7 @@ runproc(void *argvp)
av[ac++] = arg;
av[ac] = nil;
c->av = av;
procexec(cpid, sfd, av[0], av);
threadexec(cpid, sfd, av[0], av);
/* libthread uses execvp so no need to do this */
#if 0
e = av[0];
@ -1419,10 +1471,10 @@ Hard:
c->text = news;
}
}
procexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
threadexecl(cpid, sfd, "rc", "rc", "-c", t, nil);
Fail:
/* procexec hasn't happened, so send a zero */
/* threadexec hasn't happened, so send a zero */
close(sfd[0]);
close(sfd[1]);
if(sfd[2] != sfd[1])
@ -1482,7 +1534,7 @@ run(Window *win, char *s, Rune *rdir, int ndir, int newns, char *argaddr, char *
arg[7] = c;
arg[8] = cpid;
arg[9] = (void*)iseditcmd;
proccreate(runproc, arg, STACK);
threadcreate(runproc, arg, STACK);
/* mustn't block here because must be ready to answer mount() call in run() */
arg = emalloc(2*sizeof(void*));
arg[0] = c;

View file

@ -27,7 +27,7 @@ void clearmouse(void);
void allwindows(void(*)(Window*, void*), void*);
uint loadfile(int, uint, int*, int(*)(void*, uint, Rune*, int), void*);
Window* errorwin(Mntdir*, int, Window*);
Window* errorwin(Mntdir*, int);
Runestr cleanrname(Runestr);
void run(Window*, char*, Rune*, int, int, char*, char*, int);
void fsysclose(void);
@ -85,7 +85,8 @@ Window* makenewwindow(Text *t);
int expand(Text*, uint, uint, Expand*);
Rune* skipbl(Rune*, int, int*);
Rune* findbl(Rune*, int, int*);
char* edittext(Window*, int, Rune*, int);
char* edittext(Window*, int, Rune*, int);
void flushwarnings(int);
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))

View file

@ -111,8 +111,7 @@ void
fsysinit(void)
{
int p[2];
int n, fd;
char buf[256], *u;
char *u;
if(pipe(p) < 0)
error("can't create pipe");
@ -122,7 +121,7 @@ fsysinit(void)
fmtinstall('F', fcallfmt);
if((u = getuser()) != nil)
user = estrdup(u);
proccreate(fsysproc, nil, STACK);
threadcreate(fsysproc, nil, STACK);
}
void
@ -138,7 +137,7 @@ fsysproc(void *v)
x = nil;
for(;;){
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
n = read9pmsg(sfd, buf, messagesize);
n = threadread9pmsg(sfd, buf, messagesize);
if(n <= 0){
if(closing)
break;
@ -255,7 +254,11 @@ respond(Xfid *x, Fcall *t, char *err)
x->buf = emalloc(messagesize);
n = convS2M(t, x->buf, messagesize);
if(n <= 0)
{
fprint(2, "convert error (n=%d, msgsize %d): have %F\n", n, messagesize, &x->fcall);
fprint(2, "\tresponse: %F\n", t);
error("convert error in convS2M");
}
if(write(sfd, x->buf, n) != n)
error("write error in respond");
free(x->buf);

View file

@ -320,60 +320,18 @@ isfilec(Rune r)
return FALSE;
}
/* Runestr wrapper for cleanname */
Runestr
cleanrname(Runestr rs)
{
int i, j, found;
Rune *b;
int n;
static Rune Lslashdotdot[] = { '/', '.', '.', 0 };
char *s;
int nb, nulls;
b = rs.r;
n = rs.nr;
/* compress multiple slashes */
for(i=0; i<n-1; i++)
if(b[i]=='/' && b[i+1]=='/'){
runemove(b+i, b+i+1, n-i-1);
--n;
--i;
}
/* eliminate ./ */
for(i=0; i<n-1; i++)
if(b[i]=='.' && b[i+1]=='/' && (i==0 || b[i-1]=='/')){
runemove(b+i, b+i+2, n-i-2);
n -= 2;
--i;
}
/* eliminate trailing . */
if(n>=2 && b[n-2]=='/' && b[n-1]=='.')
--n;
do{
/* compress xx/.. */
found = FALSE;
for(i=1; i<=n-3; i++)
if(runeeq(b+i, 3, Lslashdotdot, 3)){
if(i==n-3 || b[i+3]=='/'){
found = TRUE;
break;
}
}
if(found)
for(j=i-1; j>=0; --j)
if(j==0 || b[j-1]=='/'){
i += 3; /* character beyond .. */
if(i<n && b[i]=='/')
++i;
runemove(b+j, b+i, n-i);
n -= (i-j);
break;
}
}while(found);
if(n == 0){
*b = '.';
n = 1;
}
return (Runestr){b, n};
s = runetobyte(rs.r, rs.nr);
cleanname(s);
cvttorunes(s, strlen(s), rs.r, &nb, &rs.nr, &nulls);
free(s);
return rs;
}
Runestr
@ -407,6 +365,11 @@ includename(Text *t, Rune *r, int n)
Window *w;
char buf[128];
Rune Lsysinclude[] = { '/', 's', 'y', 's', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
Rune Lusrinclude[] = { '/', 'u', 's', 'r', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
Rune Lusrlocalinclude[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l',
'/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
Rune Lusrlocalplan9include[] = { '/', 'u', 's', 'r', '/', 'l', 'o', 'c', 'a', 'l',
'/', 'p', 'l', 'a', 'n', '9', '/', 'i', 'n', 'c', 'l', 'u', 'd', 'e', 0 };
Runestr file;
int i;
@ -429,6 +392,12 @@ includename(Text *t, Rune *r, int n)
if(file.r == nil)
file = includefile(Lsysinclude, r, n);
if(file.r == nil)
file = includefile(Lusrlocalplan9include, r, n);
if(file.r == nil)
file = includefile(Lusrlocalinclude, r, n);
if(file.r == nil)
file = includefile(Lusrinclude, r, n);
if(file.r==nil && objdir!=nil)
file = includefile(objdir, r, n);
if(file.r == nil)
@ -702,13 +671,16 @@ openfile(Text *t, Expand *e)
t->w->dirty = FALSE;
winsettag(t->w);
textsetselect(&t->w->tag, t->w->tag.file->b.nc, t->w->tag.file->b.nc);
if(ow != nil)
if(ow != nil){
for(i=ow->nincl; --i>=0; ){
n = runestrlen(ow->incl[i]);
rp = runemalloc(n);
runemove(rp, ow->incl[i], n);
winaddincl(w, rp, n);
}
w->autoindent = ow->autoindent;
}else
w->autoindent = globalautoindent;
}
if(e->a1 == e->a0)
eval = FALSE;

View file

@ -1,3 +1,5 @@
# Acme is up-to-date w.r.t. sources as of 29 February 2004
PLAN9=../../..
<$PLAN9/src/mkhdr
@ -36,6 +38,6 @@ UPDATE=\
<$PLAN9/src/mkone
LDFLAGS=$LDFLAGS -lcomplete -lplumb -lfs -lmux -lthread -lframe -ldraw -lbio -l9 -lfmt -lutf -L$X11/lib -lX11
LDFLAGS=$LDFLAGS -lcomplete -lplumb -lfs -lmux -lthread -lframe -ldraw -lbio -l9 -L$X11/lib -lX11
edit.$O ecmd.$O elog.$O: edit.h

View file

@ -537,7 +537,7 @@ textfilewidth(Text *t, uint q0, int oneelement)
q = q0;
while(q > 0){
r = textreadc(t, q-1);
if(r<=' ')
if(r <= ' ')
break;
if(oneelement && r=='/')
break;
@ -608,10 +608,11 @@ textcomplete(Text *t)
}
if(!c->advance){
warning(nil, "%.*S%s%.*S*\n",
warning(nil, "%.*S%s%.*S*%s\n",
dir.nr, dir.r,
dir.nr>0 && dir.r[dir.nr-1]!='/' ? "/" : "",
nstr, str);
nstr, str,
c->nmatch ? "" : ": no matches in:");
for(i=0; i<c->nfile; i++)
warning(nil, " %s\n", c->filename[i]);
}
@ -643,25 +644,45 @@ texttype(Text *t, Rune r)
rp = &r;
switch(r){
case Kleft:
if(t->q0 > 0)
if(t->q0 > 0){
textcommit(t, TRUE);
textshow(t, t->q0-1, t->q0-1, TRUE);
}
return;
case Kright:
if(t->q1 < t->file->b.nc)
if(t->q1 < t->file->b.nc){
textcommit(t, TRUE);
textshow(t, t->q1+1, t->q1+1, TRUE);
}
return;
case Kdown:
n = t->fr.maxlines/3;
goto case_Down;
case Kpgdown:
n = t->fr.maxlines/2;
n = 2*t->fr.maxlines/3;
case_Down:
q0 = t->org+frcharofpt(&t->fr, Pt(t->fr.r.min.x, t->fr.r.min.y+n*t->fr.font->height));
textsetorigin(t, q0, FALSE);
return;
case Kup:
n = t->fr.maxlines/3;
goto case_Up;
case Kpgup:
n = t->fr.maxlines/2;
n = 2*t->fr.maxlines/3;
case_Up:
q0 = textbacknl(t, t->org, n);
textsetorigin(t, q0, FALSE);
return;
case Khome:
textshow(t, 0, 0, FALSE);
return;
case Kend:
if(t->w)
wincommit(t->w, t);
else
textcommit(t, TRUE);
textshow(t, t->file->b.nc, t->file->b.nc, FALSE);
return;
}
if(t->what == Body){
seq++;
@ -734,6 +755,21 @@ texttype(Text *t, Rune r)
for(i=0; i<t->file->ntext; i++)
textfill(t->file->text[i]);
return;
case '\n':
if(t->w->autoindent){
/* find beginning of previous line using backspace code */
nnb = textbswidth(t, 0x15); /* ^U case */
rp = runemalloc(nnb + 1);
nr = 0;
rp[nr++] = r;
for(i=0; i<nnb; i++){
r = textreadc(t, t->q0-nnb+i);
if(r != ' ' && r != '\t')
break;
rp[nr++] = r;
}
}
break; /* fall through to normal code */
}
/* otherwise ordinary character; just insert, typically in caches of all texts */
for(i=0; i<t->file->ntext; i++){

View file

@ -50,7 +50,7 @@ timerproc(void *v)
nt = 0;
old = msec();
for(;;){
sleep(1); /* will sleep minimum incr */
threadsleep(1); /* will sleep minimum incr */
new = msec();
dt = new-old;
old = new;
@ -98,7 +98,7 @@ void
timerinit(void)
{
ctimer = chancreate(sizeof(Timer*), 100);
proccreate(timerproc, nil, STACK);
threadcreate(timerproc, nil, STACK);
}
Timer*

View file

@ -62,9 +62,11 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
int i, n;
static Rune Lpluserrors[] = { '+', 'E', 'r', 'r', 'o', 'r', 's', 0 };
r = runemalloc(ndir+7);
if(n = ndir) /* assign = */
r = runemalloc(ndir+8);
if(n = ndir){ /* assign = */
runemove(r, dir, ndir);
r[n++] = L'/';
}
runemove(r+n, Lpluserrors, 7);
n += 7;
w = lookfile(r, n);
@ -83,12 +85,13 @@ errorwin1(Rune *dir, int ndir, Rune **incl, int nincl)
runemove(r, incl[i], n);
winaddincl(w, r, n);
}
w->autoindent = globalautoindent;
return w;
}
/* make new window, if necessary; return with it locked */
Window*
errorwin(Mntdir *md, int owner, Window *e)
errorwin(Mntdir *md, int owner)
{
Window *w;
@ -97,51 +100,100 @@ errorwin(Mntdir *md, int owner, Window *e)
w = errorwin1(nil, 0, nil, 0);
else
w = errorwin1(md->dir, md->ndir, md->incl, md->nincl);
if(w != e)
winlock(w, owner);
winlock(w, owner);
if(w->col != nil)
break;
/* window was deleted too fast */
if(w != e)
winunlock(w);
winunlock(w);
}
return w;
}
static void
printwarning(Window *ew, Mntdir *md, Rune *r)
typedef struct Warning Warning;
struct Warning{
Mntdir *md;
Buffer buf;
Warning *next;
};
static Warning *warnings;
static
void
addwarningtext(Mntdir *md, Rune *r, int nr)
{
int nr, q0, owner;
Warning *warn;
for(warn = warnings; warn; warn=warn->next){
if(warn->md == md){
bufinsert(&warn->buf, warn->buf.nc, r, nr);
return;
}
}
warn = emalloc(sizeof(Warning));
warn->next = warnings;
warnings = warn;
bufinsert(&warn->buf, 0, r, nr);
}
void
flushwarnings(int dolock)
{
Warning *warn, *next;
Window *w;
Text *t;
int owner, nr, q0, n;
Rune *r;
if(r == nil)
error("runevsmprint failed");
nr = runestrlen(r);
if(dolock)
qlock(&row.lk);
if(row.ncol == 0){ /* really early error */
rowinit(&row, screen->clipr);
rowadd(&row, nil, -1);
rowadd(&row, nil, -1);
if(row.ncol == 0)
error("initializing columns in warning()");
error("initializing columns in flushwarnings()");
}
w = errorwin(md, 'E', ew);
t = &w->body;
owner = w->owner;
if(owner == 0)
w->owner = 'E';
wincommit(w, t);
q0 = textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
textshow(t, q0, q0+nr, 1);
winsettag(t->w);
textscrdraw(t);
w->owner = owner;
w->dirty = FALSE;
if(ew != w)
for(warn=warnings; warn; warn=next) {
w = errorwin(warn->md, 'E');
t = &w->body;
owner = w->owner;
if(owner == 0)
w->owner = 'E';
wincommit(w, t);
/*
* Most commands don't generate much output. For instance,
* Edit ,>cat goes through /dev/cons and is already in blocks
* because of the i/o system, but a few can. Edit ,p will
* put the entire result into a single hunk. So it's worth doing
* this in blocks (and putting the text in a buffer in the first
* place), to avoid a big memory footprint.
*/
r = fbufalloc();
q0 = t->file->b.nc;
for(n = 0; n < warn->buf.nc; n += nr){
nr = warn->buf.nc - n;
if(nr > RBUFSIZE)
nr = RBUFSIZE;
bufread(&warn->buf, n, r, nr);
textbsinsert(t, t->file->b.nc, r, nr, TRUE, &nr);
}
textshow(t, q0, t->file->b.nc, 1);
free(r);
winsettag(t->w);
textscrdraw(t);
w->owner = owner;
w->dirty = FALSE;
winunlock(w);
free(r);
bufclose(&warn->buf);
next = warn->next;
free(warn);
}
warnings = nil;
if(dolock)
qunlock(&row.lk);
}
void
@ -153,23 +205,9 @@ warning(Mntdir *md, char *s, ...)
va_start(arg, s);
r = runevsmprint(s, arg);
va_end(arg);
printwarning(nil, md, r);
}
/*
* Warningew is like warning but avoids locking the error window
* if it's already locked by checking that ew!=error window.
*/
void
warningew(Window *ew, Mntdir *md, char *s, ...)
{
Rune *r;
va_list arg;
va_start(arg, s);
r = runevsmprint(s, arg);
va_end(arg);
printwarning(ew, md, r);
if(r == nil)
error("runevsmprint failed");
addwarningtext(md, r, runestrlen(r));
}
int

View file

@ -26,6 +26,8 @@ wininit(Window *w, Window *clone, Rectangle r)
w->body.w = w;
w->id = ++winid;
incref(&w->ref);
if(globalincref)
incref(&w->ref);
w->ctlfid = ~0;
w->utflastqid = -1;
r1 = r;
@ -141,7 +143,7 @@ winlock(Window *w, int owner)
int i;
File *f;
fprint(2, "winlock %p %d %lux\n", w, owner, getcallerpc(&w));
//fprint(2, "winlock %p %d %lux\n", w, owner, getcallerpc(&w));
f = w->body.file;
for(i=0; i<f->ntext; i++)
winlock1(f->text[i]->w, owner);
@ -153,7 +155,7 @@ winunlock(Window *w)
int i;
File *f;
fprint(2, "winunlock %p %lux\n", w, getcallerpc(&w));
//fprint(2, "winunlock %p %lux\n", w, getcallerpc(&w));
f = w->body.file;
for(i=0; i<f->ntext; i++){
w = f->text[i]->w;

View file

@ -383,7 +383,7 @@ xfidwrite(Xfid *x)
x->fcall.data[x->fcall.count] = 0;
switch(qid){
case Qcons:
w = errorwin(x->f->mntdir, 'X', nil);
w = errorwin(x->f->mntdir, 'X');
t=&w->body;
goto BodyTag;
@ -543,6 +543,7 @@ xfidwrite(Xfid *x)
}
if(w)
winunlock(w);
flushwarnings(1);
}
void
@ -813,6 +814,7 @@ xfideventwrite(Xfid *x, Window *w)
qunlock(&row.lk);
goto Rescue;
}
flushwarnings(0);
qunlock(&row.lk);
}
@ -1030,6 +1032,7 @@ xfidindexread(Xfid *x)
b[n++] = '\n';
}
}
flushwarnings(0);
qunlock(&row.lk);
off = x->fcall.offset;
cnt = x->fcall.count;

View file

@ -2,7 +2,7 @@ PLAN9=../..
<$PLAN9/src/mkhdr
TARG=`ls *.c | sed 's/\.c//'`
LDFLAGS=$LDFLAGS -lthread -lsec -lfs -lmux -lregexp9 -lbio -l9 -lfmt -lutf
LDFLAGS=$LDFLAGS -lthread -lsec -lfs -lmux -lregexp9 -lbio -l9
<$PLAN9/src/mkmany

View file

@ -99,10 +99,11 @@ extproc(void *argv)
c = arg[0];
fd = (int)arg[1];
threadfdnoblock(fd);
i = 0;
for(;;){
i = 1-i; /* toggle */
n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
n = threadread(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
if(n <= 0){
fprint(2, "samterm: extern read error: %r\n");
threadexits("extern"); /* not a fatal error */
@ -165,7 +166,7 @@ extstart(void)
plumbc = chancreate(sizeof(int), 0);
arg[0] = plumbc;
arg[1] = (void*)fd;
proccreate(extproc, arg, STACK);
threadcreate(extproc, arg, STACK);
atexit(removeextern);
}
@ -226,9 +227,10 @@ plumbproc(void *argv)
fdp = arg[1];
i = 0;
threadfdnoblock(*fdp);
for(;;){
i = 1-i; /* toggle */
n = read(*fdp, plumbbuf[i].data, READBUFSIZE);
n = threadread(*fdp, plumbbuf[i].data, READBUFSIZE);
if(n <= 0){
fprint(2, "samterm: plumb read error: %r\n");
threadexits("plumb"); /* not a fatal error */
@ -258,7 +260,7 @@ plumbstart(void)
}
arg[0] =plumbc;
arg[1] = &fd;
proccreate(plumbproc, arg, STACK);
threadcreate(plumbproc, arg, STACK);
return 1;
}
#endif
@ -278,9 +280,10 @@ hostproc(void *arg)
c = arg;
i = 0;
threadfdnoblock(hostfd[0]);
for(;;){
i = 1-i; /* toggle */
n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
n = threadread(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
if(n <= 0){
fprint(2, "samterm: host read error: %r\n");
threadexitsall("host");
@ -295,5 +298,5 @@ void
hoststart(void)
{
hostc = chancreate(sizeof(int), 0);
proccreate(hostproc, hostc, STACK);
threadcreate(hostproc, hostc, STACK);
}