Blob
- Date:
- Message:
- acme: scrolling fixes + new home/end Home and End previously navigated between two different window locations: the top and the bottom of the text. Now they include a third waypoint: the location where typing last happened. Thus, in a win window, typing ls -l <home> scrolls to the beginning of the ls -l output. A second <home> continues to the top of the file. Makes Send scroll always, along with writes by external programs to +Errors. R=r CC=mccoyst http://codereview.appspot.com/4830051
- 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 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 void407 xfidwrite(Xfid *x)408 {409 Fcall fc;410 int c, cnt, qid, q, nb, nr, eval;411 char buf[64], *err;412 Window *w;413 Rune *r;414 Range a;415 Text *t;416 uint q0, tq0, tq1;418 qid = FILE(x->f->qid);419 w = x->f->w;420 if(w){421 c = 'F';422 if(qid==QWtag || qid==QWbody)423 c = 'E';424 winlock(w, c);425 if(w->col == nil){426 winunlock(w);427 respond(x, &fc, Edel);428 return;429 }430 }431 x->fcall.data[x->fcall.count] = 0;432 switch(qid){433 case Qcons:434 w = errorwin(x->f->mntdir, 'X');435 t=&w->body;436 goto BodyTag;438 case Qlabel:439 fc.count = x->fcall.count;440 respond(x, &fc, nil);441 break;443 case QWaddr:444 x->fcall.data[x->fcall.count] = 0;445 r = bytetorune(x->fcall.data, &nr);446 t = &w->body;447 wincommit(w, t);448 eval = TRUE;449 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);450 free(r);451 if(nb < nr){452 respond(x, &fc, Ebadaddr);453 break;454 }455 if(!eval){456 respond(x, &fc, Eaddr);457 break;458 }459 w->addr = a;460 fc.count = x->fcall.count;461 respond(x, &fc, nil);462 break;464 case Qeditout:465 case QWeditout:466 r = bytetorune(x->fcall.data, &nr);467 if(w)468 err = edittext(w, w->wrselrange.q1, r, nr);469 else470 err = edittext(nil, 0, r, nr);471 free(r);472 if(err != nil){473 respond(x, &fc, err);474 break;475 }476 fc.count = x->fcall.count;477 respond(x, &fc, nil);478 break;480 case QWerrors:481 w = errorwinforwin(w);482 t = &w->body;483 goto BodyTag;485 case QWbody:486 case QWwrsel:487 t = &w->body;488 goto BodyTag;490 case QWctl:491 xfidctlwrite(x, w);492 break;494 case QWdata:495 a = w->addr;496 t = &w->body;497 wincommit(w, t);498 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){499 respond(x, &fc, Eaddr);500 break;501 }502 r = runemalloc(x->fcall.count);503 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);504 if(w->nomark == FALSE){505 seq++;506 filemark(t->file);507 }508 q0 = a.q0;509 if(a.q1 > q0){510 textdelete(t, q0, a.q1, TRUE);511 w->addr.q1 = q0;512 }513 tq0 = t->q0;514 tq1 = t->q1;515 textinsert(t, q0, r, nr, TRUE);516 if(tq0 >= q0)517 tq0 += nr;518 if(tq1 >= q0)519 tq1 += nr;520 textsetselect(t, tq0, tq1);521 if(shouldscroll(t, q0, qid))522 textshow(t, q0+nr, q0+nr, 0);523 textscrdraw(t);524 winsettag(w);525 free(r);526 w->addr.q0 += nr;527 w->addr.q1 = w->addr.q0;528 fc.count = x->fcall.count;529 respond(x, &fc, nil);530 break;532 case QWevent:533 xfideventwrite(x, w);534 break;536 case QWtag:537 t = &w->tag;538 goto BodyTag;540 BodyTag:541 q = x->f->nrpart;542 cnt = x->fcall.count;543 if(q > 0){544 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */545 memmove(x->fcall.data, x->f->rpart, q);546 cnt += q;547 x->f->nrpart = 0;548 }549 r = runemalloc(cnt);550 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);551 /* approach end of buffer */552 while(fullrune(x->fcall.data+nb, cnt-nb)){553 c = nb;554 nb += chartorune(&r[nr], x->fcall.data+c);555 if(r[nr])556 nr++;557 }558 if(nb < cnt){559 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);560 x->f->nrpart = cnt-nb;561 }562 if(nr > 0){563 wincommit(w, t);564 if(qid == QWwrsel){565 q0 = w->wrselrange.q1;566 if(q0 > t->file->b.nc)567 q0 = t->file->b.nc;568 }else569 q0 = t->file->b.nc;570 if(qid == QWtag)571 textinsert(t, q0, r, nr, TRUE);572 else{573 if(w->nomark == FALSE){574 seq++;575 filemark(t->file);576 }577 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);578 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */579 if(qid!=QWwrsel && shouldscroll(t, q0, qid))580 textshow(t, q0+nr, q0+nr, 1);581 textscrdraw(t);582 }583 winsettag(w);584 if(qid == QWwrsel)585 w->wrselrange.q1 += nr;586 free(r);587 }588 fc.count = x->fcall.count;589 respond(x, &fc, nil);590 break;592 default:593 sprint(buf, "unknown qid %d in write", qid);594 respond(x, &fc, buf);595 break;596 }597 if(w)598 winunlock(w);599 }601 void602 xfidctlwrite(Xfid *x, Window *w)603 {604 Fcall fc;605 int i, m, n, nb, nr, nulls;606 Rune *r;607 char *err, *p, *pp, *q, *e;608 int isfbuf, scrdraw, settag;609 Text *t;611 err = nil;612 e = x->fcall.data+x->fcall.count;613 scrdraw = FALSE;614 settag = FALSE;615 isfbuf = TRUE;616 if(x->fcall.count < RBUFSIZE)617 r = fbufalloc();618 else{619 isfbuf = FALSE;620 r = emalloc(x->fcall.count*UTFmax+1);621 }622 x->fcall.data[x->fcall.count] = 0;623 textcommit(&w->tag, TRUE);624 for(n=0; n<x->fcall.count; n+=m){625 p = x->fcall.data+n;626 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */627 qlock(&w->ctllock);628 w->ctlfid = x->f->fid;629 m = 4;630 }else631 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */632 w->ctlfid = ~0;633 qunlock(&w->ctllock);634 m = 6;635 }else636 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */637 t = &w->body;638 t->eq0 = ~0;639 filereset(t->file);640 t->file->mod = FALSE;641 w->dirty = FALSE;642 settag = TRUE;643 m = 5;644 }else645 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */646 t = &w->body;647 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */648 t->file->mod = TRUE;649 w->dirty = TRUE;650 settag = TRUE;651 m = 5;652 }else653 if(strncmp(p, "show", 4) == 0){ /* show dot */654 t = &w->body;655 textshow(t, t->q0, t->q1, 1);656 m = 4;657 }else658 if(strncmp(p, "name ", 5) == 0){ /* set file name */659 pp = p+5;660 m = 5;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 file name";671 break;672 }673 for(i=0; i<nr; i++)674 if(r[i] <= ' '){675 err = "bad character in file name";676 goto out;677 }678 out:679 seq++;680 filemark(w->body.file);681 winsetname(w, r, nr);682 m += (q+1) - pp;683 }else684 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */685 pp = p+5;686 m = 5;687 q = memchr(pp, '\n', e-pp);688 if(q==nil || q==pp){689 err = Ebadctl;690 break;691 }692 *q = 0;693 nulls = FALSE;694 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);695 if(nulls){696 err = "nulls in dump string";697 break;698 }699 w->dumpstr = runetobyte(r, nr);700 m += (q+1) - pp;701 }else702 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */703 pp = p+8;704 m = 8;705 q = memchr(pp, '\n', e-pp);706 if(q==nil || q==pp){707 err = Ebadctl;708 break;709 }710 *q = 0;711 nulls = FALSE;712 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);713 if(nulls){714 err = "nulls in dump directory string";715 break;716 }717 w->dumpdir = runetobyte(r, nr);718 m += (q+1) - pp;719 }else720 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */721 colclose(w->col, w, TRUE);722 m = 6;723 }else724 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */725 if(!winclean(w, TRUE)){726 err = "file dirty";727 break;728 }729 colclose(w->col, w, TRUE);730 m = 3;731 }else732 if(strncmp(p, "get", 3) == 0){ /* get file */733 get(&w->body, nil, nil, FALSE, XXX, nil, 0);734 m = 3;735 }else736 if(strncmp(p, "put", 3) == 0){ /* put file */737 put(&w->body, nil, nil, XXX, XXX, nil, 0);738 m = 3;739 }else740 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */741 textcommit(&w->body, TRUE);742 clampaddr(w);743 w->body.q0 = w->addr.q0;744 w->body.q1 = w->addr.q1;745 textsetselect(&w->body, w->body.q0, w->body.q1);746 settag = TRUE;747 m = 8;748 }else749 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */750 w->addr.q0 = w->body.q0;751 w->addr.q1 = w->body.q1;752 m = 8;753 }else754 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */755 textcommit(&w->body, TRUE);756 clampaddr(w);757 w->limit.q0 = w->addr.q0;758 w->limit.q1 = w->addr.q1;759 m = 10;760 }else761 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */762 w->nomark = TRUE;763 m = 6;764 }else765 if(strncmp(p, "mark", 4) == 0){ /* mark file */766 seq++;767 filemark(w->body.file);768 settag = TRUE;769 m = 4;770 }else771 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */772 w->filemenu = FALSE;773 m = 6;774 }else775 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */776 w->filemenu = TRUE;777 m = 4;778 }else779 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */780 wincleartag(w);781 settag = TRUE;782 m = 8;783 }else{784 err = Ebadctl;785 break;786 }787 while(p[m] == '\n')788 m++;789 }791 if(isfbuf)792 fbuffree(r);793 else794 free(r);795 if(err)796 n = 0;797 fc.count = n;798 respond(x, &fc, err);799 if(settag)800 winsettag(w);801 if(scrdraw)802 textscrdraw(&w->body);803 }805 void806 xfideventwrite(Xfid *x, Window *w)807 {808 Fcall fc;809 int m, n;810 Rune *r;811 char *err, *p, *q;812 int isfbuf;813 Text *t;814 int c;815 uint q0, q1;817 err = nil;818 isfbuf = TRUE;819 if(x->fcall.count < RBUFSIZE)820 r = fbufalloc();821 else{822 isfbuf = FALSE;823 r = emalloc(x->fcall.count*UTFmax+1);824 }825 for(n=0; n<x->fcall.count; n+=m){826 p = x->fcall.data+n;827 w->owner = *p++; /* disgusting */828 c = *p++;829 while(*p == ' ')830 p++;831 q0 = strtoul(p, &q, 10);832 if(q == p)833 goto Rescue;834 p = q;835 while(*p == ' ')836 p++;837 q1 = strtoul(p, &q, 10);838 if(q == p)839 goto Rescue;840 p = q;841 while(*p == ' ')842 p++;843 if(*p++ != '\n')844 goto Rescue;845 m = p-(x->fcall.data+n);846 if('a'<=c && c<='z')847 t = &w->tag;848 else if('A'<=c && c<='Z')849 t = &w->body;850 else851 goto Rescue;852 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)853 goto Rescue;855 qlock(&row.lk); /* just like mousethread */856 switch(c){857 case 'x':858 case 'X':859 execute(t, q0, q1, TRUE, nil);860 break;861 case 'l':862 case 'L':863 look3(t, q0, q1, TRUE);864 break;865 default:866 qunlock(&row.lk);867 goto Rescue;868 }869 qunlock(&row.lk);871 }873 Out:874 if(isfbuf)875 fbuffree(r);876 else877 free(r);878 if(err)879 n = 0;880 fc.count = n;881 respond(x, &fc, err);882 return;884 Rescue:885 err = Ebadevent;886 goto Out;887 }889 void890 xfidutfread(Xfid *x, Text *t, uint q1, int qid)891 {892 Fcall fc;893 Window *w;894 Rune *r;895 char *b, *b1;896 uint q, off, boff;897 int m, n, nr, nb;899 w = t->w;900 wincommit(w, t);901 off = x->fcall.offset;902 r = fbufalloc();903 b = fbufalloc();904 b1 = fbufalloc();905 n = 0;906 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){907 boff = w->utflastboff;908 q = w->utflastq;909 }else{910 /* BUG: stupid code: scan from beginning */911 boff = 0;912 q = 0;913 }914 w->utflastqid = qid;915 while(q<q1 && n<x->fcall.count){916 /*917 * Updating here avoids partial rune problem: we're always on a918 * char boundary. The cost is we will usually do one more read919 * than we really need, but that's better than being n^2.920 */921 w->utflastboff = boff;922 w->utflastq = q;923 nr = q1-q;924 if(nr > BUFSIZE/UTFmax)925 nr = BUFSIZE/UTFmax;926 bufread(&t->file->b, q, r, nr);927 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);928 if(boff >= off){929 m = nb;930 if(boff+m > off+x->fcall.count)931 m = off+x->fcall.count - boff;932 memmove(b1+n, b, m);933 n += m;934 }else if(boff+nb > off){935 if(n != 0)936 error("bad count in utfrune");937 m = nb - (off-boff);938 if(m > x->fcall.count)939 m = x->fcall.count;940 memmove(b1, b+(off-boff), m);941 n += m;942 }943 boff += nb;944 q += nr;945 }946 fbuffree(r);947 fbuffree(b);948 fc.count = n;949 fc.data = b1;950 respond(x, &fc, nil);951 fbuffree(b1);952 }954 int955 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)956 {957 Fcall fc;958 Window *w;959 Rune *r, junk;960 char *b, *b1;961 uint q, boff;962 int i, rw, m, n, nr, nb;964 w = t->w;965 wincommit(w, t);966 r = fbufalloc();967 b = fbufalloc();968 b1 = fbufalloc();969 n = 0;970 q = q0;971 boff = 0;972 while(q<q1 && n<x->fcall.count){973 nr = q1-q;974 if(nr > BUFSIZE/UTFmax)975 nr = BUFSIZE/UTFmax;976 bufread(&t->file->b, q, r, nr);977 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);978 m = nb;979 if(boff+m > x->fcall.count){980 i = x->fcall.count - boff;981 /* copy whole runes only */982 m = 0;983 nr = 0;984 while(m < i){985 rw = chartorune(&junk, b+m);986 if(m+rw > i)987 break;988 m += rw;989 nr++;990 }991 if(m == 0)992 break;993 }994 memmove(b1+n, b, m);995 n += m;996 boff += nb;997 q += nr;998 }999 fbuffree(r);1000 fbuffree(b);1001 fc.count = n;1002 fc.data = b1;1003 respond(x, &fc, nil);1004 fbuffree(b1);1005 return q-q0;1006 }1008 void1009 xfideventread(Xfid *x, Window *w)1010 {1011 Fcall fc;1012 int i, n;1014 i = 0;1015 x->flushed = FALSE;1016 while(w->nevents == 0){1017 if(i){1018 if(!x->flushed)1019 respond(x, &fc, "window shut down");1020 return;1021 }1022 w->eventx = x;1023 winunlock(w);1024 recvp(x->c);1025 winlock(w, 'F');1026 i++;1027 }1029 n = w->nevents;1030 if(n > x->fcall.count)1031 n = x->fcall.count;1032 fc.count = n;1033 fc.data = w->events;1034 respond(x, &fc, nil);1035 w->nevents -= n;1036 if(w->nevents){1037 memmove(w->events, w->events+n, w->nevents);1038 w->events = erealloc(w->events, w->nevents);1039 }else{1040 free(w->events);1041 w->events = nil;1042 }1043 }1045 void1046 xfidindexread(Xfid *x)1047 {1048 Fcall fc;1049 int i, j, m, n, nmax, isbuf, cnt, off;1050 Window *w;1051 char *b;1052 Rune *r;1053 Column *c;1055 qlock(&row.lk);1056 nmax = 0;1057 for(j=0; j<row.ncol; j++){1058 c = row.col[j];1059 for(i=0; i<c->nw; i++){1060 w = c->w[i];1061 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1062 }1063 }1064 nmax++;1065 isbuf = (nmax<=RBUFSIZE);1066 if(isbuf)1067 b = (char*)x->buf;1068 else1069 b = emalloc(nmax);1070 r = fbufalloc();1071 n = 0;1072 for(j=0; j<row.ncol; j++){1073 c = row.col[j];1074 for(i=0; i<c->nw; i++){1075 w = c->w[i];1076 /* only show the currently active window of a set */1077 if(w->body.file->curtext != &w->body)1078 continue;1079 winctlprint(w, b+n, 0);1080 n += Ctlsize;1081 m = min(RBUFSIZE, w->tag.file->b.nc);1082 bufread(&w->tag.file->b, 0, r, m);1083 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1084 while(n<m && b[n]!='\n')1085 n++;1086 b[n++] = '\n';1087 }1088 }1089 qunlock(&row.lk);1090 off = x->fcall.offset;1091 cnt = x->fcall.count;1092 if(off > n)1093 off = n;1094 if(off+cnt > n)1095 cnt = n-off;1096 fc.count = cnt;1097 memmove(r, b+off, cnt);1098 fc.data = (char*)r;1099 if(!isbuf)1100 free(b);1101 respond(x, &fc, nil);1102 fbuffree(r);1103 }