]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.c
4c5ec5cd39ef15dd059add093b4212c9aa2d37b5
[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 *bb)
288 {
289   byte *buf = bb->ptr, *src;
290   uns len = 0, buf_len = bb->len, src_len = bdirect_read_prepare(f, &src);
291   while (src_len)
292     {
293       uns cnt = MIN(src_len, buf_len);
294       for (uns i = cnt; i--;)
295         {
296           if (*src == '\n')
297             {
298               *buf = 0;
299               return buf - bb->ptr;
300             }
301           *buf++ = *src++;
302         }
303       len += cnt;
304       if (cnt == src_len)
305         src_len = bdirect_read_prepare(f, &src);
306       else
307         src_len -= cnt;
308       if (cnt == buf_len)
309         {
310           bb_do_grow(bb, len + 1);
311           buf = bb->ptr + len;
312           buf_len = bb->len - len;
313         }
314       else
315         buf_len -= cnt;
316     }
317   *buf = 0;
318   return len;
319 }
320
321 byte *
322 bgets_mp(struct mempool *mp, struct fastbuf *f)
323 {
324 #define BLOCK_SIZE 4096
325   struct block {
326     struct block *prev;
327     byte data[BLOCK_SIZE];
328   } *blocks = NULL;
329   uns sum = 0;
330   for (;;)
331     {
332       struct block *new_block = alloca(sizeof(struct block));
333       byte *b = new_block->data, *e = b + BLOCK_SIZE;
334       while (b < e)
335         {
336           int k = bgetc(f);
337           if (k == '\n' || k < 0)
338             {
339               uns len = b - new_block->data;
340               byte *result = mp_alloc(mp, sum + len + 1) + sum;
341               result[len] = 0;
342               memcpy(result, new_block->data, len);
343               while (blocks)
344                 {
345                   result -= BLOCK_SIZE;
346                   memcpy(result, blocks->data, BLOCK_SIZE);
347                   blocks = blocks->prev;
348                 }
349               return result;
350             }
351           *b++ = k;
352         }
353       new_block->prev = blocks;
354       blocks = new_block;
355       sum += BLOCK_SIZE;
356     }
357 #undef BLOCK_SIZE
358 }
359
360 int
361 bgets_stk_step(struct fastbuf *f, byte *old_buf, byte *buf, uns len)
362 {
363   if (old_buf)
364     {
365       len = len >> 1;
366       memcpy(buf, old_buf, len);
367       buf += len;
368     }
369   while (len--)
370     {
371       int k = bgetc(f);
372       if (k == '\n' || k < 0)
373         return *buf = 0;
374       *buf++ = k;
375     }
376   return 1;
377 }
378
379 byte *
380 bgets0(struct fastbuf *f, byte *b, uns l)
381 {
382   byte *e = b + l - 1;
383   int k;
384
385   k = bgetc(f);
386   if (k < 0)
387     return NULL;
388   while (b < e)
389     {
390       if (k <= 0)
391         {
392           *b = 0;
393           return b;
394         }
395       *b++ = k;
396       k = bgetc(f);
397     }
398   die("%s: Line too long", f->name);
399 }
400
401 void
402 bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l)
403 {
404   while (l)
405     {
406       byte *fptr, *tptr;
407       uns favail, tavail, n;
408
409       favail = bdirect_read_prepare(f, &fptr);
410       if (!favail)
411         {
412           if (l == ~0U)
413             return;
414           die("bbcopy: source exhausted");
415         }
416       tavail = bdirect_write_prepare(t, &tptr);
417       n = MIN(l, favail);
418       n = MIN(n, tavail);
419       memcpy(tptr, fptr, n);
420       bdirect_read_commit(f, fptr + n);
421       bdirect_write_commit(t, tptr + n);
422       if (l != ~0U)
423         l -= n;
424     }
425 }
426
427 int
428 bconfig(struct fastbuf *f, uns item, int value)
429 {
430   return f->config ? f->config(f, item, value) : -1;
431 }
432
433 void
434 brewind(struct fastbuf *f)
435 {
436   bflush(f);
437   bsetpos(f, 0);
438 }
439
440 int
441 bskip_slow(struct fastbuf *f, uns len)
442 {
443   while (len)
444     {
445       byte *buf;
446       uns l = bdirect_read_prepare(f, &buf);
447       if (!l)
448         return 0;
449       l = MIN(l, len);
450       bdirect_read_commit(f, buf+l);
451       len -= l;
452     }
453   return 1;
454 }
455
456 sh_off_t
457 bfilesize(struct fastbuf *f)
458 {
459   if (!f)
460     return 0;
461   sh_off_t pos = btell(f);
462   bseek(f, 0, SEEK_END);
463   sh_off_t len = btell(f);
464   bsetpos(f, pos);
465   return len;
466 }