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 if(w){102 winlock(w, 'E');103 q = FILE(x->f->qid);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 w->wrselrange = range(t->q1, t->q1);178 break;179 }180 winunlock(w);181 }182 fc.qid = x->f->qid;183 fc.iounit = messagesize-IOHDRSZ;184 x->f->open = TRUE;185 respond(x, &fc, nil);186 }188 void189 xfidclose(Xfid *x)190 {191 Fcall fc;192 Window *w;193 int q;194 Text *t;196 w = x->f->w;197 x->f->busy = FALSE;198 x->f->w = nil;199 if(x->f->open == FALSE){200 if(w != nil)201 winclose(w);202 respond(x, &fc, nil);203 return;204 }206 x->f->open = FALSE;207 if(w){208 winlock(w, 'E');209 q = FILE(x->f->qid);210 switch(q){211 case QWctl:212 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){213 w->ctlfid = ~0;214 qunlock(&w->ctllock);215 }216 break;217 case QWdata:218 case QWxdata:219 w->nomark = FALSE;220 /* fall through */221 case QWaddr:222 case QWevent: /* BUG: do we need to shut down Xfid? */223 if(--w->nopen[q] == 0){224 if(q == QWdata || q == QWxdata)225 w->nomark = FALSE;226 if(q==QWevent && !w->isdir && w->col!=nil){227 w->filemenu = TRUE;228 winsettag(w);229 }230 if(q == QWevent){231 free(w->dumpstr);232 free(w->dumpdir);233 w->dumpstr = nil;234 w->dumpdir = nil;235 }236 }237 break;238 case QWrdsel:239 close(w->rdselfd);240 w->rdselfd = 0;241 break;242 case QWwrsel:243 w->nomark = FALSE;244 t = &w->body;245 /* before: only did this if !w->noscroll, but that didn't seem right in practice */246 textshow(t, min(w->wrselrange.q0, t->file->b.nc),247 min(w->wrselrange.q1, t->file->b.nc), 1);248 textscrdraw(t);249 break;250 }251 winunlock(w);252 winclose(w);253 }254 respond(x, &fc, nil);255 }257 void258 xfidread(Xfid *x)259 {260 Fcall fc;261 int n, q;262 uint off;263 char *b;264 char buf[256];265 Window *w;267 q = FILE(x->f->qid);268 w = x->f->w;269 if(w == nil){270 fc.count = 0;271 switch(q){272 case Qcons:273 case Qlabel:274 break;275 case Qindex:276 xfidindexread(x);277 return;278 default:279 warning(nil, "unknown qid %d\n", q);280 break;281 }282 respond(x, &fc, nil);283 return;284 }285 winlock(w, 'F');286 if(w->col == nil){287 winunlock(w);288 respond(x, &fc, Edel);289 return;290 }291 off = x->fcall.offset;292 switch(q){293 case QWaddr:294 textcommit(&w->body, TRUE);295 clampaddr(w);296 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);297 goto Readbuf;299 case QWbody:300 xfidutfread(x, &w->body, w->body.file->b.nc, QWbody);301 break;303 case QWctl:304 b = winctlprint(w, buf, 1);305 goto Readb;307 Readbuf:308 b = buf;309 Readb:310 n = strlen(b);311 if(off > n)312 off = n;313 if(off+x->fcall.count > n)314 x->fcall.count = n-off;315 fc.count = x->fcall.count;316 fc.data = b+off;317 respond(x, &fc, nil);318 if(b != buf)319 free(b);320 break;322 case QWevent:323 xfideventread(x, w);324 break;326 case QWdata:327 /* BUG: what should happen if q1 > q0? */328 if(w->addr.q0 > w->body.file->b.nc){329 respond(x, &fc, Eaddr);330 break;331 }332 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);333 w->addr.q1 = w->addr.q0;334 break;336 case QWxdata:337 /* BUG: what should happen if q1 > q0? */338 if(w->addr.q0 > w->body.file->b.nc){339 respond(x, &fc, Eaddr);340 break;341 }342 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);343 break;345 case QWtag:346 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);347 break;349 case QWrdsel:350 seek(w->rdselfd, off, 0);351 n = x->fcall.count;352 if(n > BUFSIZE)353 n = BUFSIZE;354 b = fbufalloc();355 n = read(w->rdselfd, b, n);356 if(n < 0){357 respond(x, &fc, "I/O error in temp file");358 break;359 }360 fc.count = n;361 fc.data = b;362 respond(x, &fc, nil);363 fbuffree(b);364 break;366 default:367 sprint(buf, "unknown qid %d in read", q);368 respond(x, &fc, nil);369 }370 winunlock(w);371 }373 void374 xfidwrite(Xfid *x)375 {376 Fcall fc;377 int c, cnt, qid, q, nb, nr, eval;378 char buf[64], *err;379 Window *w;380 Rune *r;381 Range a;382 Text *t;383 uint q0, tq0, tq1;385 qid = FILE(x->f->qid);386 w = x->f->w;387 if(w){388 c = 'F';389 if(qid==QWtag || qid==QWbody)390 c = 'E';391 winlock(w, c);392 if(w->col == nil){393 winunlock(w);394 respond(x, &fc, Edel);395 return;396 }397 }398 x->fcall.data[x->fcall.count] = 0;399 switch(qid){400 case Qcons:401 w = errorwin(x->f->mntdir, 'X');402 t=&w->body;403 goto BodyTag;405 case Qlabel:406 fc.count = x->fcall.count;407 respond(x, &fc, nil);408 break;410 case QWaddr:411 x->fcall.data[x->fcall.count] = 0;412 r = bytetorune(x->fcall.data, &nr);413 t = &w->body;414 wincommit(w, t);415 eval = TRUE;416 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);417 free(r);418 if(nb < nr){419 respond(x, &fc, Ebadaddr);420 break;421 }422 if(!eval){423 respond(x, &fc, Eaddr);424 break;425 }426 w->addr = a;427 fc.count = x->fcall.count;428 respond(x, &fc, nil);429 break;431 case Qeditout:432 case QWeditout:433 r = bytetorune(x->fcall.data, &nr);434 if(w)435 err = edittext(w, w->wrselrange.q1, r, nr);436 else437 err = edittext(nil, 0, r, nr);438 free(r);439 if(err != nil){440 respond(x, &fc, err);441 break;442 }443 fc.count = x->fcall.count;444 respond(x, &fc, nil);445 break;447 case QWerrors:448 w = errorwinforwin(w);449 t = &w->body;450 goto BodyTag;452 case QWbody:453 case QWwrsel:454 t = &w->body;455 goto BodyTag;457 case QWctl:458 xfidctlwrite(x, w);459 break;461 case QWdata:462 a = w->addr;463 t = &w->body;464 wincommit(w, t);465 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){466 respond(x, &fc, Eaddr);467 break;468 }469 r = runemalloc(x->fcall.count);470 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);471 if(w->nomark == FALSE){472 seq++;473 filemark(t->file);474 }475 q0 = a.q0;476 if(a.q1 > q0){477 textdelete(t, q0, a.q1, TRUE);478 w->addr.q1 = q0;479 }480 tq0 = t->q0;481 tq1 = t->q1;482 textinsert(t, q0, r, nr, TRUE);483 if(tq0 >= q0)484 tq0 += nr;485 if(tq1 >= q0)486 tq1 += nr;487 textsetselect(t, tq0, tq1);488 if(!t->w->noscroll)489 textshow(t, q0, q0+nr, 0);490 textscrdraw(t);491 winsettag(w);492 free(r);493 w->addr.q0 += nr;494 w->addr.q1 = w->addr.q0;495 fc.count = x->fcall.count;496 respond(x, &fc, nil);497 break;499 case QWevent:500 xfideventwrite(x, w);501 break;503 case QWtag:504 t = &w->tag;505 goto BodyTag;507 BodyTag:508 q = x->f->nrpart;509 cnt = x->fcall.count;510 if(q > 0){511 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */512 memmove(x->fcall.data, x->f->rpart, q);513 cnt += q;514 x->f->nrpart = 0;515 }516 r = runemalloc(cnt);517 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);518 /* approach end of buffer */519 while(fullrune(x->fcall.data+nb, cnt-nb)){520 c = nb;521 nb += chartorune(&r[nr], x->fcall.data+c);522 if(r[nr])523 nr++;524 }525 if(nb < cnt){526 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);527 x->f->nrpart = cnt-nb;528 }529 if(nr > 0){530 wincommit(w, t);531 if(qid == QWwrsel){532 q0 = w->wrselrange.q1;533 if(q0 > t->file->b.nc)534 q0 = t->file->b.nc;535 }else536 q0 = t->file->b.nc;537 if(qid == QWtag)538 textinsert(t, q0, r, nr, TRUE);539 else{540 if(w->nomark == FALSE){541 seq++;542 filemark(t->file);543 }544 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);545 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */546 if(qid!=QWwrsel && !t->w->noscroll)547 textshow(t, q0+nr, q0+nr, 1);548 textscrdraw(t);549 }550 winsettag(w);551 if(qid == QWwrsel)552 w->wrselrange.q1 += nr;553 free(r);554 }555 fc.count = x->fcall.count;556 respond(x, &fc, nil);557 break;559 default:560 sprint(buf, "unknown qid %d in write", qid);561 respond(x, &fc, buf);562 break;563 }564 if(w)565 winunlock(w);566 }568 void569 xfidctlwrite(Xfid *x, Window *w)570 {571 Fcall fc;572 int i, m, n, nb, nr, nulls;573 Rune *r;574 char *err, *p, *pp, *q, *e;575 int isfbuf, scrdraw, settag;576 Text *t;578 err = nil;579 e = x->fcall.data+x->fcall.count;580 scrdraw = FALSE;581 settag = FALSE;582 isfbuf = TRUE;583 if(x->fcall.count < RBUFSIZE)584 r = fbufalloc();585 else{586 isfbuf = FALSE;587 r = emalloc(x->fcall.count*UTFmax+1);588 }589 x->fcall.data[x->fcall.count] = 0;590 textcommit(&w->tag, TRUE);591 for(n=0; n<x->fcall.count; n+=m){592 p = x->fcall.data+n;593 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */594 qlock(&w->ctllock);595 w->ctlfid = x->f->fid;596 m = 4;597 }else598 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */599 w->ctlfid = ~0;600 qunlock(&w->ctllock);601 m = 6;602 }else603 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */604 t = &w->body;605 t->eq0 = ~0;606 filereset(t->file);607 t->file->mod = FALSE;608 w->dirty = FALSE;609 settag = TRUE;610 m = 5;611 }else612 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */613 t = &w->body;614 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */615 t->file->mod = TRUE;616 w->dirty = TRUE;617 settag = TRUE;618 m = 5;619 }else620 if(strncmp(p, "show", 4) == 0){ /* show dot */621 t = &w->body;622 textshow(t, t->q0, t->q1, 1);623 m = 4;624 }else625 if(strncmp(p, "name ", 5) == 0){ /* set file name */626 pp = p+5;627 m = 5;628 q = memchr(pp, '\n', e-pp);629 if(q==nil || q==pp){630 err = Ebadctl;631 break;632 }633 *q = 0;634 nulls = FALSE;635 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);636 if(nulls){637 err = "nulls in file name";638 break;639 }640 for(i=0; i<nr; i++)641 if(r[i] <= ' '){642 err = "bad character in file name";643 goto out;644 }645 out:646 seq++;647 filemark(w->body.file);648 winsetname(w, r, nr);649 m += (q+1) - pp;650 }else651 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */652 pp = p+5;653 m = 5;654 q = memchr(pp, '\n', e-pp);655 if(q==nil || q==pp){656 err = Ebadctl;657 break;658 }659 *q = 0;660 nulls = FALSE;661 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);662 if(nulls){663 err = "nulls in dump string";664 break;665 }666 w->dumpstr = runetobyte(r, nr);667 m += (q+1) - pp;668 }else669 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */670 pp = p+8;671 m = 8;672 q = memchr(pp, '\n', e-pp);673 if(q==nil || q==pp){674 err = Ebadctl;675 break;676 }677 *q = 0;678 nulls = FALSE;679 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);680 if(nulls){681 err = "nulls in dump directory string";682 break;683 }684 w->dumpdir = runetobyte(r, nr);685 m += (q+1) - pp;686 }else687 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */688 colclose(w->col, w, TRUE);689 m = 6;690 }else691 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */692 if(!winclean(w, TRUE)){693 err = "file dirty";694 break;695 }696 colclose(w->col, w, TRUE);697 m = 3;698 }else699 if(strncmp(p, "get", 3) == 0){ /* get file */700 get(&w->body, nil, nil, FALSE, XXX, nil, 0);701 m = 3;702 }else703 if(strncmp(p, "put", 3) == 0){ /* put file */704 put(&w->body, nil, nil, XXX, XXX, nil, 0);705 m = 3;706 }else707 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */708 textcommit(&w->body, TRUE);709 clampaddr(w);710 w->body.q0 = w->addr.q0;711 w->body.q1 = w->addr.q1;712 textsetselect(&w->body, w->body.q0, w->body.q1);713 settag = TRUE;714 m = 8;715 }else716 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */717 w->addr.q0 = w->body.q0;718 w->addr.q1 = w->body.q1;719 m = 8;720 }else721 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */722 textcommit(&w->body, TRUE);723 clampaddr(w);724 w->limit.q0 = w->addr.q0;725 w->limit.q1 = w->addr.q1;726 m = 10;727 }else728 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */729 w->nomark = TRUE;730 m = 6;731 }else732 if(strncmp(p, "mark", 4) == 0){ /* mark file */733 seq++;734 filemark(w->body.file);735 settag = TRUE;736 m = 4;737 }else738 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */739 w->noscroll = TRUE;740 m = 8;741 }else742 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */743 wincleartag(w);744 settag = TRUE;745 m = 8;746 }else747 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */748 w->noscroll = FALSE;749 m = 6;750 }else{751 err = Ebadctl;752 break;753 }754 while(p[m] == '\n')755 m++;756 }758 if(isfbuf)759 fbuffree(r);760 else761 free(r);762 if(err)763 n = 0;764 fc.count = n;765 respond(x, &fc, err);766 if(settag)767 winsettag(w);768 if(scrdraw)769 textscrdraw(&w->body);770 }772 void773 xfideventwrite(Xfid *x, Window *w)774 {775 Fcall fc;776 int m, n;777 Rune *r;778 char *err, *p, *q;779 int isfbuf;780 Text *t;781 int c;782 uint q0, q1;784 err = nil;785 isfbuf = TRUE;786 if(x->fcall.count < RBUFSIZE)787 r = fbufalloc();788 else{789 isfbuf = FALSE;790 r = emalloc(x->fcall.count*UTFmax+1);791 }792 for(n=0; n<x->fcall.count; n+=m){793 p = x->fcall.data+n;794 w->owner = *p++; /* disgusting */795 c = *p++;796 while(*p == ' ')797 p++;798 q0 = strtoul(p, &q, 10);799 if(q == p)800 goto Rescue;801 p = q;802 while(*p == ' ')803 p++;804 q1 = strtoul(p, &q, 10);805 if(q == p)806 goto Rescue;807 p = q;808 while(*p == ' ')809 p++;810 if(*p++ != '\n')811 goto Rescue;812 m = p-(x->fcall.data+n);813 if('a'<=c && c<='z')814 t = &w->tag;815 else if('A'<=c && c<='Z')816 t = &w->body;817 else818 goto Rescue;819 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)820 goto Rescue;822 qlock(&row.lk); /* just like mousethread */823 switch(c){824 case 'x':825 case 'X':826 execute(t, q0, q1, TRUE, nil);827 break;828 case 'l':829 case 'L':830 look3(t, q0, q1, TRUE);831 break;832 default:833 qunlock(&row.lk);834 goto Rescue;835 }836 qunlock(&row.lk);838 }840 Out:841 if(isfbuf)842 fbuffree(r);843 else844 free(r);845 if(err)846 n = 0;847 fc.count = n;848 respond(x, &fc, err);849 return;851 Rescue:852 err = Ebadevent;853 goto Out;854 }856 void857 xfidutfread(Xfid *x, Text *t, uint q1, int qid)858 {859 Fcall fc;860 Window *w;861 Rune *r;862 char *b, *b1;863 uint q, off, boff;864 int m, n, nr, nb;866 w = t->w;867 wincommit(w, t);868 off = x->fcall.offset;869 r = fbufalloc();870 b = fbufalloc();871 b1 = fbufalloc();872 n = 0;873 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){874 boff = w->utflastboff;875 q = w->utflastq;876 }else{877 /* BUG: stupid code: scan from beginning */878 boff = 0;879 q = 0;880 }881 w->utflastqid = qid;882 while(q<q1 && n<x->fcall.count){883 /*884 * Updating here avoids partial rune problem: we're always on a885 * char boundary. The cost is we will usually do one more read886 * than we really need, but that's better than being n^2.887 */888 w->utflastboff = boff;889 w->utflastq = q;890 nr = q1-q;891 if(nr > BUFSIZE/UTFmax)892 nr = BUFSIZE/UTFmax;893 bufread(&t->file->b, q, r, nr);894 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);895 if(boff >= off){896 m = nb;897 if(boff+m > off+x->fcall.count)898 m = off+x->fcall.count - boff;899 memmove(b1+n, b, m);900 n += m;901 }else if(boff+nb > off){902 if(n != 0)903 error("bad count in utfrune");904 m = nb - (off-boff);905 if(m > x->fcall.count)906 m = x->fcall.count;907 memmove(b1, b+(off-boff), m);908 n += m;909 }910 boff += nb;911 q += nr;912 }913 fbuffree(r);914 fbuffree(b);915 fc.count = n;916 fc.data = b1;917 respond(x, &fc, nil);918 fbuffree(b1);919 }921 int922 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)923 {924 Fcall fc;925 Window *w;926 Rune *r, junk;927 char *b, *b1;928 uint q, boff;929 int i, rw, m, n, nr, nb;931 w = t->w;932 wincommit(w, t);933 r = fbufalloc();934 b = fbufalloc();935 b1 = fbufalloc();936 n = 0;937 q = q0;938 boff = 0;939 while(q<q1 && n<x->fcall.count){940 nr = q1-q;941 if(nr > BUFSIZE/UTFmax)942 nr = BUFSIZE/UTFmax;943 bufread(&t->file->b, q, r, nr);944 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);945 m = nb;946 if(boff+m > x->fcall.count){947 i = x->fcall.count - boff;948 /* copy whole runes only */949 m = 0;950 nr = 0;951 while(m < i){952 rw = chartorune(&junk, b+m);953 if(m+rw > i)954 break;955 m += rw;956 nr++;957 }958 if(m == 0)959 break;960 }961 memmove(b1+n, b, m);962 n += m;963 boff += nb;964 q += nr;965 }966 fbuffree(r);967 fbuffree(b);968 fc.count = n;969 fc.data = b1;970 respond(x, &fc, nil);971 fbuffree(b1);972 return q-q0;973 }975 void976 xfideventread(Xfid *x, Window *w)977 {978 Fcall fc;979 char *b;980 int i, n;982 i = 0;983 x->flushed = FALSE;984 while(w->nevents == 0){985 if(i){986 if(!x->flushed)987 respond(x, &fc, "window shut down");988 return;989 }990 w->eventx = x;991 winunlock(w);992 recvp(x->c);993 winlock(w, 'F');994 i++;995 }997 n = w->nevents;998 if(n > x->fcall.count)999 n = x->fcall.count;1000 fc.count = n;1001 fc.data = w->events;1002 respond(x, &fc, nil);1003 b = w->events;1004 w->events = estrdup(w->events+n);1005 free(b);1006 w->nevents -= n;1007 }1009 void1010 xfidindexread(Xfid *x)1011 {1012 Fcall fc;1013 int i, j, m, n, nmax, isbuf, cnt, off;1014 Window *w;1015 char *b;1016 Rune *r;1017 Column *c;1019 qlock(&row.lk);1020 nmax = 0;1021 for(j=0; j<row.ncol; j++){1022 c = row.col[j];1023 for(i=0; i<c->nw; i++){1024 w = c->w[i];1025 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1026 }1027 }1028 nmax++;1029 isbuf = (nmax<=RBUFSIZE);1030 if(isbuf)1031 b = (char*)x->buf;1032 else1033 b = emalloc(nmax);1034 r = fbufalloc();1035 n = 0;1036 for(j=0; j<row.ncol; j++){1037 c = row.col[j];1038 for(i=0; i<c->nw; i++){1039 w = c->w[i];1040 /* only show the currently active window of a set */1041 if(w->body.file->curtext != &w->body)1042 continue;1043 winctlprint(w, b+n, 0);1044 n += Ctlsize;1045 m = min(RBUFSIZE, w->tag.file->b.nc);1046 bufread(&w->tag.file->b, 0, r, m);1047 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1048 while(n<m && b[n]!='\n')1049 n++;1050 b[n++] = '\n';1051 }1052 }1053 qunlock(&row.lk);1054 off = x->fcall.offset;1055 cnt = x->fcall.count;1056 if(off > n)1057 off = n;1058 if(off+cnt > n)1059 cnt = n-off;1060 fc.count = cnt;1061 memmove(r, b+off, cnt);1062 fc.data = (char*)r;1063 if(!isbuf)1064 free(b);1065 respond(x, &fc, nil);1066 fbuffree(r);1067 }