windows-nt/Source/XPSP1/NT/base/crts/crtw32/stdio/fseek.c
2020-09-26 16:20:57 +08:00

274 lines
9.5 KiB
C

/***
*fseek.c - reposition file pointer on a stream
*
* Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
*
*Purpose:
* defines fseek() - move the file pointer to new place in file
*
*Revision History:
* 10-13-83 RN initial version
* 06-26-85 TC added code to allow variable buffer lengths
* 02-10-87 BCM fixed '%' mistakenly used for '/'
* 03-04-87 JCR added errno settings
* 04-16-87 JCR added _IOUNGETC support for bug fix and changes whence
* from unsigned int to int (ANSI conformance)
* 04-17-87 JCR fseek() now clears end-of-file indicator flag _IOEOF
* (for ANSI conformance)
* 04-21-87 JCR be smart about lseek'ing to the end of the file and
* back
* 09-17-87 SKS handle case of '\n' at beginning of buffer (FCRLF flag)
* 09-24-87 JCR fixed an incorrect access to flag _IOEOF
* 09-28-87 JCR Corrected _iob2 indexing (now uses _iob_index() macro).
* 09-30-87 JCR Fixed buffer allocation bug, now use _getbuf()
* 11-04-87 JCR Multi-thread support
* 12-11-87 JCR Added "_LOAD_DS" to declaration
* 01-13-88 JCR Removed unnecessary calls to mthread fileno/feof/ferror
* 03-04-88 JCR Return value from read() must be treated as unsigned
* value
* 05-27-88 PHG Merged DLL and normal versions
* 06-06-88 JCR Optimized _iob2[] references
* 06-15-88 JCR Near reference to _iob[] entries; improve REG variables
* 08-25-88 GJF Don't use FP_OFF() macro for the 386
* 12-02-88 JCR Added _IOCTRLZ support (fixes bug pertaining to ^Z at
* eof)
* 04-12-89 JCR Ripped out all of the special read-only code. See the
* comments in the routine header for more information.
* 08-17-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 flat
* model). Also fixed copyright and indents.
* 02-15-90 GJF Fixed copyright
* 03-19-90 GJF Made calling type _CALLTYPE1, added #include
* <cruntime.h> and removed #include <register.h>.
* 05-29-90 SBM Use _flush, not [_]fflush[_lk]
* 07-23-90 SBM Replaced <assertm.h> by <assert.h>
* 10-02-90 GJF New-style function declarators.
* 01-21-91 GJF ANSI naming.
* 03-27-92 DJM POSIX support.
* 08-08-92 GJF Use seek method constants!
* 08-26-92 GJF Include unistd.h for POSIX build.
* 04-06-93 SKS Replace _CRTAPI* with __cdecl
* 05-24-93 GJF If the stream was opened for read-access-only, reduce
* _bufsiz after flushing the stream. This should reduce
* the expense of the next _filbuf call, and the overall
* burden of seek-and-do-small-reads patterns of file
* input.
* 06-22-93 GJF Check _flag for _IOSETVBUF (new) before changing
* buffer size.
* 11-05-93 GJF Merged with NT SDK version. Also, replaced MTHREAD
* with _MT.
* 02-06-94 CFW assert -> _ASSERTE.
* 02-20-95 GJF Merged in Mac version.
* 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
* 03-02-98 GJF Exception-safe locking.
* 05-17-99 PML Remove all Macintosh support.
*
*******************************************************************************/
#include <cruntime.h>
#include <stdio.h>
#include <file2.h>
#include <dbgint.h>
#ifdef _POSIX_
#include <unistd.h>
#else
#include <msdos.h>
#endif
#include <errno.h>
#include <malloc.h>
#include <io.h>
#include <stddef.h>
#include <internal.h>
#ifndef _POSIX_
#include <mtdll.h>
#endif
/***
*int fseek(stream, offset, whence) - reposition file pointer
*
*Purpose:
*
* Reposition file pointer to the desired location. The new location
* is calculated as follows:
* { whence=0, beginning of file }
* <offset> bytes + { whence=1, current position }
* { whence=2, end of file }
*
* Be careful to coordinate with buffering.
*
* - - - - - - - - - - - - -
*
* [NOTE: We used to bend over backwards to try and preserve the current
* buffer and maintain disk block alignment. This ended up making our
* code big and slow and complicated, and slowed us down quite a bit.
* Some of the things pertinent to the old implimentation:
*
* (1) Read-only: We only did the special code path if the file was
* opened read-only (_IOREAD). If the file was writable, we didn't
* try to optimize.
*
* (2) Buffering: We'd assign a buffer, if necessary, since the
* later code might need it (i.e., call _getbuf).
*
* (3) Ungetc: Fseek had to be careful NOT to save the buffer if
* an ungetc had ever been done on the buffer (flag _IOUNGETC).
*
* (4) Control ^Z: Fseek had to deal with ^Z after reading a
* new buffer's worth of data (flag _IOCTRLZ).
*
* (5) Seek-to-end-and-back: To determine if the new seek was within
* the current buffer, we had to 'normalize' the desired location.
* This means that we sometimes had to seek to the end of the file
* and back to determine what the 0-relative offset was. Two extra
* lseek() calls hurt performance.
*
* (6) CR/LF accounting - When trying to seek within a buffer that
* is in text mode, we had to go account for CR/LF expansion. This
* required us to look at every character up to the new offset and
* see if it was '\n' or not. In addition, we had to check the
* FCRLF flag to see if the new buffer started with '\n'.
*
* Again, all of these notes are for the OLD implimentation just to
* remind folks of some of the issues involving seeking within a buffer
* and maintaining buffer alignment. As an aside, I think this may have
* been a big win in the 'old days' on floppy-based systems but on newer
* fast hard disks, the extra code/complexity overwhelmed any gain.
*
* - - - - - - - - - - - - -
*
*Entry:
* FILE *stream - file to reposition file pointer on
* long offset - offset to seek to
* int whence - origin offset is measured from (0=beg, 1=current pos,
* 2=end)
*
*Exit:
* returns 0 if succeeds
* returns -1 and sets errno if fails
* fields of FILE struct will be changed
*
*Exceptions:
*
*******************************************************************************/
#ifdef _MT /* multi-thread; define both fseek() and _lk_fseek() */
int __cdecl fseek (
FILE *stream,
long offset,
int whence
)
{
int retval;
_ASSERTE(stream != NULL);
_lock_str(stream);
__try {
retval = _fseek_lk (stream, offset, whence);
}
__finally {
_unlock_str(stream);
}
return(retval);
}
/***
*_fseek_lk() - Core fseek() routine (stream is locked)
*
*Purpose:
* Core fseek() routine; assumes that caller has the stream locked.
*
* [See fseek() for more info.]
*
*Entry: [See fseek()]
*
*Exit: [See fseek()]
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _fseek_lk (
#else /* non multi-thread; just define fseek() */
int __cdecl fseek (
#endif /* rejoin common code */
FILE *str,
long offset,
int whence
)
{
REG1 FILE *stream;
_ASSERTE(str != NULL);
/* Init stream pointer */
stream = str;
if ( !inuse(stream) || ((whence != SEEK_SET) && (whence != SEEK_CUR) &&
(whence != SEEK_END)) ) {
errno=EINVAL;
return(-1);
}
/* Clear EOF flag */
stream->_flag &= ~_IOEOF;
/* If seeking relative to current location, then convert to
a seek relative to beginning of file. This accounts for
buffering, etc. by letting fseek() tell us where we are. */
if (whence == SEEK_CUR) {
offset += _ftell_lk(stream);
whence = SEEK_SET;
}
/* Flush buffer as necessary */
#ifdef _POSIX_
/*
* If the stream was last read, we throw away the buffer so
* that a possible subsequent write will encounter a clean
* buffer. (The Win32 version of fflush() throws away the
* buffer if it's read.) Write buffers must be flushed.
*/
if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOREAD) {
stream->_ptr = stream->_base;
stream->_cnt = 0;
} else {
_flush(stream);
}
#else
_flush(stream);
#endif
/* If file opened for read/write, clear flags since we don't know
what the user is going to do next. If the file was opened for
read access only, decrease _bufsiz so that the next _filbuf
won't cost quite so much */
if (stream->_flag & _IORW)
stream->_flag &= ~(_IOWRT|_IOREAD);
else if ( (stream->_flag & _IOREAD) && (stream->_flag & _IOMYBUF) &&
!(stream->_flag & _IOSETVBUF) )
stream->_bufsiz = _SMALL_BUFSIZ;
/* Seek to the desired locale and return. */
#ifdef _POSIX_
return(lseek(fileno(stream), offset, whence) == -1L ? -1 : 0);
#else
return(_lseek(_fileno(stream), offset, whence) == -1L ? -1 : 0);
#endif
}