blob: ff1d11198fb36a4a876553352062cdcc5054bdd3 [file] [log] [blame]
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are 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)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE: fileiter.cpp
* VERSION: see <boost/version.hpp>
* DESCRIPTION: Implements file io primitives + directory searching for class boost::RegEx.
*/
#define BOOST_REGEX_SOURCE
#include <climits>
#include <stdexcept>
#include <string>
#include <boost/throw_exception.hpp>
#include <boost/regex/v4/fileiter.hpp>
#include <boost/regex/v4/regex_workaround.hpp>
#include <boost/regex/pattern_except.hpp>
#include <cstdio>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::sprintf;
using ::fseek;
using ::fread;
using ::ftell;
using ::fopen;
using ::fclose;
using ::FILE;
using ::strcpy;
using ::strcpy;
using ::strcat;
using ::strcmp;
using ::strlen;
}
#endif
#ifndef BOOST_REGEX_NO_FILEITER
#if defined(__CYGWIN__) || defined(__CYGWIN32__)
#include <sys/cygwin.h>
#endif
#ifdef BOOST_MSVC
# pragma warning(disable: 4800)
#endif
namespace boost{
namespace re_detail{
// start with the operating system specific stuff:
#if (defined(__BORLANDC__) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32)
// platform is DOS or Windows
// directories are separated with '\\'
// and names are insensitive of case
BOOST_REGEX_DECL const char* _fi_sep = "\\";
const char* _fi_sep_alt = "/";
#define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c)
#else
// platform is not DOS or Windows
// directories are separated with '/'
// and names are sensitive of case
BOOST_REGEX_DECL const char* _fi_sep = "/";
const char* _fi_sep_alt = _fi_sep;
#define BOOST_REGEX_FI_TRANSLATE(c) c
#endif
#ifdef BOOST_REGEX_FI_WIN32_MAP
void mapfile::open(const char* file)
{
#if defined(BOOST_NO_ANSI_APIS)
int filename_size = strlen(file);
LPWSTR wide_file = (LPWSTR)_alloca( (filename_size + 1) * sizeof(WCHAR) );
if(::MultiByteToWideChar(CP_ACP, 0, file, filename_size, wide_file, filename_size + 1) == 0)
hfile = INVALID_HANDLE_VALUE;
else
hfile = CreateFileW(wide_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
#elif defined(__CYGWIN__)||defined(__CYGWIN32__)
char win32file[ MAX_PATH ];
cygwin_conv_to_win32_path( file, win32file );
hfile = CreateFileA(win32file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
#else
hfile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
#endif
if(hfile != INVALID_HANDLE_VALUE)
{
hmap = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0);
if((hmap == INVALID_HANDLE_VALUE) || (hmap == NULL))
{
CloseHandle(hfile);
hmap = 0;
hfile = 0;
std::runtime_error err("Unable to create file mapping.");
boost::re_detail::raise_runtime_error(err);
}
_first = static_cast<const char*>(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0));
if(_first == 0)
{
CloseHandle(hmap);
CloseHandle(hfile);
hmap = 0;
hfile = 0;
std::runtime_error err("Unable to create file mapping.");
}
_last = _first + GetFileSize(hfile, 0);
}
else
{
hfile = 0;
#ifndef BOOST_NO_EXCEPTIONS
throw std::runtime_error("Unable to open file.");
#else
BOOST_REGEX_NOEH_ASSERT(hfile != INVALID_HANDLE_VALUE);
#endif
}
}
void mapfile::close()
{
if(hfile != INVALID_HANDLE_VALUE)
{
UnmapViewOfFile((void*)_first);
CloseHandle(hmap);
CloseHandle(hfile);
hmap = hfile = 0;
_first = _last = 0;
}
}
#elif !defined(BOOST_RE_NO_STL)
mapfile_iterator& mapfile_iterator::operator = (const mapfile_iterator& i)
{
if(file && node)
file->unlock(node);
file = i.file;
node = i.node;
offset = i.offset;
if(file)
file->lock(node);
return *this;
}
mapfile_iterator& mapfile_iterator::operator++ ()
{
if((++offset == mapfile::buf_size) && file)
{
++node;
offset = 0;
file->lock(node);
file->unlock(node-1);
}
return *this;
}
mapfile_iterator mapfile_iterator::operator++ (int)
{
mapfile_iterator temp(*this);
if((++offset == mapfile::buf_size) && file)
{
++node;
offset = 0;
file->lock(node);
file->unlock(node-1);
}
return temp;
}
mapfile_iterator& mapfile_iterator::operator-- ()
{
if((offset == 0) && file)
{
--node;
offset = mapfile::buf_size - 1;
file->lock(node);
file->unlock(node + 1);
}
else
--offset;
return *this;
}
mapfile_iterator mapfile_iterator::operator-- (int)
{
mapfile_iterator temp(*this);
if((offset == 0) && file)
{
--node;
offset = mapfile::buf_size - 1;
file->lock(node);
file->unlock(node + 1);
}
else
--offset;
return temp;
}
mapfile_iterator operator + (const mapfile_iterator& i, long off)
{
mapfile_iterator temp(i);
temp += off;
return temp;
}
mapfile_iterator operator - (const mapfile_iterator& i, long off)
{
mapfile_iterator temp(i);
temp -= off;
return temp;
}
mapfile::iterator mapfile::begin()const
{
return mapfile_iterator(this, 0);
}
mapfile::iterator mapfile::end()const
{
return mapfile_iterator(this, _size);
}
void mapfile::lock(pointer* node)const
{
BOOST_ASSERT(node >= _first);
BOOST_ASSERT(node <= _last);
if(node < _last)
{
if(*node == 0)
{
if(condemed.empty())
{
*node = new char[sizeof(int) + buf_size];
*(reinterpret_cast<int*>(*node)) = 1;
}
else
{
pointer* p = condemed.front();
condemed.pop_front();
*node = *p;
*p = 0;
*(reinterpret_cast<int*>(*node)) = 1;
}
std::size_t read_size = 0;
int read_pos = std::fseek(hfile, (node - _first) * buf_size, SEEK_SET);
if(0 == read_pos && node == _last - 1)
read_size = std::fread(*node + sizeof(int), _size % buf_size, 1, hfile);
else
read_size = std::fread(*node + sizeof(int), buf_size, 1, hfile);
#ifndef BOOST_NO_EXCEPTIONS
if((read_size == 0) || (std::ferror(hfile)))
{
throw std::runtime_error("Unable to read file.");
}
#else
BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile)) && (read_size != 0));
#endif
}
else
{
if(*reinterpret_cast<int*>(*node) == 0)
{
*reinterpret_cast<int*>(*node) = 1;
condemed.remove(node);
}
else
++(*reinterpret_cast<int*>(*node));
}
}
}
void mapfile::unlock(pointer* node)const
{
BOOST_ASSERT(node >= _first);
BOOST_ASSERT(node <= _last);
if(node < _last)
{
if(--(*reinterpret_cast<int*>(*node)) == 0)
{
condemed.push_back(node);
}
}
}
long int get_file_length(std::FILE* hfile)
{
long int result;
std::fseek(hfile, 0, SEEK_END);
result = std::ftell(hfile);
std::fseek(hfile, 0, SEEK_SET);
return result;
}
void mapfile::open(const char* file)
{
hfile = std::fopen(file, "rb");
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
if(hfile != 0)
{
_size = get_file_length(hfile);
long cnodes = (_size + buf_size - 1) / buf_size;
// check that number of nodes is not too high:
if(cnodes > (long)((INT_MAX) / sizeof(pointer*)))
{
std::fclose(hfile);
hfile = 0;
_size = 0;
return;
}
_first = new pointer[(int)cnodes];
_last = _first + cnodes;
std::memset(_first, 0, cnodes*sizeof(pointer));
}
else
{
std::runtime_error err("Unable to open file.");
}
#ifndef BOOST_NO_EXCEPTIONS
}catch(...)
{ close(); throw; }
#endif
}
void mapfile::close()
{
if(hfile != 0)
{
pointer* p = _first;
while(p != _last)
{
if(*p)
delete[] *p;
++p;
}
delete[] _first;
_size = 0;
_first = _last = 0;
std::fclose(hfile);
hfile = 0;
condemed.erase(condemed.begin(), condemed.end());
}
}
#endif
inline _fi_find_handle find_first_file(const char* wild, _fi_find_data& data)
{
#ifdef BOOST_NO_ANSI_APIS
std::size_t wild_size = std::strlen(wild);
LPWSTR wide_wild = (LPWSTR)_alloca( (wild_size + 1) * sizeof(WCHAR) );
if (::MultiByteToWideChar(CP_ACP, 0, wild, wild_size, wide_wild, wild_size + 1) == 0)
return _fi_invalid_handle;
return FindFirstFileW(wide_wild, &data);
#else
return FindFirstFileA(wild, &data);
#endif
}
inline bool find_next_file(_fi_find_handle hf, _fi_find_data& data)
{
#ifdef BOOST_NO_ANSI_APIS
return FindNextFileW(hf, &data);
#else
return FindNextFileA(hf, &data);
#endif
}
inline void copy_find_file_result_with_overflow_check(const _fi_find_data& data, char* path, size_t max_size)
{
#ifdef BOOST_NO_ANSI_APIS
if (::WideCharToMultiByte(CP_ACP, 0, data.cFileName, -1, path, max_size, NULL, NULL) == 0)
re_detail::overflow_error_if_not_zero(1);
#else
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(path, max_size, data.cFileName));
#endif
}
inline bool is_not_current_or_parent_path_string(const _fi_find_data& data)
{
#ifdef BOOST_NO_ANSI_APIS
return (std::wcscmp(data.cFileName, L".") && std::wcscmp(data.cFileName, L".."));
#else
return (std::strcmp(data.cFileName, ".") && std::strcmp(data.cFileName, ".."));
#endif
}
file_iterator::file_iterator()
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
ptr = _path;
*_path = 0;
*_root = 0;
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
ref->hf = _fi_invalid_handle;
ref->count = 1;
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
delete ref;
throw;
}
#endif
}
file_iterator::file_iterator(const char* wild)
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild));
ptr = _root;
while(*ptr)++ptr;
while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
{
_root[1]='\0';
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
}
else
{
*ptr = 0;
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
if(*_path == 0)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, "."));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep));
}
ptr = _path + std::strlen(_path);
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
ref->hf = find_first_file(wild, ref->_data);
ref->count = 1;
if(ref->hf == _fi_invalid_handle)
{
*_path = 0;
ptr = _path;
}
else
{
copy_find_file_result_with_overflow_check(ref->_data, ptr, (MAX_PATH - (ptr - _path)));
if(ref->_data.dwFileAttributes & _fi_dir)
next();
}
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
delete ref;
throw;
}
#endif
}
file_iterator::file_iterator(const file_iterator& other)
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
ref = other.ref;
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
throw;
}
#endif
++(ref->count);
}
file_iterator& file_iterator::operator=(const file_iterator& other)
{
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
if(--(ref->count) == 0)
{
if(ref->hf != _fi_invalid_handle)
FindClose(ref->hf);
delete ref;
}
ref = other.ref;
++(ref->count);
return *this;
}
file_iterator::~file_iterator()
{
delete[] _root;
delete[] _path;
if(--(ref->count) == 0)
{
if(ref->hf != _fi_invalid_handle)
FindClose(ref->hf);
delete ref;
}
}
file_iterator file_iterator::operator++(int)
{
file_iterator temp(*this);
next();
return temp;
}
void file_iterator::next()
{
if(ref->hf != _fi_invalid_handle)
{
bool cont = true;
while(cont)
{
cont = find_next_file(ref->hf, ref->_data);
if(cont && ((ref->_data.dwFileAttributes & _fi_dir) == 0))
break;
}
if(!cont)
{
// end of sequence
FindClose(ref->hf);
ref->hf = _fi_invalid_handle;
*_path = 0;
ptr = _path;
}
else
copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
}
}
directory_iterator::directory_iterator()
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
ptr = _path;
*_path = 0;
*_root = 0;
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
ref->hf = _fi_invalid_handle;
ref->count = 1;
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
delete ref;
throw;
}
#endif
}
directory_iterator::directory_iterator(const char* wild)
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, wild));
ptr = _root;
while(*ptr)++ptr;
while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr;
if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) )
{
_root[1]='\0';
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
}
else
{
*ptr = 0;
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, _root));
if(*_path == 0)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, "."));
re_detail::overflow_error_if_not_zero(re_detail::strcat_s(_path, MAX_PATH, _fi_sep));
}
ptr = _path + std::strlen(_path);
ref = new file_iterator_ref();
BOOST_REGEX_NOEH_ASSERT(ref)
ref->count = 1;
ref->hf = find_first_file(wild, ref->_data);
if(ref->hf == _fi_invalid_handle)
{
*_path = 0;
ptr = _path;
}
else
{
copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ptr, ".") == 0) || (std::strcmp(ptr, "..") == 0))
next();
}
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
delete ref;
throw;
}
#endif
}
directory_iterator::~directory_iterator()
{
delete[] _root;
delete[] _path;
if(--(ref->count) == 0)
{
if(ref->hf != _fi_invalid_handle)
FindClose(ref->hf);
delete ref;
}
}
directory_iterator::directory_iterator(const directory_iterator& other)
{
_root = _path = 0;
ref = 0;
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
_root = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_root)
_path = new char[MAX_PATH];
BOOST_REGEX_NOEH_ASSERT(_path)
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
ref = other.ref;
#ifndef BOOST_NO_EXCEPTIONS
}
catch(...)
{
delete[] _root;
delete[] _path;
throw;
}
#endif
++(ref->count);
}
directory_iterator& directory_iterator::operator=(const directory_iterator& other)
{
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_root, MAX_PATH, other._root));
re_detail::overflow_error_if_not_zero(re_detail::strcpy_s(_path, MAX_PATH, other._path));
ptr = _path + (other.ptr - other._path);
if(--(ref->count) == 0)
{
if(ref->hf != _fi_invalid_handle)
FindClose(ref->hf);
delete ref;
}
ref = other.ref;
++(ref->count);
return *this;
}
directory_iterator directory_iterator::operator++(int)
{
directory_iterator temp(*this);
next();
return temp;
}
void directory_iterator::next()
{
if(ref->hf != _fi_invalid_handle)
{
bool cont = true;
while(cont)
{
cont = find_next_file(ref->hf, ref->_data);
if(cont && (ref->_data.dwFileAttributes & _fi_dir))
{
if(is_not_current_or_parent_path_string(ref->_data))
break;
}
}
if(!cont)
{
// end of sequence
FindClose(ref->hf);
ref->hf = _fi_invalid_handle;
*_path = 0;
ptr = _path;
}
else
copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path));
}
}
#ifdef BOOST_REGEX_FI_POSIX_DIR
struct _fi_priv_data
{
char root[MAX_PATH];
char* mask;
DIR* d;
_fi_priv_data(const char* p);
};
_fi_priv_data::_fi_priv_data(const char* p)
{
std::strcpy(root, p);
mask = root;
while(*mask) ++mask;
while((mask > root) && (*mask != *_fi_sep) && (*mask != *_fi_sep_alt)) --mask;
if(mask == root && ((*mask== *_fi_sep) || (*mask == *_fi_sep_alt)) )
{
root[1] = '\0';
std::strcpy(root+2, p+1);
mask = root+2;
}
else if(mask == root)
{
root[0] = '.';
root[1] = '\0';
std::strcpy(root+2, p);
mask = root+2;
}
else
{
*mask = 0;
++mask;
}
}
bool iswild(const char* mask, const char* name)
{
while(*mask && *name)
{
switch(*mask)
{
case '?':
++name;
++mask;
continue;
case '*':
++mask;
if(*mask == 0)
return true;
while(*name)
{
if(iswild(mask, name))
return true;
++name;
}
return false;
case '.':
if(0 == *name)
{
++mask;
continue;
}
// fall through:
default:
if(BOOST_REGEX_FI_TRANSLATE(*mask) != BOOST_REGEX_FI_TRANSLATE(*name))
return false;
++mask;
++name;
continue;
}
}
if(*mask != *name)
return false;
return true;
}
unsigned _fi_attributes(const char* root, const char* name)
{
char buf[MAX_PATH];
if( ( (root[0] == *_fi_sep) || (root[0] == *_fi_sep_alt) ) && (root[1] == '\0') )
(std::sprintf)(buf, "%s%s", root, name);
else
(std::sprintf)(buf, "%s%s%s", root, _fi_sep, name);
DIR* d = opendir(buf);
if(d)
{
closedir(d);
return _fi_dir;
}
return 0;
}
_fi_find_handle _fi_FindFirstFile(const char* lpFileName, _fi_find_data* lpFindFileData)
{
_fi_find_handle dat = new _fi_priv_data(lpFileName);
DIR* h = opendir(dat->root);
dat->d = h;
if(h != 0)
{
if(_fi_FindNextFile(dat, lpFindFileData))
return dat;
}
delete dat;
return 0;
}
bool _fi_FindNextFile(_fi_find_handle dat, _fi_find_data* lpFindFileData)
{
dirent* d;
do
{
d = readdir(dat->d);
} while(d && !iswild(dat->mask, d->d_name));
if(d)
{
std::strcpy(lpFindFileData->cFileName, d->d_name);
lpFindFileData->dwFileAttributes = _fi_attributes(dat->root, d->d_name);
return true;
}
return false;
}
bool _fi_FindClose(_fi_find_handle dat)
{
closedir(dat->d);
delete dat;
return true;
}
#endif
} // namespace re_detail
} // namspace boost
#endif // BOOST_REGEX_NO_FILEITER