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-1)/UTFmax)
151 n = (BUFSIZE-1)/UTFmax;
152 bufread(t->file, q0, r, n);
153 m = snprint(s, BUFSIZE, "%.*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);
373 fullrunewrite(Xfid *x, int *inr)
375 int q, cnt, c, nb, nr;
381 memmove(x->data+q, x->data, cnt); /* there's room; see fsysproc */
382 memmove(x->data, x->f->rpart, q);
387 cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
388 /* approach end of buffer */
389 while(fullrune(x->data+nb, cnt-nb)){
391 nb += chartorune(&r[nr], x->data+c);
396 memmove(x->f->rpart, x->data+nb, cnt-nb);
397 x->f->nrpart = cnt-nb;
407 int c, qid, nb, nr, eval;
415 qid = FILE(x->f->qid);
419 if(qid==QWtag || qid==QWbody)
424 respond(x, &fc, Edel);
428 x->data[x->count] = 0;
431 w = errorwin(x->f->mntdir, 'X');
437 respond(x, &fc, nil);
441 x->data[x->count] = 0;
442 r = bytetorune(x->data, &nr);
446 a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
449 respond(x, &fc, Ebadaddr);
453 respond(x, &fc, Eaddr);
458 respond(x, &fc, nil);
463 r = fullrunewrite(x, &nr);
465 err = edittext(w, w->wrselrange.q1, r, nr);
467 err = edittext(nil, 0, r, nr);
470 respond(x, &fc, err);
474 respond(x, &fc, nil);
478 w = errorwinforwin(w);
495 if(a.q0>t->file->nc || a.q1>t->file->nc){
496 respond(x, &fc, Eaddr);
499 r = runemalloc(x->count);
500 cvttorunes(x->data, x->count, r, &nb, &nr, nil);
501 if(w->nomark == FALSE){
507 textdelete(t, q0, a.q1, TRUE);
512 textinsert(t, q0, r, nr, TRUE);
517 textsetselect(t, tq0, tq1);
519 textshow(t, q0, q0+nr, 0);
524 w->addr.q1 = w->addr.q0;
526 respond(x, &fc, nil);
530 xfideventwrite(x, w);
538 r = fullrunewrite(x, &nr);
542 q0 = w->wrselrange.q1;
548 textinsert(t, q0, r, nr, TRUE);
550 if(w->nomark == FALSE){
554 q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
555 textsetselect(t, t->q0, t->q1); /* insert could leave it somewhere else */
556 if(qid!=QWwrsel && !t->w->noscroll)
557 textshow(t, q0+nr, q0+nr, 1);
562 w->wrselrange.q1 += nr;
566 respond(x, &fc, nil);
570 sprint(buf, "unknown qid %d in write", qid);
571 respond(x, &fc, buf);
579 xfidctlwrite(Xfid *x, Window *w)
582 int i, m, n, nb, nr, nulls;
584 char *err, *p, *pp, *q, *e;
589 e = x->data+x->count;
592 r = emalloc(x->count*UTFmax+1);
593 x->data[x->count] = 0;
594 textcommit(&w->tag, TRUE);
595 for(n=0; n<x->count; n+=m){
597 if(strncmp(p, "lock", 4) == 0){ /* make window exclusive use */
599 w->ctlfid = x->f->fid;
602 if(strncmp(p, "unlock", 6) == 0){ /* release exclusive use */
604 qunlock(&w->ctllock);
607 if(strncmp(p, "clean", 5) == 0){ /* mark window 'clean', seq=0 */
611 t->file->mod = FALSE;
616 if(strncmp(p, "dirty", 5) == 0){ /* mark window 'dirty' */
618 /* doesn't change sequence number, so "Put" won't appear. it shouldn't. */
624 if(strncmp(p, "show", 4) == 0){ /* show dot */
626 textshow(t, t->q0, t->q1, 1);
629 if(strncmp(p, "name ", 5) == 0){ /* set file name */
632 q = memchr(pp, '\n', e-pp);
639 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
641 err = "nulls in file name";
646 err = "bad character in file name";
651 filemark(w->body.file);
652 winsetname(w, r, nr);
655 if(strncmp(p, "dump ", 5) == 0){ /* set dump string */
658 q = memchr(pp, '\n', e-pp);
665 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
667 err = "nulls in dump string";
670 w->dumpstr = runetobyte(r, nr);
673 if(strncmp(p, "dumpdir ", 8) == 0){ /* set dump directory */
676 q = memchr(pp, '\n', e-pp);
683 cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
685 err = "nulls in dump directory string";
688 w->dumpdir = runetobyte(r, nr);
691 if(strncmp(p, "delete", 6) == 0){ /* delete for sure */
692 colclose(w->col, w, TRUE);
695 if(strncmp(p, "del", 3) == 0){ /* delete, but check dirty */
696 if(!winclean(w, TRUE)){
700 colclose(w->col, w, TRUE);
703 if(strncmp(p, "get", 3) == 0){ /* get file */
704 get(&w->body, nil, nil, FALSE, XXX, nil, 0);
707 if(strncmp(p, "put", 3) == 0){ /* put file */
708 put(&w->body, nil, nil, XXX, XXX, nil, 0);
711 if(strncmp(p, "dot=addr", 8) == 0){ /* set dot */
712 textcommit(&w->body, TRUE);
714 w->body.q0 = w->addr.q0;
715 w->body.q1 = w->addr.q1;
716 textsetselect(&w->body, w->body.q0, w->body.q1);
720 if(strncmp(p, "addr=dot", 8) == 0){ /* set addr */
721 w->addr.q0 = w->body.q0;
722 w->addr.q1 = w->body.q1;
725 if(strncmp(p, "limit=addr", 10) == 0){ /* set limit */
726 textcommit(&w->body, TRUE);
728 w->limit.q0 = w->addr.q0;
729 w->limit.q1 = w->addr.q1;
732 if(strncmp(p, "nomark", 6) == 0){ /* turn off automatic marking */
736 if(strncmp(p, "mark", 4) == 0){ /* mark file */
738 filemark(w->body.file);
742 if(strncmp(p, "nomenu", 6) == 0){ /* turn off automatic menu */
746 if(strncmp(p, "menu", 4) == 0){ /* enable automatic menu */
750 if(strncmp(p, "noscroll", 8) == 0){ /* turn off automatic scrolling */
754 if(strncmp(p, "cleartag", 8) == 0){ /* wipe tag right of bar */
759 if(strncmp(p, "scroll", 6) == 0){ /* turn on automatic scrolling (writes to body only) */
774 respond(x, &fc, err);
778 textscrdraw(&w->body);
782 xfideventwrite(Xfid *x, Window *w)
793 r = emalloc(x->count*UTFmax+1);
794 for(n=0; n<x->count; n+=m){
796 w->owner = *p++; /* disgusting */
800 q0 = strtoul(p, &q, 10);
806 q1 = strtoul(p, &q, 10);
817 else if('A'<=c && c<='Z')
821 if(q0>t->file->nc || q1>t->file->nc || q0>q1)
824 qlock(&row); /* just like mousethread */
828 execute(t, q0, q1, TRUE, nil);
832 look3(t, q0, q1, TRUE);
847 respond(x, &fc, err);
856 xfidutfread(Xfid *x, Text *t, uint q1, int qid)
870 b1 = emalloc(x->count);
872 if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
873 boff = w->utflastboff;
876 /* BUG: stupid code: scan from beginning */
881 while(q<q1 && n<x->count){
883 * Updating here avoids partial rune problem: we're always on a
884 * char boundary. The cost is we will usually do one more read
885 * than we really need, but that's better than being n^2.
887 w->utflastboff = boff;
890 if(nr > (BUFSIZE-1)/UTFmax)
891 nr = (BUFSIZE-1)/UTFmax;
892 bufread(t->file, q, r, nr);
893 nb = snprint(b, BUFSIZE, "%.*S", nr, r);
896 if(boff+m > off+x->count)
897 m = off+x->count - boff;
900 }else if(boff+nb > off){
902 error("bad count in utfrune");
906 memmove(b1, b+(off-boff), m);
916 respond(x, &fc, nil);
921 xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
928 int i, rw, m, n, nr, nb;
934 b1 = emalloc(x->count);
938 while(q<q1 && n<x->count){
940 if(nr > (BUFSIZE-1)/UTFmax)
941 nr = (BUFSIZE-1)/UTFmax;
942 bufread(t->file, q, r, nr);
943 nb = snprint(b, BUFSIZE, "%.*S", nr, r);
945 if(boff+m > x->count){
947 /* copy whole runes only */
951 rw = chartorune(&junk, b+m);
969 respond(x, &fc, nil);
975 xfideventread(Xfid *x, Window *w)
983 while(w->nevents == 0){
986 respond(x, &fc, "window shut down");
1000 fc.data = w->events;
1001 respond(x, &fc, nil);
1003 w->events = estrdup(w->events+n);
1009 xfidindexread(Xfid *x)
1012 int i, j, m, n, nmax, isbuf, cnt, off;
1020 for(j=0; j<row.ncol; j++){
1022 for(i=0; i<c->nw; i++){
1024 nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
1028 isbuf = (nmax<=RBUFSIZE);
1035 for(j=0; j<row.ncol; j++){
1037 for(i=0; i<c->nw; i++){
1039 /* only show the currently active window of a set */
1040 if(w->body.file->curtext != &w->body)
1042 winctlprint(w, b+n, 0);
1044 m = min(RBUFSIZE, w->tag.file->nc);
1045 bufread(w->tag.file, 0, r, m);
1046 m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
1047 while(n<m && b[n]!='\n')
1060 memmove(r, b+off, cnt);
1064 respond(x, &fc, nil);