Introduction
Introduction Statistics Contact Development Disclaimer Help
buff.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
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 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 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.