* You aren't allowed to do anything with the underlying buffers while these
* are connected into fbmulti.
*
- * You may init a fbmulti by @fbmulti_create(bufsize, fb1, fb2, ..., NULL).
- * This call returns a fastbuf that concatenates all the given fastbufs.
- * The last parameter of @fbmulti_create must be NULL.
+ * The fbmulti is inited by @fbmulti_create(). It returns an empty fbmulti.
+ * Then you call @fbmulti_append() for each fbmulti
*
* If @bclose() is called on fbmulti, all the underlying buffers get closed
* recursively.
* @fbmulti_flatten() to flatten the structure. After @fbmulti_flatten(), the
* fbmulti is seeked to the beginning, flushed and ready to read the whole buffer.
*
- * If you want to remove a fastbuf from the chain, just call @fbmulti_remove
- * where the second parameter is a pointer to the removed fastbuf. If you pass
- * NULL, all the underlying fastbufs are removed.
+ * If you want to keep an underlying fastbuf open after @bclose, just remove it
+ * by @fbmulti_remove where the second parameter is a pointer to the removed
+ * fastbuf. If you pass NULL, all the underlying fastbufs are removed.
+ *
+ * After a @fbmulti_remove, the state of fbmulti is undefined. The only allowed
+ * operation is then another @fbmulti_remove or @bclose on that fbmulti.
*
- * When a fastbuf is removed from the chain, the overall position may change:
- * If bstop pointed into it, after removal it points to the boundary of the
- * previous and next fastbufs. Length of the removed fastbuf is subtracted from
- * the overall offset of all the fastbufs after the removed fb in the chain.
***/
-struct fastbuf *fbmulti_create(uns bufsize, ...) SENTINEL_CHECK;
+struct fastbuf *fbmulti_create(void);
void fbmulti_append(struct fastbuf *f, struct fastbuf *fa);
void fbmulti_remove(struct fastbuf *f, struct fastbuf *fb);
struct fastbuf *fb;
};
-static void
-fbmulti_subbuf_get_end(struct subbuf *s)
-{
- ASSERT(s->fb->seek);
- bseek(s->fb, 0, SEEK_END);
- s->end = s->begin + btell(s->fb);
-}
-
static void
fbmulti_get_ptrs(struct fastbuf *f)
{
static int
fbmulti_subbuf_next(struct fastbuf *f)
{
- struct subbuf *next = clist_next(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
+ struct subbuf *cur = FB_MULTI(f)->cur;
+ struct subbuf *next = clist_next(&FB_MULTI(f)->subbufs, &cur->n);
if (!next)
return 0;
- // Check the end of current buf
- if (f->seek)
- {
- FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, FB_MULTI(f)->cur->end - FB_MULTI(f)->cur->begin, SEEK_SET);
- fbmulti_get_ptrs(f);
- ASSERT(FB_MULTI(f)->cur->end == f->pos);
- }
- else
- FB_MULTI(f)->cur->end = f->pos;
+ // Get the end of current buf if not known yet.
+ if (!f->seek && !next->begin)
+ next->begin = FB_MULTI(f)->cur->end = f->pos;
// Set the beginning of the next buf
if (next->fb->seek)
next->offset = btell(next->fb);
}
- next->begin = FB_MULTI(f)->cur->end;
-
// Set the pointers
FB_MULTI(f)->cur = next;
fbmulti_get_ptrs(f);
{
// Called only when seeking, assuming everything seekable
struct subbuf *prev = clist_prev(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
- ASSERT(prev != NULL);
+ ASSERT(prev);
// Set pos to beginning, flush offset
bsetpos(prev->fb, 0);
fbmulti_refill(struct fastbuf *f)
{
fbmulti_set_ptrs(f);
+
// Refill the subbuf
uns len = FB_MULTI(f)->cur->fb->refill(FB_MULTI(f)->cur->fb);
if (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 and redo
if (fbmulti_subbuf_next(f))
return fbmulti_refill(f);
return 0;
}
-static void
-fbmulti_get_len(struct fastbuf *f)
-{
- ucw_off_t pos = btell(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;
- }
- f->seek(f, pos, SEEK_SET); // XXX: f->seek is needed here instead of bsetpos as the FE assumptions about f's state may be completely wrong.
-}
-
static int
fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
{
struct fastbuf *
fbmulti_create(void)
{
- struct mempool *mp = mp_new(bufsize);
+ struct mempool *mp = mp_new(128);
struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi));
- struct fbmulti *fbm = FB_MULTI(fb_out);
+ struct fb_multi *fbm = FB_MULTI(fb_out);
+
fbm->mp = mp;
+ fbm->len = 0;
clist_init(&fbm->subbufs);
- va_list args;
- va_start(args, bufsize);
- while (fb_in = va_arg(args, struct fastbuf *))
- fbmulti_append(fb_out, fb_in);
-
- va_end(args);
-
- fbmulti_update_capability(fb_out);
-
- fbm->cur = clist_head(&fbm->subbufs);
- bsetpos(fbm->cur->fb, 0);
-
- fbmulti_get_ptrs(fb_out);
-
- // If seekable, get the length of each subbuf, the total length and boundaries
- if (fb_out->seek)
- {
- fbmulti_get_len(fb_out);
- }
-
fb_out->name = FB_MULTI_NAME;
- f->refill = fbmulti_refill;
- f->seek = fbmulti_seek;
-
+ 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)
{
- ASSERT(fb->refill);
- if (!fb->seek)
- f->seek = NULL;
+ struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs);
struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf));
sb->fb = fb;
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);
+ }
+
+ 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_remove(struct fastbuf *f, struct fastbuf *fb)
{
bflush(f);
- uns pos = f->pos;
if (fb)
{
CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
if (fb == n->fb)
{
- // Move the pointers to another buffer if this one was the active.
- if (FB_MULTI(f)->cur == n)
- {
- pos = n->begin;
- if (!fbmulti_subbuf_next(f))
- {
- struct subbuf *prev = clist_prev(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
- if (prev == NULL)
- goto cleanup;
-
- FB_MULTI(f)->cur = prev;
- fbmulti_get_ptrs(f);
- }
- }
-
- if (n->end < pos)
- pos -= (n->end - n->begin);
-
clist_remove(&(n->n));
- fbmulti_update_capability(f);
- fbmulti_get_len(f);
- fbmulti_get_ptrs(f);
return;
};
}
else
clist_init(&FB_MULTI(f)->subbufs);
-
-cleanup:
- // The fbmulti is empty now, do some cleanup
- fbmulti_update_capability(f);
- fbmulti_get_len(f);
- f->buffer = f->bufend = f->bptr = f->bstop = NULL;
- f->pos = 0;
}
#ifdef TEST
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};
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))
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);
+ 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))