]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.h
7baa5013b77355546c7b8e5a4db1dc59f4cc7f85
[libucw.git] / lib / fastbuf.h
1 /*
2  *      Sherlock Library -- Fast Buffered I/O
3  *
4  *      (c) 1997--2002 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 #ifndef _SHERLOCK_FASTBUF_H
11 #define _SHERLOCK_FASTBUF_H
12
13 #ifndef EOF
14 #include <stdio.h>
15 #endif
16
17 #include <string.h>
18
19 #include "lib/unaligned.h"
20
21 /*
22  *  Generic buffered I/O. You supply hooks to be called for low-level operations
23  *  (swapping of buffers, seeking and closing), we do the rest.
24  *
25  *  Buffer layout when reading:
26  *
27  *  +----------------+---------------------------+
28  *  | read data      | free space                |
29  *  +----------------+---------------------------+
30  *  ^        ^        ^                           ^
31  *  buffer   bptr     bstop                       bufend
32  *
33  *  After the last character is read, bptr == bstop and buffer refill
34  *  is deferred to the next read attempt. This gives us an easy way
35  *  how to implement bungetc().
36  *
37  *  When writing:
38  *
39  *  +----------------+---------------------------+
40  *  | written data   | free space                |
41  *  +----------------+---------------------------+
42  *  ^                 ^                           ^
43  *  buffer=bstop      bptr                        bufend
44  *
45  *  Dirty tricks:
46  *
47  *    - You can mix reads and writes on the same stream, but you must
48  *      call bflush() in between and remember that the file position
49  *      points after the flushed buffer which is not necessarily the same
50  *      as after the data you've read.
51  *    - The spout/refill hooks can change not only bptr and bstop, but also
52  *      the location of the buffer; fb-mem.c takes advantage of it.
53  */
54
55 struct fastbuf {
56   byte is_fastbuf[0];                   /* Dummy field for checking of type casts */
57   byte *bptr, *bstop;                   /* Access pointers */
58   byte *buffer, *bufend;                /* Start and end of the buffer */
59   byte *name;                           /* File name for error messages */
60   sh_off_t pos;                         /* Position of bstop in the file */
61   int (*refill)(struct fastbuf *);      /* Get a buffer with new data */
62   void (*spout)(struct fastbuf *);      /* Write buffer data to the file */
63   void (*seek)(struct fastbuf *, sh_off_t, int);  /* Slow path for bseek(), buffer already flushed */
64   void (*close)(struct fastbuf *);      /* Close the stream */
65 };
66
67 /* FastIO on standard files */
68
69 struct fb_file {
70   struct fastbuf fb;
71   int fd;                               /* File descriptor, -1 if not a real file */
72   int is_temp_file;                     /* 0=normal file, 1=temporary file, delete on close, -1=shared FD */
73 };
74 #define FB_FILE(f) ((struct fb_file *)(f)->is_fastbuf)
75
76 struct fastbuf *bopen(byte *name, uns mode, uns buffer);
77 struct fastbuf *bopen_tmp(uns buffer);
78 struct fastbuf *bfdopen(int fd, uns buffer);
79 struct fastbuf *bfdopen_shared(int fd, uns buffer);
80 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l);
81 #define FB_IS_TEMP_FILE(f) FB_FILE(f)->is_temp_file
82
83 /* FastIO on in-memory streams */
84
85 struct fastbuf *fbmem_create(unsigned blocksize);       /* Create stream and return its writing fastbuf */
86 struct fastbuf *fbmem_clone_read(struct fastbuf *);     /* Create reading fastbuf */
87
88 /* Universal functions working on all fastbuf's */
89
90 void bclose(struct fastbuf *f);
91 void bflush(struct fastbuf *f);
92 void bseek(struct fastbuf *f, sh_off_t pos, int whence);
93 void bsetpos(struct fastbuf *f, sh_off_t pos);
94
95 static inline sh_off_t btell(struct fastbuf *f)
96 {
97   return f->pos + (f->bptr - f->bstop);
98 }
99
100 int bgetc_slow(struct fastbuf *f);
101 static inline int bgetc(struct fastbuf *f)
102 {
103   return (f->bptr < f->bstop) ? (int) *f->bptr++ : bgetc_slow(f);
104 }
105
106 int bpeekc_slow(struct fastbuf *f);
107 static inline int bpeekc(struct fastbuf *f)
108 {
109   return (f->bptr < f->bstop) ? (int) *f->bptr : bpeekc_slow(f);
110 }
111
112 static inline void bungetc(struct fastbuf *f)
113 {
114   f->bptr--;
115 }
116
117 void bputc_slow(struct fastbuf *f, uns c);
118 static inline void bputc(struct fastbuf *f, uns c)
119 {
120   if (f->bptr < f->bufend)
121     *f->bptr++ = c;
122   else
123     bputc_slow(f, c);
124 }
125
126 int bgetw_slow(struct fastbuf *f);
127 static inline int bgetw(struct fastbuf *f)
128 {
129   int w;
130   if (f->bptr + 2 <= f->bstop)
131     {
132       w = GET_U16(f->bptr);
133       f->bptr += 2;
134       return w;
135     }
136   else
137     return bgetw_slow(f);
138 }
139
140 u32 bgetl_slow(struct fastbuf *f);
141 static inline u32 bgetl(struct fastbuf *f)
142 {
143   u32 l;
144   if (f->bptr + 4 <= f->bstop)
145     {
146       l = GET_U32(f->bptr);
147       f->bptr += 4;
148       return l;
149     }
150   else
151     return bgetl_slow(f);
152 }
153
154 u64 bgetq_slow(struct fastbuf *f);
155 static inline u64 bgetq(struct fastbuf *f)
156 {
157   u64 l;
158   if (f->bptr + 8 <= f->bstop)
159     {
160       l = GET_U64(f->bptr);
161       f->bptr += 8;
162       return l;
163     }
164   else
165     return bgetq_slow(f);
166 }
167
168 u64 bget5_slow(struct fastbuf *f);
169 static inline u64 bget5(struct fastbuf *f)
170 {
171   u64 l;
172   if (f->bptr + 5 <= f->bstop)
173     {
174       l = GET_U40(f->bptr);
175       f->bptr += 5;
176       return l;
177     }
178   else
179     return bget5_slow(f);
180 }
181
182 void bputw_slow(struct fastbuf *f, uns w);
183 static inline void bputw(struct fastbuf *f, uns w)
184 {
185   if (f->bptr + 2 <= f->bufend)
186     {
187       PUT_U16(f->bptr, w);
188       f->bptr += 2;
189     }
190   else
191     bputw_slow(f, w);
192 }
193
194 void bputl_slow(struct fastbuf *f, u32 l);
195 static inline void bputl(struct fastbuf *f, u32 l)
196 {
197   if (f->bptr + 4 <= f->bufend)
198     {
199       PUT_U32(f->bptr, l);
200       f->bptr += 4;
201     }
202   else
203     bputl_slow(f, l);
204 }
205
206 void bputq_slow(struct fastbuf *f, u64 l);
207 static inline void bputq(struct fastbuf *f, u64 l)
208 {
209   if (f->bptr + 8 <= f->bufend)
210     {
211       PUT_U64(f->bptr, l);
212       f->bptr += 8;
213     }
214   else
215     bputq_slow(f, l);
216 }
217
218 void bput5_slow(struct fastbuf *f, u64 l);
219 static inline void bput5(struct fastbuf *f, u64 l)
220 {
221   if (f->bptr + 5 <= f->bufend)
222     {
223       PUT_U40(f->bptr, l);
224       f->bptr += 5;
225     }
226   else
227     bput5_slow(f, l);
228 }
229
230 uns bread_slow(struct fastbuf *f, void *b, uns l, uns check);
231 static inline uns bread(struct fastbuf *f, void *b, uns l)
232 {
233   if (f->bptr + l <= f->bstop)
234     {
235       memcpy(b, f->bptr, l);
236       f->bptr += l;
237       return l;
238     }
239   else
240     return bread_slow(f, b, l, 0);
241 }
242
243 static inline uns breadb(struct fastbuf *f, void *b, uns l)
244 {
245   if (f->bptr + l <= f->bstop)
246     {
247       memcpy(b, f->bptr, l);
248       f->bptr += l;
249       return l;
250     }
251   else
252     return bread_slow(f, b, l, 1);
253 }
254
255 void bwrite_slow(struct fastbuf *f, void *b, uns l);
256 static inline void bwrite(struct fastbuf *f, void *b, uns l)
257 {
258   if (f->bptr + l <= f->bufend)
259     {
260       memcpy(f->bptr, b, l);
261       f->bptr += l;
262     }
263   else
264     bwrite_slow(f, b, l);
265 }
266
267 byte *bgets(struct fastbuf *f, byte *b, uns l); /* Non-std */
268 byte *bgets0(struct fastbuf *f, byte *b, uns l);
269
270 static inline void
271 bputs(struct fastbuf *f, byte *b)
272 {
273   bwrite(f, b, strlen(b));
274 }
275
276 static inline void
277 bputs0(struct fastbuf *f, byte *b)
278 {
279   bwrite(f, b, strlen(b)+1);
280 }
281
282 static inline void
283 bputsn(struct fastbuf *f, byte *b)
284 {
285   bputs(f, b);
286   bputc(f, '\n');
287 }
288
289 /* I/O on addr_int_t */
290
291 #ifdef CPU_64BIT_POINTERS
292 #define bputa(x,p) bputq(x,p)
293 #define bgeta(x) bgetq(x)
294 #else
295 #define bputa(x,p) bputl(x,p)
296 #define bgeta(x) bgetl(x)
297 #endif
298
299 /* Direct I/O on buffers */
300
301 int bdirect_read_prepare(struct fastbuf *f, byte **buf);
302 void bdirect_read_commit(struct fastbuf *f, byte *pos);
303 int bdirect_write_prepare(struct fastbuf *f, byte **buf);
304 void bdirect_write_commit(struct fastbuf *f, byte *pos);
305
306 #endif