summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/fseek.c
blob: 79a97587003108ad623d89621ac67777a6b7bd88 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
/***
*fseek.c - reposition file pointer on a stream
*
*	Copyright (c) 1985-1992, 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.
*
*******************************************************************************/

#include <cruntime.h>
#include <stdio.h>
#include <file2.h>
#include <assert.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 <os2dll.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 MTHREAD	/* multi-thread; define both fseek() and _lk_fseek() */

int _CALLTYPE1 fseek (
	FILE *stream,
	long offset,
	int whence
	)
{
	int retval;
#ifdef MTHREAD
	int index;
#endif

	assert(stream != NULL);

#ifdef MTHREAD
	index = _iob_index(stream);
#endif

	_lock_str(index);

	retval = _fseek_lk (stream, offset, whence);

	_unlock_str(index);

	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 _CALLTYPE1 _fseek_lk (

#else	/* non multi-thread; just define fseek() */

int _CALLTYPE1 fseek (

#endif	/* rejoin common code */

	FILE *str,
	long offset,
	int whence
	)
{


	REG1 FILE *stream;

	assert(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 (stream->_flag & _IORW)
		stream->_flag &= ~(_IOWRT|_IOREAD);

	/* 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
}