diff options
Diffstat (limited to 'stdio/fseek.c')
-rw-r--r-- | stdio/fseek.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/stdio/fseek.c b/stdio/fseek.c new file mode 100644 index 0000000000..a5abfe4866 --- /dev/null +++ b/stdio/fseek.c @@ -0,0 +1,177 @@ +/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Move the file position of STREAM to OFFSET + bytes from the beginning of the file if WHENCE + is SEEK_SET, the end of the file is it is SEEK_END, + or the current position if it is SEEK_CUR. */ +int +DEFUN(fseek, (stream, offset, whence), + register FILE *stream AND long int offset AND int whence) +{ + long int o; + + if (!__validfp (stream)) + { + errno = EINVAL; + return EOF; + } + + /* Write out any pending data. */ + if (stream->__mode.__write && __flshfp (stream, EOF) == EOF) + return EOF; + + /* Make sure we know the current offset info. */ + if (__stdio_check_offset (stream) == EOF) + return EOF; + + /* We are moving the file position, so we are no longer at EOF. */ + stream->__eof = 0; + + if (stream->__pushed_back) + { + /* Discard the character pushed back by ungetc. */ + stream->__bufp = stream->__pushback_bufp; + stream->__pushed_back = 0; + } + + /* Check the WHENCE argument for validity, and process OFFSET + into an absolute position in O. By the end of this switch, + either we have returned, or O contains an absolute position. */ + o = offset; + switch (whence) + { + default: + errno = EINVAL; + return EOF; + + case SEEK_END: + /* We don't know where the end of the file is, + so seek to the position in the file the user asked + for, and then look where that is. */ + if (stream->__io_funcs.__seek == NULL) + { + errno = ESPIPE; + return EOF; + } + else + { + fpos_t pos = (fpos_t) o; + if ((*stream->__io_funcs.__seek) + (stream->__cookie, &pos, SEEK_END) < 0) + { + if (errno == ESPIPE) + stream->__io_funcs.__seek = NULL; + return EOF; + } + stream->__offset = pos; + /* Make O be absolute, rather than + relative to the end of the file. */ + o = pos; + } + + /* Fall through to try an absolute seek. */ + + case SEEK_SET: + /* Make O be relative to the buffer. */ + o -= stream->__target; + /* Make O be relative to the current position in the buffer. */ + o -= stream->__bufp - stream->__buffer; + + /* Fall through to see if we can do it by + moving the pointer around in the buffer. */ + + case SEEK_CUR: + /* If the offset is small enough, we can just + move the pointer around in the buffer. */ + +#if 0 /* Why did I think this would ever work??? */ + if (stream->__put_limit > stream->__buffer) + { + /* We are writing. */ + if (stream->__bufp + o >= stream->__buffer && + stream->__put_limit > stream->__bufp + o && + stream->__get_limit > stream->__bufp + o) + { + /* We have read all the data we will change soon. + We can just move the pointer around. */ + stream->__bufp += o; + return 0; + } + else + { + /* Flush the buffer. */ + if (__flshfp(stream, EOF) == EOF) + return EOF; + } + } else +#endif + if (o < 0 ? + (-o <= stream->__bufp - stream->__buffer) : + (o <= stream->__get_limit - stream->__bufp)) + { + stream->__bufp += o; + return 0; + } + + /* Turn it into an absolute seek. */ + o += stream->__bufp - stream->__buffer; + o += stream->__target; + break; + } + + if (o < 0) + { + /* Negative file position is meaningless. */ + errno = EINVAL; + return -1; + } + + /* O is now an absolute position, the new target. */ + stream->__target = o; + + /* Set bufp and both end pointers to the beginning of the buffer. + The next i/o will force a call to the input/output room function. */ + stream->__bufp + = stream->__get_limit = stream->__put_limit = stream->__buffer; + + /* Make sure __flshfp doesn't think the put_limit is at the beginning + of the buffer because of line-buffering magic. */ + stream->__linebuf_active = 0; + + /* If there is no seek function, seeks always fail. */ + if (stream->__io_funcs.__seek == NULL) + { + /* This is preemptive, since we don't actually do the seeking. + But it makes more sense for fseek to to fail with ESPIPE + than for the next reading or writing operation to fail + that way. */ + errno = ESPIPE; + return EOF; + } + + /* Don't actually seek. The next reading or writing operation + will force a call to the input or output room function, + which will move to the target file position before reading or writing. */ + return 0; +} |