]> mj.ucw.cz Git - libucw.git/blob - lib/fb-mem.c
Generate index cards.
[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   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 static 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 static 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 ((unsigned) 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 static 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       xfree(b);
119     }
120   xfree(m);
121 }
122
123 struct fastbuf *
124 fbmem_create(unsigned blocksize)
125 {
126   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
127   struct memstream *m = xmalloc_zero(sizeof(struct memstream));
128
129   m->blocksize = blocksize;
130   m->uc = 1;
131
132   f->name = "<fbmem-write>";
133   f->lldata = m;
134   f->spout = fbmem_spout;
135   f->close = fbmem_close;
136   return f;
137 }
138
139 struct fastbuf *
140 fbmem_clone_read(struct fastbuf *b)
141 {
142   struct fastbuf *f = xmalloc_zero(sizeof(struct fastbuf));
143   struct memstream *s = b->lldata;
144
145   bflush(b);
146   s->uc++;
147
148   f->name = "<fbmem-read>";
149   f->lldata = s;
150   f->refill = fbmem_refill;
151   f->seek = fbmem_seek;
152   f->close = fbmem_close;
153   return f;
154 }
155
156 #ifdef TEST
157
158 int main(void)
159 {
160   struct fastbuf *w, *r;
161   int t;
162
163   w = fbmem_create(7);
164   r = fbmem_clone_read(w);
165   bwrite(w, "12345", 5);
166   bwrite(w, "12345", 5);
167   printf("<%d>", btell(w));
168   bflush(w);
169   printf("<%d>", btell(w));
170   printf("<%d>", btell(r));
171   while ((t = bgetc(r)) >= 0)
172     putchar(t);
173   printf("<%d>", btell(r));
174   bwrite(w, "12345", 5);
175   bwrite(w, "12345", 5);
176   printf("<%d>", btell(w));
177   bclose(w);
178   bsetpos(r, 0);
179   printf("<!%d>", btell(r));
180   while ((t = bgetc(r)) >= 0)
181     putchar(t);
182   bsetpos(r, 3);
183   printf("<!%d>", btell(r));
184   while ((t = bgetc(r)) >= 0)
185     putchar(t);
186   fflush(stdout);
187   bclose(r);
188   return 0;
189 }
190
191 #endif