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