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[256];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 b = winctlprint(w, buf, 1);299 goto Readb;301 Readbuf:302 b = buf;303 Readb:304 n = strlen(b);305 if(off > n)306 off = n;307 if(off+x->fcall.count > n)308 x->fcall.count = n-off;309 fc.count = x->fcall.count;310 fc.data = b+off;311 respond(x, &fc, nil);312 if(b != buf)313 free(b);314 break;316 case QWevent:317 xfideventread(x, w);318 break;320 case QWdata:321 /* BUG: what should happen if q1 > q0? */322 if(w->addr.q0 > w->body.file->b.nc){323 respond(x, &fc, Eaddr);324 break;325 }326 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);327 w->addr.q1 = w->addr.q0;328 break;330 case QWxdata:331 /* BUG: what should happen if q1 > q0? */332 if(w->addr.q0 > w->body.file->b.nc){333 respond(x, &fc, Eaddr);334 break;335 }336 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);337 break;339 case QWtag:340 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);341 break;343 case QWrdsel:344 seek(w->rdselfd, off, 0);345 n = x->fcall.count;346 if(n > BUFSIZE)347 n = BUFSIZE;348 b = fbufalloc();349 n = read(w->rdselfd, b, n);350 if(n < 0){351 respond(x, &fc, "I/O error in temp file");352 break;353 }354 fc.count = n;355 fc.data = b;356 respond(x, &fc, nil);357 fbuffree(b);358 break;360 default:361 sprint(buf, "unknown qid %d in read", q);362 respond(x, &fc, nil);363 }364 winunlock(w);365 }367 void368 xfidwrite(Xfid *x)369 {370 Fcall fc;371 int c, cnt, qid, q, nb, nr, eval;372 char buf[64], *err;373 Window *w;374 Rune *r;375 Range a;376 Text *t;377 uint q0, tq0, tq1;379 qid = FILE(x->f->qid);380 w = x->f->w;381 if(w){382 c = 'F';383 if(qid==QWtag || qid==QWbody)384 c = 'E';385 winlock(w, c);386 if(w->col == nil){387 winunlock(w);388 respond(x, &fc, Edel);389 return;390 }391 }392 x->fcall.data[x->fcall.count] = 0;393 switch(qid){394 case Qcons:395 w = errorwin(x->f->mntdir, 'X');396 t=&w->body;397 goto BodyTag;399 case Qlabel:400 fc.count = x->fcall.count;401 respond(x, &fc, nil);402 break;404 case QWaddr:405 x->fcall.data[x->fcall.count] = 0;406 r = bytetorune(x->fcall.data, &nr);407 t = &w->body;408 wincommit(w, t);409 eval = TRUE;410 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);411 free(r);412 if(nb < nr){413 respond(x, &fc, Ebadaddr);414 break;415 }416 if(!eval){417 respond(x, &fc, Eaddr);418 break;419 }420 w->addr = a;421 fc.count = x->fcall.count;422 respond(x, &fc, nil);423 break;425 case Qeditout:426 case QWeditout:427 r = bytetorune(x->fcall.data, &nr);428 if(w)429 err = edittext(w, w->wrselrange.q1, r, nr);430 else431 err = edittext(nil, 0, r, nr);432 free(r);433 if(err != nil){434 respond(x, &fc, err);435 break;436 }437 fc.count = x->fcall.count;438 respond(x, &fc, nil);439 break;441 case QWbody:442 case QWwrsel:443 t = &w->body;444 goto BodyTag;446 case QWctl:447 xfidctlwrite(x, w);448 break;450 case QWdata:451 a = w->addr;452 t = &w->body;453 wincommit(w, t);454 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){455 respond(x, &fc, Eaddr);456 break;457 }458 r = runemalloc(x->fcall.count);459 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);460 if(w->nomark == FALSE){461 seq++;462 filemark(t->file);463 }464 q0 = a.q0;465 if(a.q1 > q0){466 textdelete(t, q0, a.q1, TRUE);467 w->addr.q1 = q0;468 }469 tq0 = t->q0;470 tq1 = t->q1;471 textinsert(t, q0, r, nr, TRUE);472 if(tq0 >= q0)473 tq0 += nr;474 if(tq1 >= q0)475 tq1 += nr;476 textsetselect(t, tq0, tq1);477 if(!t->w->noscroll)478 textshow(t, q0, q0+nr, 0);479 textscrdraw(t);480 winsettag(w);481 free(r);482 w->addr.q0 += nr;483 w->addr.q1 = w->addr.q0;484 fc.count = x->fcall.count;485 respond(x, &fc, nil);486 break;488 case QWevent:489 xfideventwrite(x, w);490 break;492 case QWtag:493 t = &w->tag;494 goto BodyTag;496 BodyTag:497 q = x->f->nrpart;498 cnt = x->fcall.count;499 if(q > 0){500 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */501 memmove(x->fcall.data, x->f->rpart, q);502 cnt += q;503 x->f->nrpart = 0;504 }505 r = runemalloc(cnt);506 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);507 /* approach end of buffer */508 while(fullrune(x->fcall.data+nb, cnt-nb)){509 c = nb;510 nb += chartorune(&r[nr], x->fcall.data+c);511 if(r[nr])512 nr++;513 }514 if(nb < cnt){515 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);516 x->f->nrpart = cnt-nb;517 }518 if(nr > 0){519 wincommit(w, t);520 if(qid == QWwrsel){521 q0 = w->wrselrange.q1;522 if(q0 > t->file->b.nc)523 q0 = t->file->b.nc;524 }else525 q0 = t->file->b.nc;526 if(qid == QWtag)527 textinsert(t, q0, r, nr, TRUE);528 else{529 if(w->nomark == FALSE){530 seq++;531 filemark(t->file);532 }533 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);534 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */535 if(qid!=QWwrsel && !t->w->noscroll)536 textshow(t, q0+nr, q0+nr, 1);537 textscrdraw(t);538 }539 winsettag(w);540 if(qid == QWwrsel)541 w->wrselrange.q1 += nr;542 free(r);543 }544 fc.count = x->fcall.count;545 respond(x, &fc, nil);546 break;548 default:549 sprint(buf, "unknown qid %d in write", qid);550 respond(x, &fc, buf);551 break;552 }553 if(w)554 winunlock(w);555 }557 void558 xfidctlwrite(Xfid *x, Window *w)559 {560 Fcall fc;561 int i, m, n, nb, nr, nulls;562 Rune *r;563 char *err, *p, *pp, *q, *e;564 int isfbuf, scrdraw, settag;565 Text *t;567 err = nil;568 e = x->fcall.data+x->fcall.count;569 scrdraw = FALSE;570 settag = FALSE;571 isfbuf = TRUE;572 if(x->fcall.count < RBUFSIZE)573 r = fbufalloc();574 else{575 isfbuf = FALSE;576 r = emalloc(x->fcall.count*UTFmax+1);577 }578 x->fcall.data[x->fcall.count] = 0;579 textcommit(&w->tag, TRUE);580 for(n=0; n<x->fcall.count; n+=m){581 p = x->fcall.data+n;582 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */583 qlock(&w->ctllock);584 w->ctlfid = x->f->fid;585 m = 4;586 }else587 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */588 w->ctlfid = ~0;589 qunlock(&w->ctllock);590 m = 6;591 }else592 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */593 t = &w->body;594 t->eq0 = ~0;595 filereset(t->file);596 t->file->mod = FALSE;597 w->dirty = FALSE;598 settag = TRUE;599 m = 5;600 }else601 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */602 t = &w->body;603 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */604 t->file->mod = TRUE;605 w->dirty = TRUE;606 settag = TRUE;607 m = 5;608 }else609 if(strncmp(p, "show", 4) == 0){ /* show dot */610 t = &w->body;611 textshow(t, t->q0, t->q1, 1);612 m = 4;613 }else614 if(strncmp(p, "name ", 5) == 0){ /* set file name */615 pp = p+5;616 m = 5;617 q = memchr(pp, '\n', e-pp);618 if(q==nil || q==pp){619 err = Ebadctl;620 break;621 }622 *q = 0;623 nulls = FALSE;624 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);625 if(nulls){626 err = "nulls in file name";627 break;628 }629 for(i=0; i<nr; i++)630 if(r[i] <= ' '){631 err = "bad character in file name";632 goto out;633 }634 out:635 seq++;636 filemark(w->body.file);637 winsetname(w, r, nr);638 m += (q+1) - pp;639 }else640 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */641 pp = p+5;642 m = 5;643 q = memchr(pp, '\n', e-pp);644 if(q==nil || q==pp){645 err = Ebadctl;646 break;647 }648 *q = 0;649 nulls = FALSE;650 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);651 if(nulls){652 err = "nulls in dump string";653 break;654 }655 w->dumpstr = runetobyte(r, nr);656 m += (q+1) - pp;657 }else658 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */659 pp = p+8;660 m = 8;661 q = memchr(pp, '\n', e-pp);662 if(q==nil || q==pp){663 err = Ebadctl;664 break;665 }666 *q = 0;667 nulls = FALSE;668 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);669 if(nulls){670 err = "nulls in dump directory string";671 break;672 }673 w->dumpdir = runetobyte(r, nr);674 m += (q+1) - pp;675 }else676 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */677 colclose(w->col, w, TRUE);678 m = 6;679 }else680 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */681 if(!winclean(w, TRUE)){682 err = "file dirty";683 break;684 }685 colclose(w->col, w, TRUE);686 m = 3;687 }else688 if(strncmp(p, "get", 3) == 0){ /* get file */689 get(&w->body, nil, nil, FALSE, XXX, nil, 0);690 m = 3;691 }else692 if(strncmp(p, "put", 3) == 0){ /* put file */693 put(&w->body, nil, nil, XXX, XXX, nil, 0);694 m = 3;695 }else696 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */697 textcommit(&w->body, TRUE);698 clampaddr(w);699 w->body.q0 = w->addr.q0;700 w->body.q1 = w->addr.q1;701 textsetselect(&w->body, w->body.q0, w->body.q1);702 settag = TRUE;703 m = 8;704 }else705 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */706 w->addr.q0 = w->body.q0;707 w->addr.q1 = w->body.q1;708 m = 8;709 }else710 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */711 textcommit(&w->body, TRUE);712 clampaddr(w);713 w->limit.q0 = w->addr.q0;714 w->limit.q1 = w->addr.q1;715 m = 10;716 }else717 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */718 w->nomark = TRUE;719 m = 6;720 }else721 if(strncmp(p, "mark", 4) == 0){ /* mark file */722 seq++;723 filemark(w->body.file);724 settag = TRUE;725 m = 4;726 }else727 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */728 w->noscroll = TRUE;729 m = 8;730 }else731 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */732 wincleartag(w);733 settag = TRUE;734 m = 8;735 }else736 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */737 w->noscroll = FALSE;738 m = 6;739 }else{740 err = Ebadctl;741 break;742 }743 while(p[m] == '\n')744 m++;745 }747 if(isfbuf)748 fbuffree(r);749 else750 free(r);751 if(err)752 n = 0;753 fc.count = n;754 respond(x, &fc, err);755 if(settag)756 winsettag(w);757 if(scrdraw)758 textscrdraw(&w->body);759 }761 void762 xfideventwrite(Xfid *x, Window *w)763 {764 Fcall fc;765 int m, n;766 Rune *r;767 char *err, *p, *q;768 int isfbuf;769 Text *t;770 int c;771 uint q0, q1;773 err = nil;774 isfbuf = TRUE;775 if(x->fcall.count < RBUFSIZE)776 r = fbufalloc();777 else{778 isfbuf = FALSE;779 r = emalloc(x->fcall.count*UTFmax+1);780 }781 for(n=0; n<x->fcall.count; n+=m){782 p = x->fcall.data+n;783 w->owner = *p++; /* disgusting */784 c = *p++;785 while(*p == ' ')786 p++;787 q0 = strtoul(p, &q, 10);788 if(q == p)789 goto Rescue;790 p = q;791 while(*p == ' ')792 p++;793 q1 = strtoul(p, &q, 10);794 if(q == p)795 goto Rescue;796 p = q;797 while(*p == ' ')798 p++;799 if(*p++ != '\n')800 goto Rescue;801 m = p-(x->fcall.data+n);802 if('a'<=c && c<='z')803 t = &w->tag;804 else if('A'<=c && c<='Z')805 t = &w->body;806 else807 goto Rescue;808 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)809 goto Rescue;811 qlock(&row.lk); /* just like mousethread */812 switch(c){813 case 'x':814 case 'X':815 execute(t, q0, q1, TRUE, nil);816 break;817 case 'l':818 case 'L':819 look3(t, q0, q1, TRUE);820 break;821 default:822 qunlock(&row.lk);823 goto Rescue;824 }825 qunlock(&row.lk);827 }829 Out:830 if(isfbuf)831 fbuffree(r);832 else833 free(r);834 if(err)835 n = 0;836 fc.count = n;837 respond(x, &fc, err);838 return;840 Rescue:841 err = Ebadevent;842 goto Out;843 }845 void846 xfidutfread(Xfid *x, Text *t, uint q1, int qid)847 {848 Fcall fc;849 Window *w;850 Rune *r;851 char *b, *b1;852 uint q, off, boff;853 int m, n, nr, nb;855 w = t->w;856 wincommit(w, t);857 off = x->fcall.offset;858 r = fbufalloc();859 b = fbufalloc();860 b1 = fbufalloc();861 n = 0;862 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){863 boff = w->utflastboff;864 q = w->utflastq;865 }else{866 /* BUG: stupid code: scan from beginning */867 boff = 0;868 q = 0;869 }870 w->utflastqid = qid;871 while(q<q1 && n<x->fcall.count){872 /*873 * Updating here avoids partial rune problem: we're always on a874 * char boundary. The cost is we will usually do one more read875 * than we really need, but that's better than being n^2.876 */877 w->utflastboff = boff;878 w->utflastq = q;879 nr = q1-q;880 if(nr > BUFSIZE/UTFmax)881 nr = BUFSIZE/UTFmax;882 bufread(&t->file->b, q, r, nr);883 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);884 if(boff >= off){885 m = nb;886 if(boff+m > off+x->fcall.count)887 m = off+x->fcall.count - boff;888 memmove(b1+n, b, m);889 n += m;890 }else if(boff+nb > off){891 if(n != 0)892 error("bad count in utfrune");893 m = nb - (off-boff);894 if(m > x->fcall.count)895 m = x->fcall.count;896 memmove(b1, b+(off-boff), m);897 n += m;898 }899 boff += nb;900 q += nr;901 }902 fbuffree(r);903 fbuffree(b);904 fc.count = n;905 fc.data = b1;906 respond(x, &fc, nil);907 fbuffree(b1);908 }910 int911 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)912 {913 Fcall fc;914 Window *w;915 Rune *r, junk;916 char *b, *b1;917 uint q, boff;918 int i, rw, m, n, nr, nb;920 w = t->w;921 wincommit(w, t);922 r = fbufalloc();923 b = fbufalloc();924 b1 = fbufalloc();925 n = 0;926 q = q0;927 boff = 0;928 while(q<q1 && n<x->fcall.count){929 nr = q1-q;930 if(nr > BUFSIZE/UTFmax)931 nr = BUFSIZE/UTFmax;932 bufread(&t->file->b, q, r, nr);933 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);934 m = nb;935 if(boff+m > x->fcall.count){936 i = x->fcall.count - boff;937 /* copy whole runes only */938 m = 0;939 nr = 0;940 while(m < i){941 rw = chartorune(&junk, b+m);942 if(m+rw > i)943 break;944 m += rw;945 nr++;946 }947 if(m == 0)948 break;949 }950 memmove(b1+n, b, m);951 n += m;952 boff += nb;953 q += nr;954 }955 fbuffree(r);956 fbuffree(b);957 fc.count = n;958 fc.data = b1;959 respond(x, &fc, nil);960 fbuffree(b1);961 return q-q0;962 }964 void965 xfideventread(Xfid *x, Window *w)966 {967 Fcall fc;968 char *b;969 int i, n;971 i = 0;972 x->flushed = FALSE;973 while(w->nevents == 0){974 if(i){975 if(!x->flushed)976 respond(x, &fc, "window shut down");977 return;978 }979 w->eventx = x;980 winunlock(w);981 recvp(x->c);982 winlock(w, 'F');983 i++;984 }986 n = w->nevents;987 if(n > x->fcall.count)988 n = x->fcall.count;989 fc.count = n;990 fc.data = w->events;991 respond(x, &fc, nil);992 b = w->events;993 w->events = estrdup(w->events+n);994 free(b);995 w->nevents -= n;996 }998 void999 xfidindexread(Xfid *x)1000 {1001 Fcall fc;1002 int i, j, m, n, nmax, isbuf, cnt, off;1003 Window *w;1004 char *b;1005 Rune *r;1006 Column *c;1008 qlock(&row.lk);1009 nmax = 0;1010 for(j=0; j<row.ncol; j++){1011 c = row.col[j];1012 for(i=0; i<c->nw; i++){1013 w = c->w[i];1014 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1015 }1016 }1017 nmax++;1018 isbuf = (nmax<=RBUFSIZE);1019 if(isbuf)1020 b = (char*)x->buf;1021 else1022 b = emalloc(nmax);1023 r = fbufalloc();1024 n = 0;1025 for(j=0; j<row.ncol; j++){1026 c = row.col[j];1027 for(i=0; i<c->nw; i++){1028 w = c->w[i];1029 /* only show the currently active window of a set */1030 if(w->body.file->curtext != &w->body)1031 continue;1032 winctlprint(w, b+n, 0);1033 n += Ctlsize;1034 m = min(RBUFSIZE, w->tag.file->b.nc);1035 bufread(&w->tag.file->b, 0, r, m);1036 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1037 while(n<m && b[n]!='\n')1038 n++;1039 b[n++] = '\n';1040 }1041 }1042 qunlock(&row.lk);1043 off = x->fcall.offset;1044 cnt = x->fcall.count;1045 if(off > n)1046 off = n;1047 if(off+cnt > n)1048 cnt = n-off;1049 fc.count = cnt;1050 memmove(r, b+off, cnt);1051 fc.data = (char*)r;1052 if(!isbuf)1053 free(b);1054 respond(x, &fc, nil);1055 fbuffree(r);1056 }