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 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);
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);
122 break;
123 case QWrdsel:
124 /*
125 * Use a temporary file.
126 * A pipe would be the obvious, but we can't afford the
127 * broken pipe notification. Using the code to read QWbody
128 * is n², which should probably also be fixed. Even then,
129 * though, we'd need to squirrel away the data in case it's
130 * modified during the operation, e.g. by |sort
131 */
132 if(w->rdselfd > 0){
133 winunlock(w);
134 respond(x, &fc, Einuse);
135 return;
137 w->rdselfd = tempfile();
138 if(w->rdselfd < 0){
139 winunlock(w);
140 respond(x, &fc, "can't create temp file");
141 return;
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;
158 q0 += n;
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;
177 if(!canqlock(&w->editoutlk)){
178 winunlock(w);
179 respond(x, &fc, Einuse);
180 return;
182 w->wrselrange = range(t->q1, t->q1);
183 break;
185 winunlock(w);
187 else{
188 switch(q){
189 case Qeditout:
190 if(!canqlock(&editoutlk)){
191 respond(x, &fc, Einuse);
192 return;
194 break;
197 fc.qid = x->f->qid;
198 fc.iounit = messagesize-IOHDRSZ;
199 x->f->open = TRUE;
200 respond(x, &fc, nil);
203 void
204 xfidclose(Xfid *x)
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;
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);
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);
245 if(q == QWevent){
246 free(w->dumpstr);
247 free(w->dumpdir);
248 w->dumpstr = nil;
249 w->dumpdir = nil;
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;
269 winunlock(w);
270 winclose(w);
272 else{
273 switch(q){
274 case Qeditout:
275 qunlock(&editoutlk);
276 break;
279 respond(x, &fc, nil);
282 void
283 xfidread(Xfid *x)
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;
307 respond(x, &fc, nil);
308 return;
310 winlock(w, 'F');
311 if(w->col == nil){
312 winunlock(w);
313 respond(x, &fc, Edel);
314 return;
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;
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;
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;
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);
395 winunlock(w);
398 void
399 xfidwrite(Xfid *x)
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;
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;
447 if(!eval){
448 respond(x, &fc, Eaddr);
449 break;
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 else
462 err = edittext(nil, 0, r, nr);
463 free(r);
464 if(err != nil){
465 respond(x, &fc, err);
466 break;
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;
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);
500 q0 = a.q0;
501 if(a.q1 > q0){
502 textdelete(t, q0, a.q1, TRUE);
503 w->addr.q1 = q0;
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->w->noscroll)
514 textshow(t, q0, 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;
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++;
550 if(nb < cnt){
551 memmove(x->f->rpart, x->fcall.data+nb, cnt-nb);
552 x->f->nrpart = cnt-nb;
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 }else
561 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);
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->w->noscroll)
572 textshow(t, q0+nr, q0+nr, 1);
573 textscrdraw(t);
575 winsettag(w);
576 if(qid == QWwrsel)
577 w->wrselrange.q1 += nr;
578 free(r);
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;
589 if(w)
590 winunlock(w);
593 void
594 xfidctlwrite(Xfid *x, Window *w)
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);
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 }else
623 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
624 w->ctlfid = ~0;
625 qunlock(&w->ctllock);
626 m = 6;
627 }else
628 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 }else
637 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 }else
645 if(strncmp(p, "show", 4) == 0){ /* show dot */
646 t = &w->body;
647 textshow(t, t->q0, t->q1, 1);
648 m = 4;
649 }else
650 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;
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;
665 for(i=0; i<nr; i++)
666 if(r[i] <= ' '){
667 err = "bad character in file name";
668 goto out;
670 out:
671 seq++;
672 filemark(w->body.file);
673 winsetname(w, r, nr);
674 m += (q+1) - pp;
675 }else
676 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;
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;
691 w->dumpstr = runetobyte(r, nr);
692 m += (q+1) - pp;
693 }else
694 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;
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;
709 w->dumpdir = runetobyte(r, nr);
710 m += (q+1) - pp;
711 }else
712 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
713 colclose(w->col, w, TRUE);
714 m = 6;
715 }else
716 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
717 if(!winclean(w, TRUE)){
718 err = "file dirty";
719 break;
721 colclose(w->col, w, TRUE);
722 m = 3;
723 }else
724 if(strncmp(p, "get", 3) == 0){ /* get file */
725 get(&w->body, nil, nil, FALSE, XXX, nil, 0);
726 m = 3;
727 }else
728 if(strncmp(p, "put", 3) == 0){ /* put file */
729 put(&w->body, nil, nil, XXX, XXX, nil, 0);
730 m = 3;
731 }else
732 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 }else
741 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 }else
746 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 }else
753 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
754 w->nomark = TRUE;
755 m = 6;
756 }else
757 if(strncmp(p, "mark", 4) == 0){ /* mark file */
758 seq++;
759 filemark(w->body.file);
760 settag = TRUE;
761 m = 4;
762 }else
763 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
764 w->noscroll = TRUE;
765 m = 8;
766 }else
767 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
768 wincleartag(w);
769 settag = TRUE;
770 m = 8;
771 }else
772 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
773 w->noscroll = FALSE;
774 m = 6;
775 }else{
776 err = Ebadctl;
777 break;
779 while(p[m] == '\n')
780 m++;
783 if(isfbuf)
784 fbuffree(r);
785 else
786 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);
797 void
798 xfideventwrite(Xfid *x, Window *w)
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);
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 else
843 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;
861 qunlock(&row.lk);
865 Out:
866 if(isfbuf)
867 fbuffree(r);
868 else
869 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;
881 void
882 xfidutfread(Xfid *x, Text *t, uint q1, int qid)
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;
906 w->utflastqid = qid;
907 while(q<q1 && n<x->fcall.count){
908 /*
909 * Updating here avoids partial rune problem: we're always on a
910 * char boundary. The cost is we will usually do one more read
911 * 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;
935 boff += nb;
936 q += nr;
938 fbuffree(r);
939 fbuffree(b);
940 fc.count = n;
941 fc.data = b1;
942 respond(x, &fc, nil);
943 fbuffree(b1);
946 int
947 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
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++;
983 if(m == 0)
984 break;
986 memmove(b1+n, b, m);
987 n += m;
988 boff += nb;
989 q += nr;
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;
1000 void
1001 xfideventread(Xfid *x, Window *w)
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;
1014 w->eventx = x;
1015 winunlock(w);
1016 recvp(x->c);
1017 winlock(w, 'F');
1018 i++;
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;
1037 void
1038 xfidindexread(Xfid *x)
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;
1056 nmax++;
1057 isbuf = (nmax<=RBUFSIZE);
1058 if(isbuf)
1059 b = (char*)x->buf;
1060 else
1061 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';
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);