tbuff.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tbuff.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 th… | |
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: bufinsert… | |
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: bufinsert… | |
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 } |