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