home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / ftell.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  8KB  |  225 lines

  1. /***
  2. *ftell.c - get current file position
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines ftell() - find current current position of file pointer
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <stdio.h>
  13. #include <file2.h>
  14. #include <dbgint.h>
  15. #include <errno.h>
  16. #include <msdos.h>
  17. #include <stddef.h>
  18. #include <io.h>
  19. #include <internal.h>
  20. #include <mtdll.h>
  21.  
  22. /***
  23. *long ftell(stream) - query stream file pointer
  24. *
  25. *Purpose:
  26. *       Find out what stream's position is. coordinate with buffering; adjust
  27. *       backward for read-ahead and forward for write-behind. This is NOT
  28. *       equivalent to fseek(stream,0L,1), because fseek will remove an ungetc,
  29. *       may flush buffers, etc.
  30. *
  31. *Entry:
  32. *       FILE *stream - stream to query for position
  33. *
  34. *Exit:
  35. *       return present file position if succeeds
  36. *       returns -1L and sets errno if fails
  37. *
  38. *Exceptions:
  39. *
  40. *******************************************************************************/
  41.  
  42. #ifdef _MT
  43.  
  44. long __cdecl ftell (
  45.         FILE *stream
  46.         )
  47. {
  48.         long retval;
  49.  
  50.         _ASSERTE(stream != NULL);
  51.  
  52.         _lock_str(stream);
  53.  
  54.         retval = _ftell_lk (stream);
  55.  
  56.         _unlock_str(stream);
  57.  
  58.         return(retval);
  59. }
  60.  
  61.  
  62. /***
  63. *_ftell_lk() - Ftell() core routine (assumes stream is locked).
  64. *
  65. *Purpose:
  66. *       Core ftell() routine; assumes caller has aquired stream lock).
  67. *
  68. *       [See ftell() above for more info.]
  69. *
  70. *Entry: [See ftell()]
  71. *
  72. *Exit:  [See ftell()]
  73. *
  74. *Exceptions:
  75. *
  76. *******************************************************************************/
  77.  
  78. long __cdecl _ftell_lk (
  79.  
  80. #else  /* _MT */
  81.  
  82. long __cdecl ftell (
  83.  
  84. #endif  /* _MT */
  85.  
  86.         FILE *str
  87.         )
  88. {
  89.         REG1 FILE *stream;
  90.         unsigned int offset;
  91.         long filepos;
  92. #if !defined (_M_MPPC) && !defined (_M_M68K)
  93.         REG2 char *p;
  94.         char *max;
  95. #endif  /* !defined (_M_MPPC) && !defined (_M_M68K) */
  96.         int fd;
  97.         unsigned int rdcnt;
  98.  
  99.         _ASSERTE(str != NULL);
  100.  
  101.         /* Init stream pointer and file descriptor */
  102.         stream = str;
  103.         fd = _fileno(stream);
  104.  
  105.         if (stream->_cnt < 0)
  106.                 stream->_cnt = 0;
  107.  
  108.         if ((filepos = _lseek(fd, 0L, SEEK_CUR)) < 0L)
  109.                 return(-1L);
  110.  
  111.         if (!bigbuf(stream))            /* _IONBF or no buffering designated */
  112.                 return(filepos - stream->_cnt);
  113.  
  114.         offset = stream->_ptr - stream->_base;
  115.  
  116.         if (stream->_flag & (_IOWRT|_IOREAD)) {
  117. #if !defined (_M_MPPC) && !defined (_M_M68K)
  118.                 if (_osfile(fd) & FTEXT)
  119.                         for (p = stream->_base; p < stream->_ptr; p++)
  120.                                 if (*p == '\n')  /* adjust for '\r' */
  121.                                         offset++;
  122. #endif  /* !defined (_M_MPPC) && !defined (_M_M68K) */
  123.         }
  124.         else if (!(stream->_flag & _IORW)) {
  125.                 errno=EINVAL;
  126.                 return(-1L);
  127.         }
  128.  
  129.         if (filepos == 0L)
  130.                 return((long)offset);
  131.  
  132.         if (stream->_flag & _IOREAD)    /* go to preceding sector */
  133.  
  134.                 if (stream->_cnt == 0)  /* filepos holds correct location */
  135.                         offset = 0;
  136.  
  137.                 else {
  138.  
  139.                         /* Subtract out the number of unread bytes left in the
  140.                            buffer. [We can't simply use _iob[]._bufsiz because
  141.                            the last read may have hit EOF and, thus, the buffer
  142.                            was not completely filled.] */
  143.  
  144.                         rdcnt = stream->_cnt + (stream->_ptr - stream->_base);
  145.  
  146. #if !defined (_M_MPPC) && !defined (_M_M68K)
  147.                         /* If text mode, adjust for the cr/lf substitution. If
  148.                            binary mode, we're outta here. */
  149.                         if (_osfile(fd) & FTEXT) {
  150.                                 /* (1) If we're not at eof, simply copy _bufsiz
  151.                                    onto rdcnt to get the # of untranslated
  152.                                    chars read. (2) If we're at eof, we must
  153.                                    look through the buffer expanding the '\n'
  154.                                    chars one at a time. */
  155.  
  156.                                 /* [NOTE: Performance issue -- it is faster to
  157.                                    do the two _lseek() calls than to blindly go
  158.                                    through and expand the '\n' chars regardless
  159.                                    of whether we're at eof or not.] */
  160.  
  161.                                 if (_lseek(fd, 0L, 2) == filepos) {
  162.  
  163.                                         max = stream->_base + rdcnt;
  164.                                         for (p = stream->_base; p < max; p++)
  165.                                                 if (*p == '\n')
  166.                                                         /* adjust for '\r' */
  167.                                                         rdcnt++;
  168.  
  169.                                         /* If last byte was ^Z, the lowio read
  170.                                            didn't tell us about it.  Check flag
  171.                                            and bump count, if necessary. */
  172.  
  173.                                         if (stream->_flag & _IOCTRLZ)
  174.                                                 ++rdcnt;
  175.                                 }
  176.  
  177.                                 else {
  178.  
  179.                                         _lseek(fd, filepos, 0);
  180.  
  181.                                         /* We want to set rdcnt to the number
  182.                                            of bytes originally read into the
  183.                                            stream buffer (before crlf->lf
  184.                                            translation). In most cases, this
  185.                                            will just be _bufsiz. However, the
  186.                                            buffer size may have been changed,
  187.                                            due to fseek optimization, at the
  188.                                            END of the last _filbuf call. */
  189.  
  190.                                         if ( (rdcnt <= _SMALL_BUFSIZ) &&
  191.                                              (stream->_flag & _IOMYBUF) &&
  192.                                              !(stream->_flag & _IOSETVBUF) )
  193.                                         {
  194.                                                 /* The translated contents of
  195.                                                    the buffer is small and we
  196.                                                    are not at eof. The buffer
  197.                                                    size must have been set to
  198.                                                    _SMALL_BUFSIZ during the
  199.                                                    last _filbuf call. */
  200.  
  201.                                                 rdcnt = _SMALL_BUFSIZ;
  202.                                         }
  203.                                         else
  204.                                                 rdcnt = stream->_bufsiz;
  205.  
  206.  
  207.                                         /* If first byte in untranslated buffer
  208.                                            was a '\n', assume it was preceeded
  209.                                            by a '\r' which was discarded by the
  210.                                            previous read operation and count
  211.                                            the '\n'. */
  212.                                         if  (_osfile(fd) & FCRLF)
  213.                                                 ++rdcnt;
  214.                                 }
  215.  
  216.                         } /* end if FTEXT */
  217. #endif  /* !defined (_M_MPPC) && !defined (_M_M68K) */
  218.  
  219.                         filepos -= (long)rdcnt;
  220.  
  221.                 } /* end else stream->_cnt != 0 */
  222.  
  223.         return(filepos + (long)offset);
  224. }
  225.