X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Ffb-multi.c;h=097804c128ccb5a6900903ee71ab1148f96d3d37;hb=bc2bbfcbe76e78db9cde27455ddbcfe1ddcc61d6;hp=c9eac1511ed89e75ed10e1010a13e2537c0fd89a;hpb=9f337d4b2be7124ec44c4701ba3816a2831ce9c5;p=libucw.git diff --git a/ucw/fb-multi.c b/ucw/fb-multi.c index c9eac151..097804c1 100644 --- a/ucw/fb-multi.c +++ b/ucw/fb-multi.c @@ -14,116 +14,143 @@ #include +#define FB_MULTI_NAME "" + 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; - struct fastbuf* fb; + ucw_off_t begin, end, offset; + struct fastbuf *fb; }; -#define SUBBUF(f) ((struct subbuf *)(f)) -static inline void -fbmulti_subbuf_get_end(struct subbuf *s) +static void +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 inline int +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) { - bseek(FB_MULTI(f)->cur->fb, 0, SEEK_SET); - 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 + 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) { - 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"); - if (!fbmulti_subbuf_next(f)) - bthrow(f, "seek", "Seek out of range"); + while (pos > FB_MULTI(f)->cur->end) // Moving forward + { + int r = fbmulti_subbuf_next(f); + ASSERT(r); + } + + 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); - bseek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET); - 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_CUR); - break; + return fbmulti_seek(f, FB_MULTI(f)->len + pos, SEEK_SET); default: ASSERT(0); @@ -131,61 +158,98 @@ fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence) } 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; +fbmulti_close(struct fastbuf *f) +{ + CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs) + bclose(n->fb); - CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) { - if (!n->fb->refill) - f->refill = NULL; + mp_delete(FB_MULTI(f)->mp); +} - if (!n->fb->seek) - f->seek = NULL; - } +struct fastbuf * +fbmulti_create(void) +{ + 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); + + 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; } -struct fastbuf* -fbmulti_create(uns bufsize, ...) +void +fbmulti_append(struct fastbuf *f, struct fastbuf *fb) { - struct mempool *mp = mp_new(bufsize); - struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi)); - FB_MULTI(fb_out)->mp = mp; + struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs); - struct fastbuf *fb_in; - clist* subbufs = mp_alloc(mp, sizeof(clist)); - clist_init(subbufs); - FB_MULTI(fb_out)->subbufs = subbufs; + struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(*sb)); + sb->fb = fb; + clist_add_tail(&FB_MULTI(f)->subbufs, &(sb->n)); - va_list args; - va_start(args, bufsize); - while (fb_in = va_arg(args, struct fastbuf *)) { - struct subbuf *sb = mp_alloc(mp, sizeof(struct subbuf)); - sb->fb = fb_in; - clist_add_tail(subbufs, &(sb->n)); - } - va_end(args); + ASSERT(fb->refill); - FB_MULTI(fb_out)->cur = clist_head(subbufs); + 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); + } - 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 = ""; + bsetpos(fb, 0); + } - fbmulti_update_capability(fb_out); + else + { + f->seek = NULL; + sb->offset = btell(fb); + sb->begin = 0; + sb->end = 0; + } - return fb_out; + 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) + 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]) @@ -194,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