/*=============================================================================
    Spirit v1.6.1
    Copyright (c) 2002 Jeff Westfahl
    http://spirit.sourceforge.net/

    Permission to copy, use, modify, sell and distribute this software is
    granted provided this copyright notice appears in all copies. This
    software is provided "as is" without express or implied warranty, and
    with no claim as to its suitability for any purpose.
=============================================================================*/

// This code is inspired by FILEiter.h by Stephen Cleary, and is basically a
// superset of the functionality provided there. FILEiter.h is available from
// http://groups.yahoo.com/group/boost/files/2000/IOGlue/IOGlue.zip and has
// the following copyright notice:

// FILEiter: Input and Output iterators for FILE * objects

// (C) Copyright Stephen Cleary 2000.  Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies.  This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.

#if !defined FILE_ITERATOR_IPP
#define      FILE_ITERATOR_IPP

///////////////////////////////////////////////////////////////////////////////
#include <cassert>
#include <fcntl.h>

#ifdef BOOST_HAS_UNISTD_H
#  include <unistd.h>
#else
#  include <io.h>
#endif

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

///////////////////////////////////////////////////////////////////////////////
namespace impl {

// Systems that have _lseeki64, such as Win32.
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#  if defined BOOST_MSVC              \
   || defined __MINGW32_VERSION       \
   || defined BOOST_INTEL_CXX_VERSION

