X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Ffb-mem.c;h=2b0d7e941fa6cf1c9e0e408efe02a3a184bb67d8;hb=43b1b86e0fb28a3b383df336acfadbb1baaa87aa;hp=2e0769a4642be8139e9094b086f160359f14dc26;hpb=76ee03dea8ff0a04d7659ded5a9a53ef3eb39aa7;p=libucw.git diff --git a/lib/fb-mem.c b/lib/fb-mem.c index 2e0769a4..2b0d7e94 100644 --- a/lib/fb-mem.c +++ b/lib/fb-mem.c @@ -1,13 +1,15 @@ /* * Sherlock Library -- Fast Buffered I/O on Memory Streams * - * (c) 1997--2000 Martin Mares + * (c) 1997--2002 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. */ #include "lib/lib.h" #include "lib/fastbuf.h" -#include #include struct memstream { @@ -18,15 +20,23 @@ struct memstream { struct msblock { struct msblock *next; + sh_off_t pos; unsigned size; byte data[0]; }; +struct fb_mem { + struct fastbuf fb; + struct memstream *stream; + struct msblock *block; +}; +#define FB_MEM(f) ((struct fb_mem *)(f)->is_fastbuf) + static int fbmem_refill(struct fastbuf *f) { - struct memstream *s = f->lldata; - struct msblock *b = f->llpos; + struct memstream *s = FB_MEM(f)->stream; + struct msblock *b = FB_MEM(f)->block; if (!b) { @@ -34,29 +44,30 @@ fbmem_refill(struct fastbuf *f) if (!b) return 0; } - else if (f->bstop < b->data + b->size) + else if (f->buffer == b->data && f->bstop < b->data + b->size) { f->bstop = b->data + b->size; + f->pos = b->pos + b->size; return 1; } + else if (!b->next) + return 0; else - { - if (!b->next) - return 0; - f->pos += b->size; - b = b->next; - } + b = b->next; + if (!b->size) + return 0; f->buffer = f->bptr = b->data; f->bufend = f->bstop = b->data + b->size; - f->llpos = b; + f->pos = b->pos + b->size; + FB_MEM(f)->block = b; return 1; } static void fbmem_spout(struct fastbuf *f) { - struct memstream *s = f->lldata; - struct msblock *b = f->llpos; + struct memstream *s = FB_MEM(f)->stream; + struct msblock *b = FB_MEM(f)->block; struct msblock *bb; if (b) @@ -64,41 +75,50 @@ fbmem_spout(struct fastbuf *f) b->size = f->bptr - b->data; if (b->size < s->blocksize) return; - f->pos += b->size; } bb = xmalloc(sizeof(struct msblock) + s->blocksize); if (b) - b->next = bb; + { + b->next = bb; + bb->pos = b->pos + b->size; + } else - s->first = bb; + { + s->first = bb; + bb->pos = 0; + } bb->next = NULL; bb->size = 0; f->buffer = f->bptr = f->bstop = bb->data; f->bufend = bb->data + s->blocksize; - f->llpos = bb; + f->pos = bb->pos; + FB_MEM(f)->block = bb; } static void fbmem_seek(struct fastbuf *f, sh_off_t pos, int whence) { - struct memstream *m = f->lldata; + struct memstream *m = FB_MEM(f)->stream; struct msblock *b; - unsigned int p = 0; - if (whence != SEEK_SET) - die("fbmem_seek: only SEEK_SET supported"); + ASSERT(whence == SEEK_SET || whence == SEEK_END); + if (whence == SEEK_END) + { + for (b=m->first; b; b=b->next) + pos += b->size; + } + /* Yes, this is linear. But considering the average number of buckets, it doesn't matter. */ for (b=m->first; b; b=b->next) { - if (pos <= p + b->size) /* <=, because we need to be able to seek just after file end */ + if (pos <= b->pos + (sh_off_t)b->size) /* <=, because we need to be able to seek just after file end */ { - f->pos = p; f->buffer = b->data; - f->bptr = b->data + (pos - p); + f->bptr = b->data + (pos - b->pos); f->bufend = f->bstop = b->data + b->size; - f->llpos = b; + f->pos = b->pos + b->size; + FB_MEM(f)->block = b; return; } - p += b->size; } die("fbmem_seek to invalid offset"); } @@ -106,37 +126,33 @@ fbmem_seek(struct fastbuf *f, sh_off_t pos, int whence) static void fbmem_close(struct fastbuf *f) { - struct memstream *m = f->lldata; + struct memstream *m = FB_MEM(f)->stream; struct msblock *b; - if (--m->uc) - return; - - while (b = m->first) + if (!--m->uc) { - m->first = b->next; - xfree(b); + while (b = m->first) + { + m->first = b->next; + xfree(b); + } + xfree(m); } - xfree(m); + xfree(f); } struct fastbuf * fbmem_create(unsigned blocksize) { - struct fastbuf *f = xmalloc(sizeof(struct fastbuf)); - struct memstream *m = xmalloc(sizeof(struct memstream)); + struct fastbuf *f = xmalloc_zero(sizeof(struct fb_mem)); + struct memstream *s = xmalloc_zero(sizeof(struct memstream)); - m->blocksize = blocksize; - m->uc = 1; - m->first = NULL; + s->blocksize = blocksize; + s->uc = 1; - f->bptr = f->bstop = f->buffer = f->bufend = NULL; - f->pos = f->fdpos = 0; + FB_MEM(f)->stream = s; f->name = ""; - f->lldata = m; - f->refill = NULL; f->spout = fbmem_spout; - f->seek = NULL; f->close = fbmem_close; return f; } @@ -144,17 +160,15 @@ fbmem_create(unsigned blocksize) struct fastbuf * fbmem_clone_read(struct fastbuf *b) { - struct fastbuf *f = xmalloc(sizeof(struct fastbuf)); - struct memstream *s = b->lldata; + struct fastbuf *f = xmalloc_zero(sizeof(struct fb_mem)); + struct memstream *s = FB_MEM(b)->stream; + bflush(b); s->uc++; - f->bptr = f->bstop = f->buffer = f->bufend = NULL; - f->pos = f->fdpos = 0; + FB_MEM(f)->stream = s; f->name = ""; - f->lldata = s; f->refill = fbmem_refill; - f->spout = NULL; f->seek = fbmem_seek; f->close = fbmem_close; return f; @@ -171,23 +185,23 @@ int main(void) r = fbmem_clone_read(w); bwrite(w, "12345", 5); bwrite(w, "12345", 5); - printf("<%d>", btell(w)); + printf("<%d>", (int)btell(w)); bflush(w); - printf("<%d>", btell(w)); - printf("<%d>", btell(r)); + printf("<%d>", (int)btell(w)); + printf("<%d>", (int)btell(r)); while ((t = bgetc(r)) >= 0) putchar(t); - printf("<%d>", btell(r)); + printf("<%d>", (int)btell(r)); bwrite(w, "12345", 5); bwrite(w, "12345", 5); - printf("<%d>", btell(w)); + printf("<%d>", (int)btell(w)); bclose(w); bsetpos(r, 0); - printf("", btell(r)); + printf("", (int)btell(r)); while ((t = bgetc(r)) >= 0) putchar(t); bsetpos(r, 3); - printf("", btell(r)); + printf("", (int)btell(r)); while ((t = bgetc(r)) >= 0) putchar(t); fflush(stdout);