X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=inline;f=ucw%2Ffastbuf.c;h=22501f43ed87cba8ff3e1529da0ebe2b57038b8c;hb=bc2bbfcbe76e78db9cde27455ddbcfe1ddcc61d6;hp=fb2cc49f88513f73e16d4035a0dc26c417baf5d2;hpb=681b277c0aabea785a21e109dc07338847c0cb32;p=libucw.git diff --git a/ucw/fastbuf.c b/ucw/fastbuf.c index fb2cc49f..22501f43 100644 --- a/ucw/fastbuf.c +++ b/ucw/fastbuf.c @@ -1,16 +1,19 @@ /* * UCW Library -- Fast Buffered I/O * - * (c) 1997--2007 Martin Mares + * (c) 1997--2011 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ -#include "ucw/lib.h" -#include "ucw/fastbuf.h" -#include "ucw/respool.h" -#include "ucw/trans.h" +#undef LOCAL_DEBUG + +#include +#include +#include +#include +#include #include #include @@ -19,70 +22,102 @@ void bclose(struct fastbuf *f) { if (f) { - if (!(f->flags & FB_DEAD)) - bflush(f); + bflush(f); + res_detach(f->res); + DBG("FB: closing", f); if (f->close) - f->close(f); - if (f->res) - res_drop(f->res); + f->close(f); /* Should always free all internal resources, even if it throws an exception */ } } void NONRET bthrow(struct fastbuf *f, const char *id, const char *fmt, ...) { - ASSERT(!(f->flags & FB_DEAD)); - f->flags |= FB_DEAD; + DBG("FB: throwing %s", full_id); + char full_id[16]; + snprintf(full_id, sizeof(full_id), "ucw.fb.%s", id); + ASSERT(!(f->flags & FB_DEAD)); /* Only one bthrow() is allowed before bclose() */ va_list args; va_start(args, fmt); - trans_vthrow(id, f, fmt, args); + if (!f->res) + die("Fastbuf %s error: %s", f->name ? : "", stk_vprintf(fmt, args)); + f->flags |= FB_DEAD; + f->bptr = f->bstop = f->bufend; /* Reset the buffer to guard consecutive seek/read/write */ + trans_vthrow(full_id, f, fmt, args); } int brefill(struct fastbuf *f, int allow_eof) { - ASSERT(f->bptr >= f->bstop); + DBG("FB: refill"); + ASSERT(!(f->flags & FB_DEAD) && f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend); if (!f->refill) - bthrow(f, "fb.read", "Stream not readable"); + bthrow(f, "read", "Stream not readable"); if (f->refill(f)) { - ASSERT(f->bptr < f->bstop); + ASSERT(f->buffer <= f->bptr && f->bptr < f->bstop && f->bstop <= f->bufend); return 1; } else { + ASSERT(f->buffer <= f->bptr && f->bptr == f->bstop && f->bstop <= f->bufend); if (!allow_eof && (f->flags & FB_DIE_ON_EOF)) - bthrow(f, "fb.eof", "Unexpected EOF"); - ASSERT(f->bptr == f->bstop); + bthrow(f, "eof", "Unexpected EOF"); return 0; } } -void bspout(struct fastbuf *f) +static void do_spout(struct fastbuf *f) { - ASSERT(f->bptr > f->bstop || f->bptr >= f->bufend); + DBG("FB: spout"); + ASSERT(!(f->flags & FB_DEAD) && f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend); /* Check write mode possibly with unflushed data */ if (!f->spout) - bthrow(f, "fb.write", "Stream not writeable"); + bthrow(f, "write", "Stream not writeable"); f->spout(f); - ASSERT(f->bptr < f->bufend); + ASSERT(f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend); +} + +void bspout(struct fastbuf *f) +{ + do_spout(f); + if (f->bstop == f->bufend) + { + do_spout(f); + ASSERT(f->bstop < f->bufend); + } } void bflush(struct fastbuf *f) { if (f->bptr > f->bstop) - bspout(f); - else if (f->bstop > f->buffer) - f->bptr = f->bstop = f->buffer; + do_spout(f); + else + f->bptr = f->bstop; /* XXX: Skip the rest of the reading buffer ==> it breaks the position of the FE cursor */ + DBG("FB: flushed"); +} + +static void do_seek(struct fastbuf *f, ucw_off_t pos, int whence) +{ + bflush(f); + DBG("FB: seeking to pos=%lld whence=%d %p %p %p %p", (long long)pos, whence, f->buffer, f->bstop, f->bptr, f->bufend); + if (!f->seek || !f->seek(f, pos, whence)) + bthrow(f, "seek", "Stream not seekable"); + DBG("FB: seeked %p %p %p %p", f->buffer, f->bstop, f->bptr, f->bufend); + ASSERT(f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend); + if (whence == SEEK_SET) + ASSERT(pos == btell(f)); + else + ASSERT(btell(f) >= 0); } -inline void bsetpos(struct fastbuf *f, ucw_off_t pos) +void bsetpos(struct fastbuf *f, ucw_off_t pos) { /* We can optimize seeks only when reading */ - if (pos >= f->pos - (f->bstop - f->buffer) && pos <= f->pos) + if (f->bptr < f->bstop && pos <= f->pos && pos >= f->pos - (f->bstop - f->buffer)) /* If bptr == bstop, then [buffer, bstop] may be undefined */ f->bptr = f->bstop + (pos - f->pos); - else + else if (pos != btell(f)) { - bflush(f); - if (!f->seek || !f->seek(f, pos, SEEK_SET)) - bthrow(f, "fb.seek", "Stream not seekable"); + if (pos < 0) + bthrow(f, "seek", "Seek out of range"); + do_seek(f, pos, SEEK_SET); } } @@ -91,13 +126,15 @@ void bseek(struct fastbuf *f, ucw_off_t pos, int whence) switch (whence) { case SEEK_SET: - return bsetpos(f, pos); + bsetpos(f, pos); + break; case SEEK_CUR: - return bsetpos(f, btell(f) + pos); + bsetpos(f, btell(f) + pos); /* btell() is non-negative, so an overflow will always throw "Seek out of range" in bsetpos() */ + break; case SEEK_END: - bflush(f); - if (!f->seek || !f->seek(f, pos, SEEK_END)) - bthrow(f, "fb.seek", "Stream not seekable"); + if (pos > 0) + bthrow(f, "seek", "Seek out of range"); + do_seek(f, pos, SEEK_END); break; default: die("bseek: invalid whence=%d", whence); @@ -127,19 +164,19 @@ int beof_slow(struct fastbuf *f) return f->bptr >= f->bstop && !brefill(f, 1); } -void bputc_slow(struct fastbuf *f, uns c) +void bputc_slow(struct fastbuf *f, uint c) { if (f->bptr >= f->bufend) bspout(f); *f->bptr++ = c; } -uns bread_slow(struct fastbuf *f, void *b, uns l, uns check) +uint bread_slow(struct fastbuf *f, void *b, uint l, uint check) { - uns total = 0; + uint total = 0; while (l) { - uns k = f->bstop - f->bptr; + uint k = f->bstop - f->bptr; if (!k) { @@ -157,15 +194,15 @@ uns bread_slow(struct fastbuf *f, void *b, uns l, uns check) total += k; } if (check && total && l) - bthrow(f, "fb.read", "breadb: short read"); + bthrow(f, "eof", "breadb: short read"); return total; } -void bwrite_slow(struct fastbuf *f, const void *b, uns l) +void bwrite_slow(struct fastbuf *f, const void *b, uint l) { while (l) { - uns k = f->bufend - f->bptr; + uint k = f->bufend - f->bptr; if (!k) { @@ -181,20 +218,19 @@ void bwrite_slow(struct fastbuf *f, const void *b, uns l) } } -void -bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l) +void bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uint l) { while (l) { byte *fptr, *tptr; - uns favail, tavail, n; + uint favail, tavail, n; favail = bdirect_read_prepare(f, &fptr); if (!favail) { if (l == ~0U) return; - die("bbcopy: source exhausted"); + bthrow(f, "eof", "bbcopy: source exhausted"); } tavail = bdirect_write_prepare(t, &tptr); n = MIN(l, favail); @@ -207,26 +243,23 @@ bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l) } } -int -bconfig(struct fastbuf *f, uns item, int value) +int bconfig(struct fastbuf *f, uint item, int value) { - return f->config ? f->config(f, item, value) : -1; + return (f->config && !(f->flags & FB_DEAD)) ? f->config(f, item, value) : -1; } -void -brewind(struct fastbuf *f) +void brewind(struct fastbuf *f) { bflush(f); bsetpos(f, 0); } -int -bskip_slow(struct fastbuf *f, uns len) +int bskip_slow(struct fastbuf *f, uint len) { while (len) { byte *buf; - uns l = bdirect_read_prepare(f, &buf); + uint l = bdirect_read_prepare(f, &buf); if (!l) return 0; l = MIN(l, len); @@ -236,11 +269,12 @@ bskip_slow(struct fastbuf *f, uns len) return 1; } -ucw_off_t -bfilesize(struct fastbuf *f) +ucw_off_t bfilesize(struct fastbuf *f) { if (!f) return 0; + if (!f->seek) + return -1; ucw_off_t pos = btell(f); bflush(f); if (!f->seek(f, 0, SEEK_END)) @@ -252,26 +286,23 @@ bfilesize(struct fastbuf *f) /* Resources */ -static void -fb_res_detach(struct resource *r) +static void fb_res_detach(struct resource *r) { struct fastbuf *f = r->priv; f->res = NULL; } -static void -fb_res_free(struct resource *r) +static void fb_res_free(struct resource *r) { struct fastbuf *f = r->priv; f->res = NULL; bclose(f); } -static void -fb_res_dump(struct resource *r) +static void fb_res_dump(struct resource *r, uint indent UNUSED) { struct fastbuf *f = r->priv; - printf(" name=%s", f->name); + printf(" name=%s\n", f->name); } static const struct res_class fb_res_class = { @@ -281,8 +312,8 @@ static const struct res_class fb_res_class = { .free = fb_res_free, }; -void -fb_tie(struct fastbuf *f) +struct fastbuf *fb_tie(struct fastbuf *f) { f->res = res_new(&fb_res_class, f); + return f; }