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";
35 if(w->addr.q0 > w->body.file->nc)
36 w->addr.q0 = w->body.file->nc;
37 if(w->addr.q1 > w->body.file->nc)
38 w->addr.q1 = w->body.file->nc;
47 threadsetname("xfidctlthread");
52 flushimage(display, 1);
66 /* search windows for matching tag */
68 for(j=0; j<row.ncol; j++){
70 for(i=0; i<c->nw; i++){
74 if(wx!=nil && wx->tag==x->oldtag){
106 if(w->nopen[q]++ == 0){
107 w->addr = (Range){0,0};
108 w->limit = (Range){-1,-1};
116 if(w->nopen[q]++ == 0){
117 if(!w->isdir && w->col!=nil){
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
134 respond(x, &fc, Einuse);
137 w->rdselfd = tempfile();
140 respond(x, &fc, "can't create temp file");
150 if(n > BUFSIZE/UTFmax)
152 bufread(t->file, 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");
167 cut(t, t, nil, FALSE, TRUE, nil, 0);
168 w->wrselrange = (Range){t->q1, t->q1};
172 if(editing == FALSE){
174 respond(x, &fc, Eperm);
177 w->wrselrange = (Range){t->q1, t->q1};
183 fc.iounit = messagesize-IOHDRSZ;
185 respond(x, &fc, nil);
198 if(x->f->open == FALSE){
201 respond(x, &fc, nil);
211 if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){
213 qunlock(&w->ctllock);
221 case QWevent: /* BUG: do we need to shut down Xfid? */
222 if(--w->nopen[q] == 0){
223 if(q == QWdata || q == QWxdata)
225 if(q==QWevent && !w->isdir && w->col!=nil){
244 /* before: only did this if !w->noscroll, but that didn't seem right in practice */
245 textshow(t, min(w->wrselrange.q0, t->file->nc),
246 min(w->wrselrange.q1, t->file->nc), 1);
253 respond(x, &fc, nil);
278 warning(nil, "unknown qid %d\n", q);
281 respond(x, &fc, nil);
287 respond(x, &fc, Edel);
293 textcommit(&w->body, TRUE);
295 sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);
299 xfidutfread(x, &w->body, w->body.file->nc, QWbody);
303 b = winctlprint(w, buf, 1);
316 respond(x, &fc, nil);
326 /* BUG: what should happen if q1 > q0? */
327 if(w->addr.q0 > w->body.file->nc){
328 respond(x, &fc, Eaddr);
331 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc);
332 w->addr.q1 = w->addr.q0;
336 /* BUG: what should happen if q1 > q0? */
337 if(w->addr.q0 > w->body.file->nc){
338 respond(x, &fc, Eaddr);
341 w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);
345 xfidutfread(x, &w->tag, w->tag.file->nc, QWtag);
349 seek(w->rdselfd, off, 0);
354 n = read(w->rdselfd, b, n);
356 respond(x, &fc, "I/O error in temp file");
361 respond(x, &fc, nil);
366 sprint(buf, "unknown qid %d in read", q);
367 respond(x, &fc, nil);
376 int c, cnt, qid, q, nb, nr, eval;
384 qid = FILE(x->f->qid);
388 if(qid==QWtag || qid==QWbody)
393 respond(x, &fc, Edel);
397 x->data[x->count] = 0;
400 w = errorwin(x->f->mntdir, 'X');
406 respond(x, &fc, nil);
410 x->data[x->count] = 0;
411 r = bytetorune(x->data, &nr);
415 a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
418 respond(x, &fc, Ebadaddr);
422 respond(x, &fc, Eaddr);
427 respond(x, &fc, nil);
432 r = bytetorune(x->data, &nr);
434 err = edittext(w, w->wrselrange.q1, r, nr);
436 err = edittext(nil, 0, r, nr);
439 respond(x, &fc, err);
443 respond(x, &fc, nil);
447 w = errorwinforwin(w);
464 if(a.q0>t->file->nc || a.q1>t->file->nc){
465 respond(x, &fc, Eaddr);
468 r = runemalloc(x->count);
469 cvttorunes(x->data, x->count, r, &nb, &nr, nil);
470 if(w->nomark == FALSE){
476 textdelete(t, q0, a.q1, TRUE);
481 textinsert(t, q0, r, nr, TRUE);
486 textsetselect(t, tq0, tq1);
488 textshow(t, q0, q0+nr, 0);
493 w->addr.q1 = w->addr.q0;
495 respond(x, &fc, nil);
499 xfideventwrite(x, w);
510 memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */
511 memmove(x->data, x->f->rpart, q);
516 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
517 /* approach end of buffer */
518 while(fullrune(x->data+nb, cnt-nb)){
520 nb += chartorune(&r[nr], x->data+c);
525 memmove(x->f->rpart, x->data+nb, cnt-nb);
526 x->f->nrpart = cnt-nb;
531 q0 = w->wrselrange.q1;
537 textinsert(t, q0, r, nr, TRUE);
539 if(w->nomark == FALSE){
543 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
544 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
545 if(qid!=QWwrsel && !t->w->noscroll)
546 textshow(t, q0+nr, q0+nr, 1);
551 w->wrselrange.q1 += nr;
555 respond(x, &fc, nil);
559 sprint(buf, "unknown qid %d in write", qid);
560 respond(x, &fc, buf);
568 xfidctlwrite(Xfid *x, Window *w)
571 int i, m, n, nb, nr, nulls;
573 char *err, *p, *pp, *q, *e;
574 int isfbuf, scrdraw, settag;
578 e = x->data+x->count;
582 if(x->count < RBUFSIZE)
586 r = emalloc(x->count*UTFmax+1);
588 x->data[x->count] = 0;
589 textcommit(&w->tag, TRUE);
590 for(n=0; n<x->count; n+=m){
592 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
594 w->ctlfid = x->f->fid;
597 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
599 qunlock(&w->ctllock);
602 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
606 t->file->mod = FALSE;
611 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
613 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
619 if(strncmp(p, "show", 4) == 0){ /* show dot */
621 textshow(t, t->q0, t->q1, 1);
624 if(strncmp(p, "name ", 5) == 0){ /* set file name */
627 q = memchr(pp, '\n', e-pp);
634 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
636 err = "nulls in file name";
641 err = "bad character in file name";
646 filemark(w->body.file);
647 winsetname(w, r, nr);
650 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
653 q = memchr(pp, '\n', e-pp);
660 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
662 err = "nulls in dump string";
665 w->dumpstr = runetobyte(r, nr);
668 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
671 q = memchr(pp, '\n', e-pp);
678 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
680 err = "nulls in dump directory string";
683 w->dumpdir = runetobyte(r, nr);
686 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
687 colclose(w->col, w, TRUE);
690 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
691 if(!winclean(w, TRUE)){
695 colclose(w->col, w, TRUE);
698 if(strncmp(p, "get", 3) == 0){ /* get file */
699 get(&w->body, nil, nil, FALSE, XXX, nil, 0);
702 if(strncmp(p, "put", 3) == 0){ /* put file */
703 put(&w->body, nil, nil, XXX, XXX, nil, 0);
706 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
707 textcommit(&w->body, TRUE);
709 w->body.q0 = w->addr.q0;
710 w->body.q1 = w->addr.q1;
711 textsetselect(&w->body, w->body.q0, w->body.q1);
715 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
716 w->addr.q0 = w->body.q0;
717 w->addr.q1 = w->body.q1;
720 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
721 textcommit(&w->body, TRUE);
723 w->limit.q0 = w->addr.q0;
724 w->limit.q1 = w->addr.q1;
727 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
731 if(strncmp(p, "mark", 4) == 0){ /* mark file */
733 filemark(w->body.file);
737 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */
741 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */
745 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
749 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
754 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
772 respond(x, &fc, err);
776 textscrdraw(&w->body);
780 xfideventwrite(Xfid *x, Window *w)
793 if(x->count < RBUFSIZE)
797 r = emalloc(x->count*UTFmax+1);
799 for(n=0; n<x->count; n+=m){
801 w->owner = *p++; /* disgusting */
805 q0 = strtoul(p, &q, 10);
811 q1 = strtoul(p, &q, 10);
822 else if('A'<=c && c<='Z')
826 if(q0>t->file->nc || q1>t->file->nc || q0>q1)
829 qlock(&row); /* just like mousethread */
833 execute(t, q0, q1, TRUE, nil);
837 look3(t, q0, q1, TRUE);
855 respond(x, &fc, err);
864 xfidutfread(Xfid *x, Text *t, uint q1, int qid)
880 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
881 boff = w->utflastboff;
884 /* BUG: stupid code: scan from beginning */
889 while(q<q1 && n<x->count){
891 * Updating here avoids partial rune problem: we're always on a
892 * char boundary. The cost is we will usually do one more read
893 * than we really need, but that's better than being n^2.
895 w->utflastboff = boff;
898 if(nr > BUFSIZE/UTFmax)
900 bufread(t->file, q, r, nr);
901 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
904 if(boff+m > off+x->count)
905 m = off+x->count - boff;
908 }else if(boff+nb > off){
910 error("bad count in utfrune");
914 memmove(b1, b+(off-boff), m);
924 respond(x, &fc, nil);
929 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
936 int i, rw, m, n, nr, nb;
946 while(q<q1 && n<x->count){
948 if(nr > BUFSIZE/UTFmax)
950 bufread(t->file, q, r, nr);
951 nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
953 if(boff+m > x->count){
955 /* copy whole runes only */
959 rw = chartorune(&junk, b+m);
977 respond(x, &fc, nil);
983 xfideventread(Xfid *x, Window *w)
991 while(w->nevents == 0){
994 respond(x, &fc, "window shut down");
1008 fc.data = w->events;
1009 respond(x, &fc, nil);
1011 w->events = estrdup(w->events+n);
1017 xfidindexread(Xfid *x)
1020 int i, j, m, n, nmax, isbuf, cnt, off;
1028 for(j=0; j<row.ncol; j++){
1030 for(i=0; i<c->nw; i++){
1032 nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
1036 isbuf = (nmax<=RBUFSIZE);
1043 for(j=0; j<row.ncol; j++){
1045 for(i=0; i<c->nw; i++){
1047 /* only show the currently active window of a set */
1048 if(w->body.file->curtext != &w->body)
1050 winctlprint(w, b+n, 0);
1052 m = min(RBUFSIZE, w->tag.file->nc);
1053 bufread(w->tag.file, 0, r, m);
1054 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
1055 while(n<m && b[n]!='\n')
1068 memmove(r, b+off, cnt);
1072 respond(x, &fc, nil);