diff options
Diffstat (limited to 'src/base/bufio/seek.c')
-rw-r--r-- | src/base/bufio/seek.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/base/bufio/seek.c b/src/base/bufio/seek.c new file mode 100644 index 0000000..5d25173 --- /dev/null +++ b/src/base/bufio/seek.c @@ -0,0 +1,57 @@ +#include "internal.h" + +int +bio·seek(io·Header *io, intptr offset, int whence, intptr *pos) +{ + intptr n,d,cap; + + switch(io->state){ + default: + fmt·fprint(2, "seek: unknown state %d\n", io->state); + return io·BufEof; + case io·BufEnd: + io->state = io·BufRdr; + io->ilen = 0; + io->g = io->e; + /* fallthrough */ + case io·BufRdr: + n = offset; + if(whence == sys·SeekCur){ + n += bio·offset(io); + whence = sys·SeekSet; + } + + /* can we seek inside our buffer */ + if(whence == sys·SeekSet){ + d = n - bio·offset(io); + cap = io->e - io->g; + if(-cap <= d && d <= cap){ + io->ilen += d; + if(d >= 0){ + if(io->ilen <= 0){ + *pos = n; + return 0; + } + }else{ + if(io->e - io->g >= -io->ilen){ + *pos = n; + return 0; + } + } + } + } + + /* nope, call the kernel to do it for us */ + sys·seek(io->fd, offset, whence, &n); + io->ilen = 0; + io->g = io->e; + break; + + case io·BufWtr: + bio·flush(io); + sys·seek(io->fd, offset, whence, &n); + break; + } + io->pos = *pos = n; + return 0; +} |