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 <libsec.h>12 #include "dat.h"13 #include "fns.h"15 enum16 {17 Ctlsize = 5*1218 };20 char Edel[] = "deleted window";21 char Ebadctl[] = "ill-formed control message";22 char Ebadaddr[] = "bad address syntax";23 char Eaddr[] = "address out of range";24 char Einuse[] = "already in use";25 char Ebadevent[] = "bad event syntax";26 extern char Eperm[];28 static29 void30 clampaddr(Window *w)31 {32 if(w->addr.q0 < 0)33 w->addr.q0 = 0;34 if(w->addr.q1 < 0)35 w->addr.q1 = 0;36 if(w->addr.q0 > w->body.file->b.nc)37 w->addr.q0 = w->body.file->b.nc;38 if(w->addr.q1 > w->body.file->b.nc)39 w->addr.q1 = w->body.file->b.nc;40 }42 void43 xfidctl(void *arg)44 {45 Xfid *x;46 void (*f)(Xfid*);48 threadsetname("xfidctlthread");49 x = arg;50 for(;;){51 f = (void(*)(Xfid*))recvp(x->c);52 (*f)(x);53 flushimage(display, 1);54 sendp(cxfidfree, x);55 }56 }58 void59 xfidflush(Xfid *x)60 {61 Fcall fc;62 int i, j;63 Window *w;64 Column *c;65 Xfid *wx;67 xfidlogflush(x);69 /* search windows for matching tag */70 qlock(&row.lk);71 for(j=0; j<row.ncol; j++){72 c = row.col[j];73 for(i=0; i<c->nw; i++){74 w = c->w[i];75 winlock(w, 'E');76 wx = w->eventx;77 if(wx!=nil && wx->fcall.tag==x->fcall.oldtag){78 w->eventx = nil;79 wx->flushed = TRUE;80 sendp(wx->c, nil);81 winunlock(w);82 goto out;83 }84 winunlock(w);85 }86 }87 out:88 qunlock(&row.lk);89 respond(x, &fc, nil);90 }92 void93 xfidopen(Xfid *x)94 {95 Fcall fc;96 Window *w;97 Text *t;98 char *s;99 Rune *r;100 int m, n, q, q0, q1;102 w = x->f->w;103 t = &w->body;104 q = FILE(x->f->qid);105 if(w){106 winlock(w, 'E');107 switch(q){108 case QWaddr:109 if(w->nopen[q]++ == 0){110 w->addr = range(0, 0);111 w->limit = range(-1,-1);112 }113 break;114 case QWdata:115 case QWxdata:116 w->nopen[q]++;117 break;118 case QWevent:119 if(w->nopen[q]++ == 0){120 if(!w->isdir && w->col!=nil){121 w->filemenu = FALSE;122 winsettag(w);123 }124 }125 break;126 case QWrdsel:127 /*128 * Use a temporary file.129 * A pipe would be the obvious, but we can't afford the130 * broken pipe notification. Using the code to read QWbody131 * is n², which should probably also be fixed. Even then,132 * though, we'd need to squirrel away the data in case it's133 * modified during the operation, e.g. by |sort134 */135 if(w->rdselfd > 0){136 winunlock(w);137 respond(x, &fc, Einuse);138 return;139 }140 w->rdselfd = tempfile();141 if(w->rdselfd < 0){142 winunlock(w);143 respond(x, &fc, "can't create temp file");144 return;145 }146 w->nopen[q]++;147 q0 = t->q0;148 q1 = t->q1;149 r = fbufalloc();150 s = fbufalloc();151 while(q0 < q1){152 n = q1 - q0;153 if(n > BUFSIZE/UTFmax)154 n = BUFSIZE/UTFmax;155 bufread(&t->file->b, q0, r, n);156 m = snprint(s, BUFSIZE+1, "%.*S", n, r);157 if(write(w->rdselfd, s, m) != m){158 warning(nil, "can't write temp file for pipe command %r\n");159 break;160 }161 q0 += n;162 }163 fbuffree(s);164 fbuffree(r);165 break;166 case QWwrsel:167 w->nopen[q]++;168 seq++;169 filemark(t->file);170 cut(t, t, nil, FALSE, TRUE, nil, 0);171 w->wrselrange = range(t->q1, t->q1);172 w->nomark = TRUE;173 break;174 case QWeditout:175 if(editing == FALSE){176 winunlock(w);177 respond(x, &fc, Eperm);178 return;179 }180 if(!canqlock(&w->editoutlk)){181 winunlock(w);182 respond(x, &fc, Einuse);183 return;184 }185 w->wrselrange = range(t->q1, t->q1);186 break;187 }188 winunlock(w);189 }190 else{191 switch(q){192 case Qlog:193 xfidlogopen(x);194 break;195 case Qeditout:196 if(!canqlock(&editoutlk)){197 respond(x, &fc, Einuse);198 return;199 }200 break;201 }202 }203 fc.qid = x->f->qid;204 fc.iounit = messagesize-IOHDRSZ;205 x->f->open = TRUE;206 respond(x, &fc, nil);207 }209 void210 xfidclose(Xfid *x)211 {212 Fcall fc;213 Window *w;214 int q;215 Text *t;217 w = x->f->w;218 x->f->busy = FALSE;219 x->f->w = nil;220 if(x->f->open == FALSE){221 if(w != nil)222 winclose(w);223 respond(x, &fc, nil);224 return;225 }227 q = FILE(x->f->qid);228 x->f->open = FALSE;229 if(w){230 winlock(w, 'E');231 switch(q){232 case QWctl:233 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){234 w->ctlfid = ~0;235 qunlock(&w->ctllock);236 }237 break;238 case QWdata:239 case QWxdata:240 w->nomark = FALSE;241 /* fall through */242 case QWaddr:243 case QWevent: /* BUG: do we need to shut down Xfid? */244 if(--w->nopen[q] == 0){245 if(q == QWdata || q == QWxdata)246 w->nomark = FALSE;247 if(q==QWevent && !w->isdir && w->col!=nil){248 w->filemenu = TRUE;249 winsettag(w);250 }251 if(q == QWevent){252 free(w->dumpstr);253 free(w->dumpdir);254 w->dumpstr = nil;255 w->dumpdir = nil;256 }257 }258 break;259 case QWrdsel:260 close(w->rdselfd);261 w->rdselfd = 0;262 break;263 case QWwrsel:264 w->nomark = FALSE;265 t = &w->body;266 /* before: only did this if !w->noscroll, but that didn't seem right in practice */267 textshow(t, min(w->wrselrange.q0, t->file->b.nc),268 min(w->wrselrange.q1, t->file->b.nc), 1);269 textscrdraw(t);270 break;271 case QWeditout:272 qunlock(&w->editoutlk);273 break;274 }275 winunlock(w);276 winclose(w);277 }278 else{279 switch(q){280 case Qeditout:281 qunlock(&editoutlk);282 break;283 }284 }285 respond(x, &fc, nil);286 }288 void289 xfidread(Xfid *x)290 {291 Fcall fc;292 int n, q;293 uint off;294 char *b;295 char buf[256];296 Window *w;298 q = FILE(x->f->qid);299 w = x->f->w;300 if(w == nil){301 fc.count = 0;302 switch(q){303 case Qcons:304 case Qlabel:305 break;306 case Qindex:307 xfidindexread(x);308 return;309 case Qlog:310 xfidlogread(x);311 return;312 default:313 warning(nil, "unknown qid %d\n", q);314 break;315 }316 respond(x, &fc, nil);317 return;318 }319 winlock(w, 'F');320 if(w->col == nil){321 winunlock(w);322 respond(x, &fc, Edel);323 return;324 }325 off = x->fcall.offset;326 switch(q){327 case QWaddr:328 textcommit(&w->body, TRUE);329 clampaddr(w);330 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);331 goto Readbuf;333 case QWbody:334 xfidutfread(x, &w->body, w->body.file->b.nc, QWbody);335 break;337 case QWctl:338 b = winctlprint(w, buf, 1);339 goto Readb;341 Readbuf:342 b = buf;343 Readb:344 n = strlen(b);345 if(off > n)346 off = n;347 if(off+x->fcall.count > n)348 x->fcall.count = n-off;349 fc.count = x->fcall.count;350 fc.data = b+off;351 respond(x, &fc, nil);352 if(b != buf)353 free(b);354 break;356 case QWevent:357 xfideventread(x, w);358 break;360 case QWdata:361 /* BUG: what should happen if q1 > q0? */362 if(w->addr.q0 > w->body.file->b.nc){363 respond(x, &fc, Eaddr);364 break;365 }366 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);367 w->addr.q1 = w->addr.q0;368 break;370 case QWxdata:371 /* BUG: what should happen if q1 > q0? */372 if(w->addr.q0 > w->body.file->b.nc){373 respond(x, &fc, Eaddr);374 break;375 }376 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);377 break;379 case QWtag:380 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);381 break;383 case QWrdsel:384 seek(w->rdselfd, off, 0);385 n = x->fcall.count;386 if(n > BUFSIZE)387 n = BUFSIZE;388 b = fbufalloc();389 n = read(w->rdselfd, b, n);390 if(n < 0){391 respond(x, &fc, "I/O error in temp file");392 break;393 }394 fc.count = n;395 fc.data = b;396 respond(x, &fc, nil);397 fbuffree(b);398 break;400 default:401 sprint(buf, "unknown qid %d in read", q);402 respond(x, &fc, nil);403 }404 winunlock(w);405 }407 static int408 shouldscroll(Text *t, uint q0, int qid)409 {410 if(qid == Qcons)411 return TRUE;412 return t->org <= q0 && q0 <= t->org+t->fr.nchars;413 }415 static Rune*416 fullrunewrite(Xfid *x, int *inr)417 {418 int q, cnt, c, nb, nr;419 Rune *r;421 q = x->f->nrpart;422 cnt = x->fcall.count;423 if(q > 0){424 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */425 memmove(x->fcall.data, x->f->rpart, q);426 cnt += q;427 x->f->nrpart = 0;428 }429 r = runemalloc(cnt);430 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);431 /* approach end of buffer */432 while(fullrune(x->fcall.data+nb, cnt-nb)){433 c = nb;434 nb += chartorune(&r[nr], x->fcall.data+c);435 if(r[nr])436 nr++;437 }438 if(nb < cnt){439 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);440 x->f->nrpart = cnt-nb;441 }442 *inr = nr;443 return r;444 }446 void447 xfidwrite(Xfid *x)448 {449 Fcall fc;450 int c, qid, nb, nr, eval;451 char buf[64], *err;452 Window *w;453 Rune *r;454 Range a;455 Text *t;456 uint q0, tq0, tq1;458 qid = FILE(x->f->qid);459 w = x->f->w;460 if(w){461 c = 'F';462 if(qid==QWtag || qid==QWbody)463 c = 'E';464 winlock(w, c);465 if(w->col == nil){466 winunlock(w);467 respond(x, &fc, Edel);468 return;469 }470 }471 x->fcall.data[x->fcall.count] = 0;472 switch(qid){473 case Qcons:474 w = errorwin(x->f->mntdir, 'X');475 t=&w->body;476 goto BodyTag;478 case Qlabel:479 fc.count = x->fcall.count;480 respond(x, &fc, nil);481 break;483 case QWaddr:484 x->fcall.data[x->fcall.count] = 0;485 r = bytetorune(x->fcall.data, &nr);486 t = &w->body;487 wincommit(w, t);488 eval = TRUE;489 a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);490 free(r);491 if(nb < nr){492 respond(x, &fc, Ebadaddr);493 break;494 }495 if(!eval){496 respond(x, &fc, Eaddr);497 break;498 }499 w->addr = a;500 fc.count = x->fcall.count;501 respond(x, &fc, nil);502 break;504 case Qeditout:505 case QWeditout:506 r = fullrunewrite(x, &nr);507 if(w)508 err = edittext(w, w->wrselrange.q1, r, nr);509 else510 err = edittext(nil, 0, r, nr);511 free(r);512 if(err != nil){513 respond(x, &fc, err);514 break;515 }516 fc.count = x->fcall.count;517 respond(x, &fc, nil);518 break;520 case QWerrors:521 w = errorwinforwin(w);522 t = &w->body;523 goto BodyTag;525 case QWbody:526 case QWwrsel:527 t = &w->body;528 goto BodyTag;530 case QWctl:531 xfidctlwrite(x, w);532 break;534 case QWdata:535 a = w->addr;536 t = &w->body;537 wincommit(w, t);538 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){539 respond(x, &fc, Eaddr);540 break;541 }542 r = runemalloc(x->fcall.count);543 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);544 if(w->nomark == FALSE){545 seq++;546 filemark(t->file);547 }548 q0 = a.q0;549 if(a.q1 > q0){550 textdelete(t, q0, a.q1, TRUE);551 w->addr.q1 = q0;552 }553 tq0 = t->q0;554 tq1 = t->q1;555 textinsert(t, q0, r, nr, TRUE);556 if(tq0 >= q0)557 tq0 += nr;558 if(tq1 >= q0)559 tq1 += nr;560 textsetselect(t, tq0, tq1);561 if(shouldscroll(t, q0, qid))562 textshow(t, q0+nr, q0+nr, 0);563 textscrdraw(t);564 winsettag(w);565 free(r);566 w->addr.q0 += nr;567 w->addr.q1 = w->addr.q0;568 fc.count = x->fcall.count;569 respond(x, &fc, nil);570 break;572 case QWevent:573 xfideventwrite(x, w);574 break;576 case QWtag:577 t = &w->tag;578 goto BodyTag;580 BodyTag:581 r = fullrunewrite(x, &nr);582 if(nr > 0){583 wincommit(w, t);584 if(qid == QWwrsel){585 q0 = w->wrselrange.q1;586 if(q0 > t->file->b.nc)587 q0 = t->file->b.nc;588 }else589 q0 = t->file->b.nc;590 if(qid == QWtag)591 textinsert(t, q0, r, nr, TRUE);592 else{593 if(w->nomark == FALSE){594 seq++;595 filemark(t->file);596 }597 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);598 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */599 if(qid!=QWwrsel && shouldscroll(t, q0, qid))600 textshow(t, q0+nr, q0+nr, 1);601 textscrdraw(t);602 }603 winsettag(w);604 if(qid == QWwrsel)605 w->wrselrange.q1 += nr;606 free(r);607 }608 fc.count = x->fcall.count;609 respond(x, &fc, nil);610 break;612 default:613 sprint(buf, "unknown qid %d in write", qid);614 respond(x, &fc, buf);615 break;616 }617 if(w)618 winunlock(w);619 }621 void622 xfidctlwrite(Xfid *x, Window *w)623 {624 Fcall fc;625 int i, m, n, nb, nr, nulls;626 Rune *r;627 char *err, *p, *pp, *q, *e;628 int isfbuf, scrdraw, settag;629 Text *t;631 err = nil;632 e = x->fcall.data+x->fcall.count;633 scrdraw = FALSE;634 settag = FALSE;635 isfbuf = TRUE;636 if(x->fcall.count < RBUFSIZE)637 r = fbufalloc();638 else{639 isfbuf = FALSE;640 r = emalloc(x->fcall.count*UTFmax+1);641 }642 x->fcall.data[x->fcall.count] = 0;643 textcommit(&w->tag, TRUE);644 for(n=0; n<x->fcall.count; n+=m){645 p = x->fcall.data+n;646 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */647 qlock(&w->ctllock);648 w->ctlfid = x->f->fid;649 m = 4;650 }else651 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */652 w->ctlfid = ~0;653 qunlock(&w->ctllock);654 m = 6;655 }else656 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */657 t = &w->body;658 t->eq0 = ~0;659 filereset(t->file);660 t->file->mod = FALSE;661 w->dirty = FALSE;662 settag = TRUE;663 m = 5;664 }else665 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */666 t = &w->body;667 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */668 t->file->mod = TRUE;669 w->dirty = TRUE;670 settag = TRUE;671 m = 5;672 }else673 if(strncmp(p, "show", 4) == 0){ /* show dot */674 t = &w->body;675 textshow(t, t->q0, t->q1, 1);676 m = 4;677 }else678 if(strncmp(p, "name ", 5) == 0){ /* set file name */679 pp = p+5;680 m = 5;681 q = memchr(pp, '\n', e-pp);682 if(q==nil || q==pp){683 err = Ebadctl;684 break;685 }686 *q = 0;687 nulls = FALSE;688 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);689 if(nulls){690 err = "nulls in file name";691 break;692 }693 for(i=0; i<nr; i++)694 if(r[i] <= ' '){695 err = "bad character in file name";696 goto out;697 }698 out:699 seq++;700 filemark(w->body.file);701 winsetname(w, r, nr);702 m += (q+1) - pp;703 }else704 if(strncmp(p, "font ", 5) == 0){ /* execute font command */705 pp = p+5;706 m = 5;707 q = memchr(pp, '\n', e-pp);708 if(q==nil || q==pp){709 err = Ebadctl;710 break;711 }712 *q = 0;713 nulls = FALSE;714 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);715 if(nulls){716 err = "nulls in font string";717 break;718 }719 fontx(&w->body, nil, nil, FALSE, XXX, r, nr);720 m += (q+1) - pp;721 }else722 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */723 pp = p+5;724 m = 5;725 q = memchr(pp, '\n', e-pp);726 if(q==nil || q==pp){727 err = Ebadctl;728 break;729 }730 *q = 0;731 nulls = FALSE;732 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);733 if(nulls){734 err = "nulls in dump string";735 break;736 }737 w->dumpstr = runetobyte(r, nr);738 m += (q+1) - pp;739 }else740 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */741 pp = p+8;742 m = 8;743 q = memchr(pp, '\n', e-pp);744 if(q==nil || q==pp){745 err = Ebadctl;746 break;747 }748 *q = 0;749 nulls = FALSE;750 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);751 if(nulls){752 err = "nulls in dump directory string";753 break;754 }755 w->dumpdir = runetobyte(r, nr);756 m += (q+1) - pp;757 }else758 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */759 colclose(w->col, w, TRUE);760 m = 6;761 }else762 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */763 if(!winclean(w, TRUE)){764 err = "file dirty";765 break;766 }767 colclose(w->col, w, TRUE);768 m = 3;769 }else770 if(strncmp(p, "get", 3) == 0){ /* get file */771 get(&w->body, nil, nil, FALSE, XXX, nil, 0);772 m = 3;773 }else774 if(strncmp(p, "put", 3) == 0){ /* put file */775 put(&w->body, nil, nil, XXX, XXX, nil, 0);776 m = 3;777 }else778 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */779 textcommit(&w->body, TRUE);780 clampaddr(w);781 w->body.q0 = w->addr.q0;782 w->body.q1 = w->addr.q1;783 textsetselect(&w->body, w->body.q0, w->body.q1);784 settag = TRUE;785 m = 8;786 }else787 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */788 w->addr.q0 = w->body.q0;789 w->addr.q1 = w->body.q1;790 m = 8;791 }else792 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */793 textcommit(&w->body, TRUE);794 clampaddr(w);795 w->limit.q0 = w->addr.q0;796 w->limit.q1 = w->addr.q1;797 m = 10;798 }else799 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */800 w->nomark = TRUE;801 m = 6;802 }else803 if(strncmp(p, "mark", 4) == 0){ /* mark file */804 seq++;805 filemark(w->body.file);806 settag = TRUE;807 m = 4;808 }else809 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */810 w->filemenu = FALSE;811 settag = TRUE;812 m = 6;813 }else814 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */815 w->filemenu = TRUE;816 settag = TRUE;817 m = 4;818 }else819 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */820 wincleartag(w);821 settag = TRUE;822 m = 8;823 }else{824 err = Ebadctl;825 break;826 }827 while(p[m] == '\n')828 m++;829 }831 if(isfbuf)832 fbuffree(r);833 else834 free(r);835 if(err)836 n = 0;837 fc.count = n;838 respond(x, &fc, err);839 if(settag)840 winsettag(w);841 if(scrdraw)842 textscrdraw(&w->body);843 }845 void846 xfideventwrite(Xfid *x, Window *w)847 {848 Fcall fc;849 int m, n;850 Rune *r;851 char *err, *p, *q;852 int isfbuf;853 Text *t;854 int c;855 uint q0, q1;857 err = nil;858 isfbuf = TRUE;859 if(x->fcall.count < RBUFSIZE)860 r = fbufalloc();861 else{862 isfbuf = FALSE;863 r = emalloc(x->fcall.count*UTFmax+1);864 }865 for(n=0; n<x->fcall.count; n+=m){866 p = x->fcall.data+n;867 w->owner = *p++; /* disgusting */868 c = *p++;869 while(*p == ' ')870 p++;871 q0 = strtoul(p, &q, 10);872 if(q == p)873 goto Rescue;874 p = q;875 while(*p == ' ')876 p++;877 q1 = strtoul(p, &q, 10);878 if(q == p)879 goto Rescue;880 p = q;881 while(*p == ' ')882 p++;883 if(*p++ != '\n')884 goto Rescue;885 m = p-(x->fcall.data+n);886 if('a'<=c && c<='z')887 t = &w->tag;888 else if('A'<=c && c<='Z')889 t = &w->body;890 else891 goto Rescue;892 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)893 goto Rescue;895 qlock(&row.lk); /* just like mousethread */896 switch(c){897 case 'x':898 case 'X':899 execute(t, q0, q1, TRUE, nil);900 break;901 case 'l':902 case 'L':903 look3(t, q0, q1, TRUE);904 break;905 default:906 qunlock(&row.lk);907 goto Rescue;908 }909 qunlock(&row.lk);911 }913 Out:914 if(isfbuf)915 fbuffree(r);916 else917 free(r);918 if(err)919 n = 0;920 fc.count = n;921 respond(x, &fc, err);922 return;924 Rescue:925 err = Ebadevent;926 goto Out;927 }929 void930 xfidutfread(Xfid *x, Text *t, uint q1, int qid)931 {932 Fcall fc;933 Window *w;934 Rune *r;935 char *b, *b1;936 uint q, off, boff;937 int m, n, nr, nb;939 w = t->w;940 wincommit(w, t);941 off = x->fcall.offset;942 r = fbufalloc();943 b = fbufalloc();944 b1 = fbufalloc();945 n = 0;946 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){947 boff = w->utflastboff;948 q = w->utflastq;949 }else{950 /* BUG: stupid code: scan from beginning */951 boff = 0;952 q = 0;953 }954 w->utflastqid = qid;955 while(q<q1 && n<x->fcall.count){956 /*957 * Updating here avoids partial rune problem: we're always on a958 * char boundary. The cost is we will usually do one more read959 * than we really need, but that's better than being n^2.960 */961 w->utflastboff = boff;962 w->utflastq = q;963 nr = q1-q;964 if(nr > BUFSIZE/UTFmax)965 nr = BUFSIZE/UTFmax;966 bufread(&t->file->b, q, r, nr);967 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);968 if(boff >= off){969 m = nb;970 if(boff+m > off+x->fcall.count)971 m = off+x->fcall.count - boff;972 memmove(b1+n, b, m);973 n += m;974 }else if(boff+nb > off){975 if(n != 0)976 error("bad count in utfrune");977 m = nb - (off-boff);978 if(m > x->fcall.count)979 m = x->fcall.count;980 memmove(b1, b+(off-boff), m);981 n += m;982 }983 boff += nb;984 q += nr;985 }986 fbuffree(r);987 fbuffree(b);988 fc.count = n;989 fc.data = b1;990 respond(x, &fc, nil);991 fbuffree(b1);992 }994 int995 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)996 {997 Fcall fc;998 Window *w;999 Rune *r, junk;1000 char *b, *b1;1001 uint q, boff;1002 int i, rw, m, n, nr, nb;1004 w = t->w;1005 wincommit(w, t);1006 r = fbufalloc();1007 b = fbufalloc();1008 b1 = fbufalloc();1009 n = 0;1010 q = q0;1011 boff = 0;1012 while(q<q1 && n<x->fcall.count){1013 nr = q1-q;1014 if(nr > BUFSIZE/UTFmax)1015 nr = BUFSIZE/UTFmax;1016 bufread(&t->file->b, q, r, nr);1017 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);1018 m = nb;1019 if(boff+m > x->fcall.count){1020 i = x->fcall.count - boff;1021 /* copy whole runes only */1022 m = 0;1023 nr = 0;1024 while(m < i){1025 rw = chartorune(&junk, b+m);1026 if(m+rw > i)1027 break;1028 m += rw;1029 nr++;1030 }1031 if(m == 0)1032 break;1033 }1034 memmove(b1+n, b, m);1035 n += m;1036 boff += nb;1037 q += nr;1038 }1039 fbuffree(r);1040 fbuffree(b);1041 fc.count = n;1042 fc.data = b1;1043 respond(x, &fc, nil);1044 fbuffree(b1);1045 return q-q0;1046 }1048 void1049 xfideventread(Xfid *x, Window *w)1050 {1051 Fcall fc;1052 int i, n;1054 i = 0;1055 x->flushed = FALSE;1056 while(w->nevents == 0){1057 if(i){1058 if(!x->flushed)1059 respond(x, &fc, "window shut down");1060 return;1061 }1062 w->eventx = x;1063 winunlock(w);1064 recvp(x->c);1065 winlock(w, 'F');1066 i++;1067 }1069 n = w->nevents;1070 if(n > x->fcall.count)1071 n = x->fcall.count;1072 fc.count = n;1073 fc.data = w->events;1074 respond(x, &fc, nil);1075 w->nevents -= n;1076 if(w->nevents){1077 memmove(w->events, w->events+n, w->nevents);1078 w->events = erealloc(w->events, w->nevents);1079 }else{1080 free(w->events);1081 w->events = nil;1082 }1083 }1085 void1086 xfidindexread(Xfid *x)1087 {1088 Fcall fc;1089 int i, j, m, n, nmax, isbuf, cnt, off;1090 Window *w;1091 char *b;1092 Rune *r;1093 Column *c;1095 qlock(&row.lk);1096 nmax = 0;1097 for(j=0; j<row.ncol; j++){1098 c = row.col[j];1099 for(i=0; i<c->nw; i++){1100 w = c->w[i];1101 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1102 }1103 }1104 nmax++;1105 isbuf = (nmax<=RBUFSIZE);1106 if(isbuf)1107 b = (char*)x->buf;1108 else1109 b = emalloc(nmax);1110 r = fbufalloc();1111 n = 0;1112 for(j=0; j<row.ncol; j++){1113 c = row.col[j];1114 for(i=0; i<c->nw; i++){1115 w = c->w[i];1116 /* only show the currently active window of a set */1117 if(w->body.file->curtext != &w->body)1118 continue;1119 winctlprint(w, b+n, 0);1120 n += Ctlsize;1121 m = min(RBUFSIZE, w->tag.file->b.nc);1122 bufread(&w->tag.file->b, 0, r, m);1123 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1124 while(n<m && b[n]!='\n')1125 n++;1126 b[n++] = '\n';1127 }1128 }1129 qunlock(&row.lk);1130 off = x->fcall.offset;1131 cnt = x->fcall.count;1132 if(off > n)1133 off = n;1134 if(off+cnt > n)1135 cnt = n-off;1136 fc.count = cnt;1137 memmove(r, b+off, cnt);1138 fc.data = (char*)r;1139 if(!isbuf)1140 free(b);1141 respond(x, &fc, nil);1142 fbuffree(r);1143 }