xref: /plan9-contrib/sys/src/cmd/acme/xfid.c (revision 9b7bf7df4595c26f1e9b67beb0c6e44c9876fb05)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
59a747e4fSDavid du Colombier #include <cursor.h>
67dd7cddfSDavid du Colombier #include <mouse.h>
77dd7cddfSDavid du Colombier #include <keyboard.h>
87dd7cddfSDavid du Colombier #include <frame.h>
97dd7cddfSDavid du Colombier #include <fcall.h>
107dd7cddfSDavid du Colombier #include <plumb.h>
117dd7cddfSDavid du Colombier #include "dat.h"
127dd7cddfSDavid du Colombier #include "fns.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier enum
157dd7cddfSDavid du Colombier {
167dd7cddfSDavid du Colombier 	Ctlsize	= 5*12
177dd7cddfSDavid du Colombier };
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier char	Edel[]		= "deleted window";
207dd7cddfSDavid du Colombier char	Ebadctl[]		= "ill-formed control message";
217dd7cddfSDavid du Colombier char	Ebadaddr[]	= "bad address syntax";
227dd7cddfSDavid du Colombier char	Eaddr[]		= "address out of range";
237dd7cddfSDavid du Colombier char	Einuse[]		= "already in use";
247dd7cddfSDavid du Colombier char	Ebadevent[]	= "bad event syntax";
2559cc4ca5SDavid du Colombier extern char Eperm[];
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier static
287dd7cddfSDavid du Colombier void
clampaddr(Window * w)297dd7cddfSDavid du Colombier clampaddr(Window *w)
307dd7cddfSDavid du Colombier {
317dd7cddfSDavid du Colombier 	if(w->addr.q0 < 0)
327dd7cddfSDavid du Colombier 		w->addr.q0 = 0;
337dd7cddfSDavid du Colombier 	if(w->addr.q1 < 0)
347dd7cddfSDavid du Colombier 		w->addr.q1 = 0;
357dd7cddfSDavid du Colombier 	if(w->addr.q0 > w->body.file->nc)
367dd7cddfSDavid du Colombier 		w->addr.q0 = w->body.file->nc;
377dd7cddfSDavid du Colombier 	if(w->addr.q1 > w->body.file->nc)
387dd7cddfSDavid du Colombier 		w->addr.q1 = w->body.file->nc;
397dd7cddfSDavid du Colombier }
407dd7cddfSDavid du Colombier 
417dd7cddfSDavid du Colombier void
xfidctl(void * arg)427dd7cddfSDavid du Colombier xfidctl(void *arg)
437dd7cddfSDavid du Colombier {
447dd7cddfSDavid du Colombier 	Xfid *x;
457dd7cddfSDavid du Colombier 	void (*f)(Xfid*);
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	threadsetname("xfidctlthread");
487dd7cddfSDavid du Colombier 	x = arg;
497dd7cddfSDavid du Colombier 	for(;;){
507dd7cddfSDavid du Colombier 		f = recvp(x->c);
517dd7cddfSDavid du Colombier 		(*f)(x);
527dd7cddfSDavid du Colombier 		flushimage(display, 1);
537dd7cddfSDavid du Colombier 		sendp(cxfidfree, x);
547dd7cddfSDavid du Colombier 	}
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier void
xfidflush(Xfid * x)587dd7cddfSDavid du Colombier xfidflush(Xfid *x)
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier 	Fcall fc;
617dd7cddfSDavid du Colombier 	int i, j;
627dd7cddfSDavid du Colombier 	Window *w;
637dd7cddfSDavid du Colombier 	Column *c;
647dd7cddfSDavid du Colombier 	Xfid *wx;
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	/* search windows for matching tag */
677dd7cddfSDavid du Colombier 	qlock(&row);
687dd7cddfSDavid du Colombier 	for(j=0; j<row.ncol; j++){
697dd7cddfSDavid du Colombier 		c = row.col[j];
707dd7cddfSDavid du Colombier 		for(i=0; i<c->nw; i++){
717dd7cddfSDavid du Colombier 			w = c->w[i];
727dd7cddfSDavid du Colombier 			winlock(w, 'E');
737dd7cddfSDavid du Colombier 			wx = w->eventx;
747dd7cddfSDavid du Colombier 			if(wx!=nil && wx->tag==x->oldtag){
757dd7cddfSDavid du Colombier 				w->eventx = nil;
767dd7cddfSDavid du Colombier 				wx->flushed = TRUE;
777dd7cddfSDavid du Colombier 				sendp(wx->c, nil);
787dd7cddfSDavid du Colombier 				winunlock(w);
797dd7cddfSDavid du Colombier 				goto out;
807dd7cddfSDavid du Colombier 			}
817dd7cddfSDavid du Colombier 			winunlock(w);
827dd7cddfSDavid du Colombier 		}
837dd7cddfSDavid du Colombier 	}
847dd7cddfSDavid du Colombier out:
857dd7cddfSDavid du Colombier 	qunlock(&row);
867dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier void
xfidopen(Xfid * x)907dd7cddfSDavid du Colombier xfidopen(Xfid *x)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	Fcall fc;
937dd7cddfSDavid du Colombier 	Window *w;
947dd7cddfSDavid du Colombier 	Text *t;
957dd7cddfSDavid du Colombier 	char *s;
967dd7cddfSDavid du Colombier 	Rune *r;
977dd7cddfSDavid du Colombier 	int m, n, q, q0, q1;
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier 	w = x->f->w;
1007dd7cddfSDavid du Colombier 	t = &w->body;
1017dd7cddfSDavid du Colombier 	if(w){
1027dd7cddfSDavid du Colombier 		winlock(w, 'E');
1037dd7cddfSDavid du Colombier 		q = FILE(x->f->qid);
1047dd7cddfSDavid du Colombier 		switch(q){
1057dd7cddfSDavid du Colombier 		case QWaddr:
1067dd7cddfSDavid du Colombier 			if(w->nopen[q]++ == 0){
1077dd7cddfSDavid du Colombier 				w->addr = (Range){0,0};
1087dd7cddfSDavid du Colombier 				w->limit = (Range){-1,-1};
1097dd7cddfSDavid du Colombier 			}
1107dd7cddfSDavid du Colombier 			break;
1117dd7cddfSDavid du Colombier 		case QWdata:
112673c3d8aSDavid du Colombier 		case QWxdata:
1137dd7cddfSDavid du Colombier 			w->nopen[q]++;
1147dd7cddfSDavid du Colombier 			break;
1157dd7cddfSDavid du Colombier 		case QWevent:
1167dd7cddfSDavid du Colombier 			if(w->nopen[q]++ == 0){
1177dd7cddfSDavid du Colombier 				if(!w->isdir && w->col!=nil){
1187dd7cddfSDavid du Colombier 					w->filemenu = FALSE;
1197dd7cddfSDavid du Colombier 					winsettag(w);
1207dd7cddfSDavid du Colombier 				}
1217dd7cddfSDavid du Colombier 			}
1227dd7cddfSDavid du Colombier 			break;
1237dd7cddfSDavid du Colombier 		case QWrdsel:
1247dd7cddfSDavid du Colombier 			/*
1257dd7cddfSDavid du Colombier 			 * Use a temporary file.
1267dd7cddfSDavid du Colombier 			 * A pipe would be the obvious, but we can't afford the
1277dd7cddfSDavid du Colombier 			 * broken pipe notification.  Using the code to read QWbody
1287dd7cddfSDavid du Colombier 			 * is n², which should probably also be fixed.  Even then,
1297dd7cddfSDavid du Colombier 			 * though, we'd need to squirrel away the data in case it's
1307dd7cddfSDavid du Colombier 			 * modified during the operation, e.g. by |sort
1317dd7cddfSDavid du Colombier 			 */
1327dd7cddfSDavid du Colombier 			if(w->rdselfd > 0){
1337dd7cddfSDavid du Colombier 				winunlock(w);
1347dd7cddfSDavid du Colombier 				respond(x, &fc, Einuse);
1357dd7cddfSDavid du Colombier 				return;
1367dd7cddfSDavid du Colombier 			}
1377dd7cddfSDavid du Colombier 			w->rdselfd = tempfile();
1387dd7cddfSDavid du Colombier 			if(w->rdselfd < 0){
1397dd7cddfSDavid du Colombier 				winunlock(w);
1407dd7cddfSDavid du Colombier 				respond(x, &fc, "can't create temp file");
1417dd7cddfSDavid du Colombier 				return;
1427dd7cddfSDavid du Colombier 			}
1437dd7cddfSDavid du Colombier 			w->nopen[q]++;
1447dd7cddfSDavid du Colombier 			q0 = t->q0;
1457dd7cddfSDavid du Colombier 			q1 = t->q1;
1467dd7cddfSDavid du Colombier 			r = fbufalloc();
1477dd7cddfSDavid du Colombier 			s = fbufalloc();
1487dd7cddfSDavid du Colombier 			while(q0 < q1){
1497dd7cddfSDavid du Colombier 				n = q1 - q0;
1507dd7cddfSDavid du Colombier 				if(n > BUFSIZE/UTFmax)
1517dd7cddfSDavid du Colombier 					n = BUFSIZE/UTFmax;
1527dd7cddfSDavid du Colombier 				bufread(t->file, q0, r, n);
1537dd7cddfSDavid du Colombier 				m = snprint(s, BUFSIZE+1, "%.*S", n, r);
1547dd7cddfSDavid du Colombier 				if(write(w->rdselfd, s, m) != m){
1557dd7cddfSDavid du Colombier 					warning(nil, "can't write temp file for pipe command %r\n");
1567dd7cddfSDavid du Colombier 					break;
1577dd7cddfSDavid du Colombier 				}
1587dd7cddfSDavid du Colombier 				q0 += n;
1597dd7cddfSDavid du Colombier 			}
1607dd7cddfSDavid du Colombier 			fbuffree(s);
1617dd7cddfSDavid du Colombier 			fbuffree(r);
1627dd7cddfSDavid du Colombier 			break;
1637dd7cddfSDavid du Colombier 		case QWwrsel:
1647dd7cddfSDavid du Colombier 			w->nopen[q]++;
1657dd7cddfSDavid du Colombier 			seq++;
1667dd7cddfSDavid du Colombier 			filemark(t->file);
1677dd7cddfSDavid du Colombier 			cut(t, t, nil, FALSE, TRUE, nil, 0);
1687dd7cddfSDavid du Colombier 			w->wrselrange = (Range){t->q1, t->q1};
1697dd7cddfSDavid du Colombier 			w->nomark = TRUE;
1707dd7cddfSDavid du Colombier 			break;
17159cc4ca5SDavid du Colombier 		case QWeditout:
17259cc4ca5SDavid du Colombier 			if(editing == FALSE){
17359cc4ca5SDavid du Colombier 				winunlock(w);
17459cc4ca5SDavid du Colombier 				respond(x, &fc, Eperm);
17559cc4ca5SDavid du Colombier 				return;
17659cc4ca5SDavid du Colombier 			}
17759cc4ca5SDavid du Colombier 			w->wrselrange = (Range){t->q1, t->q1};
17859cc4ca5SDavid du Colombier 			break;
1797dd7cddfSDavid du Colombier 		}
1807dd7cddfSDavid du Colombier 		winunlock(w);
1817dd7cddfSDavid du Colombier 	}
1827dd7cddfSDavid du Colombier 	fc.qid = x->f->qid;
1839a747e4fSDavid du Colombier 	fc.iounit = messagesize-IOHDRSZ;
1847dd7cddfSDavid du Colombier 	x->f->open = TRUE;
1857dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
1867dd7cddfSDavid du Colombier }
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier void
xfidclose(Xfid * x)1897dd7cddfSDavid du Colombier xfidclose(Xfid *x)
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier 	Fcall fc;
1927dd7cddfSDavid du Colombier 	Window *w;
1937dd7cddfSDavid du Colombier 	int q;
1947dd7cddfSDavid du Colombier 	Text *t;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier 	w = x->f->w;
1977dd7cddfSDavid du Colombier 	x->f->busy = FALSE;
1987dd7cddfSDavid du Colombier 	if(x->f->open == FALSE){
1997dd7cddfSDavid du Colombier 		if(w != nil)
2007dd7cddfSDavid du Colombier 			winclose(w);
2017dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
2027dd7cddfSDavid du Colombier 		return;
2037dd7cddfSDavid du Colombier 	}
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 	x->f->open = FALSE;
2067dd7cddfSDavid du Colombier 	if(w){
2077dd7cddfSDavid du Colombier 		winlock(w, 'E');
2087dd7cddfSDavid du Colombier 		q = FILE(x->f->qid);
2097dd7cddfSDavid du Colombier 		switch(q){
2107dd7cddfSDavid du Colombier 		case QWctl:
2117dd7cddfSDavid du Colombier 			if(w->ctlfid!=~0 && w->ctlfid==x->f->fid){
2127dd7cddfSDavid du Colombier 				w->ctlfid = ~0;
2137dd7cddfSDavid du Colombier 				qunlock(&w->ctllock);
2147dd7cddfSDavid du Colombier 			}
2157dd7cddfSDavid du Colombier 			break;
2167dd7cddfSDavid du Colombier 		case QWdata:
217673c3d8aSDavid du Colombier 		case QWxdata:
2187dd7cddfSDavid du Colombier 			w->nomark = FALSE;
2197dd7cddfSDavid du Colombier 			/* fall through */
2207dd7cddfSDavid du Colombier 		case QWaddr:
2217dd7cddfSDavid du Colombier 		case QWevent:	/* BUG: do we need to shut down Xfid? */
2227dd7cddfSDavid du Colombier 			if(--w->nopen[q] == 0){
223673c3d8aSDavid du Colombier 				if(q == QWdata || q == QWxdata)
2247dd7cddfSDavid du Colombier 					w->nomark = FALSE;
2257dd7cddfSDavid du Colombier 				if(q==QWevent && !w->isdir && w->col!=nil){
2267dd7cddfSDavid du Colombier 					w->filemenu = TRUE;
2277dd7cddfSDavid du Colombier 					winsettag(w);
2287dd7cddfSDavid du Colombier 				}
2297dd7cddfSDavid du Colombier 				if(q == QWevent){
2307dd7cddfSDavid du Colombier 					free(w->dumpstr);
2317dd7cddfSDavid du Colombier 					free(w->dumpdir);
2327dd7cddfSDavid du Colombier 					w->dumpstr = nil;
2337dd7cddfSDavid du Colombier 					w->dumpdir = nil;
2347dd7cddfSDavid du Colombier 				}
2357dd7cddfSDavid du Colombier 			}
2367dd7cddfSDavid du Colombier 			break;
2377dd7cddfSDavid du Colombier 		case QWrdsel:
2387dd7cddfSDavid du Colombier 			close(w->rdselfd);
2397dd7cddfSDavid du Colombier 			w->rdselfd = 0;
2407dd7cddfSDavid du Colombier 			break;
2417dd7cddfSDavid du Colombier 		case QWwrsel:
2427dd7cddfSDavid du Colombier 			w->nomark = FALSE;
2437dd7cddfSDavid du Colombier 			t = &w->body;
2447dd7cddfSDavid du Colombier 			/* before: only did this if !w->noscroll, but that didn't seem right in practice */
2457dd7cddfSDavid du Colombier 			textshow(t, min(w->wrselrange.q0, t->file->nc),
2469a747e4fSDavid du Colombier 				min(w->wrselrange.q1, t->file->nc), 1);
2477dd7cddfSDavid du Colombier 			textscrdraw(t);
2487dd7cddfSDavid du Colombier 			break;
2497dd7cddfSDavid du Colombier 		}
2507dd7cddfSDavid du Colombier 		winunlock(w);
2517dd7cddfSDavid du Colombier 		winclose(w);
2527dd7cddfSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier void
xfidread(Xfid * x)2577dd7cddfSDavid du Colombier xfidread(Xfid *x)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier 	Fcall fc;
2607dd7cddfSDavid du Colombier 	int n, q;
2617dd7cddfSDavid du Colombier 	uint off;
2627dd7cddfSDavid du Colombier 	char *b;
263*9b7bf7dfSDavid du Colombier 	char buf[256];
2647dd7cddfSDavid du Colombier 	Window *w;
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	q = FILE(x->f->qid);
2677dd7cddfSDavid du Colombier 	w = x->f->w;
2687dd7cddfSDavid du Colombier 	if(w == nil){
2697dd7cddfSDavid du Colombier 		fc.count = 0;
2707dd7cddfSDavid du Colombier 		switch(q){
2717dd7cddfSDavid du Colombier 		case Qcons:
2727dd7cddfSDavid du Colombier 		case Qlabel:
2737dd7cddfSDavid du Colombier 			break;
2747dd7cddfSDavid du Colombier 		case Qindex:
2757dd7cddfSDavid du Colombier 			xfidindexread(x);
2767dd7cddfSDavid du Colombier 			return;
2777dd7cddfSDavid du Colombier 		default:
2787dd7cddfSDavid du Colombier 			warning(nil, "unknown qid %d\n", q);
2797dd7cddfSDavid du Colombier 			break;
2807dd7cddfSDavid du Colombier 		}
2817dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
2827dd7cddfSDavid du Colombier 		return;
2837dd7cddfSDavid du Colombier 	}
2847dd7cddfSDavid du Colombier 	winlock(w, 'F');
2857dd7cddfSDavid du Colombier 	if(w->col == nil){
2867dd7cddfSDavid du Colombier 		winunlock(w);
2877dd7cddfSDavid du Colombier 		respond(x, &fc, Edel);
2887dd7cddfSDavid du Colombier 		return;
2897dd7cddfSDavid du Colombier 	}
2907dd7cddfSDavid du Colombier 	off = x->offset;
2917dd7cddfSDavid du Colombier 	switch(q){
2927dd7cddfSDavid du Colombier 	case QWaddr:
2937dd7cddfSDavid du Colombier 		textcommit(&w->body, TRUE);
2947dd7cddfSDavid du Colombier 		clampaddr(w);
2957dd7cddfSDavid du Colombier 		sprint(buf, "%11d %11d ", w->addr.q0, w->addr.q1);
2967dd7cddfSDavid du Colombier 		goto Readbuf;
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	case QWbody:
2997dd7cddfSDavid du Colombier 		xfidutfread(x, &w->body, w->body.file->nc, QWbody);
3007dd7cddfSDavid du Colombier 		break;
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 	case QWctl:
3038a2c5ad0SDavid du Colombier 		b = winctlprint(w, buf, 1);
3048a2c5ad0SDavid du Colombier 		goto Readb;
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier 	Readbuf:
3078a2c5ad0SDavid du Colombier 		b = buf;
3088a2c5ad0SDavid du Colombier 	Readb:
3098a2c5ad0SDavid du Colombier 		n = strlen(b);
3107dd7cddfSDavid du Colombier 		if(off > n)
3117dd7cddfSDavid du Colombier 			off = n;
3127dd7cddfSDavid du Colombier 		if(off+x->count > n)
3137dd7cddfSDavid du Colombier 			x->count = n-off;
3147dd7cddfSDavid du Colombier 		fc.count = x->count;
3158a2c5ad0SDavid du Colombier 		fc.data = b+off;
3167dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
3178a2c5ad0SDavid du Colombier 		if(b != buf)
3188a2c5ad0SDavid du Colombier 			free(b);
3197dd7cddfSDavid du Colombier 		break;
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier 	case QWevent:
3227dd7cddfSDavid du Colombier 		xfideventread(x, w);
3237dd7cddfSDavid du Colombier 		break;
3247dd7cddfSDavid du Colombier 
3257dd7cddfSDavid du Colombier 	case QWdata:
3267dd7cddfSDavid du Colombier 		/* BUG: what should happen if q1 > q0? */
3277dd7cddfSDavid du Colombier 		if(w->addr.q0 > w->body.file->nc){
3287dd7cddfSDavid du Colombier 			respond(x, &fc, Eaddr);
3297dd7cddfSDavid du Colombier 			break;
3307dd7cddfSDavid du Colombier 		}
3317dd7cddfSDavid du Colombier 		w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->body.file->nc);
3327dd7cddfSDavid du Colombier 		w->addr.q1 = w->addr.q0;
3337dd7cddfSDavid du Colombier 		break;
3347dd7cddfSDavid du Colombier 
335673c3d8aSDavid du Colombier 	case QWxdata:
336673c3d8aSDavid du Colombier 		/* BUG: what should happen if q1 > q0? */
337673c3d8aSDavid du Colombier 		if(w->addr.q0 > w->body.file->nc){
338673c3d8aSDavid du Colombier 			respond(x, &fc, Eaddr);
339673c3d8aSDavid du Colombier 			break;
340673c3d8aSDavid du Colombier 		}
341673c3d8aSDavid du Colombier 		w->addr.q0 += xfidruneread(x, &w->body, w->addr.q0, w->addr.q1);
342673c3d8aSDavid du Colombier 		break;
343673c3d8aSDavid du Colombier 
3447dd7cddfSDavid du Colombier 	case QWtag:
3457dd7cddfSDavid du Colombier 		xfidutfread(x, &w->tag, w->tag.file->nc, QWtag);
3467dd7cddfSDavid du Colombier 		break;
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier 	case QWrdsel:
3497dd7cddfSDavid du Colombier 		seek(w->rdselfd, off, 0);
3507dd7cddfSDavid du Colombier 		n = x->count;
3517dd7cddfSDavid du Colombier 		if(n > BUFSIZE)
3527dd7cddfSDavid du Colombier 			n = BUFSIZE;
3537dd7cddfSDavid du Colombier 		b = fbufalloc();
3547dd7cddfSDavid du Colombier 		n = read(w->rdselfd, b, n);
3557dd7cddfSDavid du Colombier 		if(n < 0){
3567dd7cddfSDavid du Colombier 			respond(x, &fc, "I/O error in temp file");
3577dd7cddfSDavid du Colombier 			break;
3587dd7cddfSDavid du Colombier 		}
3597dd7cddfSDavid du Colombier 		fc.count = n;
3607dd7cddfSDavid du Colombier 		fc.data = b;
3617dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
3627dd7cddfSDavid du Colombier 		fbuffree(b);
3637dd7cddfSDavid du Colombier 		break;
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 	default:
3667dd7cddfSDavid du Colombier 		sprint(buf, "unknown qid %d in read", q);
3677dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
3687dd7cddfSDavid du Colombier 	}
3697dd7cddfSDavid du Colombier 	winunlock(w);
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier 
372*9b7bf7dfSDavid du Colombier static Rune*
fullrunewrite(Xfid * x,int * inr)373*9b7bf7dfSDavid du Colombier fullrunewrite(Xfid *x, int *inr)
374*9b7bf7dfSDavid du Colombier {
375*9b7bf7dfSDavid du Colombier 	int q, cnt, c, nb, nr;
376*9b7bf7dfSDavid du Colombier 	Rune *r;
377*9b7bf7dfSDavid du Colombier 
378*9b7bf7dfSDavid du Colombier 	q = x->f->nrpart;
379*9b7bf7dfSDavid du Colombier 	cnt = x->count;
380*9b7bf7dfSDavid du Colombier 	if(q > 0){
381*9b7bf7dfSDavid du Colombier 		memmove(x->data+q, x->data, cnt);	/* there's room; see fsysproc */
382*9b7bf7dfSDavid du Colombier 		memmove(x->data, x->f->rpart, q);
383*9b7bf7dfSDavid du Colombier 		cnt += q;
384*9b7bf7dfSDavid du Colombier 		x->f->nrpart = 0;
385*9b7bf7dfSDavid du Colombier 	}
386*9b7bf7dfSDavid du Colombier 	r = runemalloc(cnt);
387*9b7bf7dfSDavid du Colombier 	cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
388*9b7bf7dfSDavid du Colombier 	/* approach end of buffer */
389*9b7bf7dfSDavid du Colombier 	while(fullrune(x->data+nb, cnt-nb)){
390*9b7bf7dfSDavid du Colombier 		c = nb;
391*9b7bf7dfSDavid du Colombier 		nb += chartorune(&r[nr], x->data+c);
392*9b7bf7dfSDavid du Colombier 		if(r[nr])
393*9b7bf7dfSDavid du Colombier 			nr++;
394*9b7bf7dfSDavid du Colombier 	}
395*9b7bf7dfSDavid du Colombier 	if(nb < cnt){
396*9b7bf7dfSDavid du Colombier 		memmove(x->f->rpart, x->data+nb, cnt-nb);
397*9b7bf7dfSDavid du Colombier 		x->f->nrpart = cnt-nb;
398*9b7bf7dfSDavid du Colombier 	}
399*9b7bf7dfSDavid du Colombier 	*inr = nr;
400*9b7bf7dfSDavid du Colombier 	return r;
401*9b7bf7dfSDavid du Colombier }
402*9b7bf7dfSDavid du Colombier 
4037dd7cddfSDavid du Colombier void
xfidwrite(Xfid * x)4047dd7cddfSDavid du Colombier xfidwrite(Xfid *x)
4057dd7cddfSDavid du Colombier {
4067dd7cddfSDavid du Colombier 	Fcall fc;
407*9b7bf7dfSDavid du Colombier 	int c, qid, nb, nr, eval;
4089a747e4fSDavid du Colombier 	char buf[64], *err;
4097dd7cddfSDavid du Colombier 	Window *w;
4107dd7cddfSDavid du Colombier 	Rune *r;
4117dd7cddfSDavid du Colombier 	Range a;
4127dd7cddfSDavid du Colombier 	Text *t;
4137dd7cddfSDavid du Colombier 	uint q0, tq0, tq1;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	qid = FILE(x->f->qid);
4167dd7cddfSDavid du Colombier 	w = x->f->w;
4177dd7cddfSDavid du Colombier 	if(w){
4187dd7cddfSDavid du Colombier 		c = 'F';
4197dd7cddfSDavid du Colombier 		if(qid==QWtag || qid==QWbody)
4207dd7cddfSDavid du Colombier 			c = 'E';
4217dd7cddfSDavid du Colombier 		winlock(w, c);
4227dd7cddfSDavid du Colombier 		if(w->col == nil){
4237dd7cddfSDavid du Colombier 			winunlock(w);
4247dd7cddfSDavid du Colombier 			respond(x, &fc, Edel);
4257dd7cddfSDavid du Colombier 			return;
4267dd7cddfSDavid du Colombier 		}
4277dd7cddfSDavid du Colombier 	}
4287dd7cddfSDavid du Colombier 	x->data[x->count] = 0;
4297dd7cddfSDavid du Colombier 	switch(qid){
4307dd7cddfSDavid du Colombier 	case Qcons:
4314fec87e5SDavid du Colombier 		w = errorwin(x->f->mntdir, 'X');
4323ff48bf5SDavid du Colombier 		t=&w->body;
4333ff48bf5SDavid du Colombier 		goto BodyTag;
4343ff48bf5SDavid du Colombier 
4357dd7cddfSDavid du Colombier 	case Qlabel:
4367dd7cddfSDavid du Colombier 		fc.count = x->count;
4377dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
4387dd7cddfSDavid du Colombier 		break;
4397dd7cddfSDavid du Colombier 
4407dd7cddfSDavid du Colombier 	case QWaddr:
4417dd7cddfSDavid du Colombier 		x->data[x->count] = 0;
4427dd7cddfSDavid du Colombier 		r = bytetorune(x->data, &nr);
4437dd7cddfSDavid du Colombier 		t = &w->body;
4447dd7cddfSDavid du Colombier 		wincommit(w, t);
4457dd7cddfSDavid du Colombier 		eval = TRUE;
44659cc4ca5SDavid du Colombier 		a = address(x->f->mntdir, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
4477dd7cddfSDavid du Colombier 		free(r);
4487dd7cddfSDavid du Colombier 		if(nb < nr){
4497dd7cddfSDavid du Colombier 			respond(x, &fc, Ebadaddr);
4507dd7cddfSDavid du Colombier 			break;
4517dd7cddfSDavid du Colombier 		}
4527dd7cddfSDavid du Colombier 		if(!eval){
4537dd7cddfSDavid du Colombier 			respond(x, &fc, Eaddr);
4547dd7cddfSDavid du Colombier 			break;
4557dd7cddfSDavid du Colombier 		}
4567dd7cddfSDavid du Colombier 		w->addr = a;
4577dd7cddfSDavid du Colombier 		fc.count = x->count;
4587dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
4597dd7cddfSDavid du Colombier 		break;
4607dd7cddfSDavid du Colombier 
46159cc4ca5SDavid du Colombier 	case Qeditout:
46259cc4ca5SDavid du Colombier 	case QWeditout:
463*9b7bf7dfSDavid du Colombier 		r = fullrunewrite(x, &nr);
46459cc4ca5SDavid du Colombier 		if(w)
465e288d156SDavid du Colombier 			err = edittext(w, w->wrselrange.q1, r, nr);
46659cc4ca5SDavid du Colombier 		else
46759cc4ca5SDavid du Colombier 			err = edittext(nil, 0, r, nr);
46859cc4ca5SDavid du Colombier 		free(r);
46959cc4ca5SDavid du Colombier 		if(err != nil){
47059cc4ca5SDavid du Colombier 			respond(x, &fc, err);
47159cc4ca5SDavid du Colombier 			break;
47259cc4ca5SDavid du Colombier 		}
47359cc4ca5SDavid du Colombier 		fc.count = x->count;
47459cc4ca5SDavid du Colombier 		respond(x, &fc, nil);
47559cc4ca5SDavid du Colombier 		break;
47659cc4ca5SDavid du Colombier 
477673c3d8aSDavid du Colombier 	case QWerrors:
478673c3d8aSDavid du Colombier 		w = errorwinforwin(w);
479673c3d8aSDavid du Colombier 		t = &w->body;
480673c3d8aSDavid du Colombier 		goto BodyTag;
481673c3d8aSDavid du Colombier 
4827dd7cddfSDavid du Colombier 	case QWbody:
4837dd7cddfSDavid du Colombier 	case QWwrsel:
4847dd7cddfSDavid du Colombier 		t = &w->body;
4857dd7cddfSDavid du Colombier 		goto BodyTag;
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier 	case QWctl:
4887dd7cddfSDavid du Colombier 		xfidctlwrite(x, w);
4897dd7cddfSDavid du Colombier 		break;
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier 	case QWdata:
4927dd7cddfSDavid du Colombier 		a = w->addr;
4937dd7cddfSDavid du Colombier 		t = &w->body;
4947dd7cddfSDavid du Colombier 		wincommit(w, t);
4957dd7cddfSDavid du Colombier 		if(a.q0>t->file->nc || a.q1>t->file->nc){
4967dd7cddfSDavid du Colombier 			respond(x, &fc, Eaddr);
4977dd7cddfSDavid du Colombier 			break;
4987dd7cddfSDavid du Colombier 		}
4997dd7cddfSDavid du Colombier 		r = runemalloc(x->count);
5007dd7cddfSDavid du Colombier 		cvttorunes(x->data, x->count, r, &nb, &nr, nil);
5017dd7cddfSDavid du Colombier 		if(w->nomark == FALSE){
5027dd7cddfSDavid du Colombier 			seq++;
5037dd7cddfSDavid du Colombier 			filemark(t->file);
5047dd7cddfSDavid du Colombier 		}
5057dd7cddfSDavid du Colombier 		q0 = a.q0;
5067dd7cddfSDavid du Colombier 		if(a.q1 > q0){
5077dd7cddfSDavid du Colombier 			textdelete(t, q0, a.q1, TRUE);
5087dd7cddfSDavid du Colombier 			w->addr.q1 = q0;
5097dd7cddfSDavid du Colombier 		}
5107dd7cddfSDavid du Colombier 		tq0 = t->q0;
5117dd7cddfSDavid du Colombier 		tq1 = t->q1;
5127dd7cddfSDavid du Colombier 		textinsert(t, q0, r, nr, TRUE);
5137dd7cddfSDavid du Colombier 		if(tq0 >= q0)
5147dd7cddfSDavid du Colombier 			tq0 += nr;
5157dd7cddfSDavid du Colombier 		if(tq1 >= q0)
5167dd7cddfSDavid du Colombier 			tq1 += nr;
5179a747e4fSDavid du Colombier 		textsetselect(t, tq0, tq1);
5187dd7cddfSDavid du Colombier 		if(!t->w->noscroll)
5199a747e4fSDavid du Colombier 			textshow(t, q0, q0+nr, 0);
5207dd7cddfSDavid du Colombier 		textscrdraw(t);
5217dd7cddfSDavid du Colombier 		winsettag(w);
5227dd7cddfSDavid du Colombier 		free(r);
5237dd7cddfSDavid du Colombier 		w->addr.q0 += nr;
5247dd7cddfSDavid du Colombier 		w->addr.q1 = w->addr.q0;
5257dd7cddfSDavid du Colombier 		fc.count = x->count;
5267dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
5277dd7cddfSDavid du Colombier 		break;
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier 	case QWevent:
5307dd7cddfSDavid du Colombier 		xfideventwrite(x, w);
5317dd7cddfSDavid du Colombier 		break;
5327dd7cddfSDavid du Colombier 
5337dd7cddfSDavid du Colombier 	case QWtag:
5347dd7cddfSDavid du Colombier 		t = &w->tag;
5357dd7cddfSDavid du Colombier 		goto BodyTag;
5367dd7cddfSDavid du Colombier 
5377dd7cddfSDavid du Colombier 	BodyTag:
538*9b7bf7dfSDavid du Colombier 		r = fullrunewrite(x, &nr);
5397dd7cddfSDavid du Colombier 		if(nr > 0){
5407dd7cddfSDavid du Colombier 			wincommit(w, t);
5417dd7cddfSDavid du Colombier 			if(qid == QWwrsel){
5427dd7cddfSDavid du Colombier 				q0 = w->wrselrange.q1;
5437dd7cddfSDavid du Colombier 				if(q0 > t->file->nc)
5447dd7cddfSDavid du Colombier 					q0 = t->file->nc;
5457dd7cddfSDavid du Colombier 			}else
5467dd7cddfSDavid du Colombier 				q0 = t->file->nc;
5477dd7cddfSDavid du Colombier 			if(qid == QWtag)
5487dd7cddfSDavid du Colombier 				textinsert(t, q0, r, nr, TRUE);
5497dd7cddfSDavid du Colombier 			else{
5507dd7cddfSDavid du Colombier 				if(w->nomark == FALSE){
5517dd7cddfSDavid du Colombier 					seq++;
5527dd7cddfSDavid du Colombier 					filemark(t->file);
5537dd7cddfSDavid du Colombier 				}
5547dd7cddfSDavid du Colombier 				q0 = textbsinsert(t, q0, r, nr, TRUE, &nr);
55580ee5cbfSDavid du Colombier 				textsetselect(t, t->q0, t->q1);	/* insert could leave it somewhere else */
5567dd7cddfSDavid du Colombier 				if(qid!=QWwrsel && !t->w->noscroll)
5579a747e4fSDavid du Colombier 					textshow(t, q0+nr, q0+nr, 1);
5587dd7cddfSDavid du Colombier 				textscrdraw(t);
5597dd7cddfSDavid du Colombier 			}
5607dd7cddfSDavid du Colombier 			winsettag(w);
5617dd7cddfSDavid du Colombier 			if(qid == QWwrsel)
5627dd7cddfSDavid du Colombier 				w->wrselrange.q1 += nr;
5637dd7cddfSDavid du Colombier 			free(r);
5647dd7cddfSDavid du Colombier 		}
5657dd7cddfSDavid du Colombier 		fc.count = x->count;
5667dd7cddfSDavid du Colombier 		respond(x, &fc, nil);
5677dd7cddfSDavid du Colombier 		break;
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 	default:
5707dd7cddfSDavid du Colombier 		sprint(buf, "unknown qid %d in write", qid);
5717dd7cddfSDavid du Colombier 		respond(x, &fc, buf);
5727dd7cddfSDavid du Colombier 		break;
5737dd7cddfSDavid du Colombier 	}
5747dd7cddfSDavid du Colombier 	if(w)
5757dd7cddfSDavid du Colombier 		winunlock(w);
5767dd7cddfSDavid du Colombier }
5777dd7cddfSDavid du Colombier 
5787dd7cddfSDavid du Colombier void
xfidctlwrite(Xfid * x,Window * w)5797dd7cddfSDavid du Colombier xfidctlwrite(Xfid *x, Window *w)
5807dd7cddfSDavid du Colombier {
5817dd7cddfSDavid du Colombier 	Fcall fc;
5827dd7cddfSDavid du Colombier 	int i, m, n, nb, nr, nulls;
5837dd7cddfSDavid du Colombier 	Rune *r;
5847dd7cddfSDavid du Colombier 	char *err, *p, *pp, *q, *e;
5857dd7cddfSDavid du Colombier 	int isfbuf, scrdraw, settag;
5867dd7cddfSDavid du Colombier 	Text *t;
5877dd7cddfSDavid du Colombier 
5887dd7cddfSDavid du Colombier 	err = nil;
5897dd7cddfSDavid du Colombier 	e = x->data+x->count;
5907dd7cddfSDavid du Colombier 	scrdraw = FALSE;
5917dd7cddfSDavid du Colombier 	settag = FALSE;
5927dd7cddfSDavid du Colombier 	isfbuf = TRUE;
5937dd7cddfSDavid du Colombier 	if(x->count < RBUFSIZE)
5947dd7cddfSDavid du Colombier 		r = fbufalloc();
5957dd7cddfSDavid du Colombier 	else{
5967dd7cddfSDavid du Colombier 		isfbuf = FALSE;
5977dd7cddfSDavid du Colombier 		r = emalloc(x->count*UTFmax+1);
5987dd7cddfSDavid du Colombier 	}
5997dd7cddfSDavid du Colombier 	x->data[x->count] = 0;
6007dd7cddfSDavid du Colombier 	textcommit(&w->tag, TRUE);
6017dd7cddfSDavid du Colombier 	for(n=0; n<x->count; n+=m){
6027dd7cddfSDavid du Colombier 		p = x->data+n;
6037dd7cddfSDavid du Colombier 		if(strncmp(p, "lock", 4) == 0){	/* make window exclusive use */
6047dd7cddfSDavid du Colombier 			qlock(&w->ctllock);
6057dd7cddfSDavid du Colombier 			w->ctlfid = x->f->fid;
6067dd7cddfSDavid du Colombier 			m = 4;
6077dd7cddfSDavid du Colombier 		}else
6087dd7cddfSDavid du Colombier 		if(strncmp(p, "unlock", 6) == 0){	/* release exclusive use */
6097dd7cddfSDavid du Colombier 			w->ctlfid = ~0;
6107dd7cddfSDavid du Colombier 			qunlock(&w->ctllock);
6117dd7cddfSDavid du Colombier 			m = 6;
6127dd7cddfSDavid du Colombier 		}else
6137dd7cddfSDavid du Colombier 		if(strncmp(p, "clean", 5) == 0){	/* mark window 'clean', seq=0 */
6147dd7cddfSDavid du Colombier 			t = &w->body;
6157dd7cddfSDavid du Colombier 			t->eq0 = ~0;
6167dd7cddfSDavid du Colombier 			filereset(t->file);
6177dd7cddfSDavid du Colombier 			t->file->mod = FALSE;
6187dd7cddfSDavid du Colombier 			w->dirty = FALSE;
6197dd7cddfSDavid du Colombier 			settag = TRUE;
6207dd7cddfSDavid du Colombier 			m = 5;
6217dd7cddfSDavid du Colombier 		}else
62280ee5cbfSDavid du Colombier 		if(strncmp(p, "dirty", 5) == 0){	/* mark window 'dirty' */
62380ee5cbfSDavid du Colombier 			t = &w->body;
62480ee5cbfSDavid du Colombier 			/* doesn't change sequence number, so "Put" won't appear.  it shouldn't. */
62580ee5cbfSDavid du Colombier 			t->file->mod = TRUE;
62680ee5cbfSDavid du Colombier 			w->dirty = TRUE;
62780ee5cbfSDavid du Colombier 			settag = TRUE;
62880ee5cbfSDavid du Colombier 			m = 5;
62980ee5cbfSDavid du Colombier 		}else
6307dd7cddfSDavid du Colombier 		if(strncmp(p, "show", 4) == 0){	/* show dot */
6317dd7cddfSDavid du Colombier 			t = &w->body;
6329a747e4fSDavid du Colombier 			textshow(t, t->q0, t->q1, 1);
6337dd7cddfSDavid du Colombier 			m = 4;
6347dd7cddfSDavid du Colombier 		}else
6357dd7cddfSDavid du Colombier 		if(strncmp(p, "name ", 5) == 0){	/* set file name */
6367dd7cddfSDavid du Colombier 			pp = p+5;
6377dd7cddfSDavid du Colombier 			m = 5;
6387dd7cddfSDavid du Colombier 			q = memchr(pp, '\n', e-pp);
6397dd7cddfSDavid du Colombier 			if(q==nil || q==pp){
6407dd7cddfSDavid du Colombier 				err = Ebadctl;
6417dd7cddfSDavid du Colombier 				break;
6427dd7cddfSDavid du Colombier 			}
6437dd7cddfSDavid du Colombier 			*q = 0;
6447dd7cddfSDavid du Colombier 			nulls = FALSE;
6457dd7cddfSDavid du Colombier 			cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
6467dd7cddfSDavid du Colombier 			if(nulls){
6477dd7cddfSDavid du Colombier 				err = "nulls in file name";
6487dd7cddfSDavid du Colombier 				break;
6497dd7cddfSDavid du Colombier 			}
6507dd7cddfSDavid du Colombier 			for(i=0; i<nr; i++)
6517dd7cddfSDavid du Colombier 				if(r[i] <= ' '){
6527dd7cddfSDavid du Colombier 					err = "bad character in file name";
6537dd7cddfSDavid du Colombier 					goto out;
6547dd7cddfSDavid du Colombier 				}
6557dd7cddfSDavid du Colombier out:
6567dd7cddfSDavid du Colombier 			seq++;
6577dd7cddfSDavid du Colombier 			filemark(w->body.file);
6587dd7cddfSDavid du Colombier 			winsetname(w, r, nr);
6597dd7cddfSDavid du Colombier 			m += (q+1) - pp;
6607dd7cddfSDavid du Colombier 		}else
6617dd7cddfSDavid du Colombier 		if(strncmp(p, "dump ", 5) == 0){	/* set dump string */
6627dd7cddfSDavid du Colombier 			pp = p+5;
6637dd7cddfSDavid du Colombier 			m = 5;
6647dd7cddfSDavid du Colombier 			q = memchr(pp, '\n', e-pp);
6657dd7cddfSDavid du Colombier 			if(q==nil || q==pp){
6667dd7cddfSDavid du Colombier 				err = Ebadctl;
6677dd7cddfSDavid du Colombier 				break;
6687dd7cddfSDavid du Colombier 			}
6697dd7cddfSDavid du Colombier 			*q = 0;
6707dd7cddfSDavid du Colombier 			nulls = FALSE;
6717dd7cddfSDavid du Colombier 			cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
6727dd7cddfSDavid du Colombier 			if(nulls){
6737dd7cddfSDavid du Colombier 				err = "nulls in dump string";
6747dd7cddfSDavid du Colombier 				break;
6757dd7cddfSDavid du Colombier 			}
6767dd7cddfSDavid du Colombier 			w->dumpstr = runetobyte(r, nr);
6777dd7cddfSDavid du Colombier 			m += (q+1) - pp;
6787dd7cddfSDavid du Colombier 		}else
6797dd7cddfSDavid du Colombier 		if(strncmp(p, "dumpdir ", 8) == 0){	/* set dump directory */
6807dd7cddfSDavid du Colombier 			pp = p+8;
6817dd7cddfSDavid du Colombier 			m = 8;
6827dd7cddfSDavid du Colombier 			q = memchr(pp, '\n', e-pp);
6837dd7cddfSDavid du Colombier 			if(q==nil || q==pp){
6847dd7cddfSDavid du Colombier 				err = Ebadctl;
6857dd7cddfSDavid du Colombier 				break;
6867dd7cddfSDavid du Colombier 			}
6877dd7cddfSDavid du Colombier 			*q = 0;
6887dd7cddfSDavid du Colombier 			nulls = FALSE;
6897dd7cddfSDavid du Colombier 			cvttorunes(pp, q-pp, r, &nb, &nr, &nulls);
6907dd7cddfSDavid du Colombier 			if(nulls){
6917dd7cddfSDavid du Colombier 				err = "nulls in dump directory string";
6927dd7cddfSDavid du Colombier 				break;
6937dd7cddfSDavid du Colombier 			}
6947dd7cddfSDavid du Colombier 			w->dumpdir = runetobyte(r, nr);
6957dd7cddfSDavid du Colombier 			m += (q+1) - pp;
6967dd7cddfSDavid du Colombier 		}else
6977dd7cddfSDavid du Colombier 		if(strncmp(p, "delete", 6) == 0){	/* delete for sure */
6987dd7cddfSDavid du Colombier 			colclose(w->col, w, TRUE);
6997dd7cddfSDavid du Colombier 			m = 6;
7007dd7cddfSDavid du Colombier 		}else
7017dd7cddfSDavid du Colombier 		if(strncmp(p, "del", 3) == 0){	/* delete, but check dirty */
7027dd7cddfSDavid du Colombier 			if(!winclean(w, TRUE)){
7037dd7cddfSDavid du Colombier 				err = "file dirty";
7047dd7cddfSDavid du Colombier 				break;
7057dd7cddfSDavid du Colombier 			}
7067dd7cddfSDavid du Colombier 			colclose(w->col, w, TRUE);
7077dd7cddfSDavid du Colombier 			m = 3;
7087dd7cddfSDavid du Colombier 		}else
7097dd7cddfSDavid du Colombier 		if(strncmp(p, "get", 3) == 0){	/* get file */
7107dd7cddfSDavid du Colombier 			get(&w->body, nil, nil, FALSE, XXX, nil, 0);
7117dd7cddfSDavid du Colombier 			m = 3;
7127dd7cddfSDavid du Colombier 		}else
7137dd7cddfSDavid du Colombier 		if(strncmp(p, "put", 3) == 0){	/* put file */
7147dd7cddfSDavid du Colombier 			put(&w->body, nil, nil, XXX, XXX, nil, 0);
7157dd7cddfSDavid du Colombier 			m = 3;
7167dd7cddfSDavid du Colombier 		}else
7177dd7cddfSDavid du Colombier 		if(strncmp(p, "dot=addr", 8) == 0){	/* set dot */
7187dd7cddfSDavid du Colombier 			textcommit(&w->body, TRUE);
7197dd7cddfSDavid du Colombier 			clampaddr(w);
7207dd7cddfSDavid du Colombier 			w->body.q0 = w->addr.q0;
7217dd7cddfSDavid du Colombier 			w->body.q1 = w->addr.q1;
7227dd7cddfSDavid du Colombier 			textsetselect(&w->body, w->body.q0, w->body.q1);
7237dd7cddfSDavid du Colombier 			settag = TRUE;
7247dd7cddfSDavid du Colombier 			m = 8;
7257dd7cddfSDavid du Colombier 		}else
7267dd7cddfSDavid du Colombier 		if(strncmp(p, "addr=dot", 8) == 0){	/* set addr */
7277dd7cddfSDavid du Colombier 			w->addr.q0 = w->body.q0;
7287dd7cddfSDavid du Colombier 			w->addr.q1 = w->body.q1;
7297dd7cddfSDavid du Colombier 			m = 8;
7307dd7cddfSDavid du Colombier 		}else
7317dd7cddfSDavid du Colombier 		if(strncmp(p, "limit=addr", 10) == 0){	/* set limit */
7327dd7cddfSDavid du Colombier 			textcommit(&w->body, TRUE);
7337dd7cddfSDavid du Colombier 			clampaddr(w);
7347dd7cddfSDavid du Colombier 			w->limit.q0 = w->addr.q0;
7357dd7cddfSDavid du Colombier 			w->limit.q1 = w->addr.q1;
7367dd7cddfSDavid du Colombier 			m = 10;
7377dd7cddfSDavid du Colombier 		}else
7387dd7cddfSDavid du Colombier 		if(strncmp(p, "nomark", 6) == 0){	/* turn off automatic marking */
7397dd7cddfSDavid du Colombier 			w->nomark = TRUE;
7407dd7cddfSDavid du Colombier 			m = 6;
7417dd7cddfSDavid du Colombier 		}else
7427dd7cddfSDavid du Colombier 		if(strncmp(p, "mark", 4) == 0){	/* mark file */
7437dd7cddfSDavid du Colombier 			seq++;
7447dd7cddfSDavid du Colombier 			filemark(w->body.file);
7457dd7cddfSDavid du Colombier 			settag = TRUE;
7467dd7cddfSDavid du Colombier 			m = 4;
7477dd7cddfSDavid du Colombier 		}else
74890630c3aSDavid du Colombier 		if(strncmp(p, "nomenu", 6) == 0){	/* turn off automatic menu */
74990630c3aSDavid du Colombier 			w->filemenu = FALSE;
75090630c3aSDavid du Colombier 			m = 6;
75190630c3aSDavid du Colombier 		}else
75290630c3aSDavid du Colombier 		if(strncmp(p, "menu", 4) == 0){	/* enable automatic menu */
75390630c3aSDavid du Colombier 			w->filemenu = TRUE;
75490630c3aSDavid du Colombier 			m = 4;
75590630c3aSDavid du Colombier 		}else
7567dd7cddfSDavid du Colombier 		if(strncmp(p, "noscroll", 8) == 0){	/* turn off automatic scrolling */
7577dd7cddfSDavid du Colombier 			w->noscroll = TRUE;
7587dd7cddfSDavid du Colombier 			m = 8;
7597dd7cddfSDavid du Colombier 		}else
7607dd7cddfSDavid du Colombier 		if(strncmp(p, "cleartag", 8) == 0){	/* wipe tag right of bar */
7617dd7cddfSDavid du Colombier 			wincleartag(w);
7627dd7cddfSDavid du Colombier 			settag = TRUE;
7637dd7cddfSDavid du Colombier 			m = 8;
7647dd7cddfSDavid du Colombier 		}else
7657dd7cddfSDavid du Colombier 		if(strncmp(p, "scroll", 6) == 0){	/* turn on automatic scrolling (writes to body only) */
7667dd7cddfSDavid du Colombier 			w->noscroll = FALSE;
7677dd7cddfSDavid du Colombier 			m = 6;
7687dd7cddfSDavid du Colombier 		}else{
7697dd7cddfSDavid du Colombier 			err = Ebadctl;
7707dd7cddfSDavid du Colombier 			break;
7717dd7cddfSDavid du Colombier 		}
7727dd7cddfSDavid du Colombier 		while(p[m] == '\n')
7737dd7cddfSDavid du Colombier 			m++;
7747dd7cddfSDavid du Colombier 	}
7757dd7cddfSDavid du Colombier 
7767dd7cddfSDavid du Colombier 	if(isfbuf)
7777dd7cddfSDavid du Colombier 		fbuffree(r);
7787dd7cddfSDavid du Colombier 	else
7797dd7cddfSDavid du Colombier 		free(r);
7807dd7cddfSDavid du Colombier 	if(err)
7817dd7cddfSDavid du Colombier 		n = 0;
7827dd7cddfSDavid du Colombier 	fc.count = n;
7837dd7cddfSDavid du Colombier 	respond(x, &fc, err);
7847dd7cddfSDavid du Colombier 	if(settag)
7857dd7cddfSDavid du Colombier 		winsettag(w);
7867dd7cddfSDavid du Colombier 	if(scrdraw)
7877dd7cddfSDavid du Colombier 		textscrdraw(&w->body);
7887dd7cddfSDavid du Colombier }
7897dd7cddfSDavid du Colombier 
7907dd7cddfSDavid du Colombier void
xfideventwrite(Xfid * x,Window * w)7917dd7cddfSDavid du Colombier xfideventwrite(Xfid *x, Window *w)
7927dd7cddfSDavid du Colombier {
7937dd7cddfSDavid du Colombier 	Fcall fc;
7947dd7cddfSDavid du Colombier 	int m, n;
7957dd7cddfSDavid du Colombier 	Rune *r;
7967dd7cddfSDavid du Colombier 	char *err, *p, *q;
7977dd7cddfSDavid du Colombier 	int isfbuf;
7987dd7cddfSDavid du Colombier 	Text *t;
7997dd7cddfSDavid du Colombier 	int c;
8007dd7cddfSDavid du Colombier 	uint q0, q1;
8017dd7cddfSDavid du Colombier 
8027dd7cddfSDavid du Colombier 	err = nil;
8037dd7cddfSDavid du Colombier 	isfbuf = TRUE;
8047dd7cddfSDavid du Colombier 	if(x->count < RBUFSIZE)
8057dd7cddfSDavid du Colombier 		r = fbufalloc();
8067dd7cddfSDavid du Colombier 	else{
8077dd7cddfSDavid du Colombier 		isfbuf = FALSE;
8087dd7cddfSDavid du Colombier 		r = emalloc(x->count*UTFmax+1);
8097dd7cddfSDavid du Colombier 	}
8107dd7cddfSDavid du Colombier 	for(n=0; n<x->count; n+=m){
8117dd7cddfSDavid du Colombier 		p = x->data+n;
8127dd7cddfSDavid du Colombier 		w->owner = *p++;	/* disgusting */
8137dd7cddfSDavid du Colombier 		c = *p++;
8147dd7cddfSDavid du Colombier 		while(*p == ' ')
8157dd7cddfSDavid du Colombier 			p++;
8167dd7cddfSDavid du Colombier 		q0 = strtoul(p, &q, 10);
8177dd7cddfSDavid du Colombier 		if(q == p)
8187dd7cddfSDavid du Colombier 			goto Rescue;
8197dd7cddfSDavid du Colombier 		p = q;
8207dd7cddfSDavid du Colombier 		while(*p == ' ')
8217dd7cddfSDavid du Colombier 			p++;
8227dd7cddfSDavid du Colombier 		q1 = strtoul(p, &q, 10);
8237dd7cddfSDavid du Colombier 		if(q == p)
8247dd7cddfSDavid du Colombier 			goto Rescue;
8257dd7cddfSDavid du Colombier 		p = q;
8267dd7cddfSDavid du Colombier 		while(*p == ' ')
8277dd7cddfSDavid du Colombier 			p++;
8287dd7cddfSDavid du Colombier 		if(*p++ != '\n')
8297dd7cddfSDavid du Colombier 			goto Rescue;
8307dd7cddfSDavid du Colombier 		m = p-(x->data+n);
8317dd7cddfSDavid du Colombier 		if('a'<=c && c<='z')
8327dd7cddfSDavid du Colombier 			t = &w->tag;
8337dd7cddfSDavid du Colombier 		else if('A'<=c && c<='Z')
8347dd7cddfSDavid du Colombier 			t = &w->body;
8357dd7cddfSDavid du Colombier 		else
8367dd7cddfSDavid du Colombier 			goto Rescue;
8377dd7cddfSDavid du Colombier 		if(q0>t->file->nc || q1>t->file->nc || q0>q1)
8387dd7cddfSDavid du Colombier 			goto Rescue;
8397dd7cddfSDavid du Colombier 
84059cc4ca5SDavid du Colombier 		qlock(&row);	/* just like mousethread */
8417dd7cddfSDavid du Colombier 		switch(c){
8427dd7cddfSDavid du Colombier 		case 'x':
8437dd7cddfSDavid du Colombier 		case 'X':
8447dd7cddfSDavid du Colombier 			execute(t, q0, q1, TRUE, nil);
8457dd7cddfSDavid du Colombier 			break;
8467dd7cddfSDavid du Colombier 		case 'l':
8477dd7cddfSDavid du Colombier 		case 'L':
8487dd7cddfSDavid du Colombier 			look3(t, q0, q1, TRUE);
8497dd7cddfSDavid du Colombier 			break;
8507dd7cddfSDavid du Colombier 		default:
85159cc4ca5SDavid du Colombier 			qunlock(&row);
8527dd7cddfSDavid du Colombier 			goto Rescue;
8537dd7cddfSDavid du Colombier 		}
85459cc4ca5SDavid du Colombier 		qunlock(&row);
8557dd7cddfSDavid du Colombier 
8567dd7cddfSDavid du Colombier 	}
8577dd7cddfSDavid du Colombier 
8587dd7cddfSDavid du Colombier     Out:
8597dd7cddfSDavid du Colombier 	if(isfbuf)
8607dd7cddfSDavid du Colombier 		fbuffree(r);
8617dd7cddfSDavid du Colombier 	else
8627dd7cddfSDavid du Colombier 		free(r);
8637dd7cddfSDavid du Colombier 	if(err)
8647dd7cddfSDavid du Colombier 		n = 0;
8657dd7cddfSDavid du Colombier 	fc.count = n;
8667dd7cddfSDavid du Colombier 	respond(x, &fc, err);
8677dd7cddfSDavid du Colombier 	return;
8687dd7cddfSDavid du Colombier 
8697dd7cddfSDavid du Colombier     Rescue:
8707dd7cddfSDavid du Colombier 	err = Ebadevent;
8717dd7cddfSDavid du Colombier 	goto Out;
8727dd7cddfSDavid du Colombier }
8737dd7cddfSDavid du Colombier 
8747dd7cddfSDavid du Colombier void
xfidutfread(Xfid * x,Text * t,uint q1,int qid)8757dd7cddfSDavid du Colombier xfidutfread(Xfid *x, Text *t, uint q1, int qid)
8767dd7cddfSDavid du Colombier {
8777dd7cddfSDavid du Colombier 	Fcall fc;
8787dd7cddfSDavid du Colombier 	Window *w;
8797dd7cddfSDavid du Colombier 	Rune *r;
8807dd7cddfSDavid du Colombier 	char *b, *b1;
8817dd7cddfSDavid du Colombier 	uint q, off, boff;
8827dd7cddfSDavid du Colombier 	int m, n, nr, nb;
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier 	w = t->w;
8857dd7cddfSDavid du Colombier 	wincommit(w, t);
8867dd7cddfSDavid du Colombier 	off = x->offset;
8877dd7cddfSDavid du Colombier 	r = fbufalloc();
8887dd7cddfSDavid du Colombier 	b = fbufalloc();
8897dd7cddfSDavid du Colombier 	b1 = fbufalloc();
8907dd7cddfSDavid du Colombier 	n = 0;
8917dd7cddfSDavid du Colombier 	if(qid==w->utflastqid && off>=w->utflastboff && w->utflastq<=q1){
8927dd7cddfSDavid du Colombier 		boff = w->utflastboff;
8937dd7cddfSDavid du Colombier 		q = w->utflastq;
8947dd7cddfSDavid du Colombier 	}else{
8957dd7cddfSDavid du Colombier 		/* BUG: stupid code: scan from beginning */
8967dd7cddfSDavid du Colombier 		boff = 0;
8977dd7cddfSDavid du Colombier 		q = 0;
8987dd7cddfSDavid du Colombier 	}
8997dd7cddfSDavid du Colombier 	w->utflastqid = qid;
9007dd7cddfSDavid du Colombier 	while(q<q1 && n<x->count){
9017dd7cddfSDavid du Colombier 		/*
9027dd7cddfSDavid du Colombier 		 * Updating here avoids partial rune problem: we're always on a
9037dd7cddfSDavid du Colombier 		 * char boundary. The cost is we will usually do one more read
9047dd7cddfSDavid du Colombier 		 * than we really need, but that's better than being n^2.
9057dd7cddfSDavid du Colombier 		 */
9067dd7cddfSDavid du Colombier 		w->utflastboff = boff;
9077dd7cddfSDavid du Colombier 		w->utflastq = q;
9087dd7cddfSDavid du Colombier 		nr = q1-q;
9097dd7cddfSDavid du Colombier 		if(nr > BUFSIZE/UTFmax)
9107dd7cddfSDavid du Colombier 			nr = BUFSIZE/UTFmax;
9117dd7cddfSDavid du Colombier 		bufread(t->file, q, r, nr);
9127dd7cddfSDavid du Colombier 		nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
9137dd7cddfSDavid du Colombier 		if(boff >= off){
9147dd7cddfSDavid du Colombier 			m = nb;
9157dd7cddfSDavid du Colombier 			if(boff+m > off+x->count)
9167dd7cddfSDavid du Colombier 				m = off+x->count - boff;
9177dd7cddfSDavid du Colombier 			memmove(b1+n, b, m);
9187dd7cddfSDavid du Colombier 			n += m;
9197dd7cddfSDavid du Colombier 		}else if(boff+nb > off){
9207dd7cddfSDavid du Colombier 			if(n != 0)
9217dd7cddfSDavid du Colombier 				error("bad count in utfrune");
9227dd7cddfSDavid du Colombier 			m = nb - (off-boff);
9237dd7cddfSDavid du Colombier 			if(m > x->count)
9247dd7cddfSDavid du Colombier 				m = x->count;
9257dd7cddfSDavid du Colombier 			memmove(b1, b+(off-boff), m);
9267dd7cddfSDavid du Colombier 			n += m;
9277dd7cddfSDavid du Colombier 		}
9287dd7cddfSDavid du Colombier 		boff += nb;
9297dd7cddfSDavid du Colombier 		q += nr;
9307dd7cddfSDavid du Colombier 	}
9317dd7cddfSDavid du Colombier 	fbuffree(r);
9327dd7cddfSDavid du Colombier 	fbuffree(b);
9337dd7cddfSDavid du Colombier 	fc.count = n;
9347dd7cddfSDavid du Colombier 	fc.data = b1;
9357dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
9367dd7cddfSDavid du Colombier 	fbuffree(b1);
9377dd7cddfSDavid du Colombier }
9387dd7cddfSDavid du Colombier 
9397dd7cddfSDavid du Colombier int
xfidruneread(Xfid * x,Text * t,uint q0,uint q1)9407dd7cddfSDavid du Colombier xfidruneread(Xfid *x, Text *t, uint q0, uint q1)
9417dd7cddfSDavid du Colombier {
9427dd7cddfSDavid du Colombier 	Fcall fc;
9437dd7cddfSDavid du Colombier 	Window *w;
9447dd7cddfSDavid du Colombier 	Rune *r, junk;
9457dd7cddfSDavid du Colombier 	char *b, *b1;
9467dd7cddfSDavid du Colombier 	uint q, boff;
9477dd7cddfSDavid du Colombier 	int i, rw, m, n, nr, nb;
9487dd7cddfSDavid du Colombier 
9497dd7cddfSDavid du Colombier 	w = t->w;
9507dd7cddfSDavid du Colombier 	wincommit(w, t);
9517dd7cddfSDavid du Colombier 	r = fbufalloc();
9527dd7cddfSDavid du Colombier 	b = fbufalloc();
9537dd7cddfSDavid du Colombier 	b1 = fbufalloc();
9547dd7cddfSDavid du Colombier 	n = 0;
9557dd7cddfSDavid du Colombier 	q = q0;
9567dd7cddfSDavid du Colombier 	boff = 0;
9577dd7cddfSDavid du Colombier 	while(q<q1 && n<x->count){
9587dd7cddfSDavid du Colombier 		nr = q1-q;
9597dd7cddfSDavid du Colombier 		if(nr > BUFSIZE/UTFmax)
9607dd7cddfSDavid du Colombier 			nr = BUFSIZE/UTFmax;
9617dd7cddfSDavid du Colombier 		bufread(t->file, q, r, nr);
9627dd7cddfSDavid du Colombier 		nb = snprint(b, BUFSIZE+1, "%.*S", nr, r);
9637dd7cddfSDavid du Colombier 		m = nb;
9647dd7cddfSDavid du Colombier 		if(boff+m > x->count){
9657dd7cddfSDavid du Colombier 			i = x->count - boff;
9667dd7cddfSDavid du Colombier 			/* copy whole runes only */
9677dd7cddfSDavid du Colombier 			m = 0;
9687dd7cddfSDavid du Colombier 			nr = 0;
9697dd7cddfSDavid du Colombier 			while(m < i){
9707dd7cddfSDavid du Colombier 				rw = chartorune(&junk, b+m);
9717dd7cddfSDavid du Colombier 				if(m+rw > i)
9727dd7cddfSDavid du Colombier 					break;
9737dd7cddfSDavid du Colombier 				m += rw;
9747dd7cddfSDavid du Colombier 				nr++;
9757dd7cddfSDavid du Colombier 			}
9767dd7cddfSDavid du Colombier 			if(m == 0)
9777dd7cddfSDavid du Colombier 				break;
9787dd7cddfSDavid du Colombier 		}
9797dd7cddfSDavid du Colombier 		memmove(b1+n, b, m);
9807dd7cddfSDavid du Colombier 		n += m;
9817dd7cddfSDavid du Colombier 		boff += nb;
9827dd7cddfSDavid du Colombier 		q += nr;
9837dd7cddfSDavid du Colombier 	}
9847dd7cddfSDavid du Colombier 	fbuffree(r);
9857dd7cddfSDavid du Colombier 	fbuffree(b);
9867dd7cddfSDavid du Colombier 	fc.count = n;
9877dd7cddfSDavid du Colombier 	fc.data = b1;
9887dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
9897dd7cddfSDavid du Colombier 	fbuffree(b1);
9907dd7cddfSDavid du Colombier 	return q-q0;
9917dd7cddfSDavid du Colombier }
9927dd7cddfSDavid du Colombier 
9937dd7cddfSDavid du Colombier void
xfideventread(Xfid * x,Window * w)9947dd7cddfSDavid du Colombier xfideventread(Xfid *x, Window *w)
9957dd7cddfSDavid du Colombier {
9967dd7cddfSDavid du Colombier 	Fcall fc;
9977dd7cddfSDavid du Colombier 	char *b;
9987dd7cddfSDavid du Colombier 	int i, n;
9997dd7cddfSDavid du Colombier 
10007dd7cddfSDavid du Colombier 	i = 0;
10017dd7cddfSDavid du Colombier 	x->flushed = FALSE;
10027dd7cddfSDavid du Colombier 	while(w->nevents == 0){
10037dd7cddfSDavid du Colombier 		if(i){
10047dd7cddfSDavid du Colombier 			if(!x->flushed)
10057dd7cddfSDavid du Colombier 				respond(x, &fc, "window shut down");
10067dd7cddfSDavid du Colombier 			return;
10077dd7cddfSDavid du Colombier 		}
10087dd7cddfSDavid du Colombier 		w->eventx = x;
10097dd7cddfSDavid du Colombier 		winunlock(w);
10107dd7cddfSDavid du Colombier 		recvp(x->c);
10117dd7cddfSDavid du Colombier 		winlock(w, 'F');
10127dd7cddfSDavid du Colombier 		i++;
10137dd7cddfSDavid du Colombier 	}
10147dd7cddfSDavid du Colombier 
10157dd7cddfSDavid du Colombier 	n = w->nevents;
10167dd7cddfSDavid du Colombier 	if(n > x->count)
10177dd7cddfSDavid du Colombier 		n = x->count;
10187dd7cddfSDavid du Colombier 	fc.count = n;
10197dd7cddfSDavid du Colombier 	fc.data = w->events;
10207dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
10217dd7cddfSDavid du Colombier 	b = w->events;
102259cc4ca5SDavid du Colombier 	w->events = estrdup(w->events+n);
10237dd7cddfSDavid du Colombier 	free(b);
10247dd7cddfSDavid du Colombier 	w->nevents -= n;
10257dd7cddfSDavid du Colombier }
10267dd7cddfSDavid du Colombier 
10277dd7cddfSDavid du Colombier void
xfidindexread(Xfid * x)10287dd7cddfSDavid du Colombier xfidindexread(Xfid *x)
10297dd7cddfSDavid du Colombier {
10307dd7cddfSDavid du Colombier 	Fcall fc;
10317dd7cddfSDavid du Colombier 	int i, j, m, n, nmax, isbuf, cnt, off;
10327dd7cddfSDavid du Colombier 	Window *w;
10337dd7cddfSDavid du Colombier 	char *b;
10347dd7cddfSDavid du Colombier 	Rune *r;
10357dd7cddfSDavid du Colombier 	Column *c;
10367dd7cddfSDavid du Colombier 
10377dd7cddfSDavid du Colombier 	qlock(&row);
10387dd7cddfSDavid du Colombier 	nmax = 0;
10397dd7cddfSDavid du Colombier 	for(j=0; j<row.ncol; j++){
10407dd7cddfSDavid du Colombier 		c = row.col[j];
10417dd7cddfSDavid du Colombier 		for(i=0; i<c->nw; i++){
10427dd7cddfSDavid du Colombier 			w = c->w[i];
10437dd7cddfSDavid du Colombier 			nmax += Ctlsize + w->tag.file->nc*UTFmax + 1;
10447dd7cddfSDavid du Colombier 		}
10457dd7cddfSDavid du Colombier 	}
10467dd7cddfSDavid du Colombier 	nmax++;
10477dd7cddfSDavid du Colombier 	isbuf = (nmax<=RBUFSIZE);
10487dd7cddfSDavid du Colombier 	if(isbuf)
10499a747e4fSDavid du Colombier 		b = (char*)x->buf;
10507dd7cddfSDavid du Colombier 	else
10517dd7cddfSDavid du Colombier 		b = emalloc(nmax);
10527dd7cddfSDavid du Colombier 	r = fbufalloc();
10537dd7cddfSDavid du Colombier 	n = 0;
10547dd7cddfSDavid du Colombier 	for(j=0; j<row.ncol; j++){
10557dd7cddfSDavid du Colombier 		c = row.col[j];
10567dd7cddfSDavid du Colombier 		for(i=0; i<c->nw; i++){
10577dd7cddfSDavid du Colombier 			w = c->w[i];
10587dd7cddfSDavid du Colombier 			/* only show the currently active window of a set */
10597dd7cddfSDavid du Colombier 			if(w->body.file->curtext != &w->body)
10607dd7cddfSDavid du Colombier 				continue;
10619a747e4fSDavid du Colombier 			winctlprint(w, b+n, 0);
10627dd7cddfSDavid du Colombier 			n += Ctlsize;
10637dd7cddfSDavid du Colombier 			m = min(RBUFSIZE, w->tag.file->nc);
10647dd7cddfSDavid du Colombier 			bufread(w->tag.file, 0, r, m);
10657dd7cddfSDavid du Colombier 			m = n + snprint(b+n, nmax-n-1, "%.*S", m, r);
10667dd7cddfSDavid du Colombier 			while(n<m && b[n]!='\n')
10677dd7cddfSDavid du Colombier 				n++;
10687dd7cddfSDavid du Colombier 			b[n++] = '\n';
10697dd7cddfSDavid du Colombier 		}
10707dd7cddfSDavid du Colombier 	}
10717dd7cddfSDavid du Colombier 	qunlock(&row);
10727dd7cddfSDavid du Colombier 	off = x->offset;
10737dd7cddfSDavid du Colombier 	cnt = x->count;
10747dd7cddfSDavid du Colombier 	if(off > n)
10757dd7cddfSDavid du Colombier 		off = n;
10767dd7cddfSDavid du Colombier 	if(off+cnt > n)
10777dd7cddfSDavid du Colombier 		cnt = n-off;
10787dd7cddfSDavid du Colombier 	fc.count = cnt;
10797dd7cddfSDavid du Colombier 	memmove(r, b+off, cnt);
10807dd7cddfSDavid du Colombier 	fc.data = (char*)r;
10817dd7cddfSDavid du Colombier 	if(!isbuf)
10827dd7cddfSDavid du Colombier 		free(b);
10837dd7cddfSDavid du Colombier 	respond(x, &fc, nil);
10847dd7cddfSDavid du Colombier 	fbuffree(r);
10857dd7cddfSDavid du Colombier }
1086