Files
2026-05-23 11:01:52 +01:00

206 lines
5.4 KiB
C++

#include "alfe/main.h"
#ifndef INCLUDED_FIND_HANDLE_H
#define INCLUDED_FIND_HANDLE_H
#ifdef _WIN32
template<class T> class FindHandleT
{
public:
FindHandleT(const Directory& directory, const String& wildcard)
: _directory(directory), _wildcard(wildcard), _complete(false),
_handle(INVALID_HANDLE_VALUE)
{
_path = directory.child(wildcard).path();
NullTerminatedWideString data(_path);
_handle = FindFirstFile(data, &_data);
if (_handle == INVALID_HANDLE_VALUE) {
DWORD lastError = GetLastError();
if (lastError == ERROR_FILE_NOT_FOUND ||
lastError == ERROR_ACCESS_DENIED ||
lastError == ERROR_INVALID_HANDLE)
_complete = true;
else
throwError();
}
String n = name();
if (n == "." || n == "..")
next();
}
void next()
{
do {
if (FindNextFile(_handle, &_data) == 0) {
DWORD lastError = GetLastError();
if (lastError == ERROR_NO_MORE_FILES ||
lastError == ERROR_INVALID_HANDLE) {
_complete = true;
return;
}
else
throwError();
}
String n = name();
if (n == "." || n == "..")
continue;
break;
} while (true);
}
~FindHandleT()
{
if (_handle != INVALID_HANDLE_VALUE)
FindClose(_handle);
}
bool isDirectory() const
{
return (_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
bool isJunction() const
{
return (_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
}
bool isSymlink() const
{
return isJunction() && _data.dwReserved0 == IO_REPARSE_TAG_SYMLINK;
}
String name() const
{
try {
String n(_data.cFileName);
return n;
}
catch (...)
{
return "<bad filename>";
}
}
FileSystemObject object() const
{
return _directory.child(name());
}
DirectoryT<T> directory() const
{
return _directory.subDirectory(name());
}
FileT<T> file() const
{
return _directory.file(name());
}
bool complete() { return _complete; }
private:
void throwError()
{
throw Exception::systemError("Finding files " + _path);
}
HANDLE _handle;
WIN32_FIND_DATA _data;
Directory _directory;
String _wildcard;
String _path;
bool _complete;
};
#else
template<class T> class FindHandleT
{
public:
FindHandleT(const Directory& directory, const String& wildcard)
: _directory(directory), _wildcard(wildcard), _complete(false),
_dir(NULL)
{
_path = directory.child(wildcard).path();
NullTerminatedString data(_path);
_dir = opendir(data);
if (_dir == NULL)
throw Exception::systemError("Opening directory " + _path);
next();
}
void next()
{
do {
errno = 0;
_data = readdir(_dir);
if (_data == NULL)
if (errno == 0)
_complete = true;
else
throw Exception::systemError("Reading directory " + _path);
String n = name();
if (n == "." || n == "..")
continue;
if (!matches(n, _wildcard))
continue;
break;
} while (true);
}
~FindHandleT()
{
if (_dir != NULL)
closedir(_dir);
}
bool isDirectory() const
{
return _data->d_type == DT_DIR;
}
String name() const
{
return _data->d_name;
}
FileSystemObject object() const
{
return _directory.child(name());
}
Directory directory() const
{
return _directory.subDirectory(name());
}
File file() const
{
return _directory.file(name());
}
bool complete() { return _complete; }
private:
static bool matches(String name, String wildcard)
{
CharacterSourceT<T> sw(wildcard);
CharacterSourceT<T> sn(name);
do {
int cs = sw.get();
int cn = sn.get();
switch (cs) {
case '?':
if (cn == -1)
return false;
continue;
case '*':
// TODO: this code is O(n^p) where p is number of stars, we
// can do better using dynamic programming.
if (cn == -1)
continue;
do {
if (matches(name.subString(sn.offset(),
name.length() - sn.offset()), sw.offset(),
wildcard.length() - sw.offset()))
return true;
cn = sn.get();
} while (cn != -1);
return false;
case -1:
return (cn == -1);
default:
return (cn == cs);
}
} while (true);
}
struct dirent* _data;
DIR* _dir;
Directory _directory;
String _wildcard;
String _path;
bool _complete;
};
#endif
#endif // INCLUDED_FIND_HANDLE_H