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