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 enum
15 {
16 Ctlsize = 5*12
17 };
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 static
28 void
29 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 void
42 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 void
58 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 void
90 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 if(w){
102 winlock(w, 'E');
103 q = FILE(x->f->qid);
104 switch(q){
105 case QWaddr:
106 if(w->nopen[q]++ == 0){
107 w->addr = range(0,0);
108 w->limit = range(-1,-1);
110 break;
111 case QWdata:
112 w->nopen[q]++;
113 break;
114 case QWevent:
115 if(w->nopen[q]++ == 0){
116 if(!w->isdir && w->col!=nil){
117 w->filemenu = FALSE;
118 winsettag(w);
121 break;
122 case QWrdsel:
123 /*
124 * Use a temporary file.
125 * A pipe would be the obvious, but we can't afford the
126 * broken pipe notification. Using the code to read QWbody
127 * is n², which should probably also be fixed. Even then,
128 * though, we'd need to squirrel away the data in case it's
129 * modified during the operation, e.g. by |sort
130 */
131 if(w->rdselfd > 0){
132 winunlock(w);
133 respond(x, &fc, Einuse);
134 return;
136 w->rdselfd = tempfile();
137 if(w->rdselfd < 0){
138 winunlock(w);
139 respond(x, &fc, "can't create temp file");
140 return;
142 w->nopen[q]++;
143 q0 = t->q0;
144 q1 = t->q1;
145 r = fbufalloc();
146 s = fbufalloc();
147 while(q0 < q1){
148 n = q1 - q0;
149 if(n > BUFSIZE/UTFmax)
150 n = BUFSIZE/UTFmax;
151 bufread(&t->file->b, q0, r, n);
152 m = snprint(s, BUFSIZE+1, "%.*S", n, r);
153 if(write(w->rdselfd, s, m) != m){
154 warning(nil, "can't write temp file for pipe command %r\n");
155 break;
157 q0 += n;
159 fbuffree(s);
160 fbuffree(r);
161 break;
162 case QWwrsel:
163 w->nopen[q]++;
164 seq++;
165 filemark(t->file);
166 cut(t, t, nil, FALSE, TRUE, nil, 0);
167 w->wrselrange = range(t->q1, t->q1);
168 w->nomark = TRUE;
169 break;
170 case QWeditout:
171 if(editing == FALSE){
172 winunlock(w);
173 respond(x, &fc, Eperm);
174 return;
176 w->wrselrange = range(t->q1, t->q1);
177 break;
179 winunlock(w);
181 fc.qid = x->f->qid;
182 fc.iounit = messagesize-IOHDRSZ;
183 x->f->open = TRUE;
184 respond(x, &fc, nil);
187 void
188 xfidclose(Xfid *x)
190 Fcall fc;
191 Window *w;
192 int q;
193 Text *t;
195 w = x->f->w;
196 x->f->busy = FALSE;
197 x->f->w = nil;
198 if(x->f->open == FALSE){
199 if(w != nil)
200 winclose(w);
201 respond(x, &fc, nil);
202 return;
205 x->f->open = FALSE;
206 if(w){
207 winlock(w, 'E');
208 q = FILE(x->f->qid);
209 switch(q){
210 case QWctl:
211 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){
212 w->ctlfid = ~0;
213 qunlock(&w->ctllock);
215 break;
216 case QWdata:
217 w->nomark = FALSE;
218 /* fall through */
219 case QWaddr:
220 case QWevent: /* BUG: do we need to shut down Xfid? */
221 if(--w->nopen[q] == 0){
222 if(q == QWdata)
223 w->nomark = FALSE;
224 if(q==QWevent && !w->isdir && w->col!=nil){
225 w->filemenu = TRUE;
226 winsettag(w);
228 if(q == QWevent){
229 free(w->dumpstr);
230 free(w->dumpdir);
231 w->dumpstr = nil;
232 w->dumpdir = nil;
235 break;
236 case QWrdsel:
237 close(w->rdselfd);
238 w->rdselfd = 0;
239 break;
240 case QWwrsel:
241 w->nomark = FALSE;
242 t = &w->body;
243 /* before: only did this if !w->noscroll, but that didn't seem right in practice */
244 textshow(t, min(w->wrselrange.q0, t->file->b.nc),
245 min(w->wrselrange.q1, t->file->b.nc), 1);
246 textscrdraw(t);
247 break;
249 winunlock(w);
250 winclose(w);
252 respond(x, &fc, nil);
255 void
256 xfidread(Xfid *x)
258 Fcall fc;
259 int n, q;
260 uint off;
261 char *b;
262 char buf[128];
263 Window *w;
265 q = FILE(x->f->qid);
266 w = x->f->w;
267 if(w == nil){
268 fc.count = 0;
269 switch(q){
270 case Qcons:
271 case Qlabel:
272 break;
273 case Qindex:
274 xfidindexread(x);
275 return;
276 default:
277 warning(nil, "unknown qid %d\n", q);
278 break;
280 respond(x, &fc, nil);
281 return;
283 winlock(w, 'F');
284 if(w->col == nil){
285 winunlock(w);
286 respond(x, &fc, Edel);
287 return;
289 off = x->fcall.offset;
290 switch(q){
291 case QWaddr:
292 textcommit(&w->body, TRUE);
293 clampaddr(w);
294 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);
295 goto Readbuf;
297 case QWbody:
298 xfidutfread(x, &w->body, w->body.file->b.nc, QWbody);
299 break;
301 case QWctl:
302 winctlprint(w, buf, 1);
303 goto Readbuf;
305 Readbuf:
306 n = strlen(buf);
307 if(off > n)
308 off = n;
309 if(off+x->fcall.count > n)
310 x->fcall.count = n-off;
311 fc.count = x->fcall.count;
312 fc.data = buf+off;
313 respond(x, &fc, nil);
314 break;
316 case QWevent:
317 xfideventread(x, w);
318 break;
320 case QWdata:
321 /* BUG: what should happen if q1 > q0? */
322 if(w->addr.q0 > w->body.file->b.nc){
323 respond(x, &fc, Eaddr);
324 break;
326 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->b.nc);
327 w->addr.q1 = w->addr.q0;
328 break;
330 case QWtag:
331 xfidutfread(x, &w->tag, w->tag.file->b.nc, QWtag);
332 break;
334 case QWrdsel:
335 seek(w->rdselfd, off, 0);
336 n = x->fcall.count;
337 if(n > BUFSIZE)
338 n = BUFSIZE;
339 b = fbufalloc();
340 n = read(w->rdselfd, b, n);
341 if(n < 0){
342 respond(x, &fc, "I/O error in temp file");
343 break;
345 fc.count = n;
346 fc.data = b;
347 respond(x, &fc, nil);
348 fbuffree(b);
349 break;
351 default:
352 sprint(buf, "unknown qid %d in read", q);
353 respond(x, &fc, nil);
355 winunlock(w);
358 void
359 xfidwrite(Xfid *x)
361 Fcall fc;
362 int c, cnt, qid, q, nb, nr, eval;
363 char buf[64], *err;
364 Window *w;
365 Rune *r;
366 Range a;
367 Text *t;
368 uint q0, tq0, tq1;
370 qid = FILE(x->f->qid);
371 w = x->f->w;
372 if(w){
373 c = 'F';
374 if(qid==QWtag || qid==QWbody)
375 c = 'E';
376 winlock(w, c);
377 if(w->col == nil){
378 winunlock(w);
379 respond(x, &fc, Edel);
380 return;
383 x->fcall.data[x->fcall.count] = 0;
384 switch(qid){
385 case Qcons:
386 w = errorwin(x->f->mntdir, 'X');
387 t=&w->body;
388 goto BodyTag;
390 case Qlabel:
391 fc.count = x->fcall.count;
392 respond(x, &fc, nil);
393 break;
395 case QWaddr:
396 x->fcall.data[x->fcall.count] = 0;
397 r = bytetorune(x->fcall.data, &nr);
398 t = &w->body;
399 wincommit(w, t);
400 eval = TRUE;
401 a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
402 free(r);
403 if(nb < nr){
404 respond(x, &fc, Ebadaddr);
405 break;
407 if(!eval){
408 respond(x, &fc, Eaddr);
409 break;
411 w->addr = a;
412 fc.count = x->fcall.count;
413 respond(x, &fc, nil);
414 break;
416 case Qeditout:
417 case QWeditout:
418 r = bytetorune(x->fcall.data, &nr);
419 if(w)
420 err = edittext(w, w->wrselrange.q1, r, nr);
421 else
422 err = edittext(nil, 0, r, nr);
423 free(r);
424 if(err != nil){
425 respond(x, &fc, err);
426 break;
428 fc.count = x->fcall.count;
429 respond(x, &fc, nil);
430 break;
432 case QWbody:
433 case QWwrsel:
434 t = &w->body;
435 goto BodyTag;
437 case QWctl:
438 xfidctlwrite(x, w);
439 break;
441 case QWdata:
442 a = w->addr;
443 t = &w->body;
444 wincommit(w, t);
445 if(a.q0>t->file->b.nc || a.q1>t->file->b.nc){
446 respond(x, &fc, Eaddr);
447 break;
449 r = runemalloc(x->fcall.count);
450 cvttorunes(x->fcall.data, x->fcall.count, r, &nb, &nr, nil);
451 if(w->nomark == FALSE){
452 seq++;
453 filemark(t->file);
455 q0 = a.q0;
456 if(a.q1 > q0){
457 textdelete(t, q0, a.q1, TRUE);
458 w->addr.q1 = q0;
460 tq0 = t->q0;
461 tq1 = t->q1;
462 textinsert(t, q0, r, nr, TRUE);
463 if(tq0 >= q0)
464 tq0 += nr;
465 if(tq1 >= q0)
466 tq1 += nr;
467 textsetselect(t, tq0, tq1);
468 if(!t->w->noscroll)
469 textshow(t, q0, q0+nr, 0);
470 textscrdraw(t);
471 winsettag(w);
472 free(r);
473 w->addr.q0 += nr;
474 w->addr.q1 = w->addr.q0;
475 fc.count = x->fcall.count;
476 respond(x, &fc, nil);
477 break;
479 case QWevent:
480 xfideventwrite(x, w);
481 break;
483 case QWtag:
484 t = &w->tag;
485 goto BodyTag;
487 BodyTag:
488 q = x->f->nrpart;
489 cnt = x->fcall.count;
490 if(q > 0){
491 memmove(x->fcall.data+q, x->fcall.data, cnt); /* there's room; see fsysproc */
492 memmove(x->fcall.data, x->f->rpart, q);
493 cnt += q;
494 x->f->nrpart = 0;
496 r = runemalloc(cnt);
497 cvttorunes(x->fcall.data, cnt-UTFmax, r, &nb, &nr, nil);
498 /* approach end of buffer */
499 while(fullrune(x->fcall.data+nb, cnt-nb)){
500 c = nb;
501 nb += chartorune(&r[nr], x->fcall.data+c);
502 if(r[nr])
503 nr++;
505 if(nb < cnt){
506 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);
507 x->f->nrpart = cnt-nb;
509 if(nr > 0){
510 wincommit(w, t);
511 if(qid == QWwrsel){
512 q0 = w->wrselrange.q1;
513 if(q0 > t->file->b.nc)
514 q0 = t->file->b.nc;
515 }else
516 q0 = t->file->b.nc;
517 if(qid == QWtag)
518 textinsert(t, q0, r, nr, TRUE);
519 else{
520 if(w->nomark == FALSE){
521 seq++;
522 filemark(t->file);
524 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
525 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
526 if(qid!=QWwrsel && !t->w->noscroll)
527 textshow(t, q0+nr, q0+nr, 1);
528 textscrdraw(t);
530 winsettag(w);
531 if(qid == QWwrsel)
532 w->wrselrange.q1 += nr;
533 free(r);
535 fc.count = x->fcall.count;
536 respond(x, &fc, nil);
537 break;
539 default:
540 sprint(buf, "unknown qid %d in write", qid);
541 respond(x, &fc, buf);
542 break;
544 if(w)
545 winunlock(w);
548 void
549 xfidctlwrite(Xfid *x, Window *w)
551 Fcall fc;
552 int i, m, n, nb, nr, nulls;
553 Rune *r;
554 char *err, *p, *pp, *q, *e;
555 int isfbuf, scrdraw, settag;
556 Text *t;
558 err = nil;
559 e = x->fcall.data+x->fcall.count;
560 scrdraw = FALSE;
561 settag = FALSE;
562 isfbuf = TRUE;
563 if(x->fcall.count < RBUFSIZE)
564 r = fbufalloc();
565 else{
566 isfbuf = FALSE;
567 r = emalloc(x->fcall.count*UTFmax+1);
569 x->fcall.data[x->fcall.count] = 0;
570 textcommit(&w->tag, TRUE);
571 for(n=0; n<x->fcall.count; n+=m){
572 p = x->fcall.data+n;
573 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
574 qlock(&w->ctllock);
575 w->ctlfid = x->f->fid;
576 m = 4;
577 }else
578 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
579 w->ctlfid = ~0;
580 qunlock(&w->ctllock);
581 m = 6;
582 }else
583 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
584 t = &w->body;
585 t->eq0 = ~0;
586 filereset(t->file);
587 t->file->mod = FALSE;
588 w->dirty = FALSE;
589 settag = TRUE;
590 m = 5;
591 }else
592 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
593 t = &w->body;
594 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
595 t->file->mod = TRUE;
596 w->dirty = TRUE;
597 settag = TRUE;
598 m = 5;
599 }else
600 if(strncmp(p, "show", 4) == 0){ /* show dot */
601 t = &w->body;
602 textshow(t, t->q0, t->q1, 1);
603 m = 4;
604 }else
605 if(strncmp(p, "name ", 5) == 0){ /* set file name */
606 pp = p+5;
607 m = 5;
608 q = memchr(pp, '\n', e-pp);
609 if(q==nil || q==pp){
610 err = Ebadctl;
611 break;
613 *q = 0;
614 nulls = FALSE;
615 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
616 if(nulls){
617 err = "nulls in file name";
618 break;
620 for(i=0; i<nr; i++)
621 if(r[i] <= ' '){
622 err = "bad character in file name";
623 goto out;
625 out:
626 seq++;
627 filemark(w->body.file);
628 winsetname(w, r, nr);
629 m += (q+1) - pp;
630 }else
631 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
632 pp = p+5;
633 m = 5;
634 q = memchr(pp, '\n', e-pp);
635 if(q==nil || q==pp){
636 err = Ebadctl;
637 break;
639 *q = 0;
640 nulls = FALSE;
641 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
642 if(nulls){
643 err = "nulls in dump string";
644 break;
646 w->dumpstr = runetobyte(r, nr);
647 m += (q+1) - pp;
648 }else
649 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
650 pp = p+8;
651 m = 8;
652 q = memchr(pp, '\n', e-pp);
653 if(q==nil || q==pp){
654 err = Ebadctl;
655 break;
657 *q = 0;
658 nulls = FALSE;
659 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
660 if(nulls){
661 err = "nulls in dump directory string";
662 break;
664 w->dumpdir = runetobyte(r, nr);
665 m += (q+1) - pp;
666 }else
667 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
668 colclose(w->col, w, TRUE);
669 m = 6;
670 }else
671 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
672 if(!winclean(w, TRUE)){
673 err = "file dirty";
674 break;
676 colclose(w->col, w, TRUE);
677 m = 3;
678 }else
679 if(strncmp(p, "get", 3) == 0){ /* get file */
680 get(&w->body, nil, nil, FALSE, XXX, nil, 0);
681 m = 3;
682 }else
683 if(strncmp(p, "put", 3) == 0){ /* put file */
684 put(&w->body, nil, nil, XXX, XXX, nil, 0);
685 m = 3;
686 }else
687 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
688 textcommit(&w->body, TRUE);
689 clampaddr(w);
690 w->body.q0 = w->addr.q0;
691 w->body.q1 = w->addr.q1;
692 textsetselect(&w->body, w->body.q0, w->body.q1);
693 settag = TRUE;
694 m = 8;
695 }else
696 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
697 w->addr.q0 = w->body.q0;
698 w->addr.q1 = w->body.q1;
699 m = 8;
700 }else
701 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
702 textcommit(&w->body, TRUE);
703 clampaddr(w);
704 w->limit.q0 = w->addr.q0;
705 w->limit.q1 = w->addr.q1;
706 m = 10;
707 }else
708 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
709 w->nomark = TRUE;
710 m = 6;
711 }else
712 if(strncmp(p, "mark", 4) == 0){ /* mark file */
713 seq++;
714 filemark(w->body.file);
715 settag = TRUE;
716 m = 4;
717 }else
718 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
719 w->noscroll = TRUE;
720 m = 8;
721 }else
722 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
723 wincleartag(w);
724 settag = TRUE;
725 m = 8;
726 }else
727 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
728 w->noscroll = FALSE;
729 m = 6;
730 }else{
731 err = Ebadctl;
732 break;
734 while(p[m] == '\n')
735 m++;
738 if(isfbuf)
739 fbuffree(r);
740 else
741 free(r);
742 if(err)
743 n = 0;
744 fc.count = n;
745 respond(x, &fc, err);
746 if(settag)
747 winsettag(w);
748 if(scrdraw)
749 textscrdraw(&w->body);
752 void
753 xfideventwrite(Xfid *x, Window *w)
755 Fcall fc;
756 int m, n;
757 Rune *r;
758 char *err, *p, *q;
759 int isfbuf;
760 Text *t;
761 int c;
762 uint q0, q1;
764 err = nil;
765 isfbuf = TRUE;
766 if(x->fcall.count < RBUFSIZE)
767 r = fbufalloc();
768 else{
769 isfbuf = FALSE;
770 r = emalloc(x->fcall.count*UTFmax+1);
772 for(n=0; n<x->fcall.count; n+=m){
773 p = x->fcall.data+n;
774 w->owner = *p++; /* disgusting */
775 c = *p++;
776 while(*p == ' ')
777 p++;
778 q0 = strtoul(p, &q, 10);
779 if(q == p)
780 goto Rescue;
781 p = q;
782 while(*p == ' ')
783 p++;
784 q1 = strtoul(p, &q, 10);
785 if(q == p)
786 goto Rescue;
787 p = q;
788 while(*p == ' ')
789 p++;
790 if(*p++ != '\n')
791 goto Rescue;
792 m = p-(x->fcall.data+n);
793 if('a'<=c && c<='z')
794 t = &w->tag;
795 else if('A'<=c && c<='Z')
796 t = &w->body;
797 else
798 goto Rescue;
799 if(q0>t->file->b.nc || q1>t->file->b.nc || q0>q1)
800 goto Rescue;
802 qlock(&row.lk); /* just like mousethread */
803 switch(c){
804 case 'x':
805 case 'X':
806 execute(t, q0, q1, TRUE, nil);
807 break;
808 case 'l':
809 case 'L':
810 look3(t, q0, q1, TRUE);
811 break;
812 default:
813 qunlock(&row.lk);
814 goto Rescue;
816 qunlock(&row.lk);
820 Out:
821 if(isfbuf)
822 fbuffree(r);
823 else
824 free(r);
825 if(err)
826 n = 0;
827 fc.count = n;
828 respond(x, &fc, err);
829 return;
831 Rescue:
832 err = Ebadevent;
833 goto Out;
836 void
837 xfidutfread(Xfid *x, Text *t, uint q1, int qid)
839 Fcall fc;
840 Window *w;
841 Rune *r;
842 char *b, *b1;
843 uint q, off, boff;
844 int m, n, nr, nb;
846 w = t->w;
847 wincommit(w, t);
848 off = x->fcall.offset;
849 r = fbufalloc();
850 b = fbufalloc();
851 b1 = fbufalloc();
852 n = 0;
853 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
854 boff = w->utflastboff;
855 q = w->utflastq;
856 }else{
857 /* BUG: stupid code: scan from beginning */
858 boff = 0;
859 q = 0;
861 w->utflastqid = qid;
862 while(q<q1 && n<x->fcall.count){
863 /*
864 * Updating here avoids partial rune problem: we're always on a
865 * char boundary. The cost is we will usually do one more read
866 * than we really need, but that's better than being n^2.
867 */
868 w->utflastboff = boff;
869 w->utflastq = q;
870 nr = q1-q;
871 if(nr > BUFSIZE/UTFmax)
872 nr = BUFSIZE/UTFmax;
873 bufread(&t->file->b, q, r, nr);
874 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
875 if(boff >= off){
876 m = nb;
877 if(boff+m > off+x->fcall.count)
878 m = off+x->fcall.count - boff;
879 memmove(b1+n, b, m);
880 n += m;
881 }else if(boff+nb > off){
882 if(n != 0)
883 error("bad count in utfrune");
884 m = nb - (off-boff);
885 if(m > x->fcall.count)
886 m = x->fcall.count;
887 memmove(b1, b+(off-boff), m);
888 n += m;
890 boff += nb;
891 q += nr;
893 fbuffree(r);
894 fbuffree(b);
895 fc.count = n;
896 fc.data = b1;
897 respond(x, &fc, nil);
898 fbuffree(b1);
901 int
902 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
904 Fcall fc;
905 Window *w;
906 Rune *r, junk;
907 char *b, *b1;
908 uint q, boff;
909 int i, rw, m, n, nr, nb;
911 w = t->w;
912 wincommit(w, t);
913 r = fbufalloc();
914 b = fbufalloc();
915 b1 = fbufalloc();
916 n = 0;
917 q = q0;
918 boff = 0;
919 while(q<q1 && n<x->fcall.count){
920 nr = q1-q;
921 if(nr > BUFSIZE/UTFmax)
922 nr = BUFSIZE/UTFmax;
923 bufread(&t->file->b, q, r, nr);
924 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
925 m = nb;
926 if(boff+m > x->fcall.count){
927 i = x->fcall.count - boff;
928 /* copy whole runes only */
929 m = 0;
930 nr = 0;
931 while(m < i){
932 rw = chartorune(&junk, b+m);
933 if(m+rw > i)
934 break;
935 m += rw;
936 nr++;
938 if(m == 0)
939 break;
941 memmove(b1+n, b, m);
942 n += m;
943 boff += nb;
944 q += nr;
946 fbuffree(r);
947 fbuffree(b);
948 fc.count = n;
949 fc.data = b1;
950 respond(x, &fc, nil);
951 fbuffree(b1);
952 return q-q0;
955 void
956 xfideventread(Xfid *x, Window *w)
958 Fcall fc;
959 char *b;
960 int i, n;
962 i = 0;
963 x->flushed = FALSE;
964 while(w->nevents == 0){
965 if(i){
966 if(!x->flushed)
967 respond(x, &fc, "window shut down");
968 return;
970 w->eventx = x;
971 winunlock(w);
972 recvp(x->c);
973 winlock(w, 'F');
974 i++;
977 n = w->nevents;
978 if(n > x->fcall.count)
979 n = x->fcall.count;
980 fc.count = n;
981 fc.data = w->events;
982 respond(x, &fc, nil);
983 b = w->events;
984 w->events = estrdup(w->events+n);
985 free(b);
986 w->nevents -= n;
989 void
990 xfidindexread(Xfid *x)
992 Fcall fc;
993 int i, j, m, n, nmax, isbuf, cnt, off;
994 Window *w;
995 char *b;
996 Rune *r;
997 Column *c;
999 qlock(&row.lk);
1000 nmax = 0;
1001 for(j=0; j<row.ncol; j++){
1002 c = row.col[j];
1003 for(i=0; i<c->nw; i++){
1004 w = c->w[i];
1005 nmax += Ctlsize + w->tag.file->b.nc*UTFmax + 1;
1008 nmax++;
1009 isbuf = (nmax<=RBUFSIZE);
1010 if(isbuf)
1011 b = (char*)x->buf;
1012 else
1013 b = emalloc(nmax);
1014 r = fbufalloc();
1015 n = 0;
1016 for(j=0; j<row.ncol; j++){
1017 c = row.col[j];
1018 for(i=0; i<c->nw; i++){
1019 w = c->w[i];
1020 /* only show the currently active window of a set */
1021 if(w->body.file->curtext != &w->body)
1022 continue;
1023 winctlprint(w, b+n, 0);
1024 n += Ctlsize;
1025 m = min(RBUFSIZE, w->tag.file->b.nc);
1026 bufread(&w->tag.file->b, 0, r, m);
1027 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
1028 while(n<m && b[n]!='\n')
1029 n++;
1030 b[n++] = '\n';
1033 qunlock(&row.lk);
1034 off = x->fcall.offset;
1035 cnt = x->fcall.count;
1036 if(off > n)
1037 off = n;
1038 if(off+cnt > n)
1039 cnt = n-off;
1040 fc.count = cnt;
1041 memmove(r, b+off, cnt);
1042 fc.data = (char*)r;
1043 if(!isbuf)
1044 free(b);
1045 respond(x, &fc, nil);
1046 fbuffree(r);