/* ftell.c (emx+gcc) -- Copyright (c) 1990-1996 by Eberhard Mattes */

#include <sys/builtin.h>        /* For <sys/fmutex.h> */
#include <sys/fmutex.h>         /* For <sys/rmutex.h> */
#include <sys/rmutex.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <emx/io.h>

long _ftell_nolock (FILE *stream)
{
  long pos;
  int *pflags;

  if (stream->_flags & _IOSPECIAL)
    pos = 0;
  else
    {
      pos = _tell (stream->_handle);
      if (pos == -1)
        return -1;
    }
  if (stream->_flags & _IOWRT)
    {
      if (bbuf (stream))
        {
          pos += stream->_ptr - stream->_buffer;
          if (!(stream->_flags & _IOSPECIAL)
              && (pflags = _fd_flags (stream->_handle)) != NULL
              && (*pflags & O_TEXT))
            {
              const char *p;
              int n;

              /* In text mode, newlines are translated to CR/LF pairs.
                 Adjust the position to take account of this. */

              n = stream->_ptr - stream->_buffer;
              p = stream->_buffer;
              while (n > 0)
                {
                  if (*p ++ == '\n')
                    ++pos;
                  --n;
                }
            }
        }
    }
  else if (stream->_flags & _IOREAD)
    {
      /* Subtract the number of unprocessed buffered characters from
         the file position of the end of the buffer to get the current
         position. */

      if (!(stream->_flags & _IOSPECIAL)
          && stream->_ungetc_count == 0
          && (pflags = _fd_flags (stream->_handle)) != NULL
          && (*pflags & F_CRLF))
        {
          const char *p;
          int n;

          /* There has been at least one CR/LF to newline translation.
             Assume that all newlines in the buffer have been
             translated from a CR/LF pair each. */

          p = stream->_ptr;
          n = stream->_rcount;
          pos -= n;
          while (n > 0)
            {
              if (*p++ == '\n')
                --pos;
              --n;
            }
        }
      else if (stream->_ungetc_count != 0)
        {
          /* There are characters pushed back by ungetc().  For binary
             streams, each successful ungetc() decrements the file position
             indicator.  Treat text mode like binary mode as the file
             position indicator is undefined in text mode after
             calling ungetc(). */

          pos = pos + stream->_rcount - stream->_ungetc_count;
        }
      else
        {
          /* Binary mode. */

          pos -= stream->_rcount;
        }
    }
  return pos;
}


long ftell (FILE *stream)
{
  long r;

  STREAM_LOCK (stream);
  r = _ftell_nolock (stream);
  STREAM_UNLOCK (stream);
  return r;
}
