]> mj.ucw.cz Git - eval.git/blob - lib/fb-grow.c
Handle exit code translation failures gracefully.
[eval.git] / lib / fb-grow.c
1 /*
2  *      UCW Library -- Fast Buffered I/O on Growing Buffers
3  *
4  *      (c) 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 <stdio.h>
14 #include <stdlib.h>
15
16 struct fb_gbuf {
17   struct fastbuf fb;
18   byte *last_written;
19 };
20 #define FB_GBUF(f) ((struct fb_gbuf *)(f)->is_fastbuf)
21
22 static int
23 fbgrow_refill(struct fastbuf *b)
24 {
25   if (b->bstop != FB_GBUF(b)->last_written)
26     {
27       /* There was an intervening flush */
28       b->bstop = FB_GBUF(b)->last_written;
29       b->pos = b->bstop - b->buffer;
30       return 1;
31     }
32   /* We are at the end */
33   return 0;
34 }
35
36 static void
37 fbgrow_spout(struct fastbuf *b)
38 {
39   if (b->bptr >= b->bufend)
40     {
41       uns len = b->bufend - b->buffer;
42       b->buffer = xrealloc(b->buffer, 2*len);
43       b->bufend = b->buffer + 2*len;
44       b->bstop = b->buffer;
45       b->bptr = b->buffer + len;
46     }
47 }
48
49 static int
50 fbgrow_seek(struct fastbuf *b, sh_off_t pos, int whence)
51 {
52   ASSERT(FB_GBUF(b)->last_written);     /* Seeks allowed only in read mode */
53   sh_off_t len = FB_GBUF(b)->last_written - b->buffer;
54   if (whence == SEEK_END)
55     pos += len;
56   ASSERT(pos >= 0 && pos <= len);
57   b->bptr = b->buffer + pos;
58   b->bstop = FB_GBUF(b)->last_written;
59   b->pos = len;
60   return 1;
61 }
62
63 static void
64 fbgrow_close(struct fastbuf *b)
65 {
66   xfree(b->buffer);
67   xfree(b);
68 }
69
70 struct fastbuf *
71 fbgrow_create(unsigned basic_size)
72 {
73   struct fastbuf *b = xmalloc_zero(sizeof(struct fb_gbuf));
74   b->buffer = xmalloc(basic_size);
75   b->bufend = b->buffer + basic_size;
76   b->bptr = b->bstop = b->buffer;
77   b->name = "<fbgbuf>";
78   b->refill = fbgrow_refill;
79   b->spout = fbgrow_spout;
80   b->seek = fbgrow_seek;
81   b->close = fbgrow_close;
82   b->can_overwrite_buffer = 1;
83   return b;
84 }
85
86 void
87 fbgrow_reset(struct fastbuf *b)
88 {
89   b->bptr = b->bstop = b->buffer;
90   b->pos = 0;
91   FB_GBUF(b)->last_written = NULL;
92 }
93
94 void
95 fbgrow_rewind(struct fastbuf *b)
96 {
97   if (!FB_GBUF(b)->last_written)
98     {
99       /* Last operation was a write, so remember the end position */
100       FB_GBUF(b)->last_written = b->bptr;
101     }
102   b->bptr = b->buffer;
103   b->bstop = FB_GBUF(b)->last_written;
104   b->pos = b->bstop - b->buffer;
105 }
106
107 #ifdef TEST
108
109 int main(void)
110 {
111   struct fastbuf *f;
112   uns t;
113
114   f = fbgrow_create(3);
115   for (uns i=0; i<5; i++)
116     {
117       fbgrow_reset(f);
118       bwrite(f, "12345", 5);
119       bwrite(f, "12345", 5);
120       printf("<%d>", (int)btell(f));
121       bflush(f);
122       printf("<%d>", (int)btell(f));
123       fbgrow_rewind(f);
124       printf("<%d>", (int)btell(f));
125       while ((t = bgetc(f)) != ~0U)
126         putchar(t);
127       printf("<%d>", (int)btell(f));
128       fbgrow_rewind(f);
129       bseek(f, -1, SEEK_END);
130       printf("<%d>", (int)btell(f));
131       while ((t = bgetc(f)) != ~0U)
132         putchar(t);
133       printf("<%d>\n", (int)btell(f));
134     }
135   bclose(f);
136   return 0;
137 }
138
139 #endif