]> mj.ucw.cz Git - libucw.git/blob - lib/fb-mem.c
07e4efbcf640e1465414334b30867b4bfe60ffad
[libucw.git] / lib / fb-mem.c
1 /*
2  *      Sherlock Library -- Fast Buffered I/O on Memory Streams
3  *
4  *      (c) 1997--2000 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 <stdio.h>
14 #include <stdlib.h>
15
16 struct memstream {
17   unsigned blocksize;
18   unsigned uc;
19   struct msblock *first;
20 };
21
22 struct msblock {
23   struct msblock *next;
24   unsigned size;
25   byte data[0];
26 };
27
28 static int
29 fbmem_refill(struct fastbuf *f)
30 {
31   struct memstream *s = f->lldata;
32   struct msblock *b = f->llpos;
33
34   if (!b)
35     {
36       b = s->first;
37       if (!b)
38         return 0;
39     }
40   else if (f->buffer == b->data && f->bstop < b->data + b->size)
41     {
42       f->bstop = b->data + b->size;
43       return 1;
44     }
45   else
46     {
47       if (!b->next)
48         return 0;
49       f->pos += b->size;
50       b = b->next;
51     }
52   if (!b->size)
53     return 0;
54   f->buffer = f->bptr = b->data;
55   f->bufend = f->bstop = b->data + b->size;
56   f->llpos = b;
57   return 1;
58 }
59
60 static void
61 fbmem_spout(struct fastbuf *f)
62 {
63   struct memstream *s = f->lldata;
64   struct msblock *b = f->llpos;
65   struct msblock *bb;
66
67   if (b)
68     {
69       b->size = f->bptr - b->data;
70       if (b->size < s->blocksize)
71         return;
72       f->pos += b->size;
73     }
74   bb = xmalloc(sizeof(struct msblock) + s->blocksize);
75   if (b)
76     b->next = bb;
77   else
78     s->first = bb;
79   bb->next = NULL;
80   bb->size = 0;
81   f->buffer = f->bptr = f->bstop = bb->data;
82   f->bufend = bb->data + s->blocksize;
83   f->llpos = bb;
84 }
85
86 static void
87 fbmem_seek(struct fastbuf *f, sh_off_t pos, int whence)
88 {
89   struct memstream *m = f->lldata;
90   struct msblock *b;
91   unsigned int p = 0;
92
93   if (whence != SEEK_SET)
94     die("fbmem_seek: only SEEK_SET supported");
95   for (b=m->first; b; b=b->next)
96     {
97       if ((unsigned) pos <= p + b->size) /* <=, because we need to be able to seek just after file end */
98         {
99           f->pos = p;
100           f->buffer = b->data;
101           f->bptr = b->data + (pos - p);
102           f->bufend = f->bstop = b->data + b->size;
103           f->llpos = b;
104           return;
105         }
106       p += b->size;
107     }
108   die("fbmem_seek to invalid offset");
109 }
110
111 static void
112 fbmem_close(struct fastbuf *f)
113 {
114   struct memstream *m = f->lldata;
115   struct msblock *b;
116
117   if (--m->uc)
118     return;
119
120   while (b = m->first)
121     {
122       m->first = b->next;
123       xfree(b);
124     }
125   xfree(m);
126 }
127
128 struct fastbuf *
129 fbmem_create(unsigned blocksize)
130 {
131   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
132   struct memstream *m = xmalloc_zero(sizeof(struct memstream));
133
134   m->blocksize = blocksize;
135   m->uc = 1;
136
137   f->name = "<fbmem-write>";
138   f->lldata = m;
139   f->spout = fbmem_spout;
140   f->close = fbmem_close;
141   return f;
142 }
143
144 struct fastbuf *
145 fbmem_clone_read(struct fastbuf *b)
146 {
147   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
148   struct memstream *s = b->lldata;
149
150   bflush(b);
151   s->uc++;
152
153   f->name = "<fbmem-read>";
154   f->lldata = s;
155   f->refill = fbmem_refill;
156   f->seek = fbmem_seek;
157   f->close = fbmem_close;
158   return f;
159 }
160
161 #ifdef TEST
162
163 int main(void)
164 {
165   struct fastbuf *w, *r;
166   int t;
167
168   w = fbmem_create(7);
169   r = fbmem_clone_read(w);
170   bwrite(w, "12345", 5);
171   bwrite(w, "12345", 5);
172   printf("<%d>", btell(w));
173   bflush(w);
174   printf("<%d>", btell(w));
175   printf("<%d>", btell(r));
176   while ((t = bgetc(r)) >= 0)
177     putchar(t);
178   printf("<%d>", btell(r));
179   bwrite(w, "12345", 5);
180   bwrite(w, "12345", 5);
181   printf("<%d>", btell(w));
182   bclose(w);
183   bsetpos(r, 0);
184   printf("<!%d>", btell(r));
185   while ((t = bgetc(r)) >= 0)
186     putchar(t);
187   bsetpos(r, 3);
188   printf("<!%d>", btell(r));
189   while ((t = bgetc(r)) >= 0)
190     putchar(t);
191   fflush(stdout);
192   bclose(r);
193   return 0;
194 }
195
196 #endif