buff.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       buff.c (5170B)
       ---
            1 #include "sam.h"
            2 
            3 enum
            4 {
            5         Slop = 100        /* room to grow with reallocation */
            6 };
            7 
            8 static
            9 void
           10 sizecache(Buffer *b, uint n)
           11 {
           12         if(n <= b->cmax)
           13                 return;
           14         b->cmax = n+Slop;
           15         b->c = runerealloc(b->c, b->cmax);
           16 }
           17 
           18 static
           19 void
           20 addblock(Buffer *b, uint i, uint n)
           21 {
           22         if(i > b->nbl)
           23                 panic("internal error: addblock");
           24 
           25         b->bl = realloc(b->bl, (b->nbl+1)*sizeof b->bl[0]);
           26         if(i < b->nbl)
           27                 memmove(b->bl+i+1, b->bl+i, (b->nbl-i)*sizeof(Block*));
           28         b->bl[i] = disknewblock(disk, n);
           29         b->nbl++;
           30 }
           31 
           32 
           33 static
           34 void
           35 delblock(Buffer *b, uint i)
           36 {
           37         if(i >= b->nbl)
           38                 panic("internal error: delblock");
           39 
           40         diskrelease(disk, b->bl[i]);
           41         b->nbl--;
           42         if(i < b->nbl)
           43                 memmove(b->bl+i, b->bl+i+1, (b->nbl-i)*sizeof(Block*));
           44         b->bl = realloc(b->bl, b->nbl*sizeof b->bl[0]);
           45 }
           46 
           47 /*
           48  * Move cache so b->cq <= q0 < b->cq+b->cnc.
           49  * If at very end, q0 will fall on end of cache block.
           50  */
           51 
           52 static
           53 void
           54 flush(Buffer *b)
           55 {
           56         if(b->cdirty || b->cnc==0){
           57                 if(b->cnc == 0)
           58                         delblock(b, b->cbi);
           59                 else
           60                         diskwrite(disk, &b->bl[b->cbi], b->c, b->cnc);
           61                 b->cdirty = FALSE;
           62         }
           63 }
           64 
           65 static
           66 void
           67 setcache(Buffer *b, uint q0)
           68 {
           69         Block **blp, *bl;
           70         uint i, q;
           71 
           72         if(q0 > b->nc)
           73                 panic("internal error: setcache");
           74         /*
           75          * flush and reload if q0 is not in cache.
           76          */
           77         if(b->nc == 0 || (b->cq<=q0 && q0<b->cq+b->cnc))
           78                 return;
           79         /*
           80          * if q0 is at end of file and end of cache, continue to grow this block
           81          */
           82         if(q0==b->nc && q0==b->cq+b->cnc && b->cnc<=Maxblock)
           83                 return;
           84         flush(b);
           85         /* find block */
           86         if(q0 < b->cq){
           87                 q = 0;
           88                 i = 0;
           89         }else{
           90                 q = b->cq;
           91                 i = b->cbi;
           92         }
           93         blp = &b->bl[i];
           94         while(q+(*blp)->u.n <= q0 && q+(*blp)->u.n < b->nc){
           95                 q += (*blp)->u.n;
           96                 i++;
           97                 blp++;
           98                 if(i >= b->nbl)
           99                         panic("block not found");
          100         }
          101         bl = *blp;
          102         /* remember position */
          103         b->cbi = i;
          104         b->cq = q;
          105         sizecache(b, bl->u.n);
          106         b->cnc = bl->u.n;
          107         /*read block*/
          108         diskread(disk, bl, b->c, b->cnc);
          109 }
          110 
          111 void
          112 bufinsert(Buffer *b, uint q0, Rune *s, uint n)
          113 {
          114         uint i, m, t, off;
          115 
          116         if(q0 > b->nc)
          117                 panic("internal error: bufinsert");
          118 
          119         while(n > 0){
          120                 setcache(b, q0);
          121                 off = q0-b->cq;
          122                 if(b->cnc+n <= Maxblock){
          123                         /* Everything fits in one block. */
          124                         t = b->cnc+n;
          125                         m = n;
          126                         if(b->bl == nil){        /* allocate */
          127                                 if(b->cnc != 0)
          128                                         panic("internal error: bufinsert1 cnc!=0");
          129                                 addblock(b, 0, t);
          130                                 b->cbi = 0;
          131                         }
          132                         sizecache(b, t);
          133                         runemove(b->c+off+m, b->c+off, b->cnc-off);
          134                         runemove(b->c+off, s, m);
          135                         b->cnc = t;
          136                         goto Tail;
          137                 }
          138                 /*
          139                  * We must make a new block.  If q0 is at
          140                  * the very beginning or end of this block,
          141                  * just make a new block and fill it.
          142                  */
          143                 if(q0==b->cq || q0==b->cq+b->cnc){
          144                         if(b->cdirty)
          145                                 flush(b);
          146                         m = min(n, Maxblock);
          147                         if(b->bl == nil){        /* allocate */
          148                                 if(b->cnc != 0)
          149                                         panic("internal error: bufinsert2 cnc!=0");
          150                                 i = 0;
          151                         }else{
          152                                 i = b->cbi;
          153                                 if(q0 > b->cq)
          154                                         i++;
          155                         }
          156                         addblock(b, i, m);
          157                         sizecache(b, m);
          158                         runemove(b->c, s, m);
          159                         b->cq = q0;
          160                         b->cbi = i;
          161                         b->cnc = m;
          162                         goto Tail;
          163                 }
          164                 /*
          165                  * Split the block; cut off the right side and
          166                  * let go of it.
          167                  */
          168                 m = b->cnc-off;
          169                 if(m > 0){
          170                         i = b->cbi+1;
          171                         addblock(b, i, m);
          172                         diskwrite(disk, &b->bl[i], b->c+off, m);
          173                         b->cnc -= m;
          174                 }
          175                 /*
          176                  * Now at end of block.  Take as much input
          177                  * as possible and tack it on end of block.
          178                  */
          179                 m = min(n, Maxblock-b->cnc);
          180                 sizecache(b, b->cnc+m);
          181                 runemove(b->c+b->cnc, s, m);
          182                 b->cnc += m;
          183   Tail:
          184                 b->nc += m;
          185                 q0 += m;
          186                 s += m;
          187                 n -= m;
          188                 b->cdirty = TRUE;
          189         }
          190 }
          191 
          192 void
          193 bufdelete(Buffer *b, uint q0, uint q1)
          194 {
          195         uint m, n, off;
          196 
          197         if(!(q0<=q1 && q0<=b->nc && q1<=b->nc))
          198                 panic("internal error: bufdelete");
          199         while(q1 > q0){
          200                 setcache(b, q0);
          201                 off = q0-b->cq;
          202                 if(q1 > b->cq+b->cnc)
          203                         n = b->cnc - off;
          204                 else
          205                         n = q1-q0;
          206                 m = b->cnc - (off+n);
          207                 if(m > 0)
          208                         runemove(b->c+off, b->c+off+n, m);
          209                 b->cnc -= n;
          210                 b->cdirty = TRUE;
          211                 q1 -= n;
          212                 b->nc -= n;
          213         }
          214 }
          215 
          216 uint
          217 bufload(Buffer *b, uint q0, int fd, int *nulls)
          218 {
          219         char *p;
          220         Rune *r;
          221         int l, m, n, nb, nr;
          222         uint q1;
          223 
          224         if(q0 > b->nc)
          225                 panic("internal error: bufload");
          226         p = malloc((Maxblock+UTFmax+1)*sizeof p[0]);
          227         if(p == nil)
          228                 panic("bufload: malloc failed");
          229         r = runemalloc(Maxblock);
          230         m = 0;
          231         n = 1;
          232         q1 = q0;
          233         /*
          234          * At top of loop, may have m bytes left over from
          235          * last pass, possibly representing a partial rune.
          236          */
          237         while(n > 0){
          238                 n = read(fd, p+m, Maxblock);
          239                 if(n < 0){
          240                         error(Ebufload);
          241                         break;
          242                 }
          243                 m += n;
          244                 p[m] = 0;
          245                 l = m;
          246                 if(n > 0)
          247                         l -= UTFmax;
          248                 cvttorunes(p, l, r, &nb, &nr, nulls);
          249                 memmove(p, p+nb, m-nb);
          250                 m -= nb;
          251                 bufinsert(b, q1, r, nr);
          252                 q1 += nr;
          253         }
          254         free(p);
          255         free(r);
          256         return q1-q0;
          257 }
          258 
          259 void
          260 bufread(Buffer *b, uint q0, Rune *s, uint n)
          261 {
          262         uint m;
          263 
          264         if(!(q0<=b->nc && q0+n<=b->nc))
          265                 panic("bufread: internal error");
          266 
          267         while(n > 0){
          268                 setcache(b, q0);
          269                 m = min(n, b->cnc-(q0-b->cq));
          270                 runemove(s, b->c+(q0-b->cq), m);
          271                 q0 += m;
          272                 s += m;
          273                 n -= m;
          274         }
          275 }
          276 
          277 void
          278 bufreset(Buffer *b)
          279 {
          280         int i;
          281 
          282         b->nc = 0;
          283         b->cnc = 0;
          284         b->cq = 0;
          285         b->cdirty = 0;
          286         b->cbi = 0;
          287         /* delete backwards to avoid n² behavior */
          288         for(i=b->nbl-1; --i>=0; )
          289                 delblock(b, i);
          290 }
          291 
          292 void
          293 bufclose(Buffer *b)
          294 {
          295         bufreset(b);
          296         free(b->c);
          297         b->c = nil;
          298         b->cnc = 0;
          299         free(b->bl);
          300         b->bl = nil;
          301         b->nbl = 0;
          302 }