X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ffb-multi.c;h=4cd6244d444aa719ea0f640de29d1fb69bd1ed10;hb=b4aae2e94174b491161bd461b049c6d1b3b3602f;hp=e5835574e84ff5be9f58d79b8acc6a4bb3bf39a5;hpb=17129a2f190d006f88fb3bc92aafb61f31e164d8;p=libucw.git diff --git a/ucw/fb-multi.c b/ucw/fb-multi.c index e5835574..4cd6244d 100644 --- a/ucw/fb-multi.c +++ b/ucw/fb-multi.c @@ -21,7 +21,7 @@ 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)) @@ -29,26 +29,20 @@ struct fb_multi { struct subbuf { cnode n; ucw_off_t begin, end, offset; - int allow_close; 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) { - f->buffer = FB_MULTI(f)->cur->fb->buffer; - f->bptr = FB_MULTI(f)->cur->fb->bptr; - f->bstop = FB_MULTI(f)->cur->fb->bstop; - f->bufend = FB_MULTI(f)->cur->fb->bufend; - f->pos = FB_MULTI(f)->cur->begin + FB_MULTI(f)->cur->fb->pos - FB_MULTI(f)->cur->offset; + 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 @@ -60,19 +54,14 @@ fbmulti_set_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); - 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; - // 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 = cur->end = f->pos; // Set the beginning of the next buf if (next->fb->seek) @@ -86,8 +75,6 @@ fbmulti_subbuf_next(struct fastbuf *f) next->offset = btell(next->fb); } - next->begin = FB_MULTI(f)->cur->end; - // Set the pointers FB_MULTI(f)->cur = next; fbmulti_get_ptrs(f); @@ -99,8 +86,8 @@ 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 != NULL); + 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); @@ -117,6 +104,7 @@ static int 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) @@ -126,9 +114,6 @@ fbmulti_refill(struct fastbuf *f) } // 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); @@ -136,22 +121,6 @@ fbmulti_refill(struct fastbuf *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) { @@ -163,188 +132,115 @@ fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence) bthrow(f, "seek", "Seek out of range"); while (pos > FB_MULTI(f)->cur->end) // Moving forward - ASSERT(fbmulti_subbuf_next(f)); + { + int r = fbmulti_subbuf_next(f); + ASSERT(r); + } while (pos < FB_MULTI(f)->cur->begin) // Moving backwards - ASSERT(fbmulti_subbuf_prev(f)); + { + int r = fbmulti_subbuf_prev(f); + ASSERT(r); + } // 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: - 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 mempool *mp = mp_new(1024); 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; + struct fb_multi *fbm = FB_MULTI(fb_out); - 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); + fbm->mp = mp; + fbm->len = 0; - fbmulti_update_capability(fb_out); - - FB_MULTI(fb_out)->cur = clist_head(subbufs); - bsetpos(FB_MULTI(fb_out)->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); - } + 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); - uns pos = f->pos; 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) { - // 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; - }; + } - 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); - -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; -} - -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 @@ -353,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]) @@ -365,7 +261,10 @@ int main(int argc, char **argv) for (uns i=0;i