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 static int399 shouldscroll(Text *t, uint q0, int qid)400 {401 if(qid == Qcons)402 return TRUE;403 return t->org <= q0 && q0 <= t->org+t->fr.nchars;404 }406 static Rune*407 fullrunewrite(Xfid *x, int *inr)408 {409 int q, cnt, c, nb, nr;410 Rune *r;412 q = x->f->nrpart;413 cnt = x->fcall.count;414 if(q > 0){415 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */416 memmove(x->fcall.data, x->f->rpart, q);417 cnt += q;418 x->f->nrpart = 0;419 }420 r = runemalloc(cnt);421 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);422 /* approach end of buffer */423 while(fullrune(x->fcall.data+nb, cnt-nb)){424 c = nb;425 nb += chartorune(&r[nr], x->fcall.data+c);426 if(r[nr])427 nr++;428 }429 if(nb < cnt){430 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);431 x->f->nrpart = cnt-nb;432 }433 *inr = nr;434 return r;435 }437 void438 xfidwrite(Xfid *x)439 {440 Fcall fc;441 int c, qid, nb, nr, eval;442 char buf[64], *err;443 Window *w;444 Rune *r;445 Range a;446 Text *t;447 uint q0, tq0, tq1;449 qid = FILE(x->f->qid);450 w = x->f->w;451 if(w){452 c = 'F';453 if(qid==QWtag || qid==QWbody)454 c = 'E';455 winlock(w, c);456 if(w->col == nil){457 winunlock(w);458 respond(x, &fc, Edel);459 return;460 }461 }462 x->fcall.data[x->fcall.count] = 0;463 switch(qid){464 case Qcons:465 w = errorwin(x->f->mntdir, 'X');466 t=&w->body;467 goto BodyTag;469 case Qlabel:470 fc.count = x->fcall.count;471 respond(x, &fc, nil);472 break;474 case QWaddr:475 x->fcall.data[x->fcall.count] = 0;476 r = bytetorune(x->fcall.data, &nr);477 t = &w->body;478 wincommit(w, t);479 eval = TRUE;480 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);481 free(r);482 if(nb < nr){483 respond(x, &fc, Ebadaddr);484 break;485 }486 if(!eval){487 respond(x, &fc, Eaddr);488 break;489 }490 w->addr = a;491 fc.count = x->fcall.count;492 respond(x, &fc, nil);493 break;495 case Qeditout:496 case QWeditout:497 r = fullrunewrite(x, &nr);498 if(w)499 err = edittext(w, w->wrselrange.q1, r, nr);500 else501 err = edittext(nil, 0, r, nr);502 free(r);503 if(err != nil){504 respond(x, &fc, err);505 break;506 }507 fc.count = x->fcall.count;508 respond(x, &fc, nil);509 break;511 case QWerrors:512 w = errorwinforwin(w);513 t = &w->body;514 goto BodyTag;516 case QWbody:517 case QWwrsel:518 t = &w->body;519 goto BodyTag;521 case QWctl:522 xfidctlwrite(x, w);523 break;525 case QWdata:526 a = w->addr;527 t = &w->body;528 wincommit(w, t);529 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){530 respond(x, &fc, Eaddr);531 break;532 }533 r = runemalloc(x->fcall.count);534 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);535 if(w->nomark == FALSE){536 seq++;537 filemark(t->file);538 }539 q0 = a.q0;540 if(a.q1 > q0){541 textdelete(t, q0, a.q1, TRUE);542 w->addr.q1 = q0;543 }544 tq0 = t->q0;545 tq1 = t->q1;546 textinsert(t, q0, r, nr, TRUE);547 if(tq0 >= q0)548 tq0 += nr;549 if(tq1 >= q0)550 tq1 += nr;551 textsetselect(t, tq0, tq1);552 if(shouldscroll(t, q0, qid))553 textshow(t, q0+nr, q0+nr, 0);554 textscrdraw(t);555 winsettag(w);556 free(r);557 w->addr.q0 += nr;558 w->addr.q1 = w->addr.q0;559 fc.count = x->fcall.count;560 respond(x, &fc, nil);561 break;563 case QWevent:564 xfideventwrite(x, w);565 break;567 case QWtag:568 t = &w->tag;569 goto BodyTag;571 BodyTag:572 r = fullrunewrite(x, &nr);573 if(nr > 0){574 wincommit(w, t);575 if(qid == QWwrsel){576 q0 = w->wrselrange.q1;577 if(q0 > t->file->b.nc)578 q0 = t->file->b.nc;579 }else580 q0 = t->file->b.nc;581 if(qid == QWtag)582 textinsert(t, q0, r, nr, TRUE);583 else{584 if(w->nomark == FALSE){585 seq++;586 filemark(t->file);587 }588 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);589 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */590 if(qid!=QWwrsel && shouldscroll(t, q0, qid))591 textshow(t, q0+nr, q0+nr, 1);592 textscrdraw(t);593 }594 winsettag(w);595 if(qid == QWwrsel)596 w->wrselrange.q1 += nr;597 free(r);598 }599 fc.count = x->fcall.count;600 respond(x, &fc, nil);601 break;603 default:604 sprint(buf, "unknown qid %d in write", qid);605 respond(x, &fc, buf);606 break;607 }608 if(w)609 winunlock(w);610 }612 void613 xfidctlwrite(Xfid *x, Window *w)614 {615 Fcall fc;616 int i, m, n, nb, nr, nulls;617 Rune *r;618 char *err, *p, *pp, *q, *e;619 int isfbuf, scrdraw, settag;620 Text *t;622 err = nil;623 e = x->fcall.data+x->fcall.count;624 scrdraw = FALSE;625 settag = FALSE;626 isfbuf = TRUE;627 if(x->fcall.count < RBUFSIZE)628 r = fbufalloc();629 else{630 isfbuf = FALSE;631 r = emalloc(x->fcall.count*UTFmax+1);632 }633 x->fcall.data[x->fcall.count] = 0;634 textcommit(&w->tag, TRUE);635 for(n=0; n<x->fcall.count; n+=m){636 p = x->fcall.data+n;637 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */638 qlock(&w->ctllock);639 w->ctlfid = x->f->fid;640 m = 4;641 }else642 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */643 w->ctlfid = ~0;644 qunlock(&w->ctllock);645 m = 6;646 }else647 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */648 t = &w->body;649 t->eq0 = ~0;650 filereset(t->file);651 t->file->mod = FALSE;652 w->dirty = FALSE;653 settag = TRUE;654 m = 5;655 }else656 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */657 t = &w->body;658 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */659 t->file->mod = TRUE;660 w->dirty = TRUE;661 settag = TRUE;662 m = 5;663 }else664 if(strncmp(p, "show", 4) == 0){ /* show dot */665 t = &w->body;666 textshow(t, t->q0, t->q1, 1);667 m = 4;668 }else669 if(strncmp(p, "name ", 5) == 0){ /* set file name */670 pp = p+5;671 m = 5;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 file name";682 break;683 }684 for(i=0; i<nr; i++)685 if(r[i] <= ' '){686 err = "bad character in file name";687 goto out;688 }689 out:690 seq++;691 filemark(w->body.file);692 winsetname(w, r, nr);693 m += (q+1) - pp;694 }else695 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */696 pp = p+5;697 m = 5;698 q = memchr(pp, '\n', e-pp);699 if(q==nil || q==pp){700 err = Ebadctl;701 break;702 }703 *q = 0;704 nulls = FALSE;705 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);706 if(nulls){707 err = "nulls in dump string";708 break;709 }710 w->dumpstr = runetobyte(r, nr);711 m += (q+1) - pp;712 }else713 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */714 pp = p+8;715 m = 8;716 q = memchr(pp, '\n', e-pp);717 if(q==nil || q==pp){718 err = Ebadctl;719 break;720 }721 *q = 0;722 nulls = FALSE;723 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);724 if(nulls){725 err = "nulls in dump directory string";726 break;727 }728 w->dumpdir = runetobyte(r, nr);729 m += (q+1) - pp;730 }else731 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */732 colclose(w->col, w, TRUE);733 m = 6;734 }else735 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */736 if(!winclean(w, TRUE)){737 err = "file dirty";738 break;739 }740 colclose(w->col, w, TRUE);741 m = 3;742 }else743 if(strncmp(p, "get", 3) == 0){ /* get file */744 get(&w->body, nil, nil, FALSE, XXX, nil, 0);745 m = 3;746 }else747 if(strncmp(p, "put", 3) == 0){ /* put file */748 put(&w->body, nil, nil, XXX, XXX, nil, 0);749 m = 3;750 }else751 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */752 textcommit(&w->body, TRUE);753 clampaddr(w);754 w->body.q0 = w->addr.q0;755 w->body.q1 = w->addr.q1;756 textsetselect(&w->body, w->body.q0, w->body.q1);757 settag = TRUE;758 m = 8;759 }else760 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */761 w->addr.q0 = w->body.q0;762 w->addr.q1 = w->body.q1;763 m = 8;764 }else765 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */766 textcommit(&w->body, TRUE);767 clampaddr(w);768 w->limit.q0 = w->addr.q0;769 w->limit.q1 = w->addr.q1;770 m = 10;771 }else772 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */773 w->nomark = TRUE;774 m = 6;775 }else776 if(strncmp(p, "mark", 4) == 0){ /* mark file */777 seq++;778 filemark(w->body.file);779 settag = TRUE;780 m = 4;781 }else782 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */783 w->filemenu = FALSE;784 m = 6;785 }else786 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */787 w->filemenu = TRUE;788 m = 4;789 }else790 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */791 wincleartag(w);792 settag = TRUE;793 m = 8;794 }else{795 err = Ebadctl;796 break;797 }798 while(p[m] == '\n')799 m++;800 }802 if(isfbuf)803 fbuffree(r);804 else805 free(r);806 if(err)807 n = 0;808 fc.count = n;809 respond(x, &fc, err);810 if(settag)811 winsettag(w);812 if(scrdraw)813 textscrdraw(&w->body);814 }816 void817 xfideventwrite(Xfid *x, Window *w)818 {819 Fcall fc;820 int m, n;821 Rune *r;822 char *err, *p, *q;823 int isfbuf;824 Text *t;825 int c;826 uint q0, q1;828 err = nil;829 isfbuf = TRUE;830 if(x->fcall.count < RBUFSIZE)831 r = fbufalloc();832 else{833 isfbuf = FALSE;834 r = emalloc(x->fcall.count*UTFmax+1);835 }836 for(n=0; n<x->fcall.count; n+=m){837 p = x->fcall.data+n;838 w->owner = *p++; /* disgusting */839 c = *p++;840 while(*p == ' ')841 p++;842 q0 = strtoul(p, &q, 10);843 if(q == p)844 goto Rescue;845 p = q;846 while(*p == ' ')847 p++;848 q1 = strtoul(p, &q, 10);849 if(q == p)850 goto Rescue;851 p = q;852 while(*p == ' ')853 p++;854 if(*p++ != '\n')855 goto Rescue;856 m = p-(x->fcall.data+n);857 if('a'<=c && c<='z')858 t = &w->tag;859 else if('A'<=c && c<='Z')860 t = &w->body;861 else862 goto Rescue;863 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)864 goto Rescue;866 qlock(&row.lk); /* just like mousethread */867 switch(c){868 case 'x':869 case 'X':870 execute(t, q0, q1, TRUE, nil);871 break;872 case 'l':873 case 'L':874 look3(t, q0, q1, TRUE);875 break;876 default:877 qunlock(&row.lk);878 goto Rescue;879 }880 qunlock(&row.lk);882 }884 Out:885 if(isfbuf)886 fbuffree(r);887 else888 free(r);889 if(err)890 n = 0;891 fc.count = n;892 respond(x, &fc, err);893 return;895 Rescue:896 err = Ebadevent;897 goto Out;898 }900 void901 xfidutfread(Xfid *x, Text *t, uint q1, int qid)902 {903 Fcall fc;904 Window *w;905 Rune *r;906 char *b, *b1;907 uint q, off, boff;908 int m, n, nr, nb;910 w = t->w;911 wincommit(w, t);912 off = x->fcall.offset;913 r = fbufalloc();914 b = fbufalloc();915 b1 = fbufalloc();916 n = 0;917 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){918 boff = w->utflastboff;919 q = w->utflastq;920 }else{921 /* BUG: stupid code: scan from beginning */922 boff = 0;923 q = 0;924 }925 w->utflastqid = qid;926 while(q<q1 && n<x->fcall.count){927 /*928 * Updating here avoids partial rune problem: we're always on a929 * char boundary. The cost is we will usually do one more read930 * than we really need, but that's better than being n^2.931 */932 w->utflastboff = boff;933 w->utflastq = q;934 nr = q1-q;935 if(nr > BUFSIZE/UTFmax)936 nr = BUFSIZE/UTFmax;937 bufread(&t->file->b, q, r, nr);938 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);939 if(boff >= off){940 m = nb;941 if(boff+m > off+x->fcall.count)942 m = off+x->fcall.count - boff;943 memmove(b1+n, b, m);944 n += m;945 }else if(boff+nb > off){946 if(n != 0)947 error("bad count in utfrune");948 m = nb - (off-boff);949 if(m > x->fcall.count)950 m = x->fcall.count;951 memmove(b1, b+(off-boff), m);952 n += m;953 }954 boff += nb;955 q += nr;956 }957 fbuffree(r);958 fbuffree(b);959 fc.count = n;960 fc.data = b1;961 respond(x, &fc, nil);962 fbuffree(b1);963 }965 int966 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)967 {968 Fcall fc;969 Window *w;970 Rune *r, junk;971 char *b, *b1;972 uint q, boff;973 int i, rw, m, n, nr, nb;975 w = t->w;976 wincommit(w, t);977 r = fbufalloc();978 b = fbufalloc();979 b1 = fbufalloc();980 n = 0;981 q = q0;982 boff = 0;983 while(q<q1 && n<x->fcall.count){984 nr = q1-q;985 if(nr > BUFSIZE/UTFmax)986 nr = BUFSIZE/UTFmax;987 bufread(&t->file->b, q, r, nr);988 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);989 m = nb;990 if(boff+m > x->fcall.count){991 i = x->fcall.count - boff;992 /* copy whole runes only */993 m = 0;994 nr = 0;995 while(m < i){996 rw = chartorune(&junk, b+m);997 if(m+rw > i)998 break;999 m += rw;1000 nr++;1001 }1002 if(m == 0)1003 break;1004 }1005 memmove(b1+n, b, m);1006 n += m;1007 boff += nb;1008 q += nr;1009 }1010 fbuffree(r);1011 fbuffree(b);1012 fc.count = n;1013 fc.data = b1;1014 respond(x, &fc, nil);1015 fbuffree(b1);1016 return q-q0;1017 }1019 void1020 xfideventread(Xfid *x, Window *w)1021 {1022 Fcall fc;1023 int i, n;1025 i = 0;1026 x->flushed = FALSE;1027 while(w->nevents == 0){1028 if(i){1029 if(!x->flushed)1030 respond(x, &fc, "window shut down");1031 return;1032 }1033 w->eventx = x;1034 winunlock(w);1035 recvp(x->c);1036 winlock(w, 'F');1037 i++;1038 }1040 n = w->nevents;1041 if(n > x->fcall.count)1042 n = x->fcall.count;1043 fc.count = n;1044 fc.data = w->events;1045 respond(x, &fc, nil);1046 w->nevents -= n;1047 if(w->nevents){1048 memmove(w->events, w->events+n, w->nevents);1049 w->events = erealloc(w->events, w->nevents);1050 }else{1051 free(w->events);1052 w->events = nil;1053 }1054 }1056 void1057 xfidindexread(Xfid *x)1058 {1059 Fcall fc;1060 int i, j, m, n, nmax, isbuf, cnt, off;1061 Window *w;1062 char *b;1063 Rune *r;1064 Column *c;1066 qlock(&row.lk);1067 nmax = 0;1068 for(j=0; j<row.ncol; j++){1069 c = row.col[j];1070 for(i=0; i<c->nw; i++){1071 w = c->w[i];1072 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1073 }1074 }1075 nmax++;1076 isbuf = (nmax<=RBUFSIZE);1077 if(isbuf)1078 b = (char*)x->buf;1079 else1080 b = emalloc(nmax);1081 r = fbufalloc();1082 n = 0;1083 for(j=0; j<row.ncol; j++){1084 c = row.col[j];1085 for(i=0; i<c->nw; i++){1086 w = c->w[i];1087 /* only show the currently active window of a set */1088 if(w->body.file->curtext != &w->body)1089 continue;1090 winctlprint(w, b+n, 0);1091 n += Ctlsize;1092 m = min(RBUFSIZE, w->tag.file->b.nc);1093 bufread(&w->tag.file->b, 0, r, m);1094 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1095 while(n<m && b[n]!='\n')1096 n++;1097 b[n++] = '\n';1098 }1099 }1100 qunlock(&row.lk);1101 off = x->fcall.offset;1102 cnt = x->fcall.count;1103 if(off > n)1104 off = n;1105 if(off+cnt > n)1106 cnt = n-off;1107 fc.count = cnt;1108 memmove(r, b+off, cnt);1109 fc.data = (char*)r;1110 if(!isbuf)1111 free(b);1112 respond(x, &fc, nil);1113 fbuffree(r);1114 }