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