X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=ucw%2Ffb-multi.c;h=097804c128ccb5a6900903ee71ab1148f96d3d37;hb=bc2bbfcbe76e78db9cde27455ddbcfe1ddcc61d6;hp=8071aa0cbed0e5cf70d6499066a16acb29b56580;hpb=9fa0d3b00b6e436831d37ff6257a6ee8b222fa8e;p=libucw.git diff --git a/ucw/fb-multi.c b/ucw/fb-multi.c index 8071aa0c..097804c1 100644 --- a/ucw/fb-multi.c +++ b/ucw/fb-multi.c @@ -21,257 +21,226 @@ struct fb_multi { 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; + ucw_off_t begin, end, offset; struct fastbuf *fb; }; static void -fbmulti_subbuf_get_end(struct subbuf *s) +fbmulti_get_ptrs(struct fastbuf *f) { - if (s->fb->seek) - { - bseek(s->fb, 0, SEEK_END); - s->end = s->begin + btell(s->fb); - } + 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) +{ + 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) + + // 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->begin = FB_MULTI(f)->cur->end; + 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; + fbmulti_set_ptrs(f); - uns len = bread(FB_MULTI(f)->cur->fb, f->bstop, (f->bufend - f->bstop)); - f->bstop += len; - f->pos += len; + // Refill the subbuf + uint 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) + if (pos > FB_MULTI(f)->len) + bthrow(f, "seek", "Seek out of range"); + + while (pos > FB_MULTI(f)->cur->end) // Moving forward { - 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); + int r = fbmulti_subbuf_next(f); + ASSERT(r); } - do + while (pos < FB_MULTI(f)->cur->begin) // Moving backwards { - fbmulti_subbuf_get_end(FB_MULTI(f)->cur); - if (pos < FB_MULTI(f)->cur->end) - break; - - if (!fbmulti_subbuf_next(f)) - { - if (pos == FB_MULTI(f)->cur->end) - break; - else - bthrow(f, "seek", "Seek out of range"); - } - + int r = fbmulti_subbuf_prev(f); + ASSERT(r); } - while (1); - bsetpos(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin)); - f->pos = pos; - f->bptr = f->bstop = f->buffer; + // 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); + + 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); + 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, ...) +fbmulti_create(void) { - struct mempool *mp = mp_new(bufsize); - struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi)); - FB_MULTI(fb_out)->mp = mp; - - struct fastbuf *fb_in; - clist *subbufs = mp_alloc(mp, sizeof(clist)); - clist_init(subbufs); - FB_MULTI(fb_out)->subbufs = subbufs; - - 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); - - 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; + struct mempool *mp = mp_new(1024); + struct fastbuf *fb_out = mp_alloc_zero(mp, sizeof(struct fb_multi)); + struct fb_multi *fbm = FB_MULTI(fb_out); - fbmulti_update_capability(fb_out); + fbm->mp = mp; + fbm->len = 0; + + clist_init(&fbm->subbufs); + + fb_out->name = FB_MULTI_NAME; + 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) +fbmulti_append(struct fastbuf *f, struct fastbuf *fb) { - struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(struct subbuf)); + 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)); - fbmulti_update_capability(f); + 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); if (fb) { - CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) + CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs) if (fb == n->fb) { - // TODO: fix seek positions clist_remove(&(n->n)); - fbmulti_update_capability(f); return; } - die("Given fastbuf %p not in given fbmulti %p.", fb, f); + die("Given fastbuf %p not in given fbmulti %p", fb, f); } else - clist_init(FB_MULTI(f)->subbufs); - - fbmulti_update_capability(f); -} - -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); - } - } - } -} - -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; + clist_init(&FB_MULTI(f)->subbufs); } #ifdef TEST @@ -280,7 +249,7 @@ 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]) @@ -289,10 +258,13 @@ int main(int argc, char **argv) { char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" }; struct fastbuf fb[ARRAY_SIZE(data)]; - for (uns i=0;i