mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-02-25 07:32:28 +01:00
byuu says: Changelog: - hiro: BrowserDialog can navigate up to drive selection on Windows - nall: (file,path,dir,base,prefix,suffix)name => Location::(file,path,dir,base,prefix,suffix) - higan/tomoko: rename audio filter label from "Sinc" to "IIR - Biquad" - higan/tomoko: allow loading files via icarus on the command-line once again - higan/tomoko: (begrudging) quick hack to fix presentation window focus on startup - higan/audio: don't divide output audio volume by number of streams - processor/r65816: fix a regression in (read,write)DB; fixes Taz-Mania - fixed compilation regressions on Windows and Linux I'm happy with where we are at with code cleanups and stability, so I'd like to release v100. But even though I'm not assigning any special significance to this version, we should probably test it more thoroughly first.
253 lines
8.0 KiB
C++
253 lines
8.0 KiB
C++
#pragma once
|
|
|
|
#include <nall/file.hpp>
|
|
#include <nall/inode.hpp>
|
|
#include <nall/intrinsics.hpp>
|
|
#include <nall/sort.hpp>
|
|
#include <nall/string.hpp>
|
|
#include <nall/vector.hpp>
|
|
|
|
#if defined(PLATFORM_WINDOWS)
|
|
#include <nall/windows/utf8.hpp>
|
|
#else
|
|
#include <dirent.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
namespace nall {
|
|
|
|
struct directory : inode {
|
|
static auto create(const string& pathname, uint permissions = 0755) -> bool; //recursive
|
|
static auto remove(const string& pathname) -> bool; //recursive
|
|
static auto exists(const string& pathname) -> bool;
|
|
|
|
static auto folders(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto folders = directory::ufolders(pathname, pattern);
|
|
folders.sort();
|
|
return folders;
|
|
}
|
|
|
|
static auto files(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto files = directory::ufiles(pathname, pattern);
|
|
files.sort();
|
|
return files;
|
|
}
|
|
|
|
static auto contents(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
|
auto files = directory::ufiles(pathname, pattern);
|
|
folders.sort();
|
|
files.sort();
|
|
for(auto& file : files) folders.append(file);
|
|
return folders;
|
|
}
|
|
|
|
static auto ifolders(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto folders = ufolders(pathname, pattern);
|
|
folders.isort();
|
|
return folders;
|
|
}
|
|
|
|
static auto ifiles(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto files = ufiles(pathname, pattern);
|
|
files.isort();
|
|
return files;
|
|
}
|
|
|
|
static auto icontents(const string& pathname, const string& pattern = "*") -> string_vector {
|
|
auto folders = directory::ufolders(pathname); //pattern search of contents should only filter files
|
|
auto files = directory::ufiles(pathname, pattern);
|
|
folders.isort();
|
|
files.isort();
|
|
for(auto& file : files) folders.append(file);
|
|
return folders;
|
|
}
|
|
|
|
private:
|
|
//internal functions; these return unsorted lists
|
|
static auto ufolders(const string& pathname, const string& pattern = "*") -> string_vector;
|
|
static auto ufiles(const string& pathname, const string& pattern = "*") -> string_vector;
|
|
};
|
|
|
|
#if defined(PLATFORM_WINDOWS)
|
|
inline auto directory::create(const string& pathname, uint permissions) -> bool {
|
|
string path;
|
|
auto list = string{pathname}.transform("\\", "/").trimRight("/").split("/");
|
|
bool result = true;
|
|
for(auto& part : list) {
|
|
path.append(part, "/");
|
|
if(directory::exists(path)) continue;
|
|
result &= (_wmkdir(utf16_t(path)) == 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline auto directory::remove(const string& pathname) -> bool {
|
|
auto list = directory::contents(pathname);
|
|
for(auto& name : list) {
|
|
if(name.endsWith("/")) directory::remove({pathname, name});
|
|
else file::remove({pathname, name});
|
|
}
|
|
return _wrmdir(utf16_t(pathname)) == 0;
|
|
}
|
|
|
|
inline auto directory::exists(const string& pathname) -> bool {
|
|
string name = pathname;
|
|
name.trim("\"", "\"");
|
|
DWORD result = GetFileAttributes(utf16_t(name));
|
|
if(result == INVALID_FILE_ATTRIBUTES) return false;
|
|
return (result & FILE_ATTRIBUTE_DIRECTORY);
|
|
}
|
|
|
|
inline auto directory::ufolders(const string& pathname, const string& pattern) -> string_vector {
|
|
if(!pathname) {
|
|
//special root pseudo-folder (return list of drives)
|
|
wchar_t drives[PATH_MAX] = {0};
|
|
GetLogicalDriveStrings(PATH_MAX, drives);
|
|
wchar_t* p = drives;
|
|
while(*p || *(p + 1)) {
|
|
if(!*p) *p = ';';
|
|
*p++;
|
|
}
|
|
return string{(const char*)utf8_t(drives)}.replace("\\", "/").split(";");
|
|
}
|
|
|
|
string_vector list;
|
|
string path = pathname;
|
|
path.transform("/", "\\");
|
|
if(!path.endsWith("\\")) path.append("\\");
|
|
path.append("*");
|
|
HANDLE handle;
|
|
WIN32_FIND_DATA data;
|
|
handle = FindFirstFile(utf16_t(path), &data);
|
|
if(handle != INVALID_HANDLE_VALUE) {
|
|
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
|
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
string name = (const char*)utf8_t(data.cFileName);
|
|
if(name.match(pattern)) list.append(name);
|
|
}
|
|
}
|
|
while(FindNextFile(handle, &data) != false) {
|
|
if(wcscmp(data.cFileName, L".") && wcscmp(data.cFileName, L"..")) {
|
|
if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
string name = (const char*)utf8_t(data.cFileName);
|
|
if(name.match(pattern)) list.append(name);
|
|
}
|
|
}
|
|
}
|
|
FindClose(handle);
|
|
}
|
|
for(auto& name : list) name.append("/"); //must append after sorting
|
|
return list;
|
|
}
|
|
|
|
inline auto directory::ufiles(const string& pathname, const string& pattern) -> string_vector {
|
|
if(!pathname) return {};
|
|
|
|
string_vector list;
|
|
string path = pathname;
|
|
path.transform("/", "\\");
|
|
if(!path.endsWith("\\")) path.append("\\");
|
|
path.append("*");
|
|
HANDLE handle;
|
|
WIN32_FIND_DATA data;
|
|
handle = FindFirstFile(utf16_t(path), &data);
|
|
if(handle != INVALID_HANDLE_VALUE) {
|
|
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
string name = (const char*)utf8_t(data.cFileName);
|
|
if(name.match(pattern)) list.append(name);
|
|
}
|
|
while(FindNextFile(handle, &data) != false) {
|
|
if((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
|
|
string name = (const char*)utf8_t(data.cFileName);
|
|
if(name.match(pattern)) list.append(name);
|
|
}
|
|
}
|
|
FindClose(handle);
|
|
}
|
|
return list;
|
|
}
|
|
#else
|
|
inline auto directory_is_folder(DIR* dp, struct dirent* ep) -> bool {
|
|
if(ep->d_type == DT_DIR) return true;
|
|
if(ep->d_type == DT_LNK || ep->d_type == DT_UNKNOWN) {
|
|
//symbolic links must be resolved to determine type
|
|
struct stat sp = {0};
|
|
fstatat(dirfd(dp), ep->d_name, &sp, 0);
|
|
return S_ISDIR(sp.st_mode);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline auto directory::create(const string& pathname, uint permissions) -> bool {
|
|
string path;
|
|
auto list = string{pathname}.trimRight("/").split("/");
|
|
bool result = true;
|
|
for(auto& part : list) {
|
|
path.append(part, "/");
|
|
if(directory::exists(path)) continue;
|
|
result &= (mkdir(path, permissions) == 0);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline auto directory::remove(const string& pathname) -> bool {
|
|
auto list = directory::contents(pathname);
|
|
for(auto& name : list) {
|
|
if(name.endsWith("/")) directory::remove({pathname, name});
|
|
else file::remove({pathname, name});
|
|
}
|
|
return rmdir(pathname) == 0;
|
|
}
|
|
|
|
inline auto directory::exists(const string& pathname) -> bool {
|
|
struct stat data;
|
|
if(stat(pathname, &data) != 0) return false;
|
|
return S_ISDIR(data.st_mode);
|
|
}
|
|
|
|
inline auto directory::ufolders(const string& pathname, const string& pattern) -> string_vector {
|
|
if(!pathname) return string_vector{"/"};
|
|
|
|
string_vector list;
|
|
DIR* dp;
|
|
struct dirent* ep;
|
|
dp = opendir(pathname);
|
|
if(dp) {
|
|
while(ep = readdir(dp)) {
|
|
if(!strcmp(ep->d_name, ".")) continue;
|
|
if(!strcmp(ep->d_name, "..")) continue;
|
|
if(!directory_is_folder(dp, ep)) continue;
|
|
string name{ep->d_name};
|
|
if(name.match(pattern)) list.append(std::move(name));
|
|
}
|
|
closedir(dp);
|
|
}
|
|
for(auto& name : list) name.append("/"); //must append after sorting
|
|
return list;
|
|
}
|
|
|
|
inline auto directory::ufiles(const string& pathname, const string& pattern) -> string_vector {
|
|
if(!pathname) return {};
|
|
|
|
string_vector list;
|
|
DIR* dp;
|
|
struct dirent* ep;
|
|
dp = opendir(pathname);
|
|
if(dp) {
|
|
while(ep = readdir(dp)) {
|
|
if(!strcmp(ep->d_name, ".")) continue;
|
|
if(!strcmp(ep->d_name, "..")) continue;
|
|
if(directory_is_folder(dp, ep)) continue;
|
|
string name{ep->d_name};
|
|
if(name.match(pattern)) list.append(std::move(name));
|
|
}
|
|
closedir(dp);
|
|
}
|
|
return list;
|
|
}
|
|
#endif
|
|
|
|
}
|