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