   // Import _lseeki64 into this namespace under the name lseek
   inline off_t lseek (int File, off_t Offset, int Whence)
   {
      return _lseeki64 (File, Offset, Whence);
   }
#  define BOOST_SPIRIT_ITERATORS_FILE_ITERATOR_HAVE_LSEEKI64
#  endif
#endif

#ifndef BOOST_SPIRIT_ITERATORS_FILE_ITERATOR_HAVE_LSEEKI64
   // Import lseek into this namespace
   using ::lseek;
#endif


#ifdef O_BINARY
   // Windows defaults to using CR-LF translation, use O_BINARY to suppress it.
   static const int kOpenFlags = O_RDONLY | O_BINARY;
#else
   static const int kOpenFlags = O_RDONLY;
#endif


///////////////////////////////////////////////////////////////////////////////
} // namespace impl

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT>::file_iterator (char const * pFilename)
 : m_Filesize  (0),
   m_File      (-1),
   m_Offset    (0),
   m_NextChar  (),
   m_CloseFile (false)
{
   assert (NULL != pFilename);

   m_File = open (pFilename, impl::kOpenFlags);

   if (-1 != m_File)
   {
      // This instance is responsible for closing the file
      m_CloseFile = true;

      // Get the file size in bytes
      m_Filesize = impl::lseek (m_File, 0, SEEK_END);

      // The above shouldn't fail, but you never know...
      if (0 > m_Filesize)
      {
         close (m_File);

         m_CloseFile = false;

         m_File = -1;
      }

      // Move the file pointer back to the beginning
      impl::lseek (m_File, 0, SEEK_SET);

      // Read the first character
      read (m_File, &m_NextChar, kCharSize);
   }
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT>::~file_iterator ()
{
   if (
         m_CloseFile
      && (-1 != m_File)
      )
   {
      close (m_File);
   }
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> file_iterator <CharT>::make_end ()
{
   file_iterator <CharT> _Iterator (*this);

   // Make sure the offset is correctly aligned
   _Iterator.m_Offset = m_Filesize - (m_Filesize % kCharSize);

   return _Iterator;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline typename file_iterator <CharT>::difference_type
   file_iterator <CharT>::size () const
{
   return m_Filesize;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT>::file_iterator ()
 : m_Filesize  (0),
   m_File      (-1),
   m_Offset    (-1),
   m_NextChar  (),
   m_CloseFile (false)
{
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT>::file_iterator (
   file_iterator const & rCopyMe
   )
 : m_Filesize  (rCopyMe.m_Filesize),
   m_File      (rCopyMe.m_File),
   m_Offset    (rCopyMe.m_Offset),
   m_NextChar  (rCopyMe.m_NextChar),
   m_CloseFile (false)
{
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> & file_iterator <CharT>::operator = (
   file_iterator const & rAssignMe
   )
{
   // Clean up previous file if necessary
   if (
         m_CloseFile
      && (-1 != m_File)
      && (m_File != rAssignMe.m_File)
      )
   {
      close (m_File);
   }

   m_File      = rAssignMe.m_File;
   m_Offset    = rAssignMe.m_Offset;
   m_Filesize  = rAssignMe.m_Filesize;
   m_NextChar  = rAssignMe.m_NextChar;

   return *this;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline void file_iterator <CharT>::swap (
   file_iterator <CharT> & rA,
   file_iterator <CharT> & rB
   )
{
   file_iterator <CharT> _Temp (rA);

   rA = rB;

   rB = _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline typename file_iterator <CharT>::reference
   file_iterator <CharT>::operator * () const
{
   assert (-1 != m_File);

   return m_NextChar;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline typename file_iterator <CharT>::pointer
   file_iterator <CharT>::operator -> () const
{
   assert (-1 != m_File);

   return &m_NextChar;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> const &
   file_iterator <CharT>::operator ++ () const
{
   assert (-1 != m_File);

   m_Offset += kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return *this;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> const
   file_iterator <CharT>::operator ++ (int) const
{
   assert (-1 != m_File);

   file_iterator _Temp (*this);

   m_Offset += kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> const &
   file_iterator <CharT>::operator -- () const
{
   assert (-1 != m_File);

   m_Offset -= kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return *this;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline file_iterator <CharT> const
   file_iterator <CharT>::operator -- (int) const
{
   assert (-1 != m_File);

   file_iterator _Temp (*this);

   m_Offset -= kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
file_iterator <CharT> const & file_iterator <CharT>::operator += (
   difference_type Distance
   ) const
{
   assert (-1 != m_File);

   m_Offset += Distance * kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return *this;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
file_iterator <CharT> const file_iterator <CharT>::operator + (
   difference_type Distance
   ) const
{
   file_iterator <CharT> _Temp (*this);

   _Temp += Distance;

   return _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
file_iterator <CharT> const & file_iterator <CharT>::operator -= (
   difference_type Distance
   ) const
{
   assert (-1 != m_File);

   m_Offset -= Distance * kCharSize;

   impl::lseek (m_File, m_Offset, SEEK_SET);

   read (m_File, &m_NextChar, kCharSize);

   return *this;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
file_iterator <CharT> const file_iterator <CharT>::operator - (
   difference_type Distance
   ) const
{
   file_iterator <CharT> _Temp (*this);

   _Temp -= Distance;

   return _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
typename file_iterator <CharT>::difference_type
   file_iterator <CharT>::operator - (
   file_iterator <CharT> const & rIterator
   ) const
{
   return ((m_Offset - rIterator.m_Offset) / kCharSize);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline typename file_iterator <CharT>::value_type
   file_iterator <CharT>::operator [] (difference_type Index) const
{
   assert (-1 != m_File);

   CharT _ReturnValue;

   impl::lseek (m_File, m_Offset+Index, SEEK_SET);

   read (m_File, &_ReturnValue, kCharSize);

   return _ReturnValue;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
file_iterator <CharT> const operator + (
   typename file_iterator <CharT>::difference_type   Distance,
   file_iterator <CharT> const                     & rIterator
   )
{
   file_iterator <CharT> _Temp (rIterator);

   _Temp += Distance;

   return _Temp;
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool file_iterator <CharT>::operator_equal_to (
   const file_iterator <CharT> & rOther
   ) const
{
//   assert (m_File == rOther.m_File);

   return (m_Offset == rOther.m_Offset);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator == (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return rA.operator_equal_to (rB);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator != (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return !(rA.operator_equal_to (rB));
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool file_iterator <CharT>::operator_less_than (
   file_iterator <CharT> const & rOther
   ) const
{
   assert (m_File == rOther.m_File);

   return (m_Offset < rOther.m_Offset);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator < (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return rA.operator_less_than (rB);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator >= (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return !(rA.operator_less_than (rB));
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool file_iterator <CharT>::operator_greater_than (
   file_iterator <CharT> const & rOther
   ) const
{
   assert (m_File == rOther.m_File);

   return (m_Offset > rOther.m_Offset);
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator > (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return (rA.operator_greater_than (rB));
}

///////////////////////////////////////////////////////////////////////////////
template <typename CharT>
inline bool operator <= (
   file_iterator <CharT> const & rA,
   file_iterator <CharT> const & rB
   )
{
   return !(rA.operator_greater_than (rB));
}

///////////////////////////////////////////////////////////////////////////////
}} // namespace boost::spirit

#endif // #if !defined FILE_ITERATOR_IPP
