tbuff.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tbuff.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 && q0cq+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 }