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, "dump ", 5) == 0){ /* set dump string */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 dump string";717 break;718 }719 w->dumpstr = runetobyte(r, nr);720 m += (q+1) - pp;721 }else722 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */723 pp = p+8;724 m = 8;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 directory string";735 break;736 }737 w->dumpdir = runetobyte(r, nr);738 m += (q+1) - pp;739 }else740 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */741 colclose(w->col, w, TRUE);742 m = 6;743 }else744 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */745 if(!winclean(w, TRUE)){746 err = "file dirty";747 break;748 }749 colclose(w->col, w, TRUE);750 m = 3;751 }else752 if(strncmp(p, "get", 3) == 0){ /* get file */753 get(&w->body, nil, nil, FALSE, XXX, nil, 0);754 m = 3;755 }else756 if(strncmp(p, "put", 3) == 0){ /* put file */757 put(&w->body, nil, nil, XXX, XXX, nil, 0);758 m = 3;759 }else760 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */761 textcommit(&w->body, TRUE);762 clampaddr(w);763 w->body.q0 = w->addr.q0;764 w->body.q1 = w->addr.q1;765 textsetselect(&w->body, w->body.q0, w->body.q1);766 settag = TRUE;767 m = 8;768 }else769 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */770 w->addr.q0 = w->body.q0;771 w->addr.q1 = w->body.q1;772 m = 8;773 }else774 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */775 textcommit(&w->body, TRUE);776 clampaddr(w);777 w->limit.q0 = w->addr.q0;778 w->limit.q1 = w->addr.q1;779 m = 10;780 }else781 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */782 w->nomark = TRUE;783 m = 6;784 }else785 if(strncmp(p, "mark", 4) == 0){ /* mark file */786 seq++;787 filemark(w->body.file);788 settag = TRUE;789 m = 4;790 }else791 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */792 w->filemenu = FALSE;793 settag = TRUE;794 m = 6;795 }else796 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */797 w->filemenu = TRUE;798 settag = TRUE;799 m = 4;800 }else801 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */802 wincleartag(w);803 settag = TRUE;804 m = 8;805 }else{806 err = Ebadctl;807 break;808 }809 while(p[m] == '\n')810 m++;811 }813 if(isfbuf)814 fbuffree(r);815 else816 free(r);817 if(err)818 n = 0;819 fc.count = n;820 respond(x, &fc, err);821 if(settag)822 winsettag(w);823 if(scrdraw)824 textscrdraw(&w->body);825 }827 void828 xfideventwrite(Xfid *x, Window *w)829 {830 Fcall fc;831 int m, n;832 Rune *r;833 char *err, *p, *q;834 int isfbuf;835 Text *t;836 int c;837 uint q0, q1;839 err = nil;840 isfbuf = TRUE;841 if(x->fcall.count < RBUFSIZE)842 r = fbufalloc();843 else{844 isfbuf = FALSE;845 r = emalloc(x->fcall.count*UTFmax+1);846 }847 for(n=0; n<x->fcall.count; n+=m){848 p = x->fcall.data+n;849 w->owner = *p++; /* disgusting */850 c = *p++;851 while(*p == ' ')852 p++;853 q0 = strtoul(p, &q, 10);854 if(q == p)855 goto Rescue;856 p = q;857 while(*p == ' ')858 p++;859 q1 = strtoul(p, &q, 10);860 if(q == p)861 goto Rescue;862 p = q;863 while(*p == ' ')864 p++;865 if(*p++ != '\n')866 goto Rescue;867 m = p-(x->fcall.data+n);868 if('a'<=c && c<='z')869 t = &w->tag;870 else if('A'<=c && c<='Z')871 t = &w->body;872 else873 goto Rescue;874 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)875 goto Rescue;877 qlock(&row.lk); /* just like mousethread */878 switch(c){879 case 'x':880 case 'X':881 execute(t, q0, q1, TRUE, nil);882 break;883 case 'l':884 case 'L':885 look3(t, q0, q1, TRUE);886 break;887 default:888 qunlock(&row.lk);889 goto Rescue;890 }891 qunlock(&row.lk);893 }895 Out:896 if(isfbuf)897 fbuffree(r);898 else899 free(r);900 if(err)901 n = 0;902 fc.count = n;903 respond(x, &fc, err);904 return;906 Rescue:907 err = Ebadevent;908 goto Out;909 }911 void912 xfidutfread(Xfid *x, Text *t, uint q1, int qid)913 {914 Fcall fc;915 Window *w;916 Rune *r;917 char *b, *b1;918 uint q, off, boff;919 int m, n, nr, nb;921 w = t->w;922 wincommit(w, t);923 off = x->fcall.offset;924 r = fbufalloc();925 b = fbufalloc();926 b1 = fbufalloc();927 n = 0;928 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){929 boff = w->utflastboff;930 q = w->utflastq;931 }else{932 /* BUG: stupid code: scan from beginning */933 boff = 0;934 q = 0;935 }936 w->utflastqid = qid;937 while(q<q1 && n<x->fcall.count){938 /*939 * Updating here avoids partial rune problem: we're always on a940 * char boundary. The cost is we will usually do one more read941 * than we really need, but that's better than being n^2.942 */943 w->utflastboff = boff;944 w->utflastq = q;945 nr = q1-q;946 if(nr > BUFSIZE/UTFmax)947 nr = BUFSIZE/UTFmax;948 bufread(&t->file->b, q, r, nr);949 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);950 if(boff >= off){951 m = nb;952 if(boff+m > off+x->fcall.count)953 m = off+x->fcall.count - boff;954 memmove(b1+n, b, m);955 n += m;956 }else if(boff+nb > off){957 if(n != 0)958 error("bad count in utfrune");959 m = nb - (off-boff);960 if(m > x->fcall.count)961 m = x->fcall.count;962 memmove(b1, b+(off-boff), m);963 n += m;964 }965 boff += nb;966 q += nr;967 }968 fbuffree(r);969 fbuffree(b);970 fc.count = n;971 fc.data = b1;972 respond(x, &fc, nil);973 fbuffree(b1);974 }976 int977 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)978 {979 Fcall fc;980 Window *w;981 Rune *r, junk;982 char *b, *b1;983 uint q, boff;984 int i, rw, m, n, nr, nb;986 w = t->w;987 wincommit(w, t);988 r = fbufalloc();989 b = fbufalloc();990 b1 = fbufalloc();991 n = 0;992 q = q0;993 boff = 0;994 while(q<q1 && n<x->fcall.count){995 nr = q1-q;996 if(nr > BUFSIZE/UTFmax)997 nr = BUFSIZE/UTFmax;998 bufread(&t->file->b, q, r, nr);999 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);1000 m = nb;1001 if(boff+m > x->fcall.count){1002 i = x->fcall.count - boff;1003 /* copy whole runes only */1004 m = 0;1005 nr = 0;1006 while(m < i){1007 rw = chartorune(&junk, b+m);1008 if(m+rw > i)1009 break;1010 m += rw;1011 nr++;1012 }1013 if(m == 0)1014 break;1015 }1016 memmove(b1+n, b, m);1017 n += m;1018 boff += nb;1019 q += nr;1020 }1021 fbuffree(r);1022 fbuffree(b);1023 fc.count = n;1024 fc.data = b1;1025 respond(x, &fc, nil);1026 fbuffree(b1);1027 return q-q0;1028 }1030 void1031 xfideventread(Xfid *x, Window *w)1032 {1033 Fcall fc;1034 int i, n;1036 i = 0;1037 x->flushed = FALSE;1038 while(w->nevents == 0){1039 if(i){1040 if(!x->flushed)1041 respond(x, &fc, "window shut down");1042 return;1043 }1044 w->eventx = x;1045 winunlock(w);1046 recvp(x->c);1047 winlock(w, 'F');1048 i++;1049 }1051 n = w->nevents;1052 if(n > x->fcall.count)1053 n = x->fcall.count;1054 fc.count = n;1055 fc.data = w->events;1056 respond(x, &fc, nil);1057 w->nevents -= n;1058 if(w->nevents){1059 memmove(w->events, w->events+n, w->nevents);1060 w->events = erealloc(w->events, w->nevents);1061 }else{1062 free(w->events);1063 w->events = nil;1064 }1065 }1067 void1068 xfidindexread(Xfid *x)1069 {1070 Fcall fc;1071 int i, j, m, n, nmax, isbuf, cnt, off;1072 Window *w;1073 char *b;1074 Rune *r;1075 Column *c;1077 qlock(&row.lk);1078 nmax = 0;1079 for(j=0; j<row.ncol; j++){1080 c = row.col[j];1081 for(i=0; i<c->nw; i++){1082 w = c->w[i];1083 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;1084 }1085 }1086 nmax++;1087 isbuf = (nmax<=RBUFSIZE);1088 if(isbuf)1089 b = (char*)x->buf;1090 else1091 b = emalloc(nmax);1092 r = fbufalloc();1093 n = 0;1094 for(j=0; j<row.ncol; j++){1095 c = row.col[j];1096 for(i=0; i<c->nw; i++){1097 w = c->w[i];1098 /* only show the currently active window of a set */1099 if(w->body.file->curtext != &w->body)1100 continue;1101 winctlprint(w, b+n, 0);1102 n += Ctlsize;1103 m = min(RBUFSIZE, w->tag.file->b.nc);1104 bufread(&w->tag.file->b, 0, r, m);1105 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);1106 while(n<m && b[n]!='\n')1107 n++;1108 b[n++] = '\n';1109 }1110 }1111 qunlock(&row.lk);1112 off = x->fcall.offset;1113 cnt = x->fcall.count;1114 if(off > n)1115 off = n;1116 if(off+cnt > n)1117 cnt = n-off;1118 fc.count = cnt;1119 memmove(r, b+off, cnt);1120 fc.data = (char*)r;1121 if(!isbuf)1122 free(b);1123 respond(x, &fc, nil);1124 fbuffree(r);1125 }