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