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