12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <thread.h>
- #include <cursor.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <frame.h>
- #include <fcall.h>
- #include <plumb.h>
- #include "dat.h"
- #include "fns.h"
- enum
- {
- Ctlsize = 5*12
- };
- char Edel[] = "deleted window";
- char Ebadctl[] = "ill-formed control message";
- char Ebadaddr[] = "bad address syntax";
- char Eaddr[] = "address out of range";
- char Einuse[] = "already in use";
- char Ebadevent[] = "bad event syntax";
- extern char Eperm[];
- static
- void
- clampaddr(Window *w)
- {
- if(w->addr.q0 < 0)
- w->addr.q0 = 0;
- if(w->addr.q1 < 0)
- w->addr.q1 = 0;
- if(w->addr.q0 > w->body.file->Buffer.nc)
- w->addr.q0 = w->body.file->Buffer.nc;
- if(w->addr.q1 > w->body.file->Buffer.nc)
- w->addr.q1 = w->body.file->Buffer.nc;
- }
- void
- xfidctl(void *arg)
- {
- Xfid *x;
- void (*f)(Xfid*);
- threadsetname("xfidctlthread");
- x = arg;
- for(;;){
- f = recvp(x->c);
- (*f)(x);
- flushimage(display, 1);
- sendp(cxfidfree, x);
- }
- }
- void
- xfidflush(Xfid *x)
- {
- Fcall fc;
- int i, j;
- Window *w;
- Column *c;
- Xfid *wx;
- /* search windows for matching tag */
- qlock(&row.QLock);
- for(j=0; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; i++){
- w = c->w[i];
- winlock(w, 'E');
- wx = w->eventx;
- if(wx!=nil && wx->Fcall.tag==x->Fcall.oldtag){
- w->eventx = nil;
- wx->flushed = TRUE;
- sendp(wx->c, nil);
- winunlock(w);
- goto out;
- }
- winunlock(w);
- }
- }
- out:
- qunlock(&row.QLock);
- respond(x, &fc, nil);
- }
- void
- xfidopen(Xfid *x)
- {
- Fcall fc;
- Window *w;
- Text *t;
- char *s;
- Rune *r;
- int m, n, q, q0, q1;
- w = x->f->w;
- t = &w->body;
- if(w){
- winlock(w, 'E');
- q = FILE(x->f->qid);
- switch(q){
- case QWaddr:
- if(w->nopen[q]++ == 0){
- w->addr = (Range){0,0};
- w->limit = (Range){-1,-1};
- }
- break;
- case QWdata:
- case QWxdata:
- w->nopen[q]++;
- break;
- case QWevent:
- if(w->nopen[q]++ == 0){
- if(!w->isdir && w->col!=nil){
- w->filemenu = FALSE;
- winsettag(w);
- }
- }
- break;
- case QWrdsel:
- /*
- * Use a temporary file.
- * A pipe would be the obvious, but we can't afford the
- * broken pipe notification. Using the code to read QWbody
- * is n², which should probably also be fixed. Even then,
- * though, we'd need to squirrel away the data in case it's
- * modified during the operation, e.g. by |sort
- */
- if(w->rdselfd > 0){
- winunlock(w);
- respond(x, &fc, Einuse);
- return;
- }
- w->rdselfd = tempfile();
- if(w->rdselfd < 0){
- winunlock(w);
- respond(x, &fc, "can't create temp file");
- return;
- }
- w->nopen[q]++;
- q0 = t->q0;
- q1 = t->q1;
- r = fbufalloc();
- s = fbufalloc();
- while(q0 < q1){
- n = q1 - q0;
- if(n > BUFSIZE/UTFmax)
- n = BUFSIZE/UTFmax;
- bufread(&t->file->Buffer, q0, r, n);
- m = snprint(s, BUFSIZE+1, "%.*S", n, r);
- if(write(w->rdselfd, s, m) != m){
- warning(nil, "can't write temp file for pipe command %r\n");
- break;
- }
- q0 += n;
- }
- fbuffree(s);
- fbuffree(r);
- break;
- case QWwrsel:
- w->nopen[q]++;
- seq++;
- filemark(t->file);
- cut(t, t, nil, FALSE, TRUE, nil, 0);
- w->wrselrange = (Range){t->q1, t->q1};
- w->nomark = TRUE;
- break;
- case QWeditout:
- if(editing == FALSE){
- winunlock(w);
- respond(x, &fc, Eperm);
- return;
- }
- w->wrselrange = (Range){t->q1, t->q1};
- break;
- }
- winunlock(w);
- }
- fc.qid = x->f->qid;
- fc.iounit = messagesize-IOHDRSZ;
- x->f->open = TRUE;
- respond(x, &fc, nil);
- }
- void
- xfidclose(Xfid *x)
- {
- Fcall fc;
- Window *w;
- int q;
- Text *t;
- w = x->f->w;
- x->f->busy = FALSE;
- if(x->f->open == FALSE){
- if(w != nil)
- winclose(w);
- respond(x, &fc, nil);
- return;
- }
- x->f->open = FALSE;
- if(w){
- winlock(w, 'E');
- q = FILE(x->f->qid);
- switch(q){
- case QWctl:
- if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){
- w->ctlfid = ~0;
- qunlock(&w->ctllock);
- }
- break;
- case QWdata:
- case QWxdata:
- w->nomark = FALSE;
- /* fall through */
- case QWaddr:
- case QWevent: /* BUG: do we need to shut down Xfid? */
- if(--w->nopen[q] == 0){
- if(q == QWdata || q == QWxdata)
- w->nomark = FALSE;
- if(q==QWevent && !w->isdir && w->col!=nil){
- w->filemenu = TRUE;
- winsettag(w);
- }
- if(q == QWevent){
- free(w->dumpstr);
- free(w->dumpdir);
- w->dumpstr = nil;
- w->dumpdir = nil;
- }
- }
- break;
- case QWrdsel:
- close(w->rdselfd);
- w->rdselfd = 0;
- break;
- case QWwrsel:
- w->nomark = FALSE;
- t = &w->body;
- /* before: only did this if !w->noscroll, but that didn't seem right in practice */
- textshow(t, min(w->wrselrange.q0, t->file->Buffer.nc),
- min(w->wrselrange.q1, t->file->Buffer.nc), 1);
- textscrdraw(t);
- break;
- }
- winunlock(w);
- winclose(w);
- }
- respond(x, &fc, nil);
- }
- void
- xfidread(Xfid *x)
- {
- Fcall fc;
- int n, q;
- uint off;
- char *b;
- char buf[256];
- Window *w;
- q = FILE(x->f->qid);
- w = x->f->w;
- if(w == nil){
- fc.count = 0;
- switch(q){
- case Qcons:
- case Qlabel:
- break;
- case Qindex:
- xfidindexread(x);
- return;
- default:
- warning(nil, "unknown qid %d\n", q);
- break;
- }
- respond(x, &fc, nil);
- return;
- }
- winlock(w, 'F');
- if(w->col == nil){
- winunlock(w);
- respond(x, &fc, Edel);
- return;
- }
- off = x->Fcall.offset;
- switch(q){
- case QWaddr:
- textcommit(&w->body, TRUE);
- clampaddr(w);
- sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);
- goto Readbuf;
- case QWbody:
- xfidutfread(x, &w->body, w->body.file->Buffer.nc, QWbody);
- break;
- case QWctl:
- b = winctlprint(w, buf, 1);
- goto Readb;
- Readbuf:
- b = buf;
- Readb:
- n = strlen(b);
- if(off > n)
- off = n;
- if(off+x->Fcall.count > n)
- x->Fcall.count = n-off;
- fc.count = x->Fcall.count;
- fc.data = b+off;
- respond(x, &fc, nil);
- if(b != buf)
- free(b);
- break;
- case QWevent:
- xfideventread(x, w);
- break;
- case QWdata:
- /* BUG: what should happen if q1 > q0? */
- if(w->addr.q0 > w->body.file->Buffer.nc){
- respond(x, &fc, Eaddr);
- break;
- }
- w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->Buffer.nc);
- w->addr.q1 = w->addr.q0;
- break;
- case QWxdata:
- /* BUG: what should happen if q1 > q0? */
- if(w->addr.q0 > w->body.file->Buffer.nc){
- respond(x, &fc, Eaddr);
- break;
- }
- w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);
- break;
- case QWtag:
- xfidutfread(x, &w->tag, w->tag.file->Buffer.nc, QWtag);
- break;
- case QWrdsel:
- seek(w->rdselfd, off, 0);
- n = x->Fcall.count;
- if(n > BUFSIZE)
- n = BUFSIZE;
- b = fbufalloc();
- n = read(w->rdselfd, b, n);
- if(n < 0){
- respond(x, &fc, "I/O error in temp file");
- break;
- }
- fc.count = n;
- fc.data = b;
- respond(x, &fc, nil);
- fbuffree(b);
- break;
- default:
- sprint(buf, "unknown qid %d in read", q);
- respond(x, &fc, nil);
- }
- winunlock(w);
- }
- static Rune*
- fullrunewrite(Xfid *x, int *inr)
- {
- int q, cnt, c, nb, nr;
- Rune *r;
- q = x->f->nrpart;
- cnt = x->Fcall.count;
- if(q > 0){
- memmove(x->Fcall.data+q, x->Fcall.data, cnt); /* there's room; see fsysproc */
- memmove(x->Fcall.data, x->f->rpart, q);
- cnt += q;
- x->f->nrpart = 0;
- }
- r = runemalloc(cnt);
- cvttorunes(x->Fcall.data, cnt-UTFmax, r, &nb, &nr, nil);
- /* approach end of buffer */
- while(fullrune(x->Fcall.data+nb, cnt-nb)){
- c = nb;
- nb += chartorune(&r[nr], x->Fcall.data+c);
- if(r[nr])
- nr++;
- }
- if(nb < cnt){
- memmove(x->f->rpart, x->Fcall.data+nb, cnt-nb);
- x->f->nrpart = cnt-nb;
- }
- *inr = nr;
- return r;
- }
- void
- xfidwrite(Xfid *x)
- {
- Fcall fc;
- int c, qid, nb, nr, eval;
- char buf[64], *err;
- Window *w;
- Rune *r;
- Range a;
- Text *t;
- uint q0, tq0, tq1;
- qid = FILE(x->f->qid);
- w = x->f->w;
- if(w){
- c = 'F';
- if(qid==QWtag || qid==QWbody)
- c = 'E';
- winlock(w, c);
- if(w->col == nil){
- winunlock(w);
- respond(x, &fc, Edel);
- return;
- }
- }
- x->Fcall.data[x->Fcall.count] = 0;
- switch(qid){
- case Qcons:
- w = errorwin(x->f->mntdir, 'X');
- t=&w->body;
- goto BodyTag;
- case Qlabel:
- fc.count = x->Fcall.count;
- respond(x, &fc, nil);
- break;
- case QWaddr:
- x->Fcall.data[x->Fcall.count] = 0;
- r = bytetorune(x->Fcall.data, &nr);
- t = &w->body;
- wincommit(w, t);
- eval = TRUE;
- a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
- free(r);
- if(nb < nr){
- respond(x, &fc, Ebadaddr);
- break;
- }
- if(!eval){
- respond(x, &fc, Eaddr);
- break;
- }
- w->addr = a;
- fc.count = x->Fcall.count;
- respond(x, &fc, nil);
- break;
- case Qeditout:
- case QWeditout:
- r = fullrunewrite(x, &nr);
- if(w)
- err = edittext(w, w->wrselrange.q1, r, nr);
- else
- err = edittext(nil, 0, r, nr);
- free(r);
- if(err != nil){
- respond(x, &fc, err);
- break;
- }
- fc.count = x->Fcall.count;
- respond(x, &fc, nil);
- break;
- case QWerrors:
- w = errorwinforwin(w);
- t = &w->body;
- goto BodyTag;
- case QWbody:
- case QWwrsel:
- t = &w->body;
- goto BodyTag;
- case QWctl:
- xfidctlwrite(x, w);
- break;
- case QWdata:
- a = w->addr;
- t = &w->body;
- wincommit(w, t);
- if(a.q0>t->file->Buffer.nc || a.q1>t->file->Buffer.nc){
- respond(x, &fc, Eaddr);
- break;
- }
- r = runemalloc(x->Fcall.count);
- cvttorunes(x->Fcall.data, x->Fcall.count, r, &nb, &nr, nil);
- if(w->nomark == FALSE){
- seq++;
- filemark(t->file);
- }
- q0 = a.q0;
- if(a.q1 > q0){
- textdelete(t, q0, a.q1, TRUE);
- w->addr.q1 = q0;
- }
- tq0 = t->q0;
- tq1 = t->q1;
- textinsert(t, q0, r, nr, TRUE);
- if(tq0 >= q0)
- tq0 += nr;
- if(tq1 >= q0)
- tq1 += nr;
- textsetselect(t, tq0, tq1);
- if(!t->w->noscroll)
- textshow(t, q0, q0+nr, 0);
- textscrdraw(t);
- winsettag(w);
- free(r);
- w->addr.q0 += nr;
- w->addr.q1 = w->addr.q0;
- fc.count = x->Fcall.count;
- respond(x, &fc, nil);
- break;
- case QWevent:
- xfideventwrite(x, w);
- break;
- case QWtag:
- t = &w->tag;
- goto BodyTag;
- BodyTag:
- r = fullrunewrite(x, &nr);
- if(nr > 0){
- wincommit(w, t);
- if(qid == QWwrsel){
- q0 = w->wrselrange.q1;
- if(q0 > t->file->Buffer.nc)
- q0 = t->file->Buffer.nc;
- }else
- q0 = t->file->Buffer.nc;
- if(qid == QWtag)
- textinsert(t, q0, r, nr, TRUE);
- else{
- if(w->nomark == FALSE){
- seq++;
- filemark(t->file);
- }
- q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
- textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
- if(qid!=QWwrsel && !t->w->noscroll)
- textshow(t, q0+nr, q0+nr, 1);
- textscrdraw(t);
- }
- winsettag(w);
- if(qid == QWwrsel)
- w->wrselrange.q1 += nr;
- free(r);
- }
- fc.count = x->Fcall.count;
- respond(x, &fc, nil);
- break;
- default:
- sprint(buf, "unknown qid %d in write", qid);
- respond(x, &fc, buf);
- break;
- }
- if(w)
- winunlock(w);
- }
- void
- xfidctlwrite(Xfid *x, Window *w)
- {
- Fcall fc;
- int i, m, n, nb, nr, nulls;
- Rune *r;
- char *err, *p, *pp, *q, *e;
- int isfbuf, scrdraw, settag;
- Text *t;
- err = nil;
- e = x->Fcall.data+x->Fcall.count;
- scrdraw = FALSE;
- settag = FALSE;
- isfbuf = TRUE;
- if(x->Fcall.count < RBUFSIZE)
- r = fbufalloc();
- else{
- isfbuf = FALSE;
- r = emalloc(x->Fcall.count*UTFmax+1);
- }
- x->Fcall.data[x->Fcall.count] = 0;
- textcommit(&w->tag, TRUE);
- for(n=0; n<x->Fcall.count; n+=m){
- p = x->Fcall.data+n;
- if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
- qlock(&w->ctllock);
- w->ctlfid = x->f->fid;
- m = 4;
- }else
- if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
- w->ctlfid = ~0;
- qunlock(&w->ctllock);
- m = 6;
- }else
- if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
- t = &w->body;
- t->eq0 = ~0;
- filereset(t->file);
- t->file->mod = FALSE;
- w->dirty = FALSE;
- settag = TRUE;
- m = 5;
- }else
- if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
- t = &w->body;
- /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
- t->file->mod = TRUE;
- w->dirty = TRUE;
- settag = TRUE;
- m = 5;
- }else
- if(strncmp(p, "show", 4) == 0){ /* show dot */
- t = &w->body;
- textshow(t, t->q0, t->q1, 1);
- m = 4;
- }else
- if(strncmp(p, "name ", 5) == 0){ /* set file name */
- pp = p+5;
- m = 5;
- q = memchr(pp, '\n', e-pp);
- if(q==nil || q==pp){
- err = Ebadctl;
- break;
- }
- *q = 0;
- nulls = FALSE;
- cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
- if(nulls){
- err = "nulls in file name";
- break;
- }
- for(i=0; i<nr; i++)
- if(r[i] <= ' '){
- err = "bad character in file name";
- goto out;
- }
- out:
- seq++;
- filemark(w->body.file);
- winsetname(w, r, nr);
- m += (q+1) - pp;
- }else
- if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
- pp = p+5;
- m = 5;
- q = memchr(pp, '\n', e-pp);
- if(q==nil || q==pp){
- err = Ebadctl;
- break;
- }
- *q = 0;
- nulls = FALSE;
- cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
- if(nulls){
- err = "nulls in dump string";
- break;
- }
- w->dumpstr = runetobyte(r, nr);
- m += (q+1) - pp;
- }else
- if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
- pp = p+8;
- m = 8;
- q = memchr(pp, '\n', e-pp);
- if(q==nil || q==pp){
- err = Ebadctl;
- break;
- }
- *q = 0;
- nulls = FALSE;
- cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
- if(nulls){
- err = "nulls in dump directory string";
- break;
- }
- w->dumpdir = runetobyte(r, nr);
- m += (q+1) - pp;
- }else
- if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
- colclose(w->col, w, TRUE);
- m = 6;
- }else
- if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
- if(!winclean(w, TRUE)){
- err = "file dirty";
- break;
- }
- colclose(w->col, w, TRUE);
- m = 3;
- }else
- if(strncmp(p, "get", 3) == 0){ /* get file */
- get(&w->body, nil, nil, FALSE, XXX, nil, 0);
- m = 3;
- }else
- if(strncmp(p, "put", 3) == 0){ /* put file */
- put(&w->body, nil, nil, XXX, XXX, nil, 0);
- m = 3;
- }else
- if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
- textcommit(&w->body, TRUE);
- clampaddr(w);
- w->body.q0 = w->addr.q0;
- w->body.q1 = w->addr.q1;
- textsetselect(&w->body, w->body.q0, w->body.q1);
- settag = TRUE;
- m = 8;
- }else
- if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
- w->addr.q0 = w->body.q0;
- w->addr.q1 = w->body.q1;
- m = 8;
- }else
- if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
- textcommit(&w->body, TRUE);
- clampaddr(w);
- w->limit.q0 = w->addr.q0;
- w->limit.q1 = w->addr.q1;
- m = 10;
- }else
- if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
- w->nomark = TRUE;
- m = 6;
- }else
- if(strncmp(p, "mark", 4) == 0){ /* mark file */
- seq++;
- filemark(w->body.file);
- settag = TRUE;
- m = 4;
- }else
- if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */
- w->filemenu = FALSE;
- m = 6;
- }else
- if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */
- w->filemenu = TRUE;
- m = 4;
- }else
- if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
- w->noscroll = TRUE;
- m = 8;
- }else
- if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
- wincleartag(w);
- settag = TRUE;
- m = 8;
- }else
- if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
- w->noscroll = FALSE;
- m = 6;
- }else{
- err = Ebadctl;
- break;
- }
- while(p[m] == '\n')
- m++;
- }
- if(isfbuf)
- fbuffree(r);
- else
- free(r);
- if(err)
- n = 0;
- fc.count = n;
- respond(x, &fc, err);
- if(settag)
- winsettag(w);
- if(scrdraw)
- textscrdraw(&w->body);
- }
- void
- xfideventwrite(Xfid *x, Window *w)
- {
- Fcall fc;
- int m, n;
- Rune *r;
- char *err, *p, *q;
- int isfbuf;
- Text *t;
- int c;
- uint q0, q1;
- err = nil;
- isfbuf = TRUE;
- if(x->Fcall.count < RBUFSIZE)
- r = fbufalloc();
- else{
- isfbuf = FALSE;
- r = emalloc(x->Fcall.count*UTFmax+1);
- }
- for(n=0; n<x->Fcall.count; n+=m){
- p = x->Fcall.data+n;
- w->owner = *p++; /* disgusting */
- c = *p++;
- while(*p == ' ')
- p++;
- q0 = strtoul(p, &q, 10);
- if(q == p)
- goto Rescue;
- p = q;
- while(*p == ' ')
- p++;
- q1 = strtoul(p, &q, 10);
- if(q == p)
- goto Rescue;
- p = q;
- while(*p == ' ')
- p++;
- if(*p++ != '\n')
- goto Rescue;
- m = p-(x->Fcall.data+n);
- if('a'<=c && c<='z')
- t = &w->tag;
- else if('A'<=c && c<='Z')
- t = &w->body;
- else
- goto Rescue;
- if(q0>t->file->Buffer.nc || q1>t->file->Buffer.nc || q0>q1)
- goto Rescue;
- qlock(&row.QLock); /* just like mousethread */
- switch(c){
- case 'x':
- case 'X':
- execute(t, q0, q1, TRUE, nil);
- break;
- case 'l':
- case 'L':
- look3(t, q0, q1, TRUE);
- break;
- default:
- qunlock(&row.QLock);
- goto Rescue;
- }
- qunlock(&row.QLock);
- }
- Out:
- if(isfbuf)
- fbuffree(r);
- else
- free(r);
- if(err)
- n = 0;
- fc.count = n;
- respond(x, &fc, err);
- return;
- Rescue:
- err = Ebadevent;
- goto Out;
- }
- void
- xfidutfread(Xfid *x, Text *t, uint q1, int qid)
- {
- Fcall fc;
- Window *w;
- Rune *r;
- char *b, *b1;
- uint q, off, boff;
- int m, n, nr, nb;
- w = t->w;
- wincommit(w, t);
- off = x->Fcall.offset;
- r = fbufalloc();
- b = fbufalloc();
- b1 = fbufalloc();
- n = 0;
- if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
- boff = w->utflastboff;
- q = w->utflastq;
- }else{
- /* BUG: stupid code: scan from beginning */
- boff = 0;
- q = 0;
- }
- w->utflastqid = qid;
- while(q<q1 && n<x->Fcall.count){
- /*
- * Updating here avoids partial rune problem: we're always on a
- * char boundary. The cost is we will usually do one more read
- * than we really need, but that's better than being n^2.
- */
- w->utflastboff = boff;
- w->utflastq = q;
- nr = q1-q;
- if(nr > BUFSIZE/UTFmax)
- nr = BUFSIZE/UTFmax;
- bufread(&t->file->Buffer, q, r, nr);
- nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
- if(boff >= off){
- m = nb;
- if(boff+m > off+x->Fcall.count)
- m = off+x->Fcall.count - boff;
- memmove(b1+n, b, m);
- n += m;
- }else if(boff+nb > off){
- if(n != 0)
- error("bad count in utfrune");
- m = nb - (off-boff);
- if(m > x->Fcall.count)
- m = x->Fcall.count;
- memmove(b1, b+(off-boff), m);
- n += m;
- }
- boff += nb;
- q += nr;
- }
- fbuffree(r);
- fbuffree(b);
- fc.count = n;
- fc.data = b1;
- respond(x, &fc, nil);
- fbuffree(b1);
- }
- int
- xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
- {
- Fcall fc;
- Window *w;
- Rune *r, junk;
- char *b, *b1;
- uint q, boff;
- int i, rw, m, n, nr, nb;
- w = t->w;
- wincommit(w, t);
- r = fbufalloc();
- b = fbufalloc();
- b1 = fbufalloc();
- n = 0;
- q = q0;
- boff = 0;
- while(q<q1 && n<x->Fcall.count){
- nr = q1-q;
- if(nr > BUFSIZE/UTFmax)
- nr = BUFSIZE/UTFmax;
- bufread(&t->file->Buffer, q, r, nr);
- nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
- m = nb;
- if(boff+m > x->Fcall.count){
- i = x->Fcall.count - boff;
- /* copy whole runes only */
- m = 0;
- nr = 0;
- while(m < i){
- rw = chartorune(&junk, b+m);
- if(m+rw > i)
- break;
- m += rw;
- nr++;
- }
- if(m == 0)
- break;
- }
- memmove(b1+n, b, m);
- n += m;
- boff += nb;
- q += nr;
- }
- fbuffree(r);
- fbuffree(b);
- fc.count = n;
- fc.data = b1;
- respond(x, &fc, nil);
- fbuffree(b1);
- return q-q0;
- }
- void
- xfideventread(Xfid *x, Window *w)
- {
- Fcall fc;
- char *b;
- int i, n;
- i = 0;
- x->flushed = FALSE;
- while(w->nevents == 0){
- if(i){
- if(!x->flushed)
- respond(x, &fc, "window shut down");
- return;
- }
- w->eventx = x;
- winunlock(w);
- recvp(x->c);
- winlock(w, 'F');
- i++;
- }
- n = w->nevents;
- if(n > x->Fcall.count)
- n = x->Fcall.count;
- fc.count = n;
- fc.data = w->events;
- respond(x, &fc, nil);
- b = w->events;
- w->events = estrdup(w->events+n);
- free(b);
- w->nevents -= n;
- }
- void
- xfidindexread(Xfid *x)
- {
- Fcall fc;
- int i, j, m, n, nmax, isbuf, cnt, off;
- Window *w;
- char *b;
- Rune *r;
- Column *c;
- qlock(&row.QLock);
- nmax = 0;
- for(j=0; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; i++){
- w = c->w[i];
- nmax += Ctlsize + w->tag.file->Buffer.nc*UTFmax + 1;
- }
- }
- nmax++;
- isbuf = (nmax<=RBUFSIZE);
- if(isbuf)
- b = (char*)x->buf;
- else
- b = emalloc(nmax);
- r = fbufalloc();
- n = 0;
- for(j=0; j<row.ncol; j++){
- c = row.col[j];
- for(i=0; i<c->nw; i++){
- w = c->w[i];
- /* only show the currently active window of a set */
- if(w->body.file->curtext != &w->body)
- continue;
- winctlprint(w, b+n, 0);
- n += Ctlsize;
- m = min(RBUFSIZE, w->tag.file->Buffer.nc);
- bufread(&w->tag.file->Buffer, 0, r, m);
- m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
- while(n<m && b[n]!='\n')
- n++;
- b[n++] = '\n';
- }
- }
- qunlock(&row.QLock);
- off = x->Fcall.offset;
- cnt = x->Fcall.count;
- if(off > n)
- off = n;
- if(off+cnt > n)
- cnt = n-off;
- fc.count = cnt;
- memmove(r, b+off, cnt);
- fc.data = (char*)r;
- if(!isbuf)
- free(b);
- respond(x, &fc, nil);
- fbuffree(r);
- }
|