]> mj.ucw.cz Git - libucw.git/blob - ucw/fastbuf.c
de38b277353b8a0e95369b4902136ec209fc9b2c
[libucw.git] / ucw / fastbuf.c
1 /*
2  *      UCW Library -- Fast Buffered I/O
3  *
4  *      (c) 1997--2007 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 "ucw/lib.h"
11 #include "ucw/fastbuf.h"
12 #include "ucw/respool.h"
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 void bclose(struct fastbuf *f)
18 {
19   if (f)
20     {
21       bflush(f);
22       if (f->close)
23         f->close(f);
24       if (f->res)
25         res_drop(f->res);
26     }
27 }
28
29 void bflush(struct fastbuf *f)
30 {
31   if (f->bptr > f->bstop)
32     f->spout(f);
33   else if (f->bstop > f->buffer)
34     f->bptr = f->bstop = f->buffer;
35 }
36
37 inline void bsetpos(struct fastbuf *f, ucw_off_t pos)
38 {
39   /* We can optimize seeks only when reading */
40   if (pos >= f->pos - (f->bstop - f->buffer) && pos <= f->pos)
41     f->bptr = f->bstop + (pos - f->pos);
42   else
43     {
44       bflush(f);
45       if (!f->seek || !f->seek(f, pos, SEEK_SET))
46         die("bsetpos: stream not seekable");
47     }
48 }
49
50 void bseek(struct fastbuf *f, ucw_off_t pos, int whence)
51 {
52   switch (whence)
53     {
54     case SEEK_SET:
55       return bsetpos(f, pos);
56     case SEEK_CUR:
57       return bsetpos(f, btell(f) + pos);
58     case SEEK_END:
59       bflush(f);
60       if (!f->seek || !f->seek(f, pos, SEEK_END))
61         die("bseek: stream not seekable");
62       break;
63     default:
64       die("bseek: invalid whence=%d", whence);
65     }
66 }
67
68 int bgetc_slow(struct fastbuf *f)
69 {
70   if (f->bptr < f->bstop)
71     return *f->bptr++;
72   if (!f->refill(f))
73     return -1;
74   return *f->bptr++;
75 }
76
77 int bpeekc_slow(struct fastbuf *f)
78 {
79   if (f->bptr < f->bstop)
80     return *f->bptr;
81   if (!f->refill(f))
82     return -1;
83   return *f->bptr;
84 }
85
86 void bputc_slow(struct fastbuf *f, uns c)
87 {
88   if (f->bptr >= f->bufend)
89     f->spout(f);
90   *f->bptr++ = c;
91 }
92
93 uns bread_slow(struct fastbuf *f, void *b, uns l, uns check)
94 {
95   uns total = 0;
96   while (l)
97     {
98       uns k = f->bstop - f->bptr;
99
100       if (!k)
101         {
102           f->refill(f);
103           k = f->bstop - f->bptr;
104           if (!k)
105             break;
106         }
107       if (k > l)
108         k = l;
109       memcpy(b, f->bptr, k);
110       f->bptr += k;
111       b = (byte *)b + k;
112       l -= k;
113       total += k;
114     }
115   if (check && total && l)
116     die("breadb: short read");
117   return total;
118 }
119
120 void bwrite_slow(struct fastbuf *f, const void *b, uns l)
121 {
122   while (l)
123     {
124       uns k = f->bufend - f->bptr;
125
126       if (!k)
127         {
128           f->spout(f);
129           k = f->bufend - f->bptr;
130         }
131       if (k > l)
132         k = l;
133       memcpy(f->bptr, b, k);
134       f->bptr += k;
135       b = (byte *)b + k;
136       l -= k;
137     }
138 }
139
140 void
141 bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l)
142 {
143   while (l)
144     {
145       byte *fptr, *tptr;
146       uns favail, tavail, n;
147
148       favail = bdirect_read_prepare(f, &fptr);
149       if (!favail)
150         {
151           if (l == ~0U)
152             return;
153           die("bbcopy: source exhausted");
154         }
155       tavail = bdirect_write_prepare(t, &tptr);
156       n = MIN(l, favail);
157       n = MIN(n, tavail);
158       memcpy(tptr, fptr, n);
159       bdirect_read_commit(f, fptr + n);
160       bdirect_write_commit(t, tptr + n);
161       if (l != ~0U)
162         l -= n;
163     }
164 }
165
166 int
167 bconfig(struct fastbuf *f, uns item, int value)
168 {
169   return f->config ? f->config(f, item, value) : -1;
170 }
171
172 void
173 brewind(struct fastbuf *f)
174 {
175   bflush(f);
176   bsetpos(f, 0);
177 }
178
179 int
180 bskip_slow(struct fastbuf *f, uns len)
181 {
182   while (len)
183     {
184       byte *buf;
185       uns l = bdirect_read_prepare(f, &buf);
186       if (!l)
187         return 0;
188       l = MIN(l, len);
189       bdirect_read_commit(f, buf+l);
190       len -= l;
191     }
192   return 1;
193 }
194
195 ucw_off_t
196 bfilesize(struct fastbuf *f)
197 {
198   if (!f)
199     return 0;
200   ucw_off_t pos = btell(f);
201   bflush(f);
202   if (!f->seek(f, 0, SEEK_END))
203     return -1;
204   ucw_off_t len = btell(f);
205   bsetpos(f, pos);
206   return len;
207 }
208
209 /* Resources */
210
211 static void
212 fb_res_detach(struct resource *r)
213 {
214   struct fastbuf *f = r->priv;
215   f->res = NULL;
216 }
217
218 static void
219 fb_res_free(struct resource *r)
220 {
221   struct fastbuf *f = r->priv;
222   f->res = NULL;
223   bclose(f);
224 }
225
226 static void
227 fb_res_dump(struct resource *r)
228 {
229   struct fastbuf *f = r->priv;
230   printf(" name=%s", f->name);
231 }
232
233 static const struct res_class fb_res_class = {
234   .name = "fastbuf",
235   .detach = fb_res_detach,
236   .dump = fb_res_dump,
237   .free = fb_res_free,
238 };
239
240 void
241 fb_tie(struct fastbuf *f)
242 {
243   f->res = res_new(&fb_res_class, f);
244 }