]> mj.ucw.cz Git - libucw.git/blob - lib/fb-mem.c
Allow SEEK_END. (I plan to rewrite seek in fbmem streams, the current
[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   /* FIXME: Milan's quick hack to allow SEEK_END */
94   if (whence == SEEK_END)
95   {
96           for (b=m->first; b; b=b->next)
97                   p += b->size;
98           pos += p;
99           p=0;
100           whence = SEEK_SET;
101   }
102   /* EOQH */
103   
104   if (whence != SEEK_SET)
105     die("fbmem_seek: only SEEK_SET supported");
106   for (b=m->first; b; b=b->next)
107     {
108       if ((unsigned) pos <= p + b->size) /* <=, because we need to be able to seek just after file end */
109         {
110           f->pos = p;
111           f->buffer = b->data;
112           f->bptr = b->data + (pos - p);
113           f->bufend = f->bstop = b->data + b->size;
114           f->llpos = b;
115           return;
116         }
117       p += b->size;
118     }
119   die("fbmem_seek to invalid offset");
120 }
121
122 static void
123 fbmem_close(struct fastbuf *f)
124 {
125   struct memstream *m = f->lldata;
126   struct msblock *b;
127
128   if (--m->uc)
129     return;
130
131   while (b = m->first)
132     {
133       m->first = b->next;
134       xfree(b);
135     }
136   xfree(m);
137 }
138
139 struct fastbuf *
140 fbmem_create(unsigned blocksize)
141 {
142   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
143   struct memstream *m = xmalloc_zero(sizeof(struct memstream));
144
145   m->blocksize = blocksize;
146   m->uc = 1;
147
148   f->name = "<fbmem-write>";
149   f->lldata = m;
150   f->spout = fbmem_spout;
151   f->close = fbmem_close;
152   return f;
153 }
154
155 struct fastbuf *
156 fbmem_clone_read(struct fastbuf *b)
157 {
158   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
159   struct memstream *s = b->lldata;
160
161   bflush(b);
162   s->uc++;
163
164   f->name = "<fbmem-read>";
165   f->lldata = s;
166   f->refill = fbmem_refill;
167   f->seek = fbmem_seek;
168   f->close = fbmem_close;
169   return f;
170 }
171
172 #ifdef TEST
173
174 int main(void)
175 {
176   struct fastbuf *w, *r;
177   int t;
178
179   w = fbmem_create(7);
180   r = fbmem_clone_read(w);
181   bwrite(w, "12345", 5);
182   bwrite(w, "12345", 5);
183   printf("<%d>", btell(w));
184   bflush(w);
185   printf("<%d>", btell(w));
186   printf("<%d>", btell(r));
187   while ((t = bgetc(r)) >= 0)
188     putchar(t);
189   printf("<%d>", btell(r));
190   bwrite(w, "12345", 5);
191   bwrite(w, "12345", 5);
192   printf("<%d>", btell(w));
193   bclose(w);
194   bsetpos(r, 0);
195   printf("<!%d>", btell(r));
196   while ((t = bgetc(r)) >= 0)
197     putchar(t);
198   bsetpos(r, 3);
199   printf("<!%d>", btell(r));
200   while ((t = bgetc(r)) >= 0)
201     putchar(t);
202   fflush(stdout);
203   bclose(r);
204   return 0;
205 }
206
207 #endif