]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/sam/buff.c
make bind(2) error handling consistent
[plan9front.git] / sys / src / cmd / sam / buff.c
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 this block
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)->n <= q0 && q+(*blp)->n < b->nc){
95                 q += (*blp)->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->n);
106         b->cnc = bl->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: bufinsert1 cnc!=0");
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: bufinsert2 cnc!=0");
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 }