]> mj.ucw.cz Git - libucw.git/blob - lib/fastbuf.c
e5f1a873ae4a3d36436a1c6f555bb39a2da0f528
[libucw.git] / lib / fastbuf.c
1 /*
2  *      Sherlock Library -- Fast File Buffering
3  *
4  *      (c) 1997 Martin Mares, <mj@atrey.karlin.mff.cuni.cz>
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <fcntl.h>
11 #include <unistd.h>
12
13 #include "lib.h"
14 #include "fastbuf.h"
15
16 struct fastbuf *__bfdopen(int fd, uns buffer, byte *name)
17 {
18   struct fastbuf *b = xmalloc(sizeof(struct fastbuf));
19
20   b->buflen = buffer;
21   b->buffer = xmalloc(buffer);
22   b->bptr = b->bstop = b->buffer;
23   b->bufend = b->buffer + buffer;
24   b->name = stralloc(name);
25   b->pos = b->fdpos = 0;
26   b->fd = fd;
27   return b;
28 }
29
30 struct fastbuf *
31 bopen(byte *name, uns mode, uns buffer)
32 {
33   int fd = open(name, mode, 0666);
34
35   if (fd < 0)
36     die("Unable to %s file %s: %m",
37         (mode & O_CREAT) ? "create" : "open", name);
38   return __bfdopen(fd, buffer, name);
39 }
40
41 struct fastbuf *
42 bfdopen(int fd, uns buffer)
43 {
44   byte x[32];
45
46   sprintf(x, "fd%d", fd);
47   return __bfdopen(fd, buffer, x);
48 }
49
50 void bclose(struct fastbuf *f)
51 {
52   bflush(f);
53   close(f->fd);
54   free(f->name);
55   free(f->buffer);
56   free(f);
57 }
58
59 static int
60 rdbuf(struct fastbuf *f)
61 {
62   int l = read(f->fd, f->buffer, f->buflen);
63
64   if (l < 0)
65     die("Error reading %s: %m", f->name);
66   f->bptr = f->buffer;
67   f->bstop = f->buffer + l;
68   f->pos = f->fdpos;
69   f->fdpos += l;
70   return l;
71 }
72
73 static void
74 wrbuf(struct fastbuf *f)
75 {
76   int l = f->bptr - f->buffer;
77
78   if (l)
79     {
80       if (write(f->fd, f->buffer, l) != l)
81         die("Error writing %s: %m", f->name);
82       f->bptr = f->buffer;
83       f->fdpos += l;
84       f->pos = f->fdpos;
85     }
86 }
87
88 void bflush(struct fastbuf *f)
89 {
90   if (f->bptr != f->buffer)
91     {                                   /* Have something to flush */
92       if (f->bstop > f->buffer)         /* Read data? */
93         {
94           f->bptr = f->bstop = f->buffer;
95           f->pos = f->fdpos;
96         }
97       else                              /* Write data... */
98         wrbuf(f);
99     }
100 }
101
102 inline void bsetpos(struct fastbuf *f, uns pos)
103 {
104   if (pos >= f->pos && (pos <= f->pos + (f->bptr - f->buffer) || pos <= f->pos + (f->bstop - f->buffer)))
105     f->bptr = f->buffer + (pos - f->pos);
106   else
107     {
108       bflush(f);
109       if (f->fdpos != pos && lseek(f->fd, pos, SEEK_SET) < 0)
110         die("lseek on %s: %m", f->name);
111       f->fdpos = f->pos = pos;
112     }
113 }
114
115 void bseek(struct fastbuf *f, uns pos, int whence)
116 {
117   int l;
118
119   switch (whence)
120     {
121     case SEEK_SET:
122       return bsetpos(f, pos);
123     case SEEK_CUR:
124       return bsetpos(f, btell(f) + pos);
125     case SEEK_END:
126       bflush(f);
127       l = lseek(f->fd, pos, whence);
128       if (l < 0)
129         die("lseek on %s: %m", f->name);
130       f->fdpos = f->pos = l;
131       break;
132     default:
133       die("bseek: invalid whence=%d", whence);
134     }
135 }
136
137 int bgetc_slow(struct fastbuf *f)
138 {
139   if (f->bptr < f->bstop)
140     return *f->bptr++;
141   if (!rdbuf(f))
142     return EOF;
143   return *f->bptr++;
144 }
145
146 int bpeekc_slow(struct fastbuf *f)
147 {
148   if (f->bptr < f->bstop)
149     return *f->bptr;
150   if (!rdbuf(f))
151     return EOF;
152   return *f->bptr;
153 }
154
155 void bputc_slow(struct fastbuf *f, byte c)
156 {
157   if (f->bptr >= f->bufend)
158     wrbuf(f);
159   *f->bptr++ = c;
160 }
161
162 word bgetw_slow(struct fastbuf *f)
163 {
164   word w = bgetc_slow(f);
165 #ifdef CPU_BIG_ENDIAN
166   return (w << 8) | bgetc_slow(f);
167 #else
168   return w | (bgetc_slow(f) << 8);
169 #endif
170 }
171
172 ulg bgetl_slow(struct fastbuf *f)
173 {
174   ulg l = bgetc_slow(f);
175 #ifdef CPU_BIG_ENDIAN
176   l = (l << 8) | bgetc_slow(f);
177   l = (l << 8) | bgetc_slow(f);
178   return (l << 8) | bgetc_slow(f);
179 #else
180   l = (bgetc_slow(f) << 8) | l;
181   l = (bgetc_slow(f) << 16) | l;
182   return (bgetc_slow(f) << 24) | l;
183 #endif
184 }
185
186 void bputw_slow(struct fastbuf *f, word w)
187 {
188 #ifdef CPU_BIG_ENDIAN
189   bputc_slow(f, w >> 8);
190   bputc_slow(f, w);
191 #else
192   bputc_slow(f, w);
193   bputc_slow(f, w >> 8);
194 #endif
195 }
196
197 void bputl_slow(struct fastbuf *f, ulg l)
198 {
199 #ifdef CPU_BIG_ENDIAN
200   bputc_slow(f, l >> 24);
201   bputc_slow(f, l >> 16);
202   bputc_slow(f, l >> 8);
203   bputc_slow(f, l);
204 #else
205   bputc_slow(f, l);
206   bputc_slow(f, l >> 8);
207   bputc_slow(f, l >> 16);
208   bputc_slow(f, l >> 24);
209 #endif
210 }
211
212 void bread_slow(struct fastbuf *f, void *b, uns l)
213 {
214   while (l)
215     {
216       uns k = f->bstop - f->bptr;
217
218       if (!k)
219         {
220           rdbuf(f);
221           k = f->bstop - f->bptr;
222           if (!k)
223             die("bread on %s: file exhausted", f->name);
224         }
225       if (k > l)
226         k = l;
227       memcpy(b, f->bptr, k);
228       f->bptr += k;
229       b = (byte *)b + k;
230       l -= k;
231     }
232 }
233
234 void bwrite_slow(struct fastbuf *f, void *b, uns l)
235 {
236   while (l)
237     {
238       uns k = f->bufend - f->bptr;
239
240       if (!k)
241         {
242           wrbuf(f);
243           k = f->bufend - f->bptr;
244         }
245       if (k > l)
246         k = l;
247       memcpy(f->bptr, b, k);
248       f->bptr += k;
249       b = (byte *)b + k;
250       l -= k;
251     }
252 }
253
254 byte *                                  /* Non-standard */
255 bgets(struct fastbuf *f, byte *b, uns l)
256 {
257   byte *e = b + l - 1;
258   int k;
259
260   k = bgetc(f);
261   if (k == EOF)
262     return NULL;
263   while (b < e)
264     {
265       if (k == '\n' || k == EOF)
266         {
267           *b = 0;
268           return b;
269         }
270       *b++ = k;
271       k = bgetc(f);
272     }
273   die("%s: Line too long", f->name);
274 }
275
276 void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l)
277 {
278   uns rf = f->bstop - f->bptr;
279   uns rt = t->bufend - t->bptr;
280
281   if (!l)
282     return;
283   if (rf && rt)
284     {
285       uns k = l;
286       if (k > rf)
287         k = rf;
288       if (k > rt)
289         k = rt;
290       memcpy(t->bptr, f->bptr, k);
291       t->bptr += k;
292       f->bptr += k;
293       l -= k;
294     }
295   while (l >= t->buflen)
296     {
297       wrbuf(t);
298       if ((uns) read(f->fd, t->buffer, t->buflen) != t->buflen)
299         die("bbcopy: %s exhausted", f->name);
300       f->fdpos += t->buflen;
301       t->bptr = t->bufend;
302       l -= t->buflen;
303     }
304   while (l)
305     {
306       uns k = t->bufend - t->bptr;
307
308       if (!k)
309         {
310           wrbuf(t);
311           k = t->bufend - t->bptr;
312         }
313       if (k > l)
314         k = l;
315       bread(f, t->bptr, k);
316       t->bptr += k;
317       l -= k;
318     }
319 }
320
321 #ifdef TEST
322
323 int main(int argc, char **argv)
324 {
325   struct fastbuf *f, *t;
326   int c;
327
328   f = bopen("/etc/profile", O_RDONLY, 16);
329   t = bfdopen(1, 13);
330   bbcopy(f, t, 100);
331   bclose(f);
332   bclose(t);
333 }
334
335 #endif