]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.c
9a1cd4a5f265ff68511580f009159b5cd3d3e776
[libucw.git] / lib / fastbuf.c
1 /*
2  *      UCW Library -- Fast Buffered I/O
3  *
4  *      (c) 1997--2005 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "lib/lib.h"
11 #include "lib/fastbuf.h"
12 #include "lib/mempool.h"
13
14 #include <stdlib.h>
15
16 void bclose(struct fastbuf *f)
17 {
18   if (f)
19     {
20       bflush(f);
21       if (f->close)
22         f->close(f);
23     }
24 }
25
26 void bflush(struct fastbuf *f)
27 {
28   if (f->bptr > f->bstop)
29     f->spout(f);
30   else if (f->bstop > f->buffer)
31     f->bptr = f->bstop = f->buffer;
32 }
33
34 inline void bsetpos(struct fastbuf *f, sh_off_t pos)
35 {
36   /* We can optimize seeks only when reading */
37   if (pos >= f->pos - (f->bstop - f->buffer) && pos <= f->pos)
38     f->bptr = f->bstop + (pos - f->pos);
39   else
40     {
41       bflush(f);
42       f->seek(f, pos, SEEK_SET);
43     }
44 }
45
46 void bseek(struct fastbuf *f, sh_off_t pos, int whence)
47 {
48   switch (whence)
49     {
50     case SEEK_SET:
51       return bsetpos(f, pos);
52     case SEEK_CUR:
53       return bsetpos(f, btell(f) + pos);
54     case SEEK_END:
55       bflush(f);
56       f->seek(f, pos, SEEK_END);
57       break;
58     default:
59       die("bseek: invalid whence=%d", whence);
60     }
61 }
62
63 int bgetc_slow(struct fastbuf *f)
64 {
65   if (f->bptr < f->bstop)
66     return *f->bptr++;
67   if (!f->refill(f))
68     return EOF;
69   return *f->bptr++;
70 }
71
72 int bpeekc_slow(struct fastbuf *f)
73 {
74   if (f->bptr < f->bstop)
75     return *f->bptr;
76   if (!f->refill(f))
77     return EOF;
78   return *f->bptr;
79 }
80
81 void bputc_slow(struct fastbuf *f, uns c)
82 {
83   if (f->bptr >= f->bufend)
84     f->spout(f);
85   *f->bptr++ = c;
86 }
87
88 int bgetw_slow(struct fastbuf *f)
89 {
90   int w1, w2;
91   w1 = bgetc_slow(f);
92   if (w1 < 0)
93     return w1;
94   w2 = bgetc_slow(f);
95   if (w2 < 0)
96     return w2;
97 #ifdef CPU_BIG_ENDIAN
98   return (w1 << 8) | w2;
99 #else
100   return w1 | (w2 << 8);
101 #endif
102 }
103
104 u32 bgetl_slow(struct fastbuf *f)
105 {
106   u32 l = bgetc_slow(f);
107 #ifdef CPU_BIG_ENDIAN
108   l = (l << 8) | bgetc_slow(f);
109   l = (l << 8) | bgetc_slow(f);
110   return (l << 8) | bgetc_slow(f);
111 #else
112   l = (bgetc_slow(f) << 8) | l;
113   l = (bgetc_slow(f) << 16) | l;
114   return (bgetc_slow(f) << 24) | l;
115 #endif
116 }
117
118 u64 bgetq_slow(struct fastbuf *f)
119 {
120   u32 l, h;
121 #ifdef CPU_BIG_ENDIAN
122   h = bgetl_slow(f);
123   l = bgetl_slow(f);
124 #else
125   l = bgetl_slow(f);
126   h = bgetl_slow(f);
127 #endif
128   return ((u64) h << 32) | l;
129 }
130
131 u64 bget5_slow(struct fastbuf *f)
132 {
133   u32 l, h;
134 #ifdef CPU_BIG_ENDIAN
135   h = bgetc_slow(f);
136   l = bgetl_slow(f);
137 #else
138   l = bgetl_slow(f);
139   h = bgetc_slow(f);
140 #endif
141   return ((u64) h << 32) | l;
142 }
143
144 void bputw_slow(struct fastbuf *f, uns w)
145 {
146 #ifdef CPU_BIG_ENDIAN
147   bputc_slow(f, w >> 8);
148   bputc_slow(f, w);
149 #else
150   bputc_slow(f, w);
151   bputc_slow(f, w >> 8);
152 #endif
153 }
154
155 void bputl_slow(struct fastbuf *f, u32 l)
156 {
157 #ifdef CPU_BIG_ENDIAN
158   bputc_slow(f, l >> 24);
159   bputc_slow(f, l >> 16);
160   bputc_slow(f, l >> 8);
161   bputc_slow(f, l);
162 #else
163   bputc_slow(f, l);
164   bputc_slow(f, l >> 8);
165   bputc_slow(f, l >> 16);
166   bputc_slow(f, l >> 24);
167 #endif
168 }
169
170 void bputq_slow(struct fastbuf *f, u64 q)
171 {
172 #ifdef CPU_BIG_ENDIAN
173   bputl_slow(f, q >> 32);
174   bputl_slow(f, q);
175 #else
176   bputl_slow(f, q);
177   bputl_slow(f, q >> 32);
178 #endif
179 }
180
181 void bput5_slow(struct fastbuf *f, u64 o)
182 {
183   u32 hi = o >> 32;
184   u32 low = o;
185 #ifdef CPU_BIG_ENDIAN
186   bputc_slow(f, hi);
187   bputl_slow(f, low);
188 #else
189   bputl_slow(f, low);
190   bputc_slow(f, hi);
191 #endif
192 }
193
194 uns bread_slow(struct fastbuf *f, void *b, uns l, uns check)
195 {
196   uns total = 0;
197   while (l)
198     {
199       uns k = f->bstop - f->bptr;
200
201       if (!k)
202         {
203           f->refill(f);
204           k = f->bstop - f->bptr;
205           if (!k)
206             break;
207         }
208       if (k > l)
209         k = l;
210       memcpy(b, f->bptr, k);
211       f->bptr += k;
212       b = (byte *)b + k;
213       l -= k;
214       total += k;
215     }
216   if (check && total && l)
217     die("breadb: short read");
218   return total;
219 }
220
221 void bwrite_slow(struct fastbuf *f, void *b, uns l)
222 {
223   while (l)
224     {
225       uns k = f->bufend - f->bptr;
226
227       if (!k)
228         {
229           f->spout(f);
230           k = f->bufend - f->bptr;
231         }
232       if (k > l)
233         k = l;
234       memcpy(f->bptr, b, k);
235       f->bptr += k;
236       b = (byte *)b + k;
237       l -= k;
238     }
239 }
240
241 byte *                                  /* Non-standard */
242 bgets(struct fastbuf *f, byte *b, uns l)
243 {
244   byte *e = b + l - 1;
245   int k;
246
247   k = bgetc(f);
248   if (k < 0)
249     return NULL;
250   while (b < e)
251     {
252       if (k == '\n' || k < 0)
253         {
254           *b = 0;
255           return b;
256         }
257       *b++ = k;
258       k = bgetc(f);
259     }
260   die("%s: Line too long", f->name);
261 }
262
263 int
264 bgets_nodie(struct fastbuf *f, byte *b, uns l)
265 {
266   byte *start = b;
267   byte *e = b + l - 1;
268   int k;
269
270   k = bgetc(f);
271   if (k < 0)
272     return 0;
273   while (b < e)
274     {
275       if (k == '\n' || k < 0)
276         {
277           *b++ = 0;
278           return b - start;
279         }
280       *b++ = k;
281       k = bgetc(f);
282     }
283   return -1;
284 }
285
286 uns
287 bgets_bb(struct fastbuf *f, bb_t *b)
288 {
289   for (uns l = 0;; l++)
290     {
291       int k = bgetc(f);
292       byte *p = bb_grow(b, l + 1) + l;
293       if (k == '\n' || k < 0)
294         {
295           *p = 0;
296           return l;
297         }
298       *p = k;
299     }
300 }
301
302 byte *
303 bgets_mp(struct mempool *mp, struct fastbuf *f)
304 {
305   uns len = 256, l = 0;
306   byte *buf = alloca(len);
307   for (;;)
308     {
309       while (l < len)
310         {
311           int k = bgetc(f);
312           if (k == '\n' || k < 0)
313             {
314               byte *result = mp_alloc(mp, l + 1);
315               memcpy(result, buf, l);
316               result[l] = 0;
317               return result;
318             }
319           buf[l++] = k;
320         }
321       byte *old_buf = buf;
322       uns old_len = len;
323       len *= 2;
324       buf = alloca(len);
325       memcpy(buf, old_buf, old_len);
326     }
327 }
328
329 int
330 bgets_stk_step(struct fastbuf *f, byte *old_buf, byte *buf, uns len)
331 {
332   if (old_buf)
333     {
334       len = len >> 1;
335       memcpy(buf, old_buf, len);
336       buf += len;
337     }
338   while (len--)
339     {
340       int k = bgetc(f);
341       if (k == '\n' || k < 0)
342         return *buf = 0;
343       *buf++ = k;
344     }
345   return 1;
346 }
347
348 byte *
349 bgets0(struct fastbuf *f, byte *b, uns l)
350 {
351   byte *e = b + l - 1;
352   int k;
353
354   k = bgetc(f);
355   if (k < 0)
356     return NULL;
357   while (b < e)
358     {
359       if (k <= 0)
360         {
361           *b = 0;
362           return b;
363         }
364       *b++ = k;
365       k = bgetc(f);
366     }
367   die("%s: Line too long", f->name);
368 }
369
370 void
371 bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l)
372 {
373   while (l)
374     {
375       byte *fptr, *tptr;
376       uns favail, tavail, n;
377
378       favail = bdirect_read_prepare(f, &fptr);
379       if (!favail)
380         {
381           if (l == ~0U)
382             return;
383           die("bbcopy: source exhausted");
384         }
385       tavail = bdirect_write_prepare(t, &tptr);
386       n = MIN(l, favail);
387       n = MIN(n, tavail);
388       memcpy(tptr, fptr, n);
389       bdirect_read_commit(f, fptr + n);
390       bdirect_write_commit(t, tptr + n);
391       if (l != ~0U)
392         l -= n;
393     }
394 }
395
396 int
397 bconfig(struct fastbuf *f, uns item, int value)
398 {
399   return f->config ? f->config(f, item, value) : -1;
400 }
401
402 void
403 brewind(struct fastbuf *f)
404 {
405   bflush(f);
406   bsetpos(f, 0);
407 }
408
409 int
410 bskip_slow(struct fastbuf *f, uns len)
411 {
412   while (len)
413     {
414       byte *buf;
415       uns l = bdirect_read_prepare(f, &buf);
416       if (!l)
417         return 0;
418       l = MIN(l, len);
419       bdirect_read_commit(f, buf+l);
420       len -= l;
421     }
422   return 1;
423 }
424
425 sh_off_t
426 bfilesize(struct fastbuf *f)
427 {
428   if (!f)
429     return 0;
430   sh_off_t pos = btell(f);
431   bseek(f, 0, SEEK_END);
432   sh_off_t len = btell(f);
433   bsetpos(f, pos);
434   return len;
435 }