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 }