xref: /plan9/sys/src/cmd/acme/buff.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
5*9a747e4fSDavid 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 	Slop = 100,	/* room to grow with reallocation */
177dd7cddfSDavid du Colombier };
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier static
207dd7cddfSDavid du Colombier void
sizecache(Buffer * b,uint n)217dd7cddfSDavid du Colombier sizecache(Buffer *b, uint n)
227dd7cddfSDavid du Colombier {
237dd7cddfSDavid du Colombier 	if(n <= b->cmax)
247dd7cddfSDavid du Colombier 		return;
257dd7cddfSDavid du Colombier 	b->cmax = n+Slop;
267dd7cddfSDavid du Colombier 	b->c = runerealloc(b->c, b->cmax);
277dd7cddfSDavid du Colombier }
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier static
307dd7cddfSDavid du Colombier void
addblock(Buffer * b,uint i,uint n)317dd7cddfSDavid du Colombier addblock(Buffer *b, uint i, uint n)
327dd7cddfSDavid du Colombier {
337dd7cddfSDavid du Colombier 	if(i > b->nbl)
347dd7cddfSDavid du Colombier 		error("internal error: addblock");
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
377dd7cddfSDavid du Colombier 	if(i < b->nbl)
387dd7cddfSDavid du Colombier 		memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
397dd7cddfSDavid du Colombier 	b->bl[i] = disknewblock(disk, n);
407dd7cddfSDavid du Colombier 	b->nbl++;
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier static
447dd7cddfSDavid du Colombier void
delblock(Buffer * b,uint i)457dd7cddfSDavid du Colombier delblock(Buffer *b, uint i)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier 	if(i >= b->nbl)
487dd7cddfSDavid du Colombier 		error("internal error: delblock");
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	diskrelease(disk, b->bl[i]);
517dd7cddfSDavid du Colombier 	b->nbl--;
527dd7cddfSDavid du Colombier 	if(i < b->nbl)
537dd7cddfSDavid du Colombier 		memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
547dd7cddfSDavid du Colombier 	b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier /*
587dd7cddfSDavid du Colombier  * Move cache so b->cq <= q0 < b->cq+b->cnc.
597dd7cddfSDavid du Colombier  * If at very end, q0 will fall on end of cache block.
607dd7cddfSDavid du Colombier  */
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier static
637dd7cddfSDavid du Colombier void
flush(Buffer * b)647dd7cddfSDavid du Colombier flush(Buffer *b)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier 	if(b->cdirty || b->cnc==0){
677dd7cddfSDavid du Colombier 		if(b->cnc == 0)
687dd7cddfSDavid du Colombier 			delblock(b, b->cbi);
697dd7cddfSDavid du Colombier 		else
707dd7cddfSDavid du Colombier 			diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
717dd7cddfSDavid du Colombier 		b->cdirty = FALSE;
727dd7cddfSDavid du Colombier 	}
737dd7cddfSDavid du Colombier }
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier static
767dd7cddfSDavid du Colombier void
setcache(Buffer * b,uint q0)777dd7cddfSDavid du Colombier setcache(Buffer *b, uint q0)
787dd7cddfSDavid du Colombier {
797dd7cddfSDavid du Colombier 	Block **blp, *bl;
807dd7cddfSDavid du Colombier 	uint i, q;
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	if(q0 > b->nc)
837dd7cddfSDavid du Colombier 		error("internal error: setcache");
847dd7cddfSDavid du Colombier 	/*
857dd7cddfSDavid du Colombier 	 * flush and reload if q0 is not in cache.
867dd7cddfSDavid du Colombier 	 */
877dd7cddfSDavid du Colombier 	if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
887dd7cddfSDavid du Colombier 		return;
897dd7cddfSDavid du Colombier 	/*
907dd7cddfSDavid du Colombier 	 * if q0 is at end of file and end of cache, continue to grow this block
917dd7cddfSDavid du Colombier 	 */
927dd7cddfSDavid du Colombier 	if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<Maxblock)
937dd7cddfSDavid du Colombier 		return;
947dd7cddfSDavid du Colombier 	flush(b);
957dd7cddfSDavid du Colombier 	/* find block */
967dd7cddfSDavid du Colombier 	if(q0 < b->cq){
977dd7cddfSDavid du Colombier 		q = 0;
987dd7cddfSDavid du Colombier 		i = 0;
997dd7cddfSDavid du Colombier 	}else{
1007dd7cddfSDavid du Colombier 		q = b->cq;
1017dd7cddfSDavid du Colombier 		i = b->cbi;
1027dd7cddfSDavid du Colombier 	}
1037dd7cddfSDavid du Colombier 	blp = &b->bl[i];
1047dd7cddfSDavid du Colombier 	while(q+(*blp)->n <= q0 && q+(*blp)->n < b->nc){
1057dd7cddfSDavid du Colombier 		q += (*blp)->n;
1067dd7cddfSDavid du Colombier 		i++;
1077dd7cddfSDavid du Colombier 		blp++;
1087dd7cddfSDavid du Colombier 		if(i >= b->nbl)
1097dd7cddfSDavid du Colombier 			error("block not found");
1107dd7cddfSDavid du Colombier 	}
1117dd7cddfSDavid du Colombier 	bl = *blp;
1127dd7cddfSDavid du Colombier 	/* remember position */
1137dd7cddfSDavid du Colombier 	b->cbi = i;
1147dd7cddfSDavid du Colombier 	b->cq = q;
1157dd7cddfSDavid du Colombier 	sizecache(b, bl->n);
1167dd7cddfSDavid du Colombier 	b->cnc = bl->n;
1177dd7cddfSDavid du Colombier 	/*read block*/
1187dd7cddfSDavid du Colombier 	diskread(disk, bl, b->c, b->cnc);
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier void
bufinsert(Buffer * b,uint q0,Rune * s,uint n)1227dd7cddfSDavid du Colombier bufinsert(Buffer *b, uint q0, Rune *s, uint n)
1237dd7cddfSDavid du Colombier {
1247dd7cddfSDavid du Colombier 	uint i, m, t, off;
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier 	if(q0 > b->nc)
1277dd7cddfSDavid du Colombier 		error("internal error: bufinsert");
1287dd7cddfSDavid du Colombier 
1297dd7cddfSDavid du Colombier 	while(n > 0){
1307dd7cddfSDavid du Colombier 		setcache(b, q0);
1317dd7cddfSDavid du Colombier 		off = q0-b->cq;
1327dd7cddfSDavid du Colombier 		if(b->cnc+n <= Maxblock){
1337dd7cddfSDavid du Colombier 			/* Everything fits in one block. */
1347dd7cddfSDavid du Colombier 			t = b->cnc+n;
1357dd7cddfSDavid du Colombier 			m = n;
1367dd7cddfSDavid du Colombier 			if(b->bl == nil){	/* allocate */
1377dd7cddfSDavid du Colombier 				if(b->cnc != 0)
1387dd7cddfSDavid du Colombier 					error("internal error: bufinsert1 cnc!=0");
1397dd7cddfSDavid du Colombier 				addblock(b, 0, t);
1407dd7cddfSDavid du Colombier 				b->cbi = 0;
1417dd7cddfSDavid du Colombier 			}
1427dd7cddfSDavid du Colombier 			sizecache(b, t);
1437dd7cddfSDavid du Colombier 			runemove(b->c+off+m, b->c+off, b->cnc-off);
1447dd7cddfSDavid du Colombier 			runemove(b->c+off, s, m);
1457dd7cddfSDavid du Colombier 			b->cnc = t;
1467dd7cddfSDavid du Colombier 			goto Tail;
1477dd7cddfSDavid du Colombier 		}
1487dd7cddfSDavid du Colombier 		/*
1497dd7cddfSDavid du Colombier 		 * We must make a new block.  If q0 is at
1507dd7cddfSDavid du Colombier 		 * the very beginning or end of this block,
1517dd7cddfSDavid du Colombier 		 * just make a new block and fill it.
1527dd7cddfSDavid du Colombier 		 */
1537dd7cddfSDavid du Colombier 		if(q0==b->cq || q0==b->cq+b->cnc){
1547dd7cddfSDavid du Colombier 			if(b->cdirty)
1557dd7cddfSDavid du Colombier 				flush(b);
1567dd7cddfSDavid du Colombier 			m = min(n, Maxblock);
1577dd7cddfSDavid du Colombier 			if(b->bl == nil){	/* allocate */
1587dd7cddfSDavid du Colombier 				if(b->cnc != 0)
1597dd7cddfSDavid du Colombier 					error("internal error: bufinsert2 cnc!=0");
1607dd7cddfSDavid du Colombier 				i = 0;
1617dd7cddfSDavid du Colombier 			}else{
1627dd7cddfSDavid du Colombier 				i = b->cbi;
1637dd7cddfSDavid du Colombier 				if(q0 > b->cq)
1647dd7cddfSDavid du Colombier 					i++;
1657dd7cddfSDavid du Colombier 			}
1667dd7cddfSDavid du Colombier 			addblock(b, i, m);
1677dd7cddfSDavid du Colombier 			sizecache(b, m);
1687dd7cddfSDavid du Colombier 			runemove(b->c, s, m);
1697dd7cddfSDavid du Colombier 			b->cq = q0;
1707dd7cddfSDavid du Colombier 			b->cbi = i;
1717dd7cddfSDavid du Colombier 			b->cnc = m;
1727dd7cddfSDavid du Colombier 			goto Tail;
1737dd7cddfSDavid du Colombier 		}
1747dd7cddfSDavid du Colombier 		/*
1757dd7cddfSDavid du Colombier 		 * Split the block; cut off the right side and
1767dd7cddfSDavid du Colombier 		 * let go of it.
1777dd7cddfSDavid du Colombier 		 */
1787dd7cddfSDavid du Colombier 		m = b->cnc-off;
1797dd7cddfSDavid du Colombier 		if(m > 0){
1807dd7cddfSDavid du Colombier 			i = b->cbi+1;
1817dd7cddfSDavid du Colombier 			addblock(b, i, m);
1827dd7cddfSDavid du Colombier 			diskwrite(disk, &b->bl[i], b->c+off, m);
1837dd7cddfSDavid du Colombier 			b->cnc -= m;
1847dd7cddfSDavid du Colombier 		}
1857dd7cddfSDavid du Colombier 		/*
1867dd7cddfSDavid du Colombier 		 * Now at end of block.  Take as much input
1877dd7cddfSDavid du Colombier 		 * as possible and tack it on end of block.
1887dd7cddfSDavid du Colombier 		 */
1897dd7cddfSDavid du Colombier 		m = min(n, Maxblock-b->cnc);
1907dd7cddfSDavid du Colombier 		sizecache(b, b->cnc+m);
1917dd7cddfSDavid du Colombier 		runemove(b->c+b->cnc, s, m);
1927dd7cddfSDavid du Colombier 		b->cnc += m;
1937dd7cddfSDavid du Colombier   Tail:
1947dd7cddfSDavid du Colombier 		b->nc += m;
1957dd7cddfSDavid du Colombier 		q0 += m;
1967dd7cddfSDavid du Colombier 		s += m;
1977dd7cddfSDavid du Colombier 		n -= m;
1987dd7cddfSDavid du Colombier 		b->cdirty = TRUE;
1997dd7cddfSDavid du Colombier 	}
2007dd7cddfSDavid du Colombier }
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier void
bufdelete(Buffer * b,uint q0,uint q1)2037dd7cddfSDavid du Colombier bufdelete(Buffer *b, uint q0, uint q1)
2047dd7cddfSDavid du Colombier {
2057dd7cddfSDavid du Colombier 	uint m, n, off;
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 	if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
2087dd7cddfSDavid du Colombier 		error("internal error: bufdelete");
2097dd7cddfSDavid du Colombier 	while(q1 > q0){
2107dd7cddfSDavid du Colombier 		setcache(b, q0);
2117dd7cddfSDavid du Colombier 		off = q0-b->cq;
2127dd7cddfSDavid du Colombier 		if(q1 > b->cq+b->cnc)
2137dd7cddfSDavid du Colombier 			n = b->cnc - off;
2147dd7cddfSDavid du Colombier 		else
2157dd7cddfSDavid du Colombier 			n = q1-q0;
2167dd7cddfSDavid du Colombier 		m = b->cnc - (off+n);
2177dd7cddfSDavid du Colombier 		if(m > 0)
2187dd7cddfSDavid du Colombier 			runemove(b->c+off, b->c+off+n, m);
2197dd7cddfSDavid du Colombier 		b->cnc -= n;
2207dd7cddfSDavid du Colombier 		b->cdirty = TRUE;
2217dd7cddfSDavid du Colombier 		q1 -= n;
2227dd7cddfSDavid du Colombier 		b->nc -= n;
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
22659cc4ca5SDavid du Colombier static int
bufloader(void * v,uint q0,Rune * r,int nr)22759cc4ca5SDavid du Colombier bufloader(void *v, uint q0, Rune *r, int nr)
22859cc4ca5SDavid du Colombier {
22959cc4ca5SDavid du Colombier 	bufinsert(v, q0, r, nr);
23059cc4ca5SDavid du Colombier 	return nr;
23159cc4ca5SDavid du Colombier }
23259cc4ca5SDavid du Colombier 
2337dd7cddfSDavid du Colombier uint
loadfile(int fd,uint q0,int * nulls,int (* f)(void *,uint,Rune *,int),void * arg)23459cc4ca5SDavid du Colombier loadfile(int fd, uint q0, int *nulls, int(*f)(void*, uint, Rune*, int), void *arg)
2357dd7cddfSDavid du Colombier {
2367dd7cddfSDavid du Colombier 	char *p;
2377dd7cddfSDavid du Colombier 	Rune *r;
2387dd7cddfSDavid du Colombier 	int l, m, n, nb, nr;
2397dd7cddfSDavid du Colombier 	uint q1;
2407dd7cddfSDavid du Colombier 
24159cc4ca5SDavid du Colombier 	p = emalloc((Maxblock+UTFmax+1)*sizeof p[0]);
2427dd7cddfSDavid du Colombier 	r = runemalloc(Maxblock);
2437dd7cddfSDavid du Colombier 	m = 0;
2447dd7cddfSDavid du Colombier 	n = 1;
2457dd7cddfSDavid du Colombier 	q1 = q0;
2467dd7cddfSDavid du Colombier 	/*
2477dd7cddfSDavid du Colombier 	 * At top of loop, may have m bytes left over from
2487dd7cddfSDavid du Colombier 	 * last pass, possibly representing a partial rune.
2497dd7cddfSDavid du Colombier 	 */
2507dd7cddfSDavid du Colombier 	while(n > 0){
2517dd7cddfSDavid du Colombier 		n = read(fd, p+m, Maxblock);
2527dd7cddfSDavid du Colombier 		if(n < 0){
2537dd7cddfSDavid du Colombier 			warning(nil, "read error in Buffer.load");
2547dd7cddfSDavid du Colombier 			break;
2557dd7cddfSDavid du Colombier 		}
2567dd7cddfSDavid du Colombier 		m += n;
2577dd7cddfSDavid du Colombier 		p[m] = 0;
2587dd7cddfSDavid du Colombier 		l = m;
2597dd7cddfSDavid du Colombier 		if(n > 0)
2607dd7cddfSDavid du Colombier 			l -= UTFmax;
2617dd7cddfSDavid du Colombier 		cvttorunes(p, l, r, &nb, &nr, nulls);
262*9a747e4fSDavid du Colombier 		memmove(p, p+nb, m-nb);
2637dd7cddfSDavid du Colombier 		m -= nb;
26459cc4ca5SDavid du Colombier 		q1 += (*f)(arg, q1, r, nr);
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier 	free(p);
2677dd7cddfSDavid du Colombier 	free(r);
2687dd7cddfSDavid du Colombier 	return q1-q0;
2697dd7cddfSDavid du Colombier }
2707dd7cddfSDavid du Colombier 
27159cc4ca5SDavid du Colombier uint
bufload(Buffer * b,uint q0,int fd,int * nulls)27259cc4ca5SDavid du Colombier bufload(Buffer *b, uint q0, int fd, int *nulls)
27359cc4ca5SDavid du Colombier {
27459cc4ca5SDavid du Colombier 	if(q0 > b->nc)
27559cc4ca5SDavid du Colombier 		error("internal error: bufload");
27659cc4ca5SDavid du Colombier 	return loadfile(fd, q0, nulls, bufloader, b);
27759cc4ca5SDavid du Colombier }
27859cc4ca5SDavid du Colombier 
2797dd7cddfSDavid du Colombier void
bufread(Buffer * b,uint q0,Rune * s,uint n)2807dd7cddfSDavid du Colombier bufread(Buffer *b, uint q0, Rune *s, uint n)
2817dd7cddfSDavid du Colombier {
2827dd7cddfSDavid du Colombier 	uint m;
2837dd7cddfSDavid du Colombier 
2847dd7cddfSDavid du Colombier 	if(!(q0<=b->nc && q0+n<=b->nc))
2857dd7cddfSDavid du Colombier 		error("bufread: internal error");
2867dd7cddfSDavid du Colombier 
2877dd7cddfSDavid du Colombier 	while(n > 0){
2887dd7cddfSDavid du Colombier 		setcache(b, q0);
2897dd7cddfSDavid du Colombier 		m = min(n, b->cnc-(q0-b->cq));
2907dd7cddfSDavid du Colombier 		runemove(s, b->c+(q0-b->cq), m);
2917dd7cddfSDavid du Colombier 		q0 += m;
2927dd7cddfSDavid du Colombier 		s += m;
2937dd7cddfSDavid du Colombier 		n -= m;
2947dd7cddfSDavid du Colombier 	}
2957dd7cddfSDavid du Colombier }
2967dd7cddfSDavid du Colombier 
2977dd7cddfSDavid du Colombier void
bufreset(Buffer * b)2987dd7cddfSDavid du Colombier bufreset(Buffer *b)
2997dd7cddfSDavid du Colombier {
3007dd7cddfSDavid du Colombier 	int i;
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier 	b->nc = 0;
3037dd7cddfSDavid du Colombier 	b->cnc = 0;
3047dd7cddfSDavid du Colombier 	b->cq = 0;
3057dd7cddfSDavid du Colombier 	b->cdirty = 0;
3067dd7cddfSDavid du Colombier 	b->cbi = 0;
3077dd7cddfSDavid du Colombier 	/* delete backwards to avoid n² behavior */
3087dd7cddfSDavid du Colombier 	for(i=b->nbl-1; --i>=0; )
3097dd7cddfSDavid du Colombier 		delblock(b, i);
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier void
bufclose(Buffer * b)3137dd7cddfSDavid du Colombier bufclose(Buffer *b)
3147dd7cddfSDavid du Colombier {
3157dd7cddfSDavid du Colombier 	bufreset(b);
3167dd7cddfSDavid du Colombier 	free(b->c);
3177dd7cddfSDavid du Colombier 	b->c = nil;
3187dd7cddfSDavid du Colombier 	b->cnc = 0;
3197dd7cddfSDavid du Colombier 	free(b->bl);
3207dd7cddfSDavid du Colombier 	b->bl = nil;
3217dd7cddfSDavid du Colombier 	b->nbl = 0;
3227dd7cddfSDavid du Colombier }
323