2016-08-29 15:35:48 +02:00
|
|
|
#include "./path.h"
|
|
|
|
|
|
|
|
#include <cstdlib>
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
2017-01-14 00:33:02 +01:00
|
|
|
#if defined(PLATFORM_UNIX)
|
2017-05-01 03:13:11 +02:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2017-01-14 00:33:02 +01:00
|
|
|
#elif defined(PLATFORM_WINDOWS)
|
2017-05-01 03:13:11 +02:00
|
|
|
#ifdef UNICODE
|
|
|
|
#undef UNICODE
|
|
|
|
#endif
|
|
|
|
#ifdef _UNICODE
|
|
|
|
#undef _UNICODE
|
|
|
|
#endif
|
|
|
|
#include <windows.h>
|
2017-01-14 00:33:02 +01:00
|
|
|
#else
|
2017-05-01 03:13:11 +02:00
|
|
|
#error Platform not supported.
|
2016-08-29 15:35:48 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
namespace IoUtilities {
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the file name and extension of the specified \a path string.
|
|
|
|
*/
|
|
|
|
string fileName(const string &path)
|
|
|
|
{
|
|
|
|
size_t lastSlash = path.rfind('/');
|
|
|
|
size_t lastBackSlash = path.rfind('\\');
|
|
|
|
size_t lastSeparator;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (lastSlash == string::npos && lastBackSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return path;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (lastSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
lastSeparator = lastBackSlash;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (lastBackSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
lastSeparator = lastSlash;
|
|
|
|
} else {
|
|
|
|
lastSeparator = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
|
|
|
|
}
|
|
|
|
return path.substr(lastSeparator + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the directory of the specified \a path string (including trailing slash).
|
|
|
|
*/
|
|
|
|
string directory(const string &path)
|
|
|
|
{
|
|
|
|
size_t lastSlash = path.rfind('/');
|
|
|
|
size_t lastBackSlash = path.rfind('\\');
|
|
|
|
size_t lastSeparator;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (lastSlash == string::npos && lastBackSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return string();
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (lastSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
lastSeparator = lastBackSlash;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (lastBackSlash == string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
lastSeparator = lastSlash;
|
|
|
|
} else {
|
|
|
|
lastSeparator = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
|
|
|
|
}
|
|
|
|
return path.substr(0, lastSeparator + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Removes invalid characters from the specified \a fileName.
|
|
|
|
*
|
|
|
|
* The characters <, >, ?, !, *, |, /, :, \ and new lines are considered as invalid.
|
|
|
|
*/
|
|
|
|
void removeInvalidChars(std::string &fileName)
|
|
|
|
{
|
|
|
|
size_t startPos = 0;
|
2017-05-01 03:13:11 +02:00
|
|
|
static const char invalidPathChars[] = { '\"', '<', '>', '?', '!', '*', '|', '/', ':', '\\', '\n' };
|
|
|
|
for (const char *i = invalidPathChars, *end = invalidPathChars + sizeof(invalidPathChars); i != end; ++i) {
|
2016-08-29 15:35:48 +02:00
|
|
|
startPos = fileName.find(*i);
|
2017-05-01 03:13:11 +02:00
|
|
|
while (startPos != string::npos) {
|
2016-08-29 15:35:48 +02:00
|
|
|
fileName.replace(startPos, 1, string());
|
|
|
|
startPos = fileName.find(*i, startPos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Locates a directory meant to store application settings.
|
|
|
|
* \param result Specifies a string to store the path in.
|
|
|
|
* \param applicationDirectoryName Specifies the name for the application subdirectory.
|
|
|
|
* \param createApplicationDirectory Indicates wheter the application subdirectory should be created if not present.
|
2017-01-14 00:33:02 +01:00
|
|
|
* \returns Returns whether a settings directory could be located.
|
2017-02-03 00:54:44 +01:00
|
|
|
* \deprecated This function has FIXMEs. Since it is not used a good candidate for being removed.
|
2016-08-29 15:35:48 +02:00
|
|
|
*/
|
|
|
|
bool settingsDirectory(std::string &result, std::string applicationDirectoryName, bool createApplicationDirectory)
|
|
|
|
{
|
|
|
|
result.clear();
|
2017-01-14 00:33:02 +01:00
|
|
|
// FIXME: this kind of configuration is not actually used so get rid of it, maybe just read env variable instead
|
2016-08-29 15:35:48 +02:00
|
|
|
fstream pathConfigFile("path.config", ios_base::in);
|
2017-05-01 03:13:11 +02:00
|
|
|
if (pathConfigFile.good()) {
|
|
|
|
for (string line; getline(pathConfigFile, line);) {
|
2016-08-29 15:35:48 +02:00
|
|
|
string::size_type p = line.find('=');
|
2017-05-01 03:13:11 +02:00
|
|
|
if ((p != string::npos) && (p + 1 < line.length())) {
|
2016-08-29 15:35:48 +02:00
|
|
|
string fieldName = line.substr(0, p);
|
2017-05-01 03:13:11 +02:00
|
|
|
if (fieldName == "settings") {
|
2016-08-29 15:35:48 +02:00
|
|
|
result.assign(line.substr(p + 1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!result.empty()) {
|
2017-01-14 00:33:02 +01:00
|
|
|
#if defined(PLATFORM_UNIX)
|
2016-08-29 15:35:48 +02:00
|
|
|
struct stat sb;
|
|
|
|
return (stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode));
|
2017-09-17 21:45:23 +02:00
|
|
|
#else // PLATFORM_WINDOWS \
|
|
|
|
// FIXME: use UTF-16 API to support unicode, or rewrite using fs abstraction lib
|
2016-08-29 15:35:48 +02:00
|
|
|
DWORD ftyp = GetFileAttributesA(result.c_str());
|
|
|
|
return (ftyp != INVALID_FILE_ATTRIBUTES) && (ftyp & FILE_ATTRIBUTE_DIRECTORY);
|
|
|
|
#endif
|
|
|
|
} else {
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!applicationDirectoryName.empty()) {
|
2016-08-29 15:35:48 +02:00
|
|
|
removeInvalidChars(applicationDirectoryName);
|
|
|
|
}
|
2017-01-14 00:33:02 +01:00
|
|
|
#if defined(PLATFORM_UNIX) || defined(PLATFORM_MAC)
|
2017-05-01 03:13:11 +02:00
|
|
|
if (char *homeDir = getenv("HOME")) {
|
2017-01-27 18:51:54 +01:00
|
|
|
result = homeDir;
|
2016-08-29 15:35:48 +02:00
|
|
|
} else {
|
|
|
|
struct passwd *pw = getpwuid(getuid());
|
2017-01-27 18:51:54 +01:00
|
|
|
result = pw->pw_dir;
|
2016-08-29 15:35:48 +02:00
|
|
|
}
|
|
|
|
struct stat sb;
|
|
|
|
result += "/.config";
|
2017-05-01 03:13:11 +02:00
|
|
|
if (createApplicationDirectory && !(stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))) {
|
|
|
|
if (mkdir(result.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!applicationDirectoryName.empty()) {
|
2017-01-27 18:51:54 +01:00
|
|
|
result += '/';
|
|
|
|
result += applicationDirectoryName;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (createApplicationDirectory && !(stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))) {
|
|
|
|
if (mkdir(result.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-14 00:33:02 +01:00
|
|
|
#else // PLATFORM_WINDOWS
|
2017-05-01 03:13:11 +02:00
|
|
|
if (char *appData = getenv("appdata")) {
|
2016-08-29 15:35:48 +02:00
|
|
|
result = appData;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (!applicationDirectoryName.empty()) {
|
2017-01-27 18:51:54 +01:00
|
|
|
result += '\\';
|
|
|
|
result += applicationDirectoryName;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (createApplicationDirectory) {
|
2017-01-14 00:33:02 +01:00
|
|
|
// FIXME: use UTF-16 API to support unicode, or rewrite using fs abstraction lib
|
2016-08-29 15:35:48 +02:00
|
|
|
DWORD ftyp = GetFileAttributesA(result.c_str());
|
2017-05-01 03:13:11 +02:00
|
|
|
if (ftyp == INVALID_FILE_ATTRIBUTES) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return false;
|
2017-05-01 03:13:11 +02:00
|
|
|
} else if (ftyp & FILE_ATTRIBUTE_DIRECTORY) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
2017-05-01 03:13:11 +02:00
|
|
|
if (CreateDirectory(result.c_str(), NULL) == 0) {
|
2016-08-29 15:35:48 +02:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Returns the names of the directory entries in the specified \a path with the specified \a types.
|
2017-01-14 00:33:02 +01:00
|
|
|
* \deprecated This function has FIXMEs. Since it can be replaced by using fs abstraction lib it is a good candidate for being replaced.
|
2016-08-29 15:35:48 +02:00
|
|
|
*/
|
|
|
|
std::list<std::string> directoryEntries(const char *path, DirectoryEntryType types)
|
|
|
|
{
|
|
|
|
#ifdef PLATFORM_UNIX
|
|
|
|
list<string> entries;
|
2017-05-01 03:13:11 +02:00
|
|
|
if (auto dir = opendir(path)) {
|
|
|
|
while (auto dirEntry = readdir(dir)) {
|
2016-08-29 15:35:48 +02:00
|
|
|
bool filter = false;
|
2017-05-01 03:13:11 +02:00
|
|
|
switch (dirEntry->d_type) {
|
2016-08-29 15:35:48 +02:00
|
|
|
case DT_REG:
|
|
|
|
filter = (types & DirectoryEntryType::File) != DirectoryEntryType::None;
|
|
|
|
break;
|
|
|
|
case DT_DIR:
|
|
|
|
filter = (types & DirectoryEntryType::Directory) != DirectoryEntryType::None;
|
|
|
|
break;
|
|
|
|
case DT_LNK:
|
|
|
|
filter = (types & DirectoryEntryType::Symlink) != DirectoryEntryType::None;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
filter = (types & DirectoryEntryType::All) != DirectoryEntryType::None;
|
|
|
|
}
|
2017-05-01 03:13:11 +02:00
|
|
|
if (filter) {
|
2016-08-29 15:35:48 +02:00
|
|
|
entries.emplace_back(dirEntry->d_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
}
|
|
|
|
return entries;
|
|
|
|
#else
|
|
|
|
return list<string>(); // TODO
|
|
|
|
#endif
|
|
|
|
}
|
2017-09-17 21:45:23 +02:00
|
|
|
} // namespace IoUtilities
|