struct fb_multi {
struct fastbuf fb;
- struct mempool* mp;
- struct subbuf* cur;
+ struct mempool *mp;
+ struct subbuf *cur;
ucw_off_t len;
- clist* subbufs;
+ clist subbufs;
};
+
#define FB_MULTI(f) ((struct fb_multi *)(f))
struct subbuf {
cnode n;
- ucw_off_t begin, end;
- int allow_close;
- struct fastbuf* fb;
+ ucw_off_t begin, end, offset;
+ struct fastbuf *fb;
};
static void
-fbmulti_subbuf_get_end(struct subbuf *s)
+fbmulti_get_ptrs(struct fastbuf *f)
+{
+ struct subbuf *sb = FB_MULTI(f)->cur;
+ struct fastbuf *ff = sb->fb;
+
+ f->buffer = ff->buffer;
+ f->bptr = ff->bptr;
+ f->bstop = ff->bstop;
+ f->bufend = ff->bufend;
+ f->pos = sb->begin + (ff->pos - sb->offset);
+}
+
+static void
+fbmulti_set_ptrs(struct fastbuf *f)
{
- if (s->fb->seek) {
- bseek(s->fb, 0, SEEK_END);
- s->end = s->begin + btell(s->fb);
- }
+ FB_MULTI(f)->cur->fb->bptr = f->bptr;
}
static int
fbmulti_subbuf_next(struct fastbuf *f)
{
- struct subbuf* next = clist_next(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
- if (next == NULL)
+ struct subbuf *cur = FB_MULTI(f)->cur;
+ struct subbuf *next = clist_next(&FB_MULTI(f)->subbufs, &cur->n);
+ if (!next)
return 0;
-
- if (f->seek) {
- bsetpos(next->fb, 0);
- next->begin = FB_MULTI(f)->cur->end;
- }
+ // Get the end of current buf if not known yet
+ if (!f->seek && !next->begin)
+ next->begin = cur->end = f->pos;
+
+ // Set the beginning of the next buf
+ if (next->fb->seek)
+ {
+ bsetpos(next->fb, 0);
+ next->offset = 0;
+ }
+ else
+ {
+ ASSERT(!f->seek);
+ next->offset = btell(next->fb);
+ }
+
+ // Set the pointers
FB_MULTI(f)->cur = next;
+ fbmulti_get_ptrs(f);
+
+ return 1;
+}
+
+static int
+fbmulti_subbuf_prev(struct fastbuf *f)
+{
+ // Called only when seeking, assuming everything seekable
+ struct subbuf *prev = clist_prev(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
+ ASSERT(prev);
+
+ // Set pos to beginning, flush offset
+ bsetpos(prev->fb, 0);
+ prev->offset = 0;
+
+ // Set the pointers
+ FB_MULTI(f)->cur = prev;
+ fbmulti_get_ptrs(f);
+
return 1;
}
static int
fbmulti_refill(struct fastbuf *f)
{
- if (f->bufend == f->bstop)
- f->bptr = f->bstop = f->buffer;
- uns len = bread(FB_MULTI(f)->cur->fb, f->bstop, (f->bufend - f->bstop));
- f->bstop += len;
- f->pos += len;
+ fbmulti_set_ptrs(f);
+
+ // Refill the subbuf
+ uns len = FB_MULTI(f)->cur->fb->refill(FB_MULTI(f)->cur->fb);
if (len)
- return len;
+ {
+ fbmulti_get_ptrs(f);
+ return len;
+ }
// Current buf returned EOF
- // Update the information on end of this buffer
- fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
-
- // Take the next one if exists
+ // Take the next one if exists and redo
if (fbmulti_subbuf_next(f))
return fbmulti_refill(f);
else
return 0;
}
-static void
-fbmulti_get_len(struct fastbuf *f)
-{
- ASSERT(f->seek);
- FB_MULTI(f)->len = 0;
-
- CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
- {
- n->begin = FB_MULTI(f)->len;
- fbmulti_subbuf_get_end(n);
- FB_MULTI(f)->len = n->end;
- }
-}
-
static int
fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
{
+ fbmulti_set_ptrs(f);
switch(whence)
{
case SEEK_SET:
- if (f->pos > pos) {
- FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
- FB_MULTI(f)->cur->begin = 0;
- f->pos = 0;
- return fbmulti_seek(f, pos, SEEK_SET);
- }
-
- do {
- fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
- if (pos < FB_MULTI(f)->cur->end)
- break;
+ if (pos > FB_MULTI(f)->len)
+ bthrow(f, "seek", "Seek out of range");
+
+ while (pos > FB_MULTI(f)->cur->end) // Moving forward
+ {
+ int r = fbmulti_subbuf_next(f);
+ ASSERT(r);
+ }
- if (!fbmulti_subbuf_next(f)) {
- if (pos == FB_MULTI(f)->cur->end)
- break;
- else
- bthrow(f, "seek", "Seek out of range");
+ while (pos < FB_MULTI(f)->cur->begin) // Moving backwards
+ {
+ int r = fbmulti_subbuf_prev(f);
+ ASSERT(r);
}
- } while (1);
+ // Now cur is the right buffer.
+ FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET);
- bsetpos(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin));
- f->pos = pos;
- f->bptr = f->bstop = f->buffer;
+ fbmulti_get_ptrs(f);
return 1;
- break;
case SEEK_END:
- fbmulti_get_len(f);
- return fbmulti_seek(f, FB_MULTI(f)->len+pos, SEEK_SET);
- break;
+ return fbmulti_seek(f, FB_MULTI(f)->len + pos, SEEK_SET);
default:
ASSERT(0);
}
static void
-fbmulti_update_capability(struct fastbuf *f) {
- // FB Multi is only a proxy to other fastbufs ... if any of them lacks
- // support of any feature, FB Multi also provides no support of that feature
- f->refill = fbmulti_refill;
- f->seek = fbmulti_seek;
-
- CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) {
- ASSERT(n->fb->refill)
-
- if (!n->fb->seek)
- f->seek = NULL;
- }
-}
-
-static void
-fbmulti_close(struct fastbuf *f) {
- CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
- if (n->allow_close)
- bclose(n->fb);
+fbmulti_close(struct fastbuf *f)
+{
+ CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
+ bclose(n->fb);
mp_delete(FB_MULTI(f)->mp);
}
-struct fastbuf*
-fbmulti_create(uns bufsize, ...)
+struct fastbuf *
+fbmulti_create(void)
{
- struct mempool *mp = mp_new(bufsize);
+ struct mempool *mp = mp_new(1024);
struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi));
- FB_MULTI(fb_out)->mp = mp;
+ struct fb_multi *fbm = FB_MULTI(fb_out);
- struct fastbuf *fb_in;
- clist* subbufs = mp_alloc(mp, sizeof(clist));
- clist_init(subbufs);
- FB_MULTI(fb_out)->subbufs = subbufs;
+ fbm->mp = mp;
+ fbm->len = 0;
- va_list args;
- va_start(args, bufsize);
- while (fb_in = va_arg(args, struct fastbuf *)) {
- fbmulti_append(fb_out, fb_in, 1);
- }
- va_end(args);
+ clist_init(&fbm->subbufs);
- FB_MULTI(fb_out)->cur = clist_head(subbufs);
-
- fb_out->buffer = mp_alloc(mp, bufsize);
- fb_out->bptr = fb_out->bstop = fb_out->buffer;
- fb_out->bufend = fb_out->buffer + bufsize;
fb_out->name = FB_MULTI_NAME;
-
- fbmulti_update_capability(fb_out);
+ fb_out->refill = fbmulti_refill;
+ fb_out->seek = fbmulti_seek;
fb_out->close = fbmulti_close;
return fb_out;
}
void
-fbmulti_append(struct fastbuf *f, struct fastbuf *fb, int allow_close) {
- struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf));
+fbmulti_append(struct fastbuf *f, struct fastbuf *fb)
+{
+ struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs);
+
+ struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(*sb));
sb->fb = fb;
- sb->allow_close = allow_close;
- clist_add_tail(FB_MULTI(f)->subbufs, &(sb->n));
-}
+ clist_add_tail(&FB_MULTI(f)->subbufs, &(sb->n));
+
+ ASSERT(fb->refill);
+
+ if (fb->seek)
+ {
+ if (f->seek)
+ {
+ sb->begin = last ? last->end : 0;
+ bseek(fb, 0, SEEK_END);
+ FB_MULTI(f)->len = sb->end = sb->begin + btell(fb);
+ }
-static void fbmulti_flatten_internal(struct fastbuf *f, clist* c, int allow_close) {
- CLIST_FOR_EACH(struct subbuf *, n, *c) {
- if (strcmp(n->fb->name, FB_MULTI_NAME))
- fbmulti_append(f, n->fb, n->allow_close && allow_close);
- else {
- fbmulti_flatten_internal(f, FB_MULTI(n->fb)->subbufs, allow_close && n->allow_close);
- if (allow_close && n->allow_close) {
- FB_MULTI(n->fb)->subbufs = mp_alloc(FB_MULTI(n->fb)->mp, sizeof(clist));
- clist_init(FB_MULTI(n->fb)->subbufs);
- bclose(n->fb);
- }
+ bsetpos(fb, 0);
+ }
+
+ else
+ {
+ f->seek = NULL;
+ sb->offset = btell(fb);
+ sb->begin = 0;
+ sb->end = 0;
+ }
+
+ if (!last)
+ {
+ FB_MULTI(f)->cur = sb;
+ fbmulti_get_ptrs(f);
}
- }
}
void
-fbmulti_flatten(struct fastbuf *f) {
- if (strcmp(f->name, FB_MULTI_NAME)) {
- DBG("fbmulti: given fastbuf isn't fbmulti");
- return;
- }
-
- clist* c = FB_MULTI(f)->subbufs;
- FB_MULTI(f)->subbufs = mp_alloc(FB_MULTI(f)->mp, sizeof(clist));
- clist_init(FB_MULTI(f)->subbufs);
-
- fbmulti_flatten_internal(f, c, 1);
- FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
- f->bptr = f->bstop = f->buffer;
- f->pos = 0;
+fbmulti_remove(struct fastbuf *f, struct fastbuf *fb)
+{
+ bflush(f);
+ if (fb)
+ {
+ CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
+ if (fb == n->fb)
+ {
+ clist_remove(&(n->n));
+ return;
+ }
+
+ die("Given fastbuf %p not in given fbmulti %p", fb, f);
+ }
+ else
+ clist_init(&FB_MULTI(f)->subbufs);
}
#ifdef TEST
-int main(int argc, char ** argv)
+int main(int argc, char **argv)
{
if (argc < 2)
{
- fprintf(stderr, "You must specify a test (r, w, o)\n");
+ fprintf(stderr, "You must specify a test (r, m, i, n)\n");
return 1;
}
switch (*argv[1])
for (uns i=0;i<ARRAY_SIZE(data);i++)
fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
- struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], &fb[2], NULL);
+ struct fastbuf *f = fbmulti_create();
+ fbmulti_append(f, &fb[0]);
+ fbmulti_append(f, &fb[1]);
+ fbmulti_append(f, &fb[2]);
char buffer[9];
while (bgets(f, buffer, 9))
for (uns i=0;i<ARRAY_SIZE(data);i++)
fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
- struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], NULL);
+ struct fastbuf *f = fbmulti_create();
+ fbmulti_append(f, &fb[0]);
+ fbmulti_append(f, &fb[1]);
int pos[] = {0, 3, 1, 4, 2, 5};
- for (uns i=0;i<ARRAY_SIZE(pos);i++) {
- bsetpos(f, pos[i]);
- putchar(bgetc(f));
- }
+ for (uns i=0;i<ARRAY_SIZE(pos);i++)
+ {
+ bsetpos(f, pos[i]);
+ putchar(bgetc(f));
+ }
bclose(f);
break;
fbbuf_init_read(&fb[2], data + 2, 2, 0);
fbbuf_init_read(&fb[3], data + 4, 1, 0);
- struct fastbuf* f = fbmulti_create(8, &fb[0], &fb[1], &fb[2], &fb[1], &fb[3], NULL);
+ struct fastbuf *f = fbmulti_create();
+ fbmulti_append(f, &fb[0]);
+ fbmulti_append(f, &fb[1]);
+ fbmulti_append(f, &fb[2]);
+ fbmulti_append(f, &fb[1]);
+ fbmulti_append(f, &fb[3]);
char buffer[9];
while(bgets(f, buffer, 9))
bclose(f);
break;
}
- case 'f':
case 'n':
{
char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
struct fastbuf nl;
fbbuf_init_read(&nl, "\n", 1, 0);
- struct fastbuf *f = fbmulti_create(4,
- fbmulti_create(5,
- &fb[0],
- &sp,
- &fb[1],
- NULL),
- &nl,
- fbmulti_create(7,
- &fb[2],
- &sp,
- &fb[3],
- NULL),
- &nl,
- fbmulti_create(3,
- &fb[4],
- &sp,
- &fb[5],
- NULL),
- &nl,
- NULL);
-
- if (*argv[1] == 'f')
- fbmulti_flatten(f);
+ struct fastbuf *f = fbmulti_create();
+ struct fastbuf *ff;
+
+ ff = fbmulti_create();
+ fbmulti_append(ff, &fb[0]);
+ fbmulti_append(ff, &sp);
+ fbmulti_append(ff, &fb[1]);
+ fbmulti_append(f, ff);
+ fbmulti_append(f, &nl);
+
+ ff = fbmulti_create();
+ fbmulti_append(ff, &fb[2]);
+ fbmulti_append(ff, &sp);
+ fbmulti_append(ff, &fb[3]);
+ fbmulti_append(f, ff);
+ fbmulti_append(f, &nl);
+
+ ff = fbmulti_create();
+ fbmulti_append(ff, &fb[4]);
+ fbmulti_append(ff, &sp);
+ fbmulti_append(ff, &fb[5]);
+ fbmulti_append(f, ff);
+ fbmulti_append(f, &nl);
char buffer[20];
while (bgets(f, buffer, 20))