diff --git a/include/bx/filepath.h b/include/bx/filepath.h index 6c1134a..11fb4b5 100644 --- a/include/bx/filepath.h +++ b/include/bx/filepath.h @@ -6,8 +6,12 @@ #ifndef BX_FILEPATH_H_HEADER_GUARD #define BX_FILEPATH_H_HEADER_GUARD +#include "error.h" #include "string.h" +BX_ERROR_RESULT(BX_ERROR_ACCESS, BX_MAKEFOURCC('b', 'x', 0, 0) ); +BX_ERROR_RESULT(BX_ERROR_NOT_DIRECTORY, BX_MAKEFOURCC('b', 'x', 0, 1) ); + namespace bx { const int32_t kMaxFilePath = 1024; @@ -87,6 +91,18 @@ namespace bx char m_filePath[kMaxFilePath]; }; + /// Creates a directory named `_filePath`. + bool make(const FilePath& _filePath, Error* _err); + + /// Creates a directory named `_filePath` along with all necessary parents. + bool makeAll(const FilePath& _filePath, Error* _err); + + /// Removes file or directory. + bool remove(const FilePath& _filePath, Error* _err); + + /// Removes file or directory recursivelly. + bool removeAll(const FilePath& _filePath, Error* _err); + } // namespace bx #endif // BX_FILEPATH_H_HEADER_GUARD diff --git a/src/filepath.cpp b/src/filepath.cpp index 67de650..7ac001f 100644 --- a/src/filepath.cpp +++ b/src/filepath.cpp @@ -8,10 +8,14 @@ #include #include +#include // remove +#include // opendir + #if BX_CRT_MSVC -# include // _getcwd +# include // _getcwd #else -# include // getcwd +# include // mkdir +# include // getcwd #endif // BX_CRT_MSVC #if BX_PLATFORM_WINDOWS @@ -175,7 +179,7 @@ namespace bx BX_UNUSED(_buffer, _size); return NULL; #elif BX_CRT_MSVC - return ::_getcwd(_buffer, (int)_size); + return ::_getcwd(_buffer, (int32_t)_size); #else return ::getcwd(_buffer, _size); #endif // BX_COMPILER_ @@ -380,4 +384,140 @@ namespace bx ; } + bool make(const FilePath& _filePath, Error* _err) + { + BX_ERROR_SCOPE(_err); + + if (!_err->isOk() ) + { + return false; + } + +#if BX_CRT_MSVC + int32_t result = ::_mkdir(_filePath.get() ); +#else + int32_t result = ::mkdir(_filePath.get(), 0700); +#endif // BX_CRT_MSVC + + if (0 != result) + { + BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process."); + return false; + } + + return true; + } + + bool makeAll(const FilePath& _filePath, Error* _err) + { + BX_ERROR_SCOPE(_err); + + if (!_err->isOk() ) + { + return false; + } + + FileInfo fi; + + if (stat(_filePath, fi) ) + { + if (FileInfo::Directory == fi.m_type) + { + return true; + } + + BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory."); + return false; + } + + const StringView dir = strRTrim(_filePath.get(), "/"); + const char* slash = strRFind(dir, '/'); + + if (NULL != slash + && slash - dir.getPtr() > 1) + { + if (!makeAll(StringView(dir.getPtr(), slash), _err) ) + { + return false; + } + } + + FilePath path(dir); + return make(path, _err); + } + + bool remove(const FilePath& _filePath, Error* _err) + { + BX_ERROR_SCOPE(_err); + + if (!_err->isOk() ) + { + return false; + } + + int32_t result = ::remove(_filePath.get() ); + + if (0 != result) + { + BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process."); + return false; + } + + return true; + } + + bool removeAll(const FilePath& _filePath, Error* _err) + { + BX_ERROR_SCOPE(_err); + + if (remove(_filePath, _err) ) + { + return true; + } + + _err->reset(); + + FileInfo fi; + + if (!stat(_filePath, fi) ) + { + BX_ERROR_SET(_err, BX_ERROR_ACCESS, "The parent directory does not allow write permission to the process."); + return false; + } + + if (FileInfo::Directory != fi.m_type) + { + BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory."); + return false; + } + + DIR* dir = opendir(_filePath.get() ); + if (NULL == dir) + { + BX_ERROR_SET(_err, BX_ERROR_NOT_DIRECTORY, "File already exist, and is not directory."); + return false; + } + + for (dirent* item = readdir(dir); NULL != item; item = readdir(dir) ) + { + if (0 == strCmp(item->d_name, ".") + || 0 == strCmp(item->d_name, "..") ) + { + continue; + } + + FilePath path(_filePath); + path.join(item->d_name); + if (!removeAll(path, _err) ) + { + _err->reset(); + break; + } + } + + closedir(dir); + + return remove(_filePath, _err); + } + } // namespace bx diff --git a/src/settings.cpp b/src/settings.cpp index 260daf9..52b8d60 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -69,8 +69,8 @@ const char* Settings::get(const StringView& _name) const ini_t* ini = INI_T(m_ini); FilePath uri(_name); - const StringView path = strTrim(uri.getPath(), "/"); - const StringView& fileName = uri.getFileName(); + const StringView path(strTrim(uri.getPath(), "/") ); + const StringView& fileName(uri.getFileName() ); int32_t section = INI_GLOBAL_SECTION; if (!path.isEmpty() ) @@ -96,8 +96,8 @@ void Settings::set(const StringView& _name, const StringView& _value) ini_t* ini = INI_T(m_ini); FilePath uri(_name); - const StringView path = strTrim(uri.getPath(), "/"); - const StringView& fileName = uri.getFileName(); + const StringView path(strTrim(uri.getPath(), "/") ); + const StringView& fileName(uri.getFileName() ); int32_t section = INI_GLOBAL_SECTION; diff --git a/src/string.cpp b/src/string.cpp index 617cece..a225413 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -446,6 +446,7 @@ namespace bx const char* ptr = _str.getPtr(); const char* chars = _chars.getPtr(); const uint32_t charsLen = _chars.getLength(); + for (uint32_t ii = 0, len = _str.getLength(); ii < len; ++ii) { if (NULL == strFindUnsafe(chars, charsLen, ptr[ii]) ) @@ -459,6 +460,11 @@ namespace bx StringView strRTrim(const StringView& _str, const StringView& _chars) { + if (_str.isEmpty() ) + { + return StringView(); + } + const char* ptr = _str.getPtr(); const char* chars = _chars.getPtr(); const uint32_t charsLen = _chars.getLength(); diff --git a/tests/filepath_test.cpp b/tests/filepath_test.cpp index ff04261..5b743c6 100644 --- a/tests/filepath_test.cpp +++ b/tests/filepath_test.cpp @@ -123,4 +123,14 @@ TEST_CASE("FilePath temp", "") { bx::FilePath tmp(bx::Dir::Temp); REQUIRE(0 != bx::strCmp(".", tmp.getPath().getPtr() ) ); + + bx::Error err; + tmp.join("test/abvgd/555333/test"); + REQUIRE(bx::makeAll(tmp, &err) ); + REQUIRE(err.isOk() ); + + tmp.set(bx::Dir::Temp); + tmp.join("test"); + REQUIRE(bx::removeAll(tmp, &err) ); + REQUIRE(err.isOk() ); }