]> mj.ucw.cz Git - libucw.git/blob - lib/fb-grow.c
bugfixes
[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 void
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 }
60
61 static void
62 fbgrow_close(struct fastbuf *b)
63 {
64   xfree(b->buffer);
65   xfree(b);
66 }
67
68 struct fastbuf *
69 fbgrow_create(unsigned basic_size)
70 {
71   struct fastbuf *b = xmalloc_zero(sizeof(struct fb_gbuf));
72   b->buffer = xmalloc(basic_size);
73   b->bufend = b->buffer + basic_size;
74   b->bptr = b->bstop = b->buffer;
75   b->name = "<fbgbuf>";
76   b->refill = fbgrow_refill;
77   b->spout = fbgrow_spout;
78   b->seek = fbgrow_seek;
79   b->close = fbgrow_close;
80   b->can_overwrite_buffer = 1;
81   return b;
82 }
83
84 void
85 fbgrow_reset(struct fastbuf *b)
86 {
87   b->bptr = b->bstop = b->buffer;
88   b->pos = 0;
89   FB_GBUF(b)->last_written = NULL;
90 }
91
92 void
93 fbgrow_rewind(struct fastbuf *b)
94 {
95   if (!FB_GBUF(b)->last_written)
96     {
97       /* Last operation was a write, so remember the end position */
98       FB_GBUF(b)->last_written = b->bptr;
99     }
100   b->bptr = b->buffer;
101   b->bstop = FB_GBUF(b)->last_written;
102   b->pos = b->bstop - b->buffer;
103 }
104
105 #ifdef TEST
106
107 int main(void)
108 {
109   struct fastbuf *f;
110   int t;
111
112   f = fbgrow_create(3);
113   for (uns i=0; i<5; i++)
114     {
115       fbgrow_write(f);
116       bwrite(f, "12345", 5);
117       bwrite(f, "12345", 5);
118       printf("<%d>", (int)btell(f));
119       bflush(f);
120       printf("<%d>", (int)btell(f));
121       fbgrow_rewind(f);
122       printf("<%d>", (int)btell(f));
123       while ((t = bgetc(f)) >= 0)
124         putchar(t);
125       printf("<%d>", (int)btell(f));
126       fbgrow_rewind(f);
127       bseek(f, -1, SEEK_END);
128       printf("<%d>", (int)btell(f));
129       while ((t = bgetc(f)) >= 0)
130         putchar(t);
131       printf("<%d>\n", (int)btell(f));
132     }
133   bclose(f);
134   return 0;
135 }
136
137 #endif