3 * Copyright (c) 1998-2002
6 * Use, modification and distribution are subject to the
7 * Boost Software License, Version 1.0. (See accompanying file
8 * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
13 * LOCATION: see http://www.boost.org for most recent version.
15 * VERSION: see <boost/version.hpp>
16 * DESCRIPTION: Implements file io primitives + directory searching for class boost::RegEx.
20 #define BOOST_REGEX_SOURCE
22 #include <boost/config.hpp>
26 #include <boost/throw_exception.hpp>
27 #include <boost/regex/v4/fileiter.hpp>
28 #include <boost/regex/v4/regex_workaround.hpp>
29 #include <boost/regex/pattern_except.hpp>
32 #if defined(BOOST_NO_STDC_NAMESPACE)
50 #ifndef BOOST_REGEX_NO_FILEITER
52 #if defined(__CYGWIN__) || defined(__CYGWIN32__)
53 #include <sys/cygwin.h>
57 # pragma warning(disable: 4800)
61 namespace BOOST_REGEX_DETAIL_NS{
62 // start with the operating system specific stuff:
64 #if (defined(__BORLANDC__) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32)
66 // platform is DOS or Windows
67 // directories are separated with '\\'
68 // and names are insensitive of case
70 BOOST_REGEX_DECL const char* _fi_sep = "\\";
71 const char* _fi_sep_alt = "/";
72 #define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c)
76 // platform is not DOS or Windows
77 // directories are separated with '/'
78 // and names are sensitive of case
80 BOOST_REGEX_DECL const char* _fi_sep = "/";
81 const char* _fi_sep_alt = _fi_sep;
82 #define BOOST_REGEX_FI_TRANSLATE(c) c
86 #ifdef BOOST_REGEX_FI_WIN32_MAP
88 void mapfile::open(const char* file)
90 #if defined(BOOST_NO_ANSI_APIS)
91 int filename_size = strlen(file);
92 LPWSTR wide_file = (LPWSTR)_alloca( (filename_size + 1) * sizeof(WCHAR) );
93 if(::MultiByteToWideChar(CP_ACP, 0, file, filename_size, wide_file, filename_size + 1) == 0)
94 hfile = INVALID_HANDLE_VALUE;
96 hfile = CreateFileW(wide_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
97 #elif defined(__CYGWIN__)||defined(__CYGWIN32__)
98 char win32file[ MAX_PATH ];
99 cygwin_conv_to_win32_path( file, win32file );
100 hfile = CreateFileA(win32file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
102 hfile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
104 if(hfile != INVALID_HANDLE_VALUE)
106 hmap = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0);
107 if((hmap == INVALID_HANDLE_VALUE) || (hmap == NULL))
112 std::runtime_error err("Unable to create file mapping.");
113 boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
115 _first = static_cast<const char*>(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0));
122 std::runtime_error err("Unable to create file mapping.");
124 _last = _first + GetFileSize(hfile, 0);
129 #ifndef BOOST_NO_EXCEPTIONS
130 throw std::runtime_error("Unable to open file.");
132 BOOST_REGEX_NOEH_ASSERT(hfile != INVALID_HANDLE_VALUE);
137 void mapfile::close()
139 if(hfile != INVALID_HANDLE_VALUE)
141 UnmapViewOfFile((void*)_first);
149 #elif !defined(BOOST_RE_NO_STL)
151 mapfile_iterator& mapfile_iterator::operator = (const mapfile_iterator& i)
163 mapfile_iterator& mapfile_iterator::operator++ ()
165 if((++offset == mapfile::buf_size) && file)
170 file->unlock(node-1);
175 mapfile_iterator mapfile_iterator::operator++ (int)
177 mapfile_iterator temp(*this);
178 if((++offset == mapfile::buf_size) && file)
183 file->unlock(node-1);
188 mapfile_iterator& mapfile_iterator::operator-- ()
190 if((offset == 0) && file)
193 offset = mapfile::buf_size - 1;
195 file->unlock(node + 1);
202 mapfile_iterator mapfile_iterator::operator-- (int)
204 mapfile_iterator temp(*this);
205 if((offset == 0) && file)
208 offset = mapfile::buf_size - 1;
210 file->unlock(node + 1);
217 mapfile_iterator operator + (const mapfile_iterator& i, long off)
219 mapfile_iterator temp(i);
224 mapfile_iterator operator - (const mapfile_iterator& i, long off)
226 mapfile_iterator temp(i);
231 mapfile::iterator mapfile::begin()const
233 return mapfile_iterator(this, 0);
236 mapfile::iterator mapfile::end()const
238 return mapfile_iterator(this, _size);
241 void mapfile::lock(pointer* node)const
243 BOOST_ASSERT(node >= _first);
244 BOOST_ASSERT(node <= _last);
251 *node = new char[sizeof(int) + buf_size];
252 *(reinterpret_cast<int*>(*node)) = 1;
256 pointer* p = condemed.front();
257 condemed.pop_front();
260 *(reinterpret_cast<int*>(*node)) = 1;
263 std::size_t read_size = 0;
264 int read_pos = std::fseek(hfile, (node - _first) * buf_size, SEEK_SET);
266 if(0 == read_pos && node == _last - 1)
267 read_size = std::fread(*node + sizeof(int), _size % buf_size, 1, hfile);
269 read_size = std::fread(*node + sizeof(int), buf_size, 1, hfile);
270 if((read_size == 0) || (std::ferror(hfile)))
272 #ifndef BOOST_NO_EXCEPTIONS
274 throw std::runtime_error("Unable to read file.");
276 BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile)) && (read_size != 0));
282 if(*reinterpret_cast<int*>(*node) == 0)
284 *reinterpret_cast<int*>(*node) = 1;
285 condemed.remove(node);
288 ++(*reinterpret_cast<int*>(*node));
293 void mapfile::unlock(pointer* node)const
295 BOOST_ASSERT(node >= _first);
296 BOOST_ASSERT(node <= _last);
299 if(--(*reinterpret_cast<int*>(*node)) == 0)
301 condemed.push_back(node);
306 long int get_file_length(std::FILE* hfile)
309 std::fseek(hfile, 0, SEEK_END);
310 result = std::ftell(hfile);
311 std::fseek(hfile, 0, SEEK_SET);
316 void mapfile::open(const char* file)
318 hfile = std::fopen(file, "rb");
319 #ifndef BOOST_NO_EXCEPTIONS
324 _size = get_file_length(hfile);
325 long cnodes = (_size + buf_size - 1) / buf_size;
327 // check that number of nodes is not too high:
328 if(cnodes > (long)((INT_MAX) / sizeof(pointer*)))
336 _first = new pointer[(int)cnodes];
337 _last = _first + cnodes;
338 std::memset(_first, 0, cnodes*sizeof(pointer));
342 std::runtime_error err("Unable to open file.");
344 #ifndef BOOST_NO_EXCEPTIONS
350 void mapfile::close()
366 condemed.erase(condemed.begin(), condemed.end());
373 inline _fi_find_handle find_first_file(const char* wild, _fi_find_data& data)
375 #ifdef BOOST_NO_ANSI_APIS
376 std::size_t wild_size = std::strlen(wild);
377 LPWSTR wide_wild = (LPWSTR)_alloca( (wild_size + 1) * sizeof(WCHAR) );
378 if (::MultiByteToWideChar(CP_ACP, 0, wild, wild_size, wide_wild, wild_size + 1) == 0)
379 return _fi_invalid_handle;
381 return FindFirstFileW(wide_wild, &data);
383 return FindFirstFileA(wild, &data);
387 inline bool find_next_file(_fi_find_handle hf, _fi_find_data& data)
389 #ifdef BOOST_NO_ANSI_APIS
390 return FindNextFileW(hf, &data);
392 return FindNextFileA(hf, &data);
396 inline void copy_find_file_result_with_overflow_check(const _fi_find_data& data, char* path, size_t max_size)
398 #ifdef BOOST_NO_ANSI_APIS
399 if (::WideCharToMultiByte(CP_ACP, 0, data.cFileName, -1, path, max_size, NULL, NULL) == 0)
400 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(1);
402 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(path, max_size, data.cFileName));
406 inline bool is_not_current_or_parent_path_string(const _fi_find_data& data)
408 #ifdef BOOST_NO_ANSI_APIS
409 return (std::wcscmp(data.cFileName, L".") && std::wcscmp(data.cFileName, L".."));
411 return (std::strcmp(data.cFileName, ".") && std::strcmp(data.cFileName, ".."));
416 file_iterator::file_iterator()
420 #ifndef BOOST_NO_EXCEPTIONS
423 _root = new char[MAX_PATH];
424 BOOST_REGEX_NOEH_ASSERT(_root)
425 _path = new char[MAX_PATH];
426 BOOST_REGEX_NOEH_ASSERT(_path)
430 ref = new file_iterator_ref();
431 BOOST_REGEX_NOEH_ASSERT(ref)
432 ref->hf = _fi_invalid_handle;
434 #ifndef BOOST_NO_EXCEPTIONS
446 file_iterator::file_iterator(const char* wild)
450 #ifndef BOOST_NO_EXCEPTIONS
453 _root = new char[MAX_PATH];
454 BOOST_REGEX_NOEH_ASSERT(_root)
455 _path = new char[MAX_PATH];
456 BOOST_REGEX_NOEH_ASSERT(_path)
457 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild));
460 while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
461 if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
464 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root));
469 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root));
471 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, "."));
472 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep));
474 ptr = _path + std::strlen(_path);
476 ref = new file_iterator_ref();
477 BOOST_REGEX_NOEH_ASSERT(ref)
478 ref->hf = find_first_file(wild, ref->_data);
481 if(ref->hf == _fi_invalid_handle)
488 copy_find_file_result_with_overflow_check(ref->_data, ptr, (MAX_PATH - (ptr - _path)));
489 if(ref->_data.dwFileAttributes & _fi_dir)
492 #ifndef BOOST_NO_EXCEPTIONS
504 file_iterator::file_iterator(const file_iterator& other)
508 #ifndef BOOST_NO_EXCEPTIONS
511 _root = new char[MAX_PATH];
512 BOOST_REGEX_NOEH_ASSERT(_root)
513 _path = new char[MAX_PATH];
514 BOOST_REGEX_NOEH_ASSERT(_path)
515 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root));
516 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path));
517 ptr = _path + (other.ptr - other._path);
519 #ifndef BOOST_NO_EXCEPTIONS
531 file_iterator& file_iterator::operator=(const file_iterator& other)
533 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root));
534 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path));
535 ptr = _path + (other.ptr - other._path);
536 if(--(ref->count) == 0)
538 if(ref->hf != _fi_invalid_handle)
548 file_iterator::~file_iterator()
552 if(--(ref->count) == 0)
554 if(ref->hf != _fi_invalid_handle)
560 file_iterator file_iterator::operator++(int)
562 file_iterator temp(*this);
568 void file_iterator::next()
570 if(ref->hf != _fi_invalid_handle)
575 cont = find_next_file(ref->hf, ref->_data);
576 if(cont && ((ref->_data.dwFileAttributes & _fi_dir) == 0))
583 ref->hf = _fi_invalid_handle;
588 copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
594 directory_iterator::directory_iterator()
598 #ifndef BOOST_NO_EXCEPTIONS
601 _root = new char[MAX_PATH];
602 BOOST_REGEX_NOEH_ASSERT(_root)
603 _path = new char[MAX_PATH];
604 BOOST_REGEX_NOEH_ASSERT(_path)
608 ref = new file_iterator_ref();
609 BOOST_REGEX_NOEH_ASSERT(ref)
610 ref->hf = _fi_invalid_handle;
612 #ifndef BOOST_NO_EXCEPTIONS
624 directory_iterator::directory_iterator(const char* wild)
628 #ifndef BOOST_NO_EXCEPTIONS
631 _root = new char[MAX_PATH];
632 BOOST_REGEX_NOEH_ASSERT(_root)
633 _path = new char[MAX_PATH];
634 BOOST_REGEX_NOEH_ASSERT(_path)
635 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild));
638 while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
640 if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
643 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root));
648 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root));
650 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, "."));
651 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep));
653 ptr = _path + std::strlen(_path);
655 ref = new file_iterator_ref();
656 BOOST_REGEX_NOEH_ASSERT(ref)
658 ref->hf = find_first_file(wild, ref->_data);
659 if(ref->hf == _fi_invalid_handle)
666 copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
667 if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ptr, ".") == 0) || (std::strcmp(ptr, "..") == 0))
670 #ifndef BOOST_NO_EXCEPTIONS
682 directory_iterator::~directory_iterator()
686 if(--(ref->count) == 0)
688 if(ref->hf != _fi_invalid_handle)
694 directory_iterator::directory_iterator(const directory_iterator& other)
698 #ifndef BOOST_NO_EXCEPTIONS
701 _root = new char[MAX_PATH];
702 BOOST_REGEX_NOEH_ASSERT(_root)
703 _path = new char[MAX_PATH];
704 BOOST_REGEX_NOEH_ASSERT(_path)
705 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root));
706 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path));
707 ptr = _path + (other.ptr - other._path);
709 #ifndef BOOST_NO_EXCEPTIONS
721 directory_iterator& directory_iterator::operator=(const directory_iterator& other)
723 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root));
724 BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path));
725 ptr = _path + (other.ptr - other._path);
726 if(--(ref->count) == 0)
728 if(ref->hf != _fi_invalid_handle)
737 directory_iterator directory_iterator::operator++(int)
739 directory_iterator temp(*this);
744 void directory_iterator::next()
746 if(ref->hf != _fi_invalid_handle)
751 cont = find_next_file(ref->hf, ref->_data);
752 if(cont && (ref->_data.dwFileAttributes & _fi_dir))
754 if(is_not_current_or_parent_path_string(ref->_data))
762 ref->hf = _fi_invalid_handle;
767 copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
772 #ifdef BOOST_REGEX_FI_POSIX_DIR
779 _fi_priv_data(const char* p);
782 _fi_priv_data::_fi_priv_data(const char* p)
784 std::strcpy(root, p);
787 while((mask > root) && (*mask != *_fi_sep) && (*mask != *_fi_sep_alt)) --mask;
788 if(mask == root && ((*mask== *_fi_sep) || (*mask == *_fi_sep_alt)) )
791 std::strcpy(root+2, p+1);
794 else if(mask == root)
798 std::strcpy(root+2, p);
808 bool iswild(const char* mask, const char* name)
810 while(*mask && *name)
824 if(iswild(mask, name))
837 if(BOOST_REGEX_FI_TRANSLATE(*mask) != BOOST_REGEX_FI_TRANSLATE(*name))
849 unsigned _fi_attributes(const char* root, const char* name)
852 // verify that we can not overflow:
853 if(std::strlen(root) + std::strlen(_fi_sep) + std::strlen(name) >= MAX_PATH)
856 if( ( (root[0] == *_fi_sep) || (root[0] == *_fi_sep_alt) ) && (root[1] == '\0') )
857 r = (std::sprintf)(buf, "%s%s", root, name);
859 r = (std::sprintf)(buf, "%s%s%s", root, _fi_sep, name);
861 return 0; // sprintf failed
862 DIR* d = opendir(buf);
871 _fi_find_handle _fi_FindFirstFile(const char* lpFileName, _fi_find_data* lpFindFileData)
873 _fi_find_handle dat = new _fi_priv_data(lpFileName);
875 DIR* h = opendir(dat->root);
879 if(_fi_FindNextFile(dat, lpFindFileData))
887 bool _fi_FindNextFile(_fi_find_handle dat, _fi_find_data* lpFindFileData)
893 } while(d && !iswild(dat->mask, d->d_name));
897 std::strcpy(lpFindFileData->cFileName, d->d_name);
898 lpFindFileData->dwFileAttributes = _fi_attributes(dat->root, d->d_name);
904 bool _fi_FindClose(_fi_find_handle dat)
913 } // namespace BOOST_REGEX_DETAIL_NS
916 #endif // BOOST_REGEX_NO_FILEITER