buff.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 }