123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*=============================================================================
- Copyright (c) 2003 Giovanni Bajo
- Copyright (c) 2003 Martin Wille
- Copyright (c) 2003 Hartmut Kaiser
- http://spirit.sourceforge.net/
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- #ifndef BOOST_SPIRIT_FILE_ITERATOR_IPP
- #define BOOST_SPIRIT_FILE_ITERATOR_IPP
- #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
- # include <windows.h>
- #endif
- #include <cstdio>
- #include <boost/shared_ptr.hpp>
- #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
- # include <boost/type_traits/remove_pointer.hpp>
- #endif
- #ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
- # include <sys/types.h> // open, stat, mmap, munmap
- # include <sys/stat.h> // stat
- # include <fcntl.h> // open
- # include <unistd.h> // stat, mmap, munmap
- # include <sys/mman.h> // mmap, mmunmap
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- namespace boost { namespace spirit {
- BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
- ///////////////////////////////////////////////////////////////////////////////
- namespace fileiter_impl {
- ///////////////////////////////////////////////////////////////////////////////
- //
- // std_file_iterator
- //
- // Base class that implements iteration through a file using standard C
- // stream library (fopen and friends). This class and the following are
- // the base components on which the iterator is built (through the
- // iterator adaptor library).
- //
- // The opened file stream (FILE) is held with a shared_ptr<>, whose
- // custom deleter invokes fcose(). This makes the syntax of the class
- // very easy, especially everything related to copying.
- //
- ///////////////////////////////////////////////////////////////////////////////
- template <typename CharT>
- class std_file_iterator
- {
- public:
- typedef CharT value_type;
- std_file_iterator()
- {}
- explicit std_file_iterator(std::string const& fileName)
- {
- using namespace std;
- FILE* f = fopen(fileName.c_str(), "rb");
- // If the file was opened, store it into
- // the smart pointer.
- if (f)
- {
- m_file.reset(f, fclose);
- m_pos = 0;
- m_eof = false;
- update_char();
- }
- }
- std_file_iterator(const std_file_iterator& iter)
- { *this = iter; }
- std_file_iterator& operator=(const std_file_iterator& iter)
- {
- m_file = iter.m_file;
- m_curChar = iter.m_curChar;
- m_eof = iter.m_eof;
- m_pos = iter.m_pos;
- return *this;
- }
- // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
- // for shared_ptr to evaluate correctly
- operator bool() const
- { return m_file ? true : false; }
- bool operator==(const std_file_iterator& iter) const
- {
- return (m_file == iter.m_file) && (m_eof == iter.m_eof) &&
- (m_pos == iter.m_pos);
- }
- const CharT& get_cur_char(void) const
- {
- return m_curChar;
- }
- void prev_char(void)
- {
- m_pos -= sizeof(CharT);
- update_char();
- }
- void next_char(void)
- {
- m_pos += sizeof(CharT);
- update_char();
- }
- void seek_end(void)
- {
- using namespace std;
- fseek(m_file.get(), 0, SEEK_END);
- m_pos = ftell(m_file.get()) / sizeof(CharT);
- m_eof = true;
- }
- void advance(std::ptrdiff_t n)
- {
- m_pos += static_cast<long>(n) * sizeof(CharT);
- update_char();
- }
- std::ptrdiff_t distance(const std_file_iterator& iter) const
- {
- return (std::ptrdiff_t)(m_pos - iter.m_pos) / sizeof(CharT);
- }
- private:
- boost::shared_ptr<std::FILE> m_file;
- long m_pos;
- CharT m_curChar;
- bool m_eof;
- void update_char(void)
- {
- using namespace std;
- if (ftell(m_file.get()) != m_pos)
- fseek(m_file.get(), m_pos, SEEK_SET);
- m_eof = (fread(&m_curChar, sizeof(CharT), 1, m_file.get()) < 1);
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- //
- // mmap_file_iterator
- //
- // File iterator for memory mapped files, for now implemented on Windows and
- // POSIX platforms. This class has the same interface of std_file_iterator,
- // and can be used in its place (in fact, it's the default for Windows and
- // POSIX).
- //
- ///////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- // mmap_file_iterator, Windows version
- #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
- template <typename CharT>
- class mmap_file_iterator
- {
- public:
- typedef CharT value_type;
- mmap_file_iterator()
- : m_filesize(0), m_curChar(0)
- {}
- explicit mmap_file_iterator(std::string const& fileName)
- : m_filesize(0), m_curChar(0)
- {
- HANDLE hFile = ::CreateFileA(
- fileName.c_str(),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_SEQUENTIAL_SCAN,
- NULL
- );
- if (hFile == INVALID_HANDLE_VALUE)
- return;
- // Store the size of the file, it's used to construct
- // the end iterator
- m_filesize = ::GetFileSize(hFile, NULL);
- HANDLE hMap = ::CreateFileMapping(
- hFile,
- NULL,
- PAGE_READONLY,
- 0, 0,
- NULL
- );
- if (hMap == NULL)
- {
- ::CloseHandle(hFile);
- return;
- }
- LPVOID pMem = ::MapViewOfFile(
- hMap,
- FILE_MAP_READ,
- 0, 0, 0
- );
- if (pMem == NULL)
- {
- ::CloseHandle(hMap);
- ::CloseHandle(hFile);
- return;
- }
- // We hold both the file handle and the memory pointer.
- // We can close the hMap handle now because Windows holds internally
- // a reference to it since there is a view mapped.
- ::CloseHandle(hMap);
- // It seems like we can close the file handle as well (because
- // a reference is hold by the filemap object).
- ::CloseHandle(hFile);
- // Store the handles inside the shared_ptr (with the custom destructors)
- m_mem.reset(static_cast<CharT*>(pMem), ::UnmapViewOfFile);
- // Start of the file
- m_curChar = m_mem.get();
- }
- mmap_file_iterator(const mmap_file_iterator& iter)
- { *this = iter; }
- mmap_file_iterator& operator=(const mmap_file_iterator& iter)
- {
- m_curChar = iter.m_curChar;
- m_mem = iter.m_mem;
- m_filesize = iter.m_filesize;
- return *this;
- }
- // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
- // for shared_ptr to evaluate correctly
- operator bool() const
- { return m_mem ? true : false; }
- bool operator==(const mmap_file_iterator& iter) const
- { return m_curChar == iter.m_curChar; }
- const CharT& get_cur_char(void) const
- { return *m_curChar; }
- void next_char(void)
- { m_curChar++; }
- void prev_char(void)
- { m_curChar--; }
- void advance(std::ptrdiff_t n)
- { m_curChar += n; }
- std::ptrdiff_t distance(const mmap_file_iterator& iter) const
- { return m_curChar - iter.m_curChar; }
- void seek_end(void)
- {
- m_curChar = m_mem.get() +
- (m_filesize / sizeof(CharT));
- }
- private:
- typedef boost::remove_pointer<HANDLE>::type handle_t;
- boost::shared_ptr<CharT> m_mem;
- std::size_t m_filesize;
- CharT* m_curChar;
- };
- #endif // BOOST_SPIRIT_FILEITERATOR_WINDOWS
- ///////////////////////////////////////////////////////////////////////////////
- // mmap_file_iterator, POSIX version
- #ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
- template <typename CharT>
- class mmap_file_iterator
- {
- private:
- struct mapping
- {
- mapping(void *p, off_t len)
- : data(p)
- , size(len)
- { }
- CharT const *begin() const
- {
- return static_cast<CharT *>(data);
- }
- CharT const *end() const
- {
- return static_cast<CharT *>(data) + size/sizeof(CharT);
- }
- ~mapping()
- {
- munmap(static_cast<char*>(data), size);
- }
- private:
- void *data;
- off_t size;
- };
- public:
- typedef CharT value_type;
- mmap_file_iterator()
- : m_curChar(0)
- {}
- explicit mmap_file_iterator(std::string const& file_name)
- : m_curChar(0)
- {
- // open the file
- int fd = open(file_name.c_str(),
- #ifdef O_NOCTTY
- O_NOCTTY | // if stdin was closed then opening a file
- // would cause the file to become the controlling
- // terminal if the filename refers to a tty. Setting
- // O_NOCTTY inhibits this.
- #endif
- O_RDONLY);
- if (fd == -1)
- return;
- // call fstat to find get information about the file just
- // opened (size and file type)
- struct stat stat_buf;
- if ((fstat(fd, &stat_buf) != 0) || !S_ISREG(stat_buf.st_mode))
- { // if fstat returns an error or if the file isn't a
- // regular file we give up.
- close(fd);
- return;
- }
- // perform the actual mapping
- void *p = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
- // it is safe to close() here. POSIX requires that the OS keeps a
- // second handle to the file while the file is mmapped.
- close(fd);
- if (p == MAP_FAILED)
- return;
- mapping *m = 0;
- try
- {
- m = new mapping(p, stat_buf.st_size);
- }
- catch(...)
- {
- munmap(static_cast<char*>(p), stat_buf.st_size);
- throw;
- }
- m_mem.reset(m);
- // Start of the file
- m_curChar = m_mem->begin();
- }
- mmap_file_iterator(const mmap_file_iterator& iter)
- { *this = iter; }
- mmap_file_iterator& operator=(const mmap_file_iterator& iter)
- {
- m_curChar = iter.m_curChar;
- m_mem = iter.m_mem;
- return *this;
- }
- // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
- // for shared_ptr to evaluate correctly
- operator bool() const
- { return m_mem ? true : false; }
- bool operator==(const mmap_file_iterator& iter) const
- { return m_curChar == iter.m_curChar; }
- const CharT& get_cur_char(void) const
- { return *m_curChar; }
- void next_char(void)
- { m_curChar++; }
- void prev_char(void)
- { m_curChar--; }
- void advance(signed long n)
- { m_curChar += n; }
- long distance(const mmap_file_iterator& iter) const
- { return m_curChar - iter.m_curChar; }
- void seek_end(void)
- {
- m_curChar = m_mem->end();
- }
- private:
- boost::shared_ptr<mapping> m_mem;
- CharT const* m_curChar;
- };
- #endif // BOOST_SPIRIT_FILEITERATOR_POSIX
- ///////////////////////////////////////////////////////////////////////////////
- } /* namespace boost::spirit::fileiter_impl */
- template <typename CharT, typename BaseIteratorT>
- file_iterator<CharT,BaseIteratorT>
- file_iterator<CharT,BaseIteratorT>::make_end(void)
- {
- file_iterator iter(*this);
- iter.base_reference().seek_end();
- return iter;
- }
- template <typename CharT, typename BaseIteratorT>
- file_iterator<CharT,BaseIteratorT>&
- file_iterator<CharT,BaseIteratorT>::operator=(const base_t& iter)
- {
- base_t::operator=(iter);
- return *this;
- }
- ///////////////////////////////////////////////////////////////////////////////
- BOOST_SPIRIT_CLASSIC_NAMESPACE_END
- }} /* namespace boost::spirit */
- #endif /* BOOST_SPIRIT_FILE_ITERATOR_IPP */
|