]> mj.ucw.cz Git - libucw.git/blob - lib/fb-grow.c
Fastbufs now work better on unseekable files.
[libucw.git] / lib / fb-grow.c
1 /*
2  *      UCW Library -- Fast Buffered I/O on Growing Buffers
3  *
4  *      (c) 2006 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
13 #include <stdlib.h>
14
15 struct fb_gbuf {
16   struct fastbuf fb;
17   byte *last_written;
18 };
19 #define FB_GBUF(f) ((struct fb_gbuf *)(f)->is_fastbuf)
20
21 static int
22 fbgrow_refill(struct fastbuf *b)
23 {
24   if (b->bstop != FB_GBUF(b)->last_written)
25     {
26       /* There was an intervening flush */
27       b->bstop = FB_GBUF(b)->last_written;
28       b->pos = b->bstop - b->buffer;
29       return 1;
30     }
31   /* We are at the end */
32   return 0;
33 }
34
35 static void
36 fbgrow_spout(struct fastbuf *b)
37 {
38   if (b->bptr >= b->bufend)
39     {
40       uns len = b->bufend - b->buffer;
41       b->buffer = xrealloc(b->buffer, 2*len);
42       b->bufend = b->buffer + 2*len;
43       b->bstop = b->buffer;
44       b->bptr = b->buffer + len;
45     }
46 }
47
48 static int
49 fbgrow_seek(struct fastbuf *b, sh_off_t pos, int whence)
50 {
51   ASSERT(FB_GBUF(b)->last_written);     /* Seeks allowed only in read mode */
52   sh_off_t len = FB_GBUF(b)->last_written - b->buffer;
53   if (whence == SEEK_END)
54     pos += len;
55   ASSERT(pos >= 0 && pos <= len);
56   b->bptr = b->buffer + pos;
57   b->bstop = FB_GBUF(b)->last_written;
58   b->pos = len;
59   return 1;
60 }
61
62 static void
63 fbgrow_close(struct fastbuf *b)
64 {
65   xfree(b->buffer);
66   xfree(b);
67 }
68
69 struct fastbuf *
70 fbgrow_create(unsigned basic_size)
71 {
72   struct fastbuf *b = xmalloc_zero(sizeof(struct fb_gbuf));
73   b->buffer = xmalloc(basic_size);
74   b->bufend = b->buffer + basic_size;
75   b->bptr = b->bstop = b->buffer;
76   b->name = "<fbgbuf>";
77   b->refill = fbgrow_refill;
78   b->spout = fbgrow_spout;
79   b->seek = fbgrow_seek;
80   b->close = fbgrow_close;
81   b->can_overwrite_buffer = 1;
82   return b;
83 }
84
85 void
86 fbgrow_reset(struct fastbuf *b)
87 {
88   b->bptr = b->bstop = b->buffer;
89   b->pos = 0;
90   FB_GBUF(b)->last_written = NULL;
91 }
92
93 void
94 fbgrow_rewind(struct fastbuf *b)
95 {
96   if (!FB_GBUF(b)->last_written)
97     {
98       /* Last operation was a write, so remember the end position */
99       FB_GBUF(b)->last_written = b->bptr;
100     }
101   b->bptr = b->buffer;
102   b->bstop = FB_GBUF(b)->last_written;
103   b->pos = b->bstop - b->buffer;
104 }
105
106 #ifdef TEST
107
108 int main(void)
109 {
110   struct fastbuf *f;
111   int t;
112
113   f = fbgrow_create(3);
114   for (uns i=0; i<5; i++)
115     {
116       fbgrow_write(f);
117       bwrite(f, "12345", 5);
118       bwrite(f, "12345", 5);
119       printf("<%d>", (int)btell(f));
120       bflush(f);
121       printf("<%d>", (int)btell(f));
122       fbgrow_rewind(f);
123       printf("<%d>", (int)btell(f));
124       while ((t = bgetc(f)) >= 0)
125         putchar(t);
126       printf("<%d>", (int)btell(f));
127       fbgrow_rewind(f);
128       bseek(f, -1, SEEK_END);
129       printf("<%d>", (int)btell(f));
130       while ((t = bgetc(f)) >= 0)
131         putchar(t);
132       printf("<%d>\n", (int)btell(f));
133     }
134   bclose(f);
135   return 0;
136 }
137
138 #endif