plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

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 }