Blob
1 #include <u.h>2 #include <libc.h>3 #include <draw.h>4 #include <thread.h>5 #include <cursor.h>6 #include <mouse.h>7 #include <keyboard.h>8 #include <frame.h>9 #include <fcall.h>10 #include <plumb.h>11 #include "dat.h"12 #include "fns.h"14 enum15 {16 Ctlsize = 5*1217 };19 char Edel[] = "deleted window";20 char Ebadctl[] = "ill-formed control message";21 char Ebadaddr[] = "bad address syntax";22 char Eaddr[] = "address out of range";23 char Einuse[] = "already in use";24 char Ebadevent[] = "bad event syntax";25 extern char Eperm[];27 static28 void29 clampaddr(Window *w)30 {31 if(w->addr.q0 < 0)32 w->addr.q0 = 0;33 if(w->addr.q1 < 0)34 w->addr.q1 = 0;35 if(w->addr.q0 > w->body.file->b.nc)36 w->addr.q0 = w->body.file->b.nc;37 if(w->addr.q1 > w->body.file->b.nc)38 w->addr.q1 = w->body.file->b.nc;39 }41 void42 xfidctl(void *arg)43 {44 Xfid *x;45 void (*f)(Xfid*);47 threadsetname("xfidctlthread");48 x = arg;49 for(;;){50 f = (void(*)(Xfid*))recvp(x->c);51 (*f)(x);52 flushimage(display, 1);53 sendp(cxfidfree, x);54 }55 }57 void58 xfidflush(Xfid *x)59 {60 Fcall fc;61 int i, j;62 Window *w;63 Column *c;64 Xfid *wx;66 /* search windows for matching tag */67 qlock(&row.lk);68 for(j=0; j<row.ncol; j++){69 c = row.col[j];70 for(i=0; i<c->nw; i++){71 w = c->w[i];72 winlock(w, 'E');73 wx = w->eventx;74 if(wx!=nil && wx->fcall.tag==x->fcall.oldtag){75 w->eventx = nil;76 wx->flushed = TRUE;77 sendp(wx->c, nil);78 winunlock(w);79 goto out;80 }81 winunlock(w);82 }83 }84 out:85 qunlock(&row.lk);86 respond(x, &fc, nil);87 }89 void90 xfidopen(Xfid *x)91 {92 Fcall fc;93 Window *w;94 Text *t;95 char *s;96 Rune *r;97 int m, n, q, q0, q1;99 w = x->f->w;100 t = &w->body;101 q = FILE(x->f->qid);102 if(w){103 winlock(w, 'E');104 switch(q){105 case QWaddr:106 if(w->nopen[q]++ == 0){107 w->addr = range(0, 0);108 w->limit = range(-1,-1);109 }110 break;111 case QWdata:112 case QWxdata:113 w->nopen[q]++;114 break;115 case QWevent:116 if(w->nopen[q]++ == 0){117 if(!w->isdir && w->col!=nil){118 w->filemenu = FALSE;119 winsettag(w);120 }121 }122 break;123 case QWrdsel:124 /*125 * Use a temporary file.126 * A pipe would be the obvious, but we can't afford the127 * broken pipe notification. Using the code to read QWbody128 * is n², which should probably also be fixed. Even then,129 * though, we'd need to squirrel away the data in case it's130 * modified during the operation, e.g. by |sort131 */132 if(w->rdselfd > 0){133 winunlock(w);134 respond(x, &fc, Einuse);135 return;136 }137 w->rdselfd = tempfile();138 if(w->rdselfd < 0){139 winunlock(w);140 respond(x, &fc, "can't create temp file");141 return;142 }143 w->nopen[q]++;144 q0 = t->q0;145 q1 = t->q1;146 r = fbufalloc();147 s = fbufalloc();148 while(q0 < q1){149 n = q1 - q0;150 if(n > BUFSIZE/UTFmax)151 n = BUFSIZE/UTFmax;152 bufread(&t->file->b, q0, r, n);153 m = snprint(s, BUFSIZE+1, "%.*S", n, r);154 if(write(w->rdselfd, s, m) != m){155 warning(nil, "can't write temp file for pipe command %r\n");156 break;157 }158 q0 += n;159 }160 fbuffree(s);161 fbuffree(r);162 break;163 case QWwrsel:164 w->nopen[q]++;165 seq++;166 filemark(t->file);167 cut(t, t, nil, FALSE, TRUE, nil, 0);168 w->wrselrange = range(t->q1, t->q1);169 w->nomark = TRUE;170 break;171 case QWeditout:172 if(editing == FALSE){173 winunlock(w);174 respond(x, &fc, Eperm);175 return;176 }177 if(!canqlock(&w->editoutlk)){178 winunlock(w);179 respond(x, &fc, Einuse);180 return;181 }182 w->wrselrange = range(t->q1, t->q1);183 break;184 }185 winunlock(w);186 }187 else{188 switch(q){189 case Qeditout:190 if(!canqlock(&editoutlk)){191 respond(x, &fc, Einuse);192 return;193 }194 break;195 }196 }197 fc.qid = x->f->qid;198 fc.iounit = messagesize-IOHDRSZ;199 x->f->open = TRUE;200 respond(x, &fc, nil);201 }203 void204 xfidclose(Xfid *x)205 {206 Fcall fc;207 Window *w;208 int q;209 Text *t;211 w = x->f->w;212 x->f->busy = FALSE;213 x->f->w = nil;214 if(x->f->open == FALSE){215 if(w != nil)216 winclose(w);217 respond(x, &fc, nil);218 return;219 }221 q = FILE(x->f->qid);222 x->f->open = FALSE;223 if(w){224 winlock(w, 'E');225 switch(q){226 case QWctl:227 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){228 w->ctlfid = ~0;229 qunlock(&w->ctllock);230 }231 break;232 case QWdata:233 case QWxdata:234 w->nomark = FALSE;235 /* fall through */236 case QWaddr:237 case QWevent: /* BUG: do we need to shut down Xfid? */238 if(--w->nopen[q] == 0){239 if(q == QWdata || q == QWxdata)240 w->nomark = FALSE;241 if(q==QWevent && !w->isdir && w->col!=nil){242 w->filemenu = TRUE;243 winsettag(w);244 }245 if(q == QWevent){246 free(w->dumpstr);247 free(w->dumpdir);248 w->dumpstr = nil;249 w->dumpdir = nil;250 }251 }252 break;253 case QWrdsel:254 close(w->rdselfd);255 w->rdselfd = 0;256 break;257 case QWwrsel:258 w->nomark = FALSE;259 t = &w->body;260 /* before: only did this if !w->noscroll, but that didn't seem right in practice */261 textshow(t, min(w->wrselrange.q0, t->file->b.nc),262 min(w->wrselrange.q1, t->file->b.nc), 1);263 textscrdraw(t);264 break;265 case QWeditout:266 qunlock(&w->editoutlk);267 break;268 }269 winunlock(w);270 winclose(w);271 }272 else{273 switch(q){274 case Qeditout:275 qunlock(&editoutlk);276 break;277 }278 }279 respond(x, &fc, nil);280 }282 void283 xfidread(Xfid *x)284 {285 Fcall fc;286 int n, q;287 uint off;288 char *b;289 char buf[256];290 Window *w;292 q = FILE(x->f->qid);293 w = x->f->w;294 if(w == nil){295 fc.count = 0;296 switch(q){297 case Qcons:298 case Qlabel:299 break;300 case Qindex:301 xfidindexread(x);302 return;303 default:304 warning(nil, "unknown qid %d\n", q);305 break;306 }307 respond(x, &fc, nil);308 return;309 }310 winlock(w, 'F');311 if(w->col == nil){312 winunlock(w);313 respond(x, &fc, Edel);314 return;315 }316 off = x->fcall.offset;317 switch(q){318 case QWaddr:319 textcommit(&w->body, TRUE);320 clampaddr(w);321 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);322 goto Readbuf;324 case QWbody:325 xfidutfread(x, &w->body, w->body.file->b.nc, QWbody);326 break;328 case QWctl:329 b = winctlprint(w, buf, 1);330 goto Readb;332 Readbuf:333 b = buf;334 Readb:335 n = strlen(b);336 if(off > n)337 off = n;338 if(off+x->fcall.count > n)339 x->fcall.count = n-off;340 fc.count = x->fcall.count;341 fc.data = b+off;342 respond(x, &fc, nil);343 if(b != buf)344 free(b);345 break;347 case QWevent:348 xfideventread(x, w);349 break;351 case QWdata:352 /* BUG: what should happen if q1 > q0? */353 if(w->addr.q0 > w->body.file->b.nc){354 respond(x, &fc, Eaddr);355 break;356 }357 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);358 w->addr.q1 = w->addr.q0;359 break;361 case QWxdata:362 /* BUG: what should happen if q1 > q0? */363 if(w->addr.q0 > w->body.file->b.nc){364 respond(x, &fc, Eaddr);365 break;366 }367 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);368 break;370 case QWtag:371 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);372 break;374 case QWrdsel:375 seek(w->rdselfd, off, 0);376 n = x->fcall.count;377 if(n > BUFSIZE)378 n = BUFSIZE;379 b = fbufalloc();380 n = read(w->rdselfd, b, n);381 if(n < 0){382 respond(x, &fc, "I/O error in temp file");383 break;384 }385 fc.count = n;386 fc.data = b;387 respond(x, &fc, nil);388 fbuffree(b);389 break;391 default:392 sprint(buf, "unknown qid %d in read", q);393 respond(x, &fc, nil);394 }395 winunlock(w);396 }398 void399 xfidwrite(Xfid *x)400 {401 Fcall fc;402 int c, cnt, qid, q, nb, nr, eval;403 char buf[64], *err;404 Window *w;405 Rune *r;406 Range a;407 Text *t;408 uint q0, tq0, tq1;410 qid = FILE(x->f->qid);411 w = x->f->w;412 if(w){413 c = 'F';414 if(qid==QWtag || qid==QWbody)415 c = 'E';416 winlock(w, c);417 if(w->col == nil){418 winunlock(w);419 respond(x, &fc, Edel);420 return;421 }422 }423 x->fcall.data[x->fcall.count] = 0;424 switch(qid){425 case Qcons:426 w = errorwin(x->f->mntdir, 'X');427 t=&w->body;428 goto BodyTag;430 case Qlabel:431 fc.count = x->fcall.count;432 respond(x, &fc, nil);433 break;435 case QWaddr:436 x->fcall.data[x->fcall.count] = 0;437 r = bytetorune(x->fcall.data, &nr);438 t = &w->body;439 wincommit(w, t);440 eval = TRUE;441 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);442 free(r);443 if(nb < nr){444 respond(x, &fc, Ebadaddr);445 break;446 }447 if(!eval){448 respond(x, &fc, Eaddr);449 break;450 }451 w->addr = a;452 fc.count = x->fcall.count;453 respond(x, &fc, nil);454 break;456 case Qeditout:457 case QWeditout:458 r = bytetorune(x->fcall.data, &nr);459 if(w)460 err = edittext(w, w->wrselrange.q1, r, nr);461 else462 err = edittext(nil, 0, r, nr);463 free(r);464 if(err != nil){465 respond(x, &fc, err);466 break;467 }468 fc.count = x->fcall.count;469 respond(x, &fc, nil);470 break;472 case QWerrors:473 w = errorwinforwin(w);474 t = &w->body;475 goto BodyTag;477 case QWbody:478 case QWwrsel:479 t = &w->body;480 goto BodyTag;482 case QWctl:483 xfidctlwrite(x, w);484 break;486 case QWdata:487 a = w->addr;488 t = &w->body;489 wincommit(w, t);490 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){491 respond(x, &fc, Eaddr);492 break;493 }494 r = runemalloc(x->fcall.count);495 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);496 if(w->nomark == FALSE){497 seq++;498 filemark(t->file);499 }500 q0 = a.q0;501 if(a.q1 > q0){502 textdelete(t, q0, a.q1, TRUE);503 w->addr.q1 = q0;504 }505 tq0 = t->q0;506 tq1 = t->q1;507 textinsert(t, q0, r, nr, TRUE);508 if(tq0 >= q0)509 tq0 += nr;510 if(tq1 >= q0)511 tq1 += nr;512 textsetselect(t, tq0, tq1);513 if(!t->w->noscroll)514 textshow(t, q0, q0+nr, 0);515 textscrdraw(t);516 winsettag(w);517 free(r);518 w->addr.q0 += nr;519 w->addr.q1 = w->addr.q0;520 fc.count = x->fcall.count;521 respond(x, &fc, nil);522 break;524 case QWevent:525 xfideventwrite(x, w);526 break;528 case QWtag:529 t = &w->tag;530 goto BodyTag;532 BodyTag:533 q = x->f->nrpart;534 cnt = x->fcall.count;535 if(q > 0){536 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */537 memmove(x->fcall.data, x->f->rpart, q);538 cnt += q;539 x->f->nrpart = 0;540 }541 r = runemalloc(cnt);542 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);543 /* approach end of buffer */544 while(fullrune(x->fcall.data+nb, cnt-nb)){545 c = nb;546 nb += chartorune(&r[nr], x->fcall.data+c);547 if(r[nr])548 nr++;549 }550 if(nb < cnt){551 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);552 x->f->nrpart = cnt-nb;553 }554 if(nr > 0){555 wincommit(w, t);556 if(qid == QWwrsel){557 q0 = w->wrselrange.q1;558 if(q0 > t->file->b.nc)559 q0 = t->file->b.nc;560 }else561 q0 = t->file->b.nc;562 if(qid == QWtag)563 textinsert(t, q0, r, nr, TRUE);564 else{565 if(w->nomark == FALSE){566 seq++;567 filemark(t->file);568 }569 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);570 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */571 if(qid!=QWwrsel && !t->w->noscroll)572 textshow(t, q0+nr, q0+nr, 1);573 textscrdraw(t);574 }575 winsettag(w);576 if(qid == QWwrsel)577 w->wrselrange.q1 += nr;578 free(r);579 }580 fc.count = x->fcall.count;581 respond(x, &fc, nil);582 break;584 default:585 sprint(buf, "unknown qid %d in write", qid);586 respond(x, &fc, buf);587 break;588 }589 if(w)590 winunlock(w);591 }593 void594 xfidctlwrite(Xfid *x, Window *w)595 {596 Fcall fc;597 int i, m, n, nb, nr, nulls;598 Rune *r;599 char *err, *p, *pp, *q, *e;600 int isfbuf, scrdraw, settag;601 Text *t;603 err = nil;604 e = x->fcall.data+x->fcall.count;605 scrdraw = FALSE;606 settag = FALSE;607 isfbuf = TRUE;608 if(x->fcall.count < RBUFSIZE)609 r = fbufalloc();610 else{611 isfbuf = FALSE;612 r = emalloc(x->fcall.count*UTFmax+1);613 }614 x->fcall.data[x->fcall.count] = 0;615 textcommit(&w->tag, TRUE);616 for(n=0; n<x->fcall.count; n+=m){617 p = x->fcall.data+n;618 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */619 qlock(&w->ctllock);620 w->ctlfid = x->f->fid;621 m = 4;622 }else623 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */624 w->ctlfid = ~0;625 qunlock(&w->ctllock);626 m = 6;627 }else628 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */629 t = &w->body;630 t->eq0 = ~0;631 filereset(t->file);632 t->file->mod = FALSE;633 w->dirty = FALSE;634 settag = TRUE;635 m = 5;636 }else637 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */638 t = &w->body;639 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */640 t->file->mod = TRUE;641 w->dirty = TRUE;642 settag = TRUE;643 m = 5;644 }else645 if(strncmp(p, "show", 4) == 0){ /* show dot */646 t = &w->body;647 textshow(t, t->q0, t->q1, 1);648 m = 4;649 }else650 if(strncmp(p, "name ", 5) == 0){ /* set file name */651 pp = p+5;652 m = 5;653 q = memchr(pp, '\n', e-pp);654 if(q==nil || q==pp){655 err = Ebadctl;656 break;657 }658 *q = 0;659 nulls = FALSE;660 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);661 if(nulls){662 err = "nulls in file name";663 break;664 }665 for(i=0; i<nr; i++)666 if(r[i] <= ' '){667 err = "bad character in file name";668 goto out;669 }670 out:671 seq++;672 filemark(w->body.file);673 winsetname(w, r, nr);674 m += (q+1) - pp;675 }else676 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */677 pp = p+5;678 m = 5;679 q = memchr(pp, '\n', e-pp);680 if(q==nil || q==pp){681 err = Ebadctl;682 break;683 }684 *q = 0;685 nulls = FALSE;686 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);687 if(nulls){688 err = "nulls in dump string";689 break;690 }691 w->dumpstr = runetobyte(r, nr);692 m += (q+1) - pp;693 }else694 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */695 pp = p+8;696 m = 8;697 q = memchr(pp, '\n', e-pp);698 if(q==nil || q==pp){699 err = Ebadctl;700 break;701 }702 *q = 0;703 nulls = FALSE;704 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);705 if(nulls){706 err = "nulls in dump directory string";707 break;708 }709 w->dumpdir = runetobyte(r, nr);710 m += (q+1) - pp;711 }else712 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */713 colclose(w->col, w, TRUE);714 m = 6;715 }else716 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */717 if(!winclean(w, TRUE)){718 err = "file dirty";719 break;720 }721 colclose(w->col, w, TRUE);722 m = 3;723 }else724 if(strncmp(p, "get", 3) == 0){ /* get file */725 get(&w->body, nil, nil, FALSE, XXX, nil, 0);726 m = 3;727 }else728 if(strncmp(p, "put", 3) == 0){ /* put file */729 put(&w->body, nil, nil, XXX, XXX, nil, 0);730 m = 3;731 }else732 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */733 textcommit(&w->body, TRUE);734 clampaddr(w);735 w->body.q0 = w->addr.q0;736 w->body.q1 = w->addr.q1;737 textsetselect(&w->body, w->body.q0, w->body.q1);738 settag = TRUE;739 m = 8;740 }else741 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */742 w->addr.q0 = w->body.q0;743 w->addr.q1 = w->body.q1;744 m = 8;745 }else746 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */747 textcommit(&w->body, TRUE);748 clampaddr(w);749 w->limit.q0 = w->addr.q0;750 w->limit.q1 = w->addr.q1;751 m = 10;752 }else753 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */754 w->nomark = TRUE;755 m = 6;756 }else757 if(strncmp(p, "mark", 4) == 0){ /* mark file */758 seq++;759 filemark(w->body.file);760 settag = TRUE;761 m = 4;762 }else763 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */764 w->noscroll = TRUE;765 m = 8;766 }else767 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */768 wincleartag(w);769 settag = TRUE;770 m = 8;771 }else772 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */773 w->noscroll = FALSE;774 m = 6;775 }else{776 err = Ebadctl;777 break;778 }779 while(p[m] == '\n')780 m++;781 }783 if(isfbuf)784 fbuffree(r);785 else786 free(r);787 if(err)788 n = 0;789 fc.count = n;790 respond(x, &fc, err);791 if(settag)792 winsettag(w);793 if(scrdraw)794 textscrdraw(&w->body);795 }797 void798 xfideventwrite(Xfid *x, Window *w)799 {800 Fcall fc;801 int m, n;802 Rune *r;803 char *err, *p, *q;804 int isfbuf;805 Text *t;806 int c;807 uint q0, q1;809 err = nil;810 isfbuf = TRUE;811 if(x->fcall.count < RBUFSIZE)812 r = fbufalloc();813 else{814 isfbuf = FALSE;815 r = emalloc(x->fcall.count*UTFmax+1);816 }817 for(n=0; n<x->fcall.count; n+=m){818 p = x->fcall.data+n;819 w->owner = *p++; /* disgusting */820 c = *p++;821 while(*p == ' ')822 p++;823 q0 = strtoul(p, &q, 10);824 if(q == p)825 goto Rescue;826 p = q;827 while(*p == ' ')828 p++;829 q1 = strtoul(p, &q, 10);830 if(q == p)831 goto Rescue;832 p = q;833 while(*p == ' ')834 p++;835 if(*p++ != '\n')836 goto Rescue;837 m = p-(x->fcall.data+n);838 if('a'<=c && c<='z')839 t = &w->tag;840 else if('A'<=c && c<='Z')841 t = &w->body;842 else843 goto Rescue;844 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)845 goto Rescue;847 qlock(&row.lk); /* just like mousethread */848 switch(c){849 case 'x':850 case 'X':851 execute(t, q0, q1, TRUE, nil);852 break;853 case 'l':854 case 'L':855 look3(t, q0, q1, TRUE);856 break;857 default:858 qunlock(&row.lk);859 goto Rescue;860 }861 qunlock(&row.lk);863 }865 Out:866 if(isfbuf)867 fbuffree(r);868 else869 free(r);870 if(err)871 n = 0;872 fc.count = n;873 respond(x, &fc, err);874 return;876 Rescue:877 err = Ebadevent;878 goto Out;879 }881 void882 xfidutfread(Xfid *x, Text *t, uint q1, int qid)883 {884 Fcall fc;885 Window *w;886 Rune *r;887 char *b, *b1;888 uint q, off, boff;889 int m, n, nr, nb;891 w = t->w;892 wincommit(w, t);893 off = x->fcall.offset;894 r = fbufalloc();895 b = fbufalloc();896 b1 = fbufalloc();897 n = 0;898 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){899 boff = w->utflastboff;900 q = w->utflastq;901 }else{902 /* BUG: stupid code: scan from beginning */903 boff = 0;904 q = 0;905 }906 w->utflastqid = qid;907 while(q<q1 && n<x->fcall.count){908 /*909 * Updating here avoids partial rune problem: we're always on a910 * char boundary. The cost is we will usually do one more read911 * than we really need, but that's better than being n^2.912 */913 w->utflastboff = boff;914 w->utflastq = q;915 nr = q1-q;916 if(nr > BUFSIZE/UTFmax)917 nr = BUFSIZE/UTFmax;918 bufread(&t->file->b, q, r, nr);919 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);920 if(boff >= off){921 m = nb;922 if(boff+m > off+x->fcall.count)923 m = off+x->fcall.count - boff;924 memmove(b1+n, b, m);925 n += m;926 }else if(boff+nb > off){927 if(n != 0)928 error("bad count in utfrune");929 m = nb - (off-boff);930 if(m > x->fcall.count)931 m = x->fcall.count;932 memmove(b1, b+(off-boff), m);933 n += m;934 }935 boff += nb;936 q += nr;937 }938 fbuffree(r);939 fbuffree(b);940 fc.count = n;941 fc.data = b1;942 respond(x, &fc, nil);943 fbuffree(b1);944 }946 int947 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)948 {949 Fcall fc;950 Window *w;951 Rune *r, junk;952 char *b, *b1;953 uint q, boff;954 int i, rw, m, n, nr, nb;956 w = t->w;957 wincommit(w, t);958 r = fbufalloc();959 b = fbufalloc();960 b1 = fbufalloc();961 n = 0;962 q = q0;963 boff = 0;964 while(q<q1 && n<x->fcall.count){965 nr = q1-q;966 if(nr > BUFSIZE/UTFmax)967 nr = BUFSIZE/UTFmax;968 bufread(&t->file->b, q, r, nr);969 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);970 m = nb;971 if(boff+m > x->fcall.count){972 i = x->fcall.count - boff;973 /* copy whole runes only */974 m = 0;975 nr = 0;976 while(m < i){977 rw = chartorune(&junk, b+m);978 if(m+rw > i)979 break;980 m += rw;981 nr++;982 }983 if(m == 0)984 break;985 }986 memmove(b1+n, b, m);987 n += m;988 boff += nb;989 q += nr;990 }991 fbuffree(r);992 fbuffree(b);993 fc.count = n;994 fc.data = b1;995 respond(x, &fc, nil);996 fbuffree(b1);997 return q-q0;998 }1000 void1001 xfideventread(Xfid *x, Window *w)1002 {1003 Fcall fc;1004 int i, n;1006 i = 0;1007 x->flushed = FALSE;1008 while(w->nevents == 0){1009 if(i){1010 if(!x->flushed)1011 respond(x, &fc, "window shut down");1012 return;1013 }1014 w->eventx = x;1015 winunlock(w);1016 recvp(x->c);1017 winlock(w, 'F');1018 i++;1019 }1021 n = w->nevents;1022 if(n > x->fcall.count)1023 n = x->fcall.count;1024 fc.count = n;1025 fc.data = w->events;1026 respond(x, &fc, nil);1027 w->nevents -= n;1028 if(w->nevents){1029 memmove(w->events, w->events+n, w->nevents);1030 w->events = erealloc(w->events, w->nevents);1031 }else{1032 free(w->events);1033 w->events = nil;1034 }1035 }1037 void1038 xfidindexread(Xfid *x)1039 {1040 Fcall fc;1041 int i, j, m, n, nmax, isbuf, cnt, off;1042 Window *w;1043 char *b;1044 Rune *r;1045 Column *c;1047 qlock(&row.lk);1048 nmax = 0;1049 for(j=0; j<row.ncol; j++){1050 c = row.col[j];1051 for(i=0; i<c->nw; i++){1052 w = c->w[i];1053 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1054 }1055 }1056 nmax++;1057 isbuf = (nmax<=RBUFSIZE);1058 if(isbuf)1059 b = (char*)x->buf;1060 else1061 b = emalloc(nmax);1062 r = fbufalloc();1063 n = 0;1064 for(j=0; j<row.ncol; j++){1065 c = row.col[j];1066 for(i=0; i<c->nw; i++){1067 w = c->w[i];1068 /* only show the currently active window of a set */1069 if(w->body.file->curtext != &w->body)1070 continue;1071 winctlprint(w, b+n, 0);1072 n += Ctlsize;1073 m = min(RBUFSIZE, w->tag.file->b.nc);1074 bufread(&w->tag.file->b, 0, r, m);1075 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1076 while(n<m && b[n]!='\n')1077 n++;1078 b[n++] = '\n';1079 }1080 }1081 qunlock(&row.lk);1082 off = x->fcall.offset;1083 cnt = x->fcall.count;1084 if(off > n)1085 off = n;1086 if(off+cnt > n)1087 cnt = n-off;1088 fc.count = cnt;1089 memmove(r, b+off, cnt);1090 fc.data = (char*)r;1091 if(!isbuf)1092 free(b);1093 respond(x, &fc, nil);1094 fbuffree(r);1095 }