X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lib%2Ffastbuf.c;h=be7e979015e0f797021cd9eb19c53ea68188f6de;hb=5a78c3505ae7fa76a061e26676450049ec5946d5;hp=9756c978ce03592b1ba06a8e39f05690ca797248;hpb=1641c17df8008adfb4720052ec01e427543cdd94;p=libucw.git diff --git a/lib/fastbuf.c b/lib/fastbuf.c index 9756c978..be7e9790 100644 --- a/lib/fastbuf.c +++ b/lib/fastbuf.c @@ -1,125 +1,51 @@ /* - * Sherlock Library -- Fast File Buffering + * UCW Library -- Fast Buffered I/O * - * (c) 1997 Martin Mares, + * (c) 1997--2007 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 -#include -#include -#include - -#include "lib.h" -#include "fastbuf.h" - -struct fastbuf *__bfdopen(int fd, uns buffer, byte *name) -{ - struct fastbuf *b = xmalloc(sizeof(struct fastbuf)); - - b->buflen = buffer; - b->buffer = xmalloc(buffer); - b->bptr = b->bstop = b->buffer; - b->bufend = b->buffer + buffer; - b->name = stralloc(name); - b->pos = b->fdpos = 0; - b->fd = fd; - return b; -} - -struct fastbuf * -bopen(byte *name, uns mode, uns buffer) -{ - int fd = open(name, mode, 0666); - - if (fd < 0) - die("Unable to %s file %s: %m", - (mode & O_CREAT) ? "create" : "open", name); - return __bfdopen(fd, buffer, name); -} - -struct fastbuf * -bfdopen(int fd, uns buffer) -{ - byte x[32]; - - sprintf(x, "fd%d", fd); - return __bfdopen(fd, buffer, x); -} void bclose(struct fastbuf *f) { - bflush(f); - close(f->fd); - free(f->name); - free(f->buffer); - free(f); -} - -static int -rdbuf(struct fastbuf *f) -{ - int l = read(f->fd, f->buffer, f->buflen); - - if (l < 0) - die("Error reading %s: %m", f->name); - f->bptr = f->buffer; - f->bstop = f->buffer + l; - f->pos = f->fdpos; - f->fdpos += l; - return l; -} - -static void -wrbuf(struct fastbuf *f) -{ - int l = f->bptr - f->buffer; - - if (l) + if (f) { - if (write(f->fd, f->buffer, l) != l) - die("Error writing %s: %m"); - f->bptr = f->buffer; - f->fdpos += l; - f->pos = f->fdpos; + bflush(f); + if (f->close) + f->close(f); } } void bflush(struct fastbuf *f) { - if (f->bptr != f->buffer) - { /* Have something to flush */ - if (f->bstop > f->buffer) - { /* And it's read data */ - f->bptr = f->bstop = f->buffer; - } - else - { /* Write data */ - wrbuf(f); - } - } + if (f->bptr > f->bstop) + f->spout(f); + else if (f->bstop > f->buffer) + f->bptr = f->bstop = f->buffer; } -inline void bsetpos(struct fastbuf *f, uns pos) +inline void bsetpos(struct fastbuf *f, sh_off_t pos) { - if (pos >= f->pos - && (pos <= f->pos + (f->bptr - f->buffer) || pos <= f->pos + (f->bstop - f->buffer))) - { - f->bptr = f->buffer + (pos - f->pos); - } + /* We can optimize seeks only when reading */ + if (pos >= f->pos - (f->bstop - f->buffer) && pos <= f->pos) + f->bptr = f->bstop + (pos - f->pos); else { bflush(f); - if (f->fdpos != pos && lseek(f->fd, pos, SEEK_SET) < 0) - die("lseek on %s: %m", f->name); - f->fdpos = f->pos = pos; + if (!f->seek || !f->seek(f, pos, SEEK_SET)) + die("bsetpos: stream not seekable"); } } -void bseek(struct fastbuf *f, uns pos, int whence) +void bseek(struct fastbuf *f, sh_off_t pos, int whence) { - int l; - switch (whence) { case SEEK_SET: @@ -128,10 +54,8 @@ void bseek(struct fastbuf *f, uns pos, int whence) return bsetpos(f, btell(f) + pos); case SEEK_END: bflush(f); - l = lseek(f->fd, pos, whence); - if (l < 0) - die("lseek on %s: %m", f->name); - f->fdpos = f->pos = l; + if (!f->seek || !f->seek(f, pos, SEEK_END)) + die("bseek: stream not seekable"); break; default: die("bseek: invalid whence=%d", whence); @@ -142,80 +66,40 @@ int bgetc_slow(struct fastbuf *f) { if (f->bptr < f->bstop) return *f->bptr++; - if (!rdbuf(f)) - return EOF; + if (!f->refill(f)) + return -1; return *f->bptr++; } -void bputc_slow(struct fastbuf *f, byte c) -{ - if (f->bptr >= f->bufend) - wrbuf(f); - *f->bptr++ = c; -} - -word bgetw_slow(struct fastbuf *f) -{ - word w = bgetc_slow(f); -#ifdef CPU_BIG_ENDIAN - return (w << 8) | bgetc_slow(f); -#else - return w | (bgetc_slow(f) << 8); -#endif -} - -ulg bgetl_slow(struct fastbuf *f) -{ - ulg l = bgetc_slow(f); -#ifdef CPU_BIG_ENDIAN - l = (l << 8) | bgetc_slow(f); - l = (l << 8) | bgetc_slow(f); - return (l << 8) | bgetc_slow(f); -#else - l = (bgetc_slow(f) << 8) | l; - l = (bgetc_slow(f) << 16) | l; - return (bgetc_slow(f) << 24) | l; -#endif -} - -void bputw_slow(struct fastbuf *f, word w) +int bpeekc_slow(struct fastbuf *f) { -#ifdef CPU_BIG_ENDIAN - bputc_slow(f, w >> 8); - bputc_slow(f, w); -#else - bputc_slow(f, w); - bputc_slow(f, w >> 8); -#endif + if (f->bptr < f->bstop) + return *f->bptr; + if (!f->refill(f)) + return -1; + return *f->bptr; } -void bputl_slow(struct fastbuf *f, ulg l) +void bputc_slow(struct fastbuf *f, uns c) { -#ifdef CPU_BIG_ENDIAN - bputc_slow(f, l >> 24); - bputc_slow(f, l >> 16); - bputc_slow(f, l >> 8); - bputc_slow(f, l); -#else - bputc_slow(f, l); - bputc_slow(f, l >> 8); - bputc_slow(f, l >> 16); - bputc_slow(f, l >> 24); -#endif + if (f->bptr >= f->bufend) + f->spout(f); + *f->bptr++ = c; } -void bread_slow(struct fastbuf *f, void *b, uns l) +uns bread_slow(struct fastbuf *f, void *b, uns l, uns check) { + uns total = 0; while (l) { uns k = f->bstop - f->bptr; if (!k) { - rdbuf(f); + f->refill(f); k = f->bstop - f->bptr; if (!k) - die("bread on %s: file exhausted", f->name); + break; } if (k > l) k = l; @@ -223,10 +107,14 @@ void bread_slow(struct fastbuf *f, void *b, uns l) f->bptr += k; b = (byte *)b + k; l -= k; + total += k; } + if (check && total && l) + die("breadb: short read"); + return total; } -void bwrite_slow(struct fastbuf *f, void *b, uns l) +void bwrite_slow(struct fastbuf *f, const void *b, uns l) { while (l) { @@ -234,7 +122,7 @@ void bwrite_slow(struct fastbuf *f, void *b, uns l) if (!k) { - wrbuf(f); + f->spout(f); k = f->bufend - f->bptr; } if (k > l) @@ -246,63 +134,71 @@ void bwrite_slow(struct fastbuf *f, void *b, uns l) } } -void bbcopy(struct fastbuf *f, struct fastbuf *t, uns l) +void +bbcopy_slow(struct fastbuf *f, struct fastbuf *t, uns l) { - uns rf = f->bstop - f->bptr; - uns rt = t->bufend - t->bptr; - - if (!l) - return; - if (rf && rt) - { - uns k = l; - if (k > rf) - k = rf; - if (k > rt) - k = rt; - memcpy(t->bptr, f->bptr, k); - t->bptr += k; - f->bptr += k; - l -= k; - } - while (l >= t->buflen) - { - wrbuf(t); - if (read(f->fd, t->buffer, t->buflen) != t->buflen) - die("bbcopy: %s exhausted", f->name); - f->fdpos += t->buflen; - t->bptr = t->bufend; - l -= t->buflen; - } while (l) { - uns k = t->bufend - t->bptr; + byte *fptr, *tptr; + uns favail, tavail, n; - if (!k) + favail = bdirect_read_prepare(f, &fptr); + if (!favail) { - wrbuf(t); - k = t->bufend - t->bptr; + if (l == ~0U) + return; + die("bbcopy: source exhausted"); } - if (k > l) - k = l; - bread(f, t->bptr, k); - t->bptr += k; - l -= k; + tavail = bdirect_write_prepare(t, &tptr); + n = MIN(l, favail); + n = MIN(n, tavail); + memcpy(tptr, fptr, n); + bdirect_read_commit(f, fptr + n); + bdirect_write_commit(t, tptr + n); + if (l != ~0U) + l -= n; } } -#ifdef TEST +int +bconfig(struct fastbuf *f, uns item, int value) +{ + return f->config ? f->config(f, item, value) : -1; +} -int main(int argc, char **argv) +void +brewind(struct fastbuf *f) { - struct fastbuf *f, *t; - int c; + bflush(f); + bsetpos(f, 0); +} - f = bopen("/etc/profile", O_RDONLY, 16); - t = bfdopen(1, 13); - bbcopy(f, t, 100); - bclose(f); - bclose(t); +int +bskip_slow(struct fastbuf *f, uns len) +{ + while (len) + { + byte *buf; + uns l = bdirect_read_prepare(f, &buf); + if (!l) + return 0; + l = MIN(l, len); + bdirect_read_commit(f, buf+l); + len -= l; + } + return 1; } -#endif +sh_off_t +bfilesize(struct fastbuf *f) +{ + if (!f) + return 0; + sh_off_t pos = btell(f); + bflush(f); + if (!f->seek(f, 0, SEEK_END)) + return -1; + sh_off_t len = btell(f); + bsetpos(f, pos); + return len; +}