summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/ftell.c
blob: 8f59e648acec807480e8970df07b22566e6798f7 (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
/***
*ftell.c - get current file position
*
*	Copyright (c) 1985-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	defines ftell() - find current current position of file pointer
*
*Revision History:
*	09-02-83  RN	initial version
*	??-??-??  TC	added code to allow variable buffer sizes
*	05-22-86  TC	added code to seek to send if last operation was a
*			write and append mode specified
*	11-20-86  SKS	do not seek to end of file in append mode
*	12-01-86  SKS	fix off-by-1 problem in text mode when last byte in
*			buffer was a '\r', and it was followed by a '\n'. Since
*			the \n was pushed back and the \r was discarded, we
*			must adjust the computed position for the \r.
*	02-09-87  JCR	Added errno set code (if flag (_IORW not set)
*	09-09-87  JCR	Optimized to eliminate two lseek() calls in binary mode.
*	09-28-87  JCR	Corrected _iob2 indexing (now uses _iob_index() macro).
*	11-04-87  JCR	Multi-thread version
*	12-11-87  JCR	Added "_LOAD_DS" to declaration
*	01-13-88  JCR	Removed unnecessary calls to mthread fileno/feof/ferror
*	05-27-88  PHG	Merged DLL and normal versions
*	06-06-88  JCR	Use _iob2_ macro instead of _iob_index
*	06-15-88  JCR	Near reference to _iob[] entries; improve REG variables
*	07-27-88  JCR	Changed some variables from int to unsigned (bug fix)
*	08-25-88  GJF	Don't use FP_OFF() macro for the 386
*	12-05-88  JCR	Added _IOCTRLZ support (fixes bug pertaining to ^Z at
*			eof)
*	08-17-89  GJF	Cleanup, now specific to OS/2 2.0 (i.e., 386 flat
*			model), also fixed copyright
*	02-15-90  GJF	_iob[], _iob2[] merge. Also, fixed copyright and
*			indents.
*	03-19-90  GJF	Made calling type _CALLTYPE1, added #include
*			<cruntime.h> and removed #include <register.h>.
*	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-26-92  GJF	Include unistd.h for POSIX build.
*	09-01-92  GJF	Fixed POSIX support (was returning -1 for all except
*			read-write streams).
*
*******************************************************************************/

#include <cruntime.h>
#include <stdio.h>
#include <file2.h>
#include <assert.h>
#include <errno.h>
#ifdef	_POSIX_
#include <unistd.h>
#else
#include <msdos.h>
#endif
#include <stddef.h>
#include <io.h>
#include <internal.h>
#ifndef _POSIX_
#include <os2dll.h>
#endif

/***
*long ftell(stream) - query stream file pointer
*
*Purpose:
*	Find out what stream's position is. coordinate with buffering; adjust
*	backward for read-ahead and forward for write-behind. This is NOT
*	equivalent to fseek(stream,0L,1), because fseek will remove an ungetc,
*	may flush buffers, etc.
*
*Entry:
*	FILE *stream - stream to query for position
*
*Exit:
*	return present file position if succeeds
*	returns -1L and sets errno if fails
*
*Exceptions:
*
*******************************************************************************/

#ifdef MTHREAD	/* multi-thread; define both ftell() and _lk_ftell() */

long _CALLTYPE1 ftell (
	FILE *stream
	)
{
	long retval;
#ifdef MTHREAD
	int index;
#endif

	assert(stream != NULL);

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

	_lock_str(index);

	retval = _ftell_lk (stream);

	_unlock_str(index);

	return(retval);
}


/***
*_ftell_lk() - Ftell() core routine (assumes stream is locked).
*
*Purpose:
*	Core ftell() routine; assumes caller has aquired stream lock).
*
*	[See ftell() above for more info.]
*
*Entry: [See ftell()]
*
*Exit:	[See ftell()]
*
*Exceptions:
*
*******************************************************************************/

long _CALLTYPE1 _ftell_lk (

#else	/* non multi-thread; define only ftell() */

long _CALLTYPE1 ftell (

#endif	/* rejoin common code */

	FILE *str
	)
{
	REG1 FILE *stream;
	unsigned int offset;
	long filepos;
#ifndef _POSIX_
	REG2 char *p;
	char *max;
#endif
	int fd;
	unsigned int rdcnt;

	assert(str != NULL);

	/* Init stream pointer and file descriptor */
	stream = str;
#ifdef _POSIX_
	fd = fileno(stream);
#else
	fd = _fileno(stream);
#endif

	if (stream->_cnt < 0)
		stream->_cnt = 0;

#ifdef _POSIX_
	if ((filepos = lseek(fd, 0L, SEEK_CUR)) < 0L)
#else
	if ((filepos = _lseek(fd, 0L, SEEK_CUR)) < 0L)
#endif
		return(-1L);

	if (!bigbuf(stream))		/* _IONBF or no buffering designated */
		return(filepos - stream->_cnt);

	offset = stream->_ptr - stream->_base;

#ifndef _POSIX_
	if (stream->_flag & (_IOWRT|_IOREAD)) {
		if (_osfile[fd] & FTEXT)
			for (p = stream->_base; p < stream->_ptr; p++)
				if (*p == '\n')  /* adjust for '\r' */
					offset++;
	}
	else if (!(stream->_flag & _IORW)) {
		errno=EINVAL;
		return(-1L);
	}
#endif

	if (filepos == 0L)
		return((long)offset);

	if (stream->_flag & _IOREAD)	/* go to preceding sector */

		if (stream->_cnt == 0)	/* filepos holds correct location */
			offset = 0;

		else {

			/* Subtract out the number of unread bytes left in the
			   buffer. [We can't simply use _iob[]._bufsiz because
			   the last read may have hit EOF and, thus, the buffer
			   was not completely filled.] */

			rdcnt = stream->_cnt + (stream->_ptr - stream->_base);

#ifndef _POSIX_
			/* If text mode, adjust for the cr/lf substitution. If
			   binary mode, we're outta here. */
			if (_osfile[fd] & FTEXT) {
				/* (1) If we're not at eof, simply copy _bufsiz
				   onto rdcnt to get the # of untranslated
				   chars read. (2) If we're at eof, we must
				   look through the buffer expanding the '\n'
				   chars one at a time. */

				/* [NOTE: Performance issue -- it is faster to
				   do the two _lseek() calls than to blindly go
				   through and expand the '\n' chars regardless
				   of whether we're at eof or not.] */

				if (_lseek(fd, 0L, 2) == filepos) {

					max = stream->_base + rdcnt;
					for (p = stream->_base; p < max; p++)
						if (*p == '\n')
							/* adjust for '\r' */
							rdcnt++;

					/* If last byte was ^Z, the lowio read
					   didn't tell us about it.  Check flag
					   and bump count, if necessary. */

					if (stream->_flag & _IOCTRLZ)
						++rdcnt;
				}

				else {

					_lseek(fd, filepos, 0);
					rdcnt = stream->_bufsiz;

					/* If first byte in untranslated buffer
					   was a '\n', assume it was preceeded
					   by a '\r' which was discarded by the
					   previous read operation and count
					   the '\n'. */
					if  (_osfile[fd] & FCRLF)
						++rdcnt;
				}

			} /* end if FTEXT */
#endif /* !_POSIX_ */

			filepos -= (long)rdcnt;

		} /* end else stream->_cnt != 0 */

	return(filepos + (long)offset);
}