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