/*** *fseek.c - reposition file pointer on a stream * * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. * *Purpose: * defines fseek() - move the file pointer to new place in file * *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include /*** *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 } * 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 int __cdecl fseek ( FILE *stream, long offset, int whence ) { int retval; _ASSERTE(stream != NULL); _lock_str(stream); retval = _fseek_lk (stream, offset, whence); _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 /* _MT */ int __cdecl fseek ( #endif /* _MT */ 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 */ _flush(stream); /* 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); #if !defined (_M_MPPC) && !defined (_M_M68K) else if ( (stream->_flag & _IOREAD) && (stream->_flag & _IOMYBUF) && !(stream->_flag & _IOSETVBUF) ) stream->_bufsiz = _SMALL_BUFSIZ; #endif /* !defined (_M_MPPC) && !defined (_M_M68K) */ /* Seek to the desired locale and return. */ return(_lseek(_fileno(stream), offset, whence) == -1L ? -1 : 0); }