Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
9.5 KiB

  1. /***
  2. *ftell.c - get current file position
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines ftell() - find current current position of file pointer
  8. *
  9. *Revision History:
  10. * 09-02-83 RN initial version
  11. * ??-??-?? TC added code to allow variable buffer sizes
  12. * 05-22-86 TC added code to seek to send if last operation was a
  13. * write and append mode specified
  14. * 11-20-86 SKS do not seek to end of file in append mode
  15. * 12-01-86 SKS fix off-by-1 problem in text mode when last byte in
  16. * buffer was a '\r', and it was followed by a '\n'. Since
  17. * the \n was pushed back and the \r was discarded, we
  18. * must adjust the computed position for the \r.
  19. * 02-09-87 JCR Added errno set code (if flag (_IORW not set)
  20. * 09-09-87 JCR Optimized to eliminate two lseek() calls in binary mode.
  21. * 09-28-87 JCR Corrected _iob2 indexing (now uses _iob_index() macro).
  22. * 11-04-87 JCR Multi-thread version
  23. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  24. * 01-13-88 JCR Removed unnecessary calls to mthread fileno/feof/ferror
  25. * 05-27-88 PHG Merged DLL and normal versions
  26. * 06-06-88 JCR Use _iob2_ macro instead of _iob_index
  27. * 06-15-88 JCR Near reference to _iob[] entries; improve REG variables
  28. * 07-27-88 JCR Changed some variables from int to unsigned (bug fix)
  29. * 08-25-88 GJF Don't use FP_OFF() macro for the 386
  30. * 12-05-88 JCR Added _IOCTRLZ support (fixes bug pertaining to ^Z at
  31. * eof)
  32. * 08-17-89 GJF Cleanup, now specific to OS/2 2.0 (i.e., 386 flat
  33. * model), also fixed copyright
  34. * 02-15-90 GJF _iob[], _iob2[] merge. Also, fixed copyright and
  35. * indents.
  36. * 03-19-90 GJF Made calling type _CALLTYPE1, added #include
  37. * <cruntime.h> and removed #include <register.h>.
  38. * 07-23-90 SBM Replaced <assertm.h> by <assert.h>
  39. * 10-02-90 GJF New-style function declarators.
  40. * 01-21-91 GJF ANSI naming.
  41. * 03-27-92 DJM POSIX support.
  42. * 08-26-92 GJF Include unistd.h for POSIX build.
  43. * 09-01-92 GJF Fixed POSIX support (was returning -1 for all except
  44. * read-write streams).
  45. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  46. * 06-29-93 GJF Fixed bug related to variable buffer sizing (Cuda
  47. * #5456).
  48. * 09-06-94 CFW Replace MTHREAD with _MT.
  49. * 02-06-94 CFW assert -> _ASSERTE.
  50. * 02-20-95 GJF Merged in Mac version.
  51. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  52. * 06-12-95 GJF Replaced _osfile[] with _osfile() (macro referencing
  53. * field in ioinfo struct).
  54. * 02-27-98 RKP Add 64 bit support.
  55. * 03-02-98 GJF Exception-safe locking.
  56. * 05-17-99 PML Remove all Macintosh support.
  57. *
  58. *******************************************************************************/
  59. #include <cruntime.h>
  60. #include <stdio.h>
  61. #include <file2.h>
  62. #include <dbgint.h>
  63. #include <errno.h>
  64. #ifdef _POSIX_
  65. #include <unistd.h>
  66. #else
  67. #include <msdos.h>
  68. #endif
  69. #include <stddef.h>
  70. #include <io.h>
  71. #include <internal.h>
  72. #ifndef _POSIX_
  73. #include <mtdll.h>
  74. #endif
  75. /***
  76. *long ftell(stream) - query stream file pointer
  77. *
  78. *Purpose:
  79. * Find out what stream's position is. coordinate with buffering; adjust
  80. * backward for read-ahead and forward for write-behind. This is NOT
  81. * equivalent to fseek(stream,0L,1), because fseek will remove an ungetc,
  82. * may flush buffers, etc.
  83. *
  84. *Entry:
  85. * FILE *stream - stream to query for position
  86. *
  87. *Exit:
  88. * return present file position if succeeds
  89. * returns -1L and sets errno if fails
  90. *
  91. *Exceptions:
  92. *
  93. *******************************************************************************/
  94. #ifdef _MT /* multi-thread; define both ftell() and _lk_ftell() */
  95. long __cdecl ftell (
  96. FILE *stream
  97. )
  98. {
  99. long retval;
  100. _ASSERTE(stream != NULL);
  101. _lock_str(stream);
  102. __try {
  103. retval = _ftell_lk (stream);
  104. }
  105. __finally {
  106. _unlock_str(stream);
  107. }
  108. return(retval);
  109. }
  110. /***
  111. *_ftell_lk() - Ftell() core routine (assumes stream is locked).
  112. *
  113. *Purpose:
  114. * Core ftell() routine; assumes caller has aquired stream lock).
  115. *
  116. * [See ftell() above for more info.]
  117. *
  118. *Entry: [See ftell()]
  119. *
  120. *Exit: [See ftell()]
  121. *
  122. *Exceptions:
  123. *
  124. *******************************************************************************/
  125. long __cdecl _ftell_lk (
  126. #else /* non multi-thread; define only ftell() */
  127. long __cdecl ftell (
  128. #endif /* rejoin common code */
  129. FILE *str
  130. )
  131. {
  132. REG1 FILE *stream;
  133. unsigned int offset;
  134. long filepos;
  135. #if !defined(_POSIX_)
  136. REG2 char *p;
  137. char *max;
  138. #endif
  139. int fd;
  140. unsigned int rdcnt;
  141. _ASSERTE(str != NULL);
  142. /* Init stream pointer and file descriptor */
  143. stream = str;
  144. #ifdef _POSIX_
  145. fd = fileno(stream);
  146. #else
  147. fd = _fileno(stream);
  148. #endif
  149. if (stream->_cnt < 0)
  150. stream->_cnt = 0;
  151. #ifdef _POSIX_
  152. if ((filepos = lseek(fd, 0L, SEEK_CUR)) < 0L)
  153. #else
  154. if ((filepos = _lseek(fd, 0L, SEEK_CUR)) < 0L)
  155. #endif
  156. return(-1L);
  157. if (!bigbuf(stream)) /* _IONBF or no buffering designated */
  158. return(filepos - stream->_cnt);
  159. offset = (unsigned)(stream->_ptr - stream->_base);
  160. #ifndef _POSIX_
  161. if (stream->_flag & (_IOWRT|_IOREAD)) {
  162. if (_osfile(fd) & FTEXT)
  163. for (p = stream->_base; p < stream->_ptr; p++)
  164. if (*p == '\n') /* adjust for '\r' */
  165. offset++;
  166. }
  167. else if (!(stream->_flag & _IORW)) {
  168. errno=EINVAL;
  169. return(-1L);
  170. }
  171. #endif
  172. if (filepos == 0L)
  173. return((long)offset);
  174. if (stream->_flag & _IOREAD) /* go to preceding sector */
  175. if (stream->_cnt == 0) /* filepos holds correct location */
  176. offset = 0;
  177. else {
  178. /* Subtract out the number of unread bytes left in the buffer.
  179. [We can't simply use _iob[]._bufsiz because the last read
  180. may have hit EOF and, thus, the buffer was not completely
  181. filled.] */
  182. rdcnt = stream->_cnt + (unsigned)(stream->_ptr - stream->_base);
  183. #if !defined(_POSIX_)
  184. /* If text mode, adjust for the cr/lf substitution. If binary
  185. mode, we're outta here. */
  186. if (_osfile(fd) & FTEXT) {
  187. /* (1) If we're not at eof, simply copy _bufsiz onto rdcnt
  188. to get the # of untranslated chars read. (2) If we're at
  189. eof, we must look through the buffer expanding the '\n'
  190. chars one at a time. */
  191. /* [NOTE: Performance issue -- it is faster to do the two
  192. _lseek() calls than to blindly go through and expand the
  193. '\n' chars regardless of whether we're at eof or not.] */
  194. if (_lseek(fd, 0L, 2) == filepos) {
  195. max = stream->_base + rdcnt;
  196. for (p = stream->_base; p < max; p++)
  197. if (*p == '\n')
  198. /* adjust for '\r' */
  199. rdcnt++;
  200. /* If last byte was ^Z, the lowio read didn't tell us
  201. about it. Check flag and bump count, if necessary. */
  202. if (stream->_flag & _IOCTRLZ)
  203. ++rdcnt;
  204. }
  205. else {
  206. _lseek(fd, filepos, 0);
  207. /* We want to set rdcnt to the number of bytes
  208. originally read into the stream buffer (before
  209. crlf->lf translation). In most cases, this will
  210. just be _bufsiz. However, the buffer size may have
  211. been changed, due to fseek optimization, at the
  212. END of the last _filbuf call. */
  213. if ( (rdcnt <= _SMALL_BUFSIZ) &&
  214. (stream->_flag & _IOMYBUF) &&
  215. !(stream->_flag & _IOSETVBUF) )
  216. {
  217. /* The translated contents of the buffer is small
  218. and we are not at eof. The buffer size must have
  219. been set to _SMALL_BUFSIZ during the last
  220. _filbuf call. */
  221. rdcnt = _SMALL_BUFSIZ;
  222. }
  223. else
  224. rdcnt = stream->_bufsiz;
  225. /* If first byte in untranslated buffer was a '\n',
  226. assume it was preceeded by a '\r' which was
  227. discarded by the previous read operation and count
  228. the '\n'. */
  229. if (_osfile(fd) & FCRLF)
  230. ++rdcnt;
  231. }
  232. } /* end if FTEXT */
  233. #endif
  234. filepos -= (long)rdcnt;
  235. } /* end else stream->_cnt != 0 */
  236. return(filepos + (long)offset);
  237. }