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 w->nopen[q]++;107 w->limit = range(-1,-1);108 break;109 case QWevent:110 if(w->nopen[q]++ == 0){111 if(!w->isdir && w->col!=nil){112 w->filemenu = FALSE;113 winsettag(w);114 }115 }116 break;117 case QWrdsel:118 /*119 * Use a temporary file.120 * A pipe would be the obvious, but we can't afford the121 * broken pipe notification. Using the code to read QWbody122 * is n², which should probably also be fixed. Even then,123 * though, we'd need to squirrel away the data in case it's124 * modified during the operation, e.g. by |sort125 */126 if(w->rdselfd > 0){127 winunlock(w);128 respond(x, &fc, Einuse);129 return;130 }131 w->rdselfd = tempfile();132 if(w->rdselfd < 0){133 winunlock(w);134 respond(x, &fc, "can't create temp file");135 return;136 }137 w->nopen[q]++;138 q0 = t->q0;139 q1 = t->q1;140 r = fbufalloc();141 s = fbufalloc();142 while(q0 < q1){143 n = q1 - q0;144 if(n > BUFSIZE/UTFmax)145 n = BUFSIZE/UTFmax;146 bufread(&t->file->b, q0, r, n);147 m = snprint(s, BUFSIZE+1, "%.*S", n, r);148 if(write(w->rdselfd, s, m) != m){149 warning(nil, "can't write temp file for pipe command %r\n");150 break;151 }152 q0 += n;153 }154 fbuffree(s);155 fbuffree(r);156 break;157 case QWwrsel:158 w->nopen[q]++;159 seq++;160 filemark(t->file);161 cut(t, t, nil, FALSE, TRUE, nil, 0);162 w->wrselrange = range(t->q1, t->q1);163 w->nomark = TRUE;164 break;165 case QWeditout:166 if(editing == FALSE){167 winunlock(w);168 respond(x, &fc, Eperm);169 return;170 }171 w->wrselrange = range(t->q1, t->q1);172 break;173 }174 winunlock(w);175 }176 fc.qid = x->f->qid;177 fc.iounit = messagesize-IOHDRSZ;178 x->f->open = TRUE;179 respond(x, &fc, nil);180 }182 void183 xfidclose(Xfid *x)184 {185 Fcall fc;186 Window *w;187 int q;188 Text *t;190 w = x->f->w;191 x->f->busy = FALSE;192 x->f->w = nil;193 if(x->f->open == FALSE){194 if(w != nil)195 winclose(w);196 respond(x, &fc, nil);197 return;198 }200 x->f->open = FALSE;201 if(w){202 winlock(w, 'E');203 q = FILE(x->f->qid);204 switch(q){205 case QWctl:206 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){207 w->ctlfid = ~0;208 qunlock(&w->ctllock);209 }210 break;211 case QWdata:212 case QWxdata:213 w->nomark = FALSE;214 /* fall through */215 case QWaddr:216 case QWevent: /* BUG: do we need to shut down Xfid? */217 if(--w->nopen[q] == 0){218 if(q == QWdata || q == QWxdata)219 w->nomark = FALSE;220 if(q==QWevent && !w->isdir && w->col!=nil){221 w->filemenu = TRUE;222 winsettag(w);223 }224 if(q == QWevent){225 free(w->dumpstr);226 free(w->dumpdir);227 w->dumpstr = nil;228 w->dumpdir = nil;229 }230 }231 break;232 case QWrdsel:233 close(w->rdselfd);234 w->rdselfd = 0;235 break;236 case QWwrsel:237 w->nomark = FALSE;238 t = &w->body;239 /* before: only did this if !w->noscroll, but that didn't seem right in practice */240 textshow(t, min(w->wrselrange.q0, t->file->b.nc),241 min(w->wrselrange.q1, t->file->b.nc), 1);242 textscrdraw(t);243 break;244 }245 winunlock(w);246 winclose(w);247 }248 respond(x, &fc, nil);249 }251 void252 xfidread(Xfid *x)253 {254 Fcall fc;255 int n, q;256 uint off;257 char *b;258 char buf[128];259 Window *w;261 q = FILE(x->f->qid);262 w = x->f->w;263 if(w == nil){264 fc.count = 0;265 switch(q){266 case Qcons:267 case Qlabel:268 break;269 case Qindex:270 xfidindexread(x);271 return;272 default:273 warning(nil, "unknown qid %d\n", q);274 break;275 }276 respond(x, &fc, nil);277 return;278 }279 winlock(w, 'F');280 if(w->col == nil){281 winunlock(w);282 respond(x, &fc, Edel);283 return;284 }285 off = x->fcall.offset;286 switch(q){287 case QWaddr:288 textcommit(&w->body, TRUE);289 clampaddr(w);290 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);291 goto Readbuf;293 case QWbody:294 xfidutfread(x, &w->body, w->body.file->b.nc, QWbody);295 break;297 case QWctl:298 winctlprint(w, buf, 1);299 goto Readbuf;301 Readbuf:302 n = strlen(buf);303 if(off > n)304 off = n;305 if(off+x->fcall.count > n)306 x->fcall.count = n-off;307 fc.count = x->fcall.count;308 fc.data = buf+off;309 respond(x, &fc, nil);310 break;312 case QWevent:313 xfideventread(x, w);314 break;316 case QWdata:317 /* BUG: what should happen if q1 > q0? */318 if(w->addr.q0 > w->body.file->b.nc){319 respond(x, &fc, Eaddr);320 break;321 }322 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);323 w->addr.q1 = w->addr.q0;324 break;326 case QWxdata: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->addr.q1);333 break;335 case QWtag:336 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);337 break;339 case QWrdsel:340 seek(w->rdselfd, off, 0);341 n = x->fcall.count;342 if(n > BUFSIZE)343 n = BUFSIZE;344 b = fbufalloc();345 n = read(w->rdselfd, b, n);346 if(n < 0){347 respond(x, &fc, "I/O error in temp file");348 break;349 }350 fc.count = n;351 fc.data = b;352 respond(x, &fc, nil);353 fbuffree(b);354 break;356 default:357 sprint(buf, "unknown qid %d in read", q);358 respond(x, &fc, nil);359 }360 winunlock(w);361 }363 void364 xfidwrite(Xfid *x)365 {366 Fcall fc;367 int c, cnt, qid, q, nb, nr, eval;368 char buf[64], *err;369 Window *w;370 Rune *r;371 Range a;372 Text *t;373 uint q0, tq0, tq1;375 qid = FILE(x->f->qid);376 w = x->f->w;377 if(w){378 c = 'F';379 if(qid==QWtag || qid==QWbody)380 c = 'E';381 winlock(w, c);382 if(w->col == nil){383 winunlock(w);384 respond(x, &fc, Edel);385 return;386 }387 }388 x->fcall.data[x->fcall.count] = 0;389 switch(qid){390 case Qcons:391 w = errorwin(x->f->mntdir, 'X');392 t=&w->body;393 goto BodyTag;395 case Qlabel:396 fc.count = x->fcall.count;397 respond(x, &fc, nil);398 break;400 case QWaddr:401 x->fcall.data[x->fcall.count] = 0;402 r = bytetorune(x->fcall.data, &nr);403 t = &w->body;404 wincommit(w, t);405 eval = TRUE;406 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);407 free(r);408 if(nb < nr){409 respond(x, &fc, Ebadaddr);410 break;411 }412 if(!eval){413 respond(x, &fc, Eaddr);414 break;415 }416 w->addr = a;417 fc.count = x->fcall.count;418 respond(x, &fc, nil);419 break;421 case Qeditout:422 case QWeditout:423 r = bytetorune(x->fcall.data, &nr);424 if(w)425 err = edittext(w, w->wrselrange.q1, r, nr);426 else427 err = edittext(nil, 0, r, nr);428 free(r);429 if(err != nil){430 respond(x, &fc, err);431 break;432 }433 fc.count = x->fcall.count;434 respond(x, &fc, nil);435 break;437 case QWbody:438 case QWwrsel:439 t = &w->body;440 goto BodyTag;442 case QWctl:443 xfidctlwrite(x, w);444 break;446 case QWdata:447 a = w->addr;448 t = &w->body;449 wincommit(w, t);450 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){451 respond(x, &fc, Eaddr);452 break;453 }454 r = runemalloc(x->fcall.count);455 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);456 if(w->nomark == FALSE){457 seq++;458 filemark(t->file);459 }460 q0 = a.q0;461 if(a.q1 > q0){462 textdelete(t, q0, a.q1, TRUE);463 w->addr.q1 = q0;464 }465 tq0 = t->q0;466 tq1 = t->q1;467 textinsert(t, q0, r, nr, TRUE);468 if(tq0 >= q0)469 tq0 += nr;470 if(tq1 >= q0)471 tq1 += nr;472 textsetselect(t, tq0, tq1);473 if(!t->w->noscroll)474 textshow(t, q0, q0+nr, 0);475 textscrdraw(t);476 winsettag(w);477 free(r);478 w->addr.q0 += nr;479 w->addr.q1 = w->addr.q0;480 fc.count = x->fcall.count;481 respond(x, &fc, nil);482 break;484 case QWevent:485 xfideventwrite(x, w);486 break;488 case QWtag:489 t = &w->tag;490 goto BodyTag;492 BodyTag:493 q = x->f->nrpart;494 cnt = x->fcall.count;495 if(q > 0){496 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */497 memmove(x->fcall.data, x->f->rpart, q);498 cnt += q;499 x->f->nrpart = 0;500 }501 r = runemalloc(cnt);502 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);503 /* approach end of buffer */504 while(fullrune(x->fcall.data+nb, cnt-nb)){505 c = nb;506 nb += chartorune(&r[nr], x->fcall.data+c);507 if(r[nr])508 nr++;509 }510 if(nb < cnt){511 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);512 x->f->nrpart = cnt-nb;513 }514 if(nr > 0){515 wincommit(w, t);516 if(qid == QWwrsel){517 q0 = w->wrselrange.q1;518 if(q0 > t->file->b.nc)519 q0 = t->file->b.nc;520 }else521 q0 = t->file->b.nc;522 if(qid == QWtag)523 textinsert(t, q0, r, nr, TRUE);524 else{525 if(w->nomark == FALSE){526 seq++;527 filemark(t->file);528 }529 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);530 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */531 if(qid!=QWwrsel && !t->w->noscroll)532 textshow(t, q0+nr, q0+nr, 1);533 textscrdraw(t);534 }535 winsettag(w);536 if(qid == QWwrsel)537 w->wrselrange.q1 += nr;538 free(r);539 }540 fc.count = x->fcall.count;541 respond(x, &fc, nil);542 break;544 default:545 sprint(buf, "unknown qid %d in write", qid);546 respond(x, &fc, buf);547 break;548 }549 if(w)550 winunlock(w);551 }553 void554 xfidctlwrite(Xfid *x, Window *w)555 {556 Fcall fc;557 int i, m, n, nb, nr, nulls;558 Rune *r;559 char *err, *p, *pp, *q, *e;560 int isfbuf, scrdraw, settag;561 Text *t;563 err = nil;564 e = x->fcall.data+x->fcall.count;565 scrdraw = FALSE;566 settag = FALSE;567 isfbuf = TRUE;568 if(x->fcall.count < RBUFSIZE)569 r = fbufalloc();570 else{571 isfbuf = FALSE;572 r = emalloc(x->fcall.count*UTFmax+1);573 }574 x->fcall.data[x->fcall.count] = 0;575 textcommit(&w->tag, TRUE);576 for(n=0; n<x->fcall.count; n+=m){577 p = x->fcall.data+n;578 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */579 qlock(&w->ctllock);580 w->ctlfid = x->f->fid;581 m = 4;582 }else583 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */584 w->ctlfid = ~0;585 qunlock(&w->ctllock);586 m = 6;587 }else588 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */589 t = &w->body;590 t->eq0 = ~0;591 filereset(t->file);592 t->file->mod = FALSE;593 w->dirty = FALSE;594 settag = TRUE;595 m = 5;596 }else597 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */598 t = &w->body;599 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */600 t->file->mod = TRUE;601 w->dirty = TRUE;602 settag = TRUE;603 m = 5;604 }else605 if(strncmp(p, "show", 4) == 0){ /* show dot */606 t = &w->body;607 textshow(t, t->q0, t->q1, 1);608 m = 4;609 }else610 if(strncmp(p, "name ", 5) == 0){ /* set file name */611 pp = p+5;612 m = 5;613 q = memchr(pp, '\n', e-pp);614 if(q==nil || q==pp){615 err = Ebadctl;616 break;617 }618 *q = 0;619 nulls = FALSE;620 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);621 if(nulls){622 err = "nulls in file name";623 break;624 }625 for(i=0; i<nr; i++)626 if(r[i] <= ' '){627 err = "bad character in file name";628 goto out;629 }630 out:631 seq++;632 filemark(w->body.file);633 winsetname(w, r, nr);634 m += (q+1) - pp;635 }else636 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */637 pp = p+5;638 m = 5;639 q = memchr(pp, '\n', e-pp);640 if(q==nil || q==pp){641 err = Ebadctl;642 break;643 }644 *q = 0;645 nulls = FALSE;646 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);647 if(nulls){648 err = "nulls in dump string";649 break;650 }651 w->dumpstr = runetobyte(r, nr);652 m += (q+1) - pp;653 }else654 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */655 pp = p+8;656 m = 8;657 q = memchr(pp, '\n', e-pp);658 if(q==nil || q==pp){659 err = Ebadctl;660 break;661 }662 *q = 0;663 nulls = FALSE;664 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);665 if(nulls){666 err = "nulls in dump directory string";667 break;668 }669 w->dumpdir = runetobyte(r, nr);670 m += (q+1) - pp;671 }else672 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */673 colclose(w->col, w, TRUE);674 m = 6;675 }else676 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */677 if(!winclean(w, TRUE)){678 err = "file dirty";679 break;680 }681 colclose(w->col, w, TRUE);682 m = 3;683 }else684 if(strncmp(p, "get", 3) == 0){ /* get file */685 get(&w->body, nil, nil, FALSE, XXX, nil, 0);686 m = 3;687 }else688 if(strncmp(p, "put", 3) == 0){ /* put file */689 put(&w->body, nil, nil, XXX, XXX, nil, 0);690 m = 3;691 }else692 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */693 textcommit(&w->body, TRUE);694 clampaddr(w);695 w->body.q0 = w->addr.q0;696 w->body.q1 = w->addr.q1;697 textsetselect(&w->body, w->body.q0, w->body.q1);698 settag = TRUE;699 m = 8;700 }else701 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */702 w->addr.q0 = w->body.q0;703 w->addr.q1 = w->body.q1;704 m = 8;705 }else706 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */707 textcommit(&w->body, TRUE);708 clampaddr(w);709 w->limit.q0 = w->addr.q0;710 w->limit.q1 = w->addr.q1;711 m = 10;712 }else713 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */714 w->nomark = TRUE;715 m = 6;716 }else717 if(strncmp(p, "mark", 4) == 0){ /* mark file */718 seq++;719 filemark(w->body.file);720 settag = TRUE;721 m = 4;722 }else723 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */724 w->noscroll = TRUE;725 m = 8;726 }else727 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */728 wincleartag(w);729 settag = TRUE;730 m = 8;731 }else732 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */733 w->noscroll = FALSE;734 m = 6;735 }else{736 err = Ebadctl;737 break;738 }739 while(p[m] == '\n')740 m++;741 }743 if(isfbuf)744 fbuffree(r);745 else746 free(r);747 if(err)748 n = 0;749 fc.count = n;750 respond(x, &fc, err);751 if(settag)752 winsettag(w);753 if(scrdraw)754 textscrdraw(&w->body);755 }757 void758 xfideventwrite(Xfid *x, Window *w)759 {760 Fcall fc;761 int m, n;762 Rune *r;763 char *err, *p, *q;764 int isfbuf;765 Text *t;766 int c;767 uint q0, q1;769 err = nil;770 isfbuf = TRUE;771 if(x->fcall.count < RBUFSIZE)772 r = fbufalloc();773 else{774 isfbuf = FALSE;775 r = emalloc(x->fcall.count*UTFmax+1);776 }777 for(n=0; n<x->fcall.count; n+=m){778 p = x->fcall.data+n;779 w->owner = *p++; /* disgusting */780 c = *p++;781 while(*p == ' ')782 p++;783 q0 = strtoul(p, &q, 10);784 if(q == p)785 goto Rescue;786 p = q;787 while(*p == ' ')788 p++;789 q1 = strtoul(p, &q, 10);790 if(q == p)791 goto Rescue;792 p = q;793 while(*p == ' ')794 p++;795 if(*p++ != '\n')796 goto Rescue;797 m = p-(x->fcall.data+n);798 if('a'<=c && c<='z')799 t = &w->tag;800 else if('A'<=c && c<='Z')801 t = &w->body;802 else803 goto Rescue;804 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)805 goto Rescue;807 qlock(&row.lk); /* just like mousethread */808 switch(c){809 case 'x':810 case 'X':811 execute(t, q0, q1, TRUE, nil);812 break;813 case 'l':814 case 'L':815 look3(t, q0, q1, TRUE);816 break;817 default:818 qunlock(&row.lk);819 goto Rescue;820 }821 qunlock(&row.lk);823 }825 Out:826 if(isfbuf)827 fbuffree(r);828 else829 free(r);830 if(err)831 n = 0;832 fc.count = n;833 respond(x, &fc, err);834 return;836 Rescue:837 err = Ebadevent;838 goto Out;839 }841 void842 xfidutfread(Xfid *x, Text *t, uint q1, int qid)843 {844 Fcall fc;845 Window *w;846 Rune *r;847 char *b, *b1;848 uint q, off, boff;849 int m, n, nr, nb;851 w = t->w;852 wincommit(w, t);853 off = x->fcall.offset;854 r = fbufalloc();855 b = fbufalloc();856 b1 = fbufalloc();857 n = 0;858 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){859 boff = w->utflastboff;860 q = w->utflastq;861 }else{862 /* BUG: stupid code: scan from beginning */863 boff = 0;864 q = 0;865 }866 w->utflastqid = qid;867 while(q<q1 && n<x->fcall.count){868 /*869 * Updating here avoids partial rune problem: we're always on a870 * char boundary. The cost is we will usually do one more read871 * than we really need, but that's better than being n^2.872 */873 w->utflastboff = boff;874 w->utflastq = q;875 nr = q1-q;876 if(nr > BUFSIZE/UTFmax)877 nr = BUFSIZE/UTFmax;878 bufread(&t->file->b, q, r, nr);879 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);880 if(boff >= off){881 m = nb;882 if(boff+m > off+x->fcall.count)883 m = off+x->fcall.count - boff;884 memmove(b1+n, b, m);885 n += m;886 }else if(boff+nb > off){887 if(n != 0)888 error("bad count in utfrune");889 m = nb - (off-boff);890 if(m > x->fcall.count)891 m = x->fcall.count;892 memmove(b1, b+(off-boff), m);893 n += m;894 }895 boff += nb;896 q += nr;897 }898 fbuffree(r);899 fbuffree(b);900 fc.count = n;901 fc.data = b1;902 respond(x, &fc, nil);903 fbuffree(b1);904 }906 int907 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)908 {909 Fcall fc;910 Window *w;911 Rune *r, junk;912 char *b, *b1;913 uint q, boff;914 int i, rw, m, n, nr, nb;916 w = t->w;917 wincommit(w, t);918 r = fbufalloc();919 b = fbufalloc();920 b1 = fbufalloc();921 n = 0;922 q = q0;923 boff = 0;924 while(q<q1 && n<x->fcall.count){925 nr = q1-q;926 if(nr > BUFSIZE/UTFmax)927 nr = BUFSIZE/UTFmax;928 bufread(&t->file->b, q, r, nr);929 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);930 m = nb;931 if(boff+m > x->fcall.count){932 i = x->fcall.count - boff;933 /* copy whole runes only */934 m = 0;935 nr = 0;936 while(m < i){937 rw = chartorune(&junk, b+m);938 if(m+rw > i)939 break;940 m += rw;941 nr++;942 }943 if(m == 0)944 break;945 }946 memmove(b1+n, b, m);947 n += m;948 boff += nb;949 q += nr;950 }951 fbuffree(r);952 fbuffree(b);953 fc.count = n;954 fc.data = b1;955 respond(x, &fc, nil);956 fbuffree(b1);957 return q-q0;958 }960 void961 xfideventread(Xfid *x, Window *w)962 {963 Fcall fc;964 char *b;965 int i, n;967 i = 0;968 x->flushed = FALSE;969 while(w->nevents == 0){970 if(i){971 if(!x->flushed)972 respond(x, &fc, "window shut down");973 return;974 }975 w->eventx = x;976 winunlock(w);977 recvp(x->c);978 winlock(w, 'F');979 i++;980 }982 n = w->nevents;983 if(n > x->fcall.count)984 n = x->fcall.count;985 fc.count = n;986 fc.data = w->events;987 respond(x, &fc, nil);988 b = w->events;989 w->events = estrdup(w->events+n);990 free(b);991 w->nevents -= n;992 }994 void995 xfidindexread(Xfid *x)996 {997 Fcall fc;998 int i, j, m, n, nmax, isbuf, cnt, off;999 Window *w;1000 char *b;1001 Rune *r;1002 Column *c;1004 qlock(&row.lk);1005 nmax = 0;1006 for(j=0; j<row.ncol; j++){1007 c = row.col[j];1008 for(i=0; i<c->nw; i++){1009 w = c->w[i];1010 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1011 }1012 }1013 nmax++;1014 isbuf = (nmax<=RBUFSIZE);1015 if(isbuf)1016 b = (char*)x->buf;1017 else1018 b = emalloc(nmax);1019 r = fbufalloc();1020 n = 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 /* only show the currently active window of a set */1026 if(w->body.file->curtext != &w->body)1027 continue;1028 winctlprint(w, b+n, 0);1029 n += Ctlsize;1030 m = min(RBUFSIZE, w->tag.file->b.nc);1031 bufread(&w->tag.file->b, 0, r, m);1032 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1033 while(n<m && b[n]!='\n')1034 n++;1035 b[n++] = '\n';1036 }1037 }1038 qunlock(&row.lk);1039 off = x->fcall.offset;1040 cnt = x->fcall.count;1041 if(off > n)1042 off = n;1043 if(off+cnt > n)1044 cnt = n-off;1045 fc.count = cnt;1046 memmove(r, b+off, cnt);1047 fc.data = (char*)r;1048 if(!isbuf)1049 free(b);1050 respond(x, &fc, nil);1051 fbuffree(r);1052 }