Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}