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