1 /*=============================================================================
2 Copyright (c) 2003 Giovanni Bajo
3 Copyright (c) 2003 Martin Wille
4 Copyright (c) 2003 Hartmut Kaiser
5 http://spirit.sourceforge.net/
7 Use, modification and distribution is subject to the Boost Software
8 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
9 http://www.boost.org/LICENSE_1_0.txt)
10 =============================================================================*/
12 #ifndef BOOST_SPIRIT_FILE_ITERATOR_IPP
13 #define BOOST_SPIRIT_FILE_ITERATOR_IPP
15 #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
20 #include <boost/shared_ptr.hpp>
22 #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
23 # include <boost/type_traits/remove_pointer.hpp>
26 #ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
27 # include <sys/types.h> // open, stat, mmap, munmap
28 # include <sys/stat.h> // stat
29 # include <fcntl.h> // open
30 # include <unistd.h> // stat, mmap, munmap
31 # include <sys/mman.h> // mmap, mmunmap
34 ///////////////////////////////////////////////////////////////////////////////
35 namespace boost { namespace spirit {
37 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
39 ///////////////////////////////////////////////////////////////////////////////
40 namespace fileiter_impl {
42 ///////////////////////////////////////////////////////////////////////////////
46 // Base class that implements iteration through a file using standard C
47 // stream library (fopen and friends). This class and the following are
48 // the base components on which the iterator is built (through the
49 // iterator adaptor library).
51 // The opened file stream (FILE) is held with a shared_ptr<>, whose
52 // custom deleter invokes fcose(). This makes the syntax of the class
53 // very easy, especially everything related to copying.
55 ///////////////////////////////////////////////////////////////////////////////
57 template <typename CharT>
58 class std_file_iterator
61 typedef CharT value_type;
66 explicit std_file_iterator(std::string const& fileName)
69 FILE* f = fopen(fileName.c_str(), "rb");
71 // If the file was opened, store it into
75 m_file.reset(f, fclose);
82 std_file_iterator(const std_file_iterator& iter)
85 std_file_iterator& operator=(const std_file_iterator& iter)
88 m_curChar = iter.m_curChar;
95 // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
96 // for shared_ptr to evaluate correctly
98 { return m_file ? true : false; }
100 bool operator==(const std_file_iterator& iter) const
102 return (m_file == iter.m_file) && (m_eof == iter.m_eof) &&
103 (m_pos == iter.m_pos);
106 const CharT& get_cur_char(void) const
113 m_pos -= sizeof(CharT);
119 m_pos += sizeof(CharT);
126 fseek(m_file.get(), 0, SEEK_END);
127 m_pos = ftell(m_file.get()) / sizeof(CharT);
131 void advance(std::ptrdiff_t n)
133 m_pos += n * sizeof(CharT);
137 std::ptrdiff_t distance(const std_file_iterator& iter) const
139 return (std::ptrdiff_t)(m_pos - iter.m_pos) / sizeof(CharT);
143 boost::shared_ptr<std::FILE> m_file;
148 void update_char(void)
151 if ((std::size_t)ftell(m_file.get()) != m_pos)
152 fseek(m_file.get(), m_pos, SEEK_SET);
154 m_eof = (fread(&m_curChar, sizeof(CharT), 1, m_file.get()) < 1);
159 ///////////////////////////////////////////////////////////////////////////////
161 // mmap_file_iterator
163 // File iterator for memory mapped files, for now implemented on Windows and
164 // POSIX platforms. This class has the same interface of std_file_iterator,
165 // and can be used in its place (in fact, it's the default for Windows and
168 ///////////////////////////////////////////////////////////////////////////////
170 ///////////////////////////////////////////////////////////////////////////////
171 // mmap_file_iterator, Windows version
172 #ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS
173 template <typename CharT>
174 class mmap_file_iterator
177 typedef CharT value_type;
180 : m_filesize(0), m_curChar(0)
183 explicit mmap_file_iterator(std::string const& fileName)
184 : m_filesize(0), m_curChar(0)
186 HANDLE hFile = ::CreateFileA(
192 FILE_FLAG_SEQUENTIAL_SCAN,
196 if (hFile == INVALID_HANDLE_VALUE)
199 // Store the size of the file, it's used to construct
201 m_filesize = ::GetFileSize(hFile, NULL);
203 HANDLE hMap = ::CreateFileMapping(
213 ::CloseHandle(hFile);
217 LPVOID pMem = ::MapViewOfFile(
226 ::CloseHandle(hFile);
230 // We hold both the file handle and the memory pointer.
231 // We can close the hMap handle now because Windows holds internally
232 // a reference to it since there is a view mapped.
235 // It seems like we can close the file handle as well (because
236 // a reference is hold by the filemap object).
237 ::CloseHandle(hFile);
239 // Store the handles inside the shared_ptr (with the custom destructors)
240 m_mem.reset(static_cast<CharT*>(pMem), ::UnmapViewOfFile);
243 m_curChar = m_mem.get();
246 mmap_file_iterator(const mmap_file_iterator& iter)
249 mmap_file_iterator& operator=(const mmap_file_iterator& iter)
251 m_curChar = iter.m_curChar;
253 m_filesize = iter.m_filesize;
258 // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
259 // for shared_ptr to evaluate correctly
260 operator bool() const
261 { return m_mem ? true : false; }
263 bool operator==(const mmap_file_iterator& iter) const
264 { return m_curChar == iter.m_curChar; }
266 const CharT& get_cur_char(void) const
267 { return *m_curChar; }
275 void advance(std::ptrdiff_t n)
278 std::ptrdiff_t distance(const mmap_file_iterator& iter) const
279 { return m_curChar - iter.m_curChar; }
283 m_curChar = m_mem.get() +
284 (m_filesize / sizeof(CharT));
288 typedef boost::remove_pointer<HANDLE>::type handle_t;
290 boost::shared_ptr<CharT> m_mem;
291 std::size_t m_filesize;
295 #endif // BOOST_SPIRIT_FILEITERATOR_WINDOWS
297 ///////////////////////////////////////////////////////////////////////////////
298 // mmap_file_iterator, POSIX version
299 #ifdef BOOST_SPIRIT_FILEITERATOR_POSIX
300 template <typename CharT>
301 class mmap_file_iterator
306 mapping(void *p, off_t len)
311 CharT const *begin() const
313 return static_cast<CharT *>(data);
316 CharT const *end() const
318 return static_cast<CharT *>(data) + size/sizeof(CharT);
323 munmap(static_cast<char*>(data), size);
332 typedef CharT value_type;
338 explicit mmap_file_iterator(std::string const& file_name)
342 int fd = open(file_name.c_str(),
344 O_NOCTTY | // if stdin was closed then opening a file
345 // would cause the file to become the controlling
346 // terminal if the filename refers to a tty. Setting
347 // O_NOCTTY inhibits this.
354 // call fstat to find get information about the file just
355 // opened (size and file type)
356 struct stat stat_buf;
357 if ((fstat(fd, &stat_buf) != 0) || !S_ISREG(stat_buf.st_mode))
358 { // if fstat returns an error or if the file isn't a
359 // regular file we give up.
364 // perform the actual mapping
365 void *p = mmap(0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
366 // it is safe to close() here. POSIX requires that the OS keeps a
367 // second handle to the file while the file is mmapped.
376 m = new mapping(p, stat_buf.st_size);
380 munmap(static_cast<char*>(p), stat_buf.st_size);
387 m_curChar = m_mem->begin();
390 mmap_file_iterator(const mmap_file_iterator& iter)
393 mmap_file_iterator& operator=(const mmap_file_iterator& iter)
395 m_curChar = iter.m_curChar;
401 // Nasty bug in Comeau up to 4.3.0.1, we need explicit boolean context
402 // for shared_ptr to evaluate correctly
403 operator bool() const
404 { return m_mem ? true : false; }
406 bool operator==(const mmap_file_iterator& iter) const
407 { return m_curChar == iter.m_curChar; }
409 const CharT& get_cur_char(void) const
410 { return *m_curChar; }
418 void advance(signed long n)
421 long distance(const mmap_file_iterator& iter) const
422 { return m_curChar - iter.m_curChar; }
426 m_curChar = m_mem->end();
431 boost::shared_ptr<mapping> m_mem;
432 CharT const* m_curChar;
435 #endif // BOOST_SPIRIT_FILEITERATOR_POSIX
437 ///////////////////////////////////////////////////////////////////////////////
438 } /* namespace boost::spirit::fileiter_impl */
440 template <typename CharT, typename BaseIteratorT>
441 file_iterator<CharT,BaseIteratorT>
442 file_iterator<CharT,BaseIteratorT>::make_end(void)
444 file_iterator iter(*this);
445 iter.base_reference().seek_end();
449 template <typename CharT, typename BaseIteratorT>
450 file_iterator<CharT,BaseIteratorT>&
451 file_iterator<CharT,BaseIteratorT>::operator=(const base_t& iter)
453 base_t::operator=(iter);
457 ///////////////////////////////////////////////////////////////////////////////
458 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
460 }} /* namespace boost::spirit */
463 #endif /* BOOST_SPIRIT_FILE_ITERATOR_IPP */