Blob
- Date:
- Message:
- 9term, acme: autoscroll Ignore scroll/noscroll window setting. Instead, scroll when the write begins in or immediately after the displayed window content. In the new scrolling discipline, executing "Noscroll" is replaced by typing Page Up or using the mouse to scroll higher in the buffer, and executing "Scroll" is replaced by typing End or using the mouse to scroll to the bottom of the buffer. R=r, r2 http://codereview.appspot.com/4433060
- Actions:
- History | Blame | Raw File
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->org <= q0 && q0 <= t->org+t->fr.nchars)514 textshow(t, q0+nr, 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->org <= q0 && q0 < t->org+t->fr.nchars)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, "nomenu", 6) == 0){ /* turn off automatic menu */764 w->filemenu = FALSE;765 m = 6;766 }else767 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */768 w->filemenu = TRUE;769 m = 4;770 }else771 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */772 wincleartag(w);773 settag = TRUE;774 m = 8;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 }