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
25 #include <boost/throw_exception.hpp>
26 #include <boost/regex/v4/fileiter.hpp>
27 #include <boost/regex/v4/regex_workaround.hpp>
28 #include <boost/regex/pattern_except.hpp>
31 #if defined(BOOST_NO_STDC_NAMESPACE)
49 #ifndef BOOST_REGEX_NO_FILEITER
51 #if defined(__CYGWIN__) || defined(__CYGWIN32__)
52 #include <sys/cygwin.h>
56 # pragma warning(disable: 4800)
61 // start with the operating system specific stuff:
63 #if (defined(__BORLANDC__) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32)
65 // platform is DOS or Windows
66 // directories are separated with '\\'
67 // and names are insensitive of case
69 BOOST_REGEX_DECL
const char* _fi_sep
= "\\";
70 const char* _fi_sep_alt
= "/";
71 #define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c)
75 // platform is not DOS or Windows
76 // directories are separated with '/'
77 // and names are sensitive of case
79 BOOST_REGEX_DECL
const char* _fi_sep
= "/";
80 const char* _fi_sep_alt
= _fi_sep
;
81 #define BOOST_REGEX_FI_TRANSLATE(c) c
85 #ifdef BOOST_REGEX_FI_WIN32_MAP
87 void mapfile::open(const char* file
)
89 #if defined(BOOST_NO_ANSI_APIS)
90 int filename_size
= strlen(file
);
91 LPWSTR wide_file
= (LPWSTR
)_alloca( (filename_size
+ 1) * sizeof(WCHAR
) );
92 if(::MultiByteToWideChar(CP_ACP
, 0, file
, filename_size
, wide_file
, filename_size
+ 1) == 0)
93 hfile
= INVALID_HANDLE_VALUE
;
95 hfile
= CreateFileW(wide_file
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
96 #elif defined(__CYGWIN__)||defined(__CYGWIN32__)
97 char win32file
[ MAX_PATH
];
98 cygwin_conv_to_win32_path( file
, win32file
);
99 hfile
= CreateFileA(win32file
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
101 hfile
= CreateFileA(file
, GENERIC_READ
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
103 if(hfile
!= INVALID_HANDLE_VALUE
)
105 hmap
= CreateFileMapping(hfile
, 0, PAGE_READONLY
, 0, 0, 0);
106 if((hmap
== INVALID_HANDLE_VALUE
) || (hmap
== NULL
))
111 std::runtime_error
err("Unable to create file mapping.");
112 boost::re_detail::raise_runtime_error(err
);
114 _first
= static_cast<const char*>(MapViewOfFile(hmap
, FILE_MAP_READ
, 0, 0, 0));
121 std::runtime_error
err("Unable to create file mapping.");
123 _last
= _first
+ GetFileSize(hfile
, 0);
128 #ifndef BOOST_NO_EXCEPTIONS
129 throw std::runtime_error("Unable to open file.");
131 BOOST_REGEX_NOEH_ASSERT(hfile
!= INVALID_HANDLE_VALUE
);
136 void mapfile::close()
138 if(hfile
!= INVALID_HANDLE_VALUE
)
140 UnmapViewOfFile((void*)_first
);
148 #elif !defined(BOOST_RE_NO_STL)
150 mapfile_iterator
& mapfile_iterator::operator = (const mapfile_iterator
& i
)
162 mapfile_iterator
& mapfile_iterator::operator++ ()
164 if((++offset
== mapfile::buf_size
) && file
)
169 file
->unlock(node
-1);
174 mapfile_iterator
mapfile_iterator::operator++ (int)
176 mapfile_iterator
temp(*this);
177 if((++offset
== mapfile::buf_size
) && file
)
182 file
->unlock(node
-1);
187 mapfile_iterator
& mapfile_iterator::operator-- ()
189 if((offset
== 0) && file
)
192 offset
= mapfile::buf_size
- 1;
194 file
->unlock(node
+ 1);
201 mapfile_iterator
mapfile_iterator::operator-- (int)
203 mapfile_iterator
temp(*this);
204 if((offset
== 0) && file
)
207 offset
= mapfile::buf_size
- 1;
209 file
->unlock(node
+ 1);
216 mapfile_iterator
operator + (const mapfile_iterator
& i
, long off
)
218 mapfile_iterator
temp(i
);
223 mapfile_iterator
operator - (const mapfile_iterator
& i
, long off
)
225 mapfile_iterator
temp(i
);
230 mapfile::iterator
mapfile::begin()const
232 return mapfile_iterator(this, 0);
235 mapfile::iterator
mapfile::end()const
237 return mapfile_iterator(this, _size
);
240 void mapfile::lock(pointer
* node
)const
242 BOOST_ASSERT(node
>= _first
);
243 BOOST_ASSERT(node
<= _last
);
250 *node
= new char[sizeof(int) + buf_size
];
251 *(reinterpret_cast<int*>(*node
)) = 1;
255 pointer
* p
= condemed
.front();
256 condemed
.pop_front();
259 *(reinterpret_cast<int*>(*node
)) = 1;
262 std::size_t read_size
= 0;
263 int read_pos
= std::fseek(hfile
, (node
- _first
) * buf_size
, SEEK_SET
);
265 if(0 == read_pos
&& node
== _last
- 1)
266 read_size
= std::fread(*node
+ sizeof(int), _size
% buf_size
, 1, hfile
);
268 read_size
= std::fread(*node
+ sizeof(int), buf_size
, 1, hfile
);
269 #ifndef BOOST_NO_EXCEPTIONS
270 if((read_size
== 0) || (std::ferror(hfile
)))
272 throw std::runtime_error("Unable to read file.");
275 BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile
)) && (read_size
!= 0));
280 if(*reinterpret_cast<int*>(*node
) == 0)
282 *reinterpret_cast<int*>(*node
) = 1;
283 condemed
.remove(node
);
286 ++(*reinterpret_cast<int*>(*node
));
291 void mapfile::unlock(pointer
* node
)const
293 BOOST_ASSERT(node
>= _first
);
294 BOOST_ASSERT(node
<= _last
);
297 if(--(*reinterpret_cast<int*>(*node
)) == 0)
299 condemed
.push_back(node
);
304 long int get_file_length(std::FILE* hfile
)
307 std::fseek(hfile
, 0, SEEK_END
);
308 result
= std::ftell(hfile
);
309 std::fseek(hfile
, 0, SEEK_SET
);
314 void mapfile::open(const char* file
)
316 hfile
= std::fopen(file
, "rb");
317 #ifndef BOOST_NO_EXCEPTIONS
322 _size
= get_file_length(hfile
);
323 long cnodes
= (_size
+ buf_size
- 1) / buf_size
;
325 // check that number of nodes is not too high:
326 if(cnodes
> (long)((INT_MAX
) / sizeof(pointer
*)))
334 _first
= new pointer
[(int)cnodes
];
335 _last
= _first
+ cnodes
;
336 std::memset(_first
, 0, cnodes
*sizeof(pointer
));
340 std::runtime_error
err("Unable to open file.");
342 #ifndef BOOST_NO_EXCEPTIONS
348 void mapfile::close()
364 condemed
.erase(condemed
.begin(), condemed
.end());
371 inline _fi_find_handle
find_first_file(const char* wild
, _fi_find_data
& data
)
373 #ifdef BOOST_NO_ANSI_APIS
374 std::size_t wild_size
= std::strlen(wild
);
375 LPWSTR wide_wild
= (LPWSTR
)_alloca( (wild_size
+ 1) * sizeof(WCHAR
) );
376 if (::MultiByteToWideChar(CP_ACP
, 0, wild
, wild_size
, wide_wild
, wild_size
+ 1) == 0)
377 return _fi_invalid_handle
;
379 return FindFirstFileW(wide_wild
, &data
);
381 return FindFirstFileA(wild
, &data
);
385 inline bool find_next_file(_fi_find_handle hf
, _fi_find_data
& data
)
387 #ifdef BOOST_NO_ANSI_APIS
388 return FindNextFileW(hf
, &data
);
390 return FindNextFileA(hf
, &data
);
394 inline void copy_find_file_result_with_overflow_check(const _fi_find_data
& data
, char* path
, size_t max_size
)
396 #ifdef BOOST_NO_ANSI_APIS
397 if (::WideCharToMultiByte(CP_ACP
, 0, data
.cFileName
, -1, path
, max_size
, NULL
, NULL
) == 0)
398 re_detail::overflow_error_if_not_zero(1);
400 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(path
, max_size
, data
.cFileName
));
404 inline bool is_not_current_or_parent_path_string(const _fi_find_data
& data
)
406 #ifdef BOOST_NO_ANSI_APIS
407 return (std::wcscmp(data
.cFileName
, L
".") && std::wcscmp(data
.cFileName
, L
".."));
409 return (std::strcmp(data
.cFileName
, ".") && std::strcmp(data
.cFileName
, ".."));
414 file_iterator::file_iterator()
418 #ifndef BOOST_NO_EXCEPTIONS
421 _root
= new char[MAX_PATH
];
422 BOOST_REGEX_NOEH_ASSERT(_root
)
423 _path
= new char[MAX_PATH
];
424 BOOST_REGEX_NOEH_ASSERT(_path
)
428 ref
= new file_iterator_ref();
429 BOOST_REGEX_NOEH_ASSERT(ref
)
430 ref
->hf
= _fi_invalid_handle
;
432 #ifndef BOOST_NO_EXCEPTIONS
444 file_iterator::file_iterator(const char* wild
)
448 #ifndef BOOST_NO_EXCEPTIONS
451 _root
= new char[MAX_PATH
];
452 BOOST_REGEX_NOEH_ASSERT(_root
)
453 _path
= new char[MAX_PATH
];
454 BOOST_REGEX_NOEH_ASSERT(_path
)
455 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, wild
));
458 while((ptr
> _root
) && (*ptr
!= *_fi_sep
) && (*ptr
!= *_fi_sep_alt
))--ptr
;
459 if((ptr
== _root
) && ( (*ptr
== *_fi_sep
) || (*ptr
==*_fi_sep_alt
) ) )
462 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, _root
));
467 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, _root
));
469 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, "."));
470 re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path
, MAX_PATH
, _fi_sep
));
472 ptr
= _path
+ std::strlen(_path
);
474 ref
= new file_iterator_ref();
475 BOOST_REGEX_NOEH_ASSERT(ref
)
476 ref
->hf
= find_first_file(wild
, ref
->_data
);
479 if(ref
->hf
== _fi_invalid_handle
)
486 copy_find_file_result_with_overflow_check(ref
->_data
, ptr
, (MAX_PATH
- (ptr
- _path
)));
487 if(ref
->_data
.dwFileAttributes
& _fi_dir
)
490 #ifndef BOOST_NO_EXCEPTIONS
502 file_iterator::file_iterator(const file_iterator
& other
)
506 #ifndef BOOST_NO_EXCEPTIONS
509 _root
= new char[MAX_PATH
];
510 BOOST_REGEX_NOEH_ASSERT(_root
)
511 _path
= new char[MAX_PATH
];
512 BOOST_REGEX_NOEH_ASSERT(_path
)
513 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, other
._root
));
514 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, other
._path
));
515 ptr
= _path
+ (other
.ptr
- other
._path
);
517 #ifndef BOOST_NO_EXCEPTIONS
529 file_iterator
& file_iterator::operator=(const file_iterator
& other
)
531 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, other
._root
));
532 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, other
._path
));
533 ptr
= _path
+ (other
.ptr
- other
._path
);
534 if(--(ref
->count
) == 0)
536 if(ref
->hf
!= _fi_invalid_handle
)
546 file_iterator::~file_iterator()
550 if(--(ref
->count
) == 0)
552 if(ref
->hf
!= _fi_invalid_handle
)
558 file_iterator
file_iterator::operator++(int)
560 file_iterator
temp(*this);
566 void file_iterator::next()
568 if(ref
->hf
!= _fi_invalid_handle
)
573 cont
= find_next_file(ref
->hf
, ref
->_data
);
574 if(cont
&& ((ref
->_data
.dwFileAttributes
& _fi_dir
) == 0))
581 ref
->hf
= _fi_invalid_handle
;
586 copy_find_file_result_with_overflow_check(ref
->_data
, ptr
, MAX_PATH
- (ptr
- _path
));
592 directory_iterator::directory_iterator()
596 #ifndef BOOST_NO_EXCEPTIONS
599 _root
= new char[MAX_PATH
];
600 BOOST_REGEX_NOEH_ASSERT(_root
)
601 _path
= new char[MAX_PATH
];
602 BOOST_REGEX_NOEH_ASSERT(_path
)
606 ref
= new file_iterator_ref();
607 BOOST_REGEX_NOEH_ASSERT(ref
)
608 ref
->hf
= _fi_invalid_handle
;
610 #ifndef BOOST_NO_EXCEPTIONS
622 directory_iterator::directory_iterator(const char* wild
)
626 #ifndef BOOST_NO_EXCEPTIONS
629 _root
= new char[MAX_PATH
];
630 BOOST_REGEX_NOEH_ASSERT(_root
)
631 _path
= new char[MAX_PATH
];
632 BOOST_REGEX_NOEH_ASSERT(_path
)
633 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, wild
));
636 while((ptr
> _root
) && (*ptr
!= *_fi_sep
) && (*ptr
!= *_fi_sep_alt
))--ptr
;
638 if((ptr
== _root
) && ( (*ptr
== *_fi_sep
) || (*ptr
==*_fi_sep_alt
) ) )
641 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, _root
));
646 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, _root
));
648 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, "."));
649 re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path
, MAX_PATH
, _fi_sep
));
651 ptr
= _path
+ std::strlen(_path
);
653 ref
= new file_iterator_ref();
654 BOOST_REGEX_NOEH_ASSERT(ref
)
656 ref
->hf
= find_first_file(wild
, ref
->_data
);
657 if(ref
->hf
== _fi_invalid_handle
)
664 copy_find_file_result_with_overflow_check(ref
->_data
, ptr
, MAX_PATH
- (ptr
- _path
));
665 if(((ref
->_data
.dwFileAttributes
& _fi_dir
) == 0) || (std::strcmp(ptr
, ".") == 0) || (std::strcmp(ptr
, "..") == 0))
668 #ifndef BOOST_NO_EXCEPTIONS
680 directory_iterator::~directory_iterator()
684 if(--(ref
->count
) == 0)
686 if(ref
->hf
!= _fi_invalid_handle
)
692 directory_iterator::directory_iterator(const directory_iterator
& other
)
696 #ifndef BOOST_NO_EXCEPTIONS
699 _root
= new char[MAX_PATH
];
700 BOOST_REGEX_NOEH_ASSERT(_root
)
701 _path
= new char[MAX_PATH
];
702 BOOST_REGEX_NOEH_ASSERT(_path
)
703 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, other
._root
));
704 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, other
._path
));
705 ptr
= _path
+ (other
.ptr
- other
._path
);
707 #ifndef BOOST_NO_EXCEPTIONS
719 directory_iterator
& directory_iterator::operator=(const directory_iterator
& other
)
721 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root
, MAX_PATH
, other
._root
));
722 re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path
, MAX_PATH
, other
._path
));
723 ptr
= _path
+ (other
.ptr
- other
._path
);
724 if(--(ref
->count
) == 0)
726 if(ref
->hf
!= _fi_invalid_handle
)
735 directory_iterator
directory_iterator::operator++(int)
737 directory_iterator
temp(*this);
742 void directory_iterator::next()
744 if(ref
->hf
!= _fi_invalid_handle
)
749 cont
= find_next_file(ref
->hf
, ref
->_data
);
750 if(cont
&& (ref
->_data
.dwFileAttributes
& _fi_dir
))
752 if(is_not_current_or_parent_path_string(ref
->_data
))
760 ref
->hf
= _fi_invalid_handle
;
765 copy_find_file_result_with_overflow_check(ref
->_data
, ptr
, MAX_PATH
- (ptr
- _path
));
770 #ifdef BOOST_REGEX_FI_POSIX_DIR
777 _fi_priv_data(const char* p
);
780 _fi_priv_data::_fi_priv_data(const char* p
)
782 std::strcpy(root
, p
);
785 while((mask
> root
) && (*mask
!= *_fi_sep
) && (*mask
!= *_fi_sep_alt
)) --mask
;
786 if(mask
== root
&& ((*mask
== *_fi_sep
) || (*mask
== *_fi_sep_alt
)) )
789 std::strcpy(root
+2, p
+1);
792 else if(mask
== root
)
796 std::strcpy(root
+2, p
);
806 bool iswild(const char* mask
, const char* name
)
808 while(*mask
&& *name
)
822 if(iswild(mask
, name
))
835 if(BOOST_REGEX_FI_TRANSLATE(*mask
) != BOOST_REGEX_FI_TRANSLATE(*name
))
847 unsigned _fi_attributes(const char* root
, const char* name
)
850 // verify that we can not overflow:
851 if(std::strlen(root
) + std::strlen(_fi_sep
) + std::strlen(name
) >= MAX_PATH
)
854 if( ( (root
[0] == *_fi_sep
) || (root
[0] == *_fi_sep_alt
) ) && (root
[1] == '\0') )
855 r
= (std::sprintf
)(buf
, "%s%s", root
, name
);
857 r
= (std::sprintf
)(buf
, "%s%s%s", root
, _fi_sep
, name
);
859 return 0; // sprintf failed
860 DIR* d
= opendir(buf
);
869 _fi_find_handle
_fi_FindFirstFile(const char* lpFileName
, _fi_find_data
* lpFindFileData
)
871 _fi_find_handle dat
= new _fi_priv_data(lpFileName
);
873 DIR* h
= opendir(dat
->root
);
877 if(_fi_FindNextFile(dat
, lpFindFileData
))
884 bool _fi_FindNextFile(_fi_find_handle dat
, _fi_find_data
* lpFindFileData
)
890 } while(d
&& !iswild(dat
->mask
, d
->d_name
));
894 std::strcpy(lpFindFileData
->cFileName
, d
->d_name
);
895 lpFindFileData
->dwFileAttributes
= _fi_attributes(dat
->root
, d
->d_name
);
901 bool _fi_FindClose(_fi_find_handle dat
)
910 } // namespace re_detail
913 #endif // BOOST_REGEX_NO_FILEITER