From 556ab106f4079c65911805fa60e73e3ec3128d5f Mon Sep 17 00:00:00 2001 From: lifegpc Date: Thu, 16 Dec 2021 22:13:30 +0800 Subject: [PATCH] Update --- CMakeLists.txt | 2 + cfileop.cpp | 30 ++++++++++ cfileop.h | 51 +++++++++++++++++ cstr_util.c | 12 ++++ cstr_util.h | 7 +++ fileop.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++++++++- fileop.h | 65 ++++++++++++++++++++++ time_util.cpp | 14 +++++ time_util.h | 18 ++++++ 9 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 time_util.cpp create mode 100644 time_util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 16a20bf..012277a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ set(SOURCE_FILE wchar_util.cpp memfile.c cmath.c + time_util.cpp ) set(SOURCE_FILE_HEADERS cfileop.h @@ -45,6 +46,7 @@ set(SOURCE_FILE_HEADERS wchar_util.h memfile.h cmath.h + time_util.h ) add_library(utils STATIC ${SOURCE_FILE} ${SOURCE_FILE_HEADERS}) diff --git a/cfileop.cpp b/cfileop.cpp index 8aeb2e6..c8becfb 100644 --- a/cfileop.cpp +++ b/cfileop.cpp @@ -49,3 +49,33 @@ int fileop_open(const char* fn, int* fd, int oflag, int shflag, int pmode) { *fd = tfd; return re; } + +int fileop_isabs(const char* path) { + if (!path) return 0; + return fileop::isabs(path) ? 1 : 0; +} + +char* fileop_join(const char* path, const char* path2) { + if (!path || !path2) return nullptr; + auto re = fileop::join(path, path2); + char* tmp = nullptr; + return cpp2c::string2char(re, tmp) ? tmp : nullptr; +} + +int fileop_isdir(const char* path, int* result) { + if (!path || !result) return 0; + bool re; + auto r = fileop::isdir(path, re); + if (r) *result = re ? 1 : 0; + return r ? 1 : 0; +} + +int fileop_mkdir(const char* path, int mode) { + if (!path) return 0; + return fileop::mkdir(path, mode) ? 1 : 0; +} + +int fileop_set_file_time(const char* path, time_t ctime, time_t actime, time_t modtime) { + if (!path) return 0; + return fileop::set_file_time(path, ctime, actime, modtime) ? 1 : 0; +} diff --git a/cfileop.h b/cfileop.h index 3fd8b04..0bebdd9 100644 --- a/cfileop.h +++ b/cfileop.h @@ -4,6 +4,10 @@ extern "C" { #endif #include +#include +#include +#include +#include /** * @brief Check file exists * @param fn File name @@ -53,6 +57,53 @@ int fileop_parse_size(const char* size, size_t* fs, int is_byte); * @return errno */ int fileop_open(const char* fn, int* fd, int oflag, int shflag, int pmode); +/** + * @brief Check if path is absoulte path. + * @param path The path. + * @return 1 if path is absoulte path otherwise 0 +*/ +int fileop_isabs(const char* path); +/** + * @brief Join two more pathname components + * @param path + * @param path2 + * @return Result. Need free memory by using free. +*/ +char* fileop_join(const char* path, const char* path2); +/** + * @brief check if path is an existing directory. + * @param path Path + * @param result 1 if path is an existing directory otherwise 0 + * @return 0 if error occured otherwise 1 +*/ +int fileop_isdir(const char* path, int* result); +/** + * @brief Creates a new directory. + * @param path Path for a new directory. + * @param mode Directory permission. (Linux only) + * @return 1 if created successfully otherwise 0 +*/ +int fileop_mkdir(const char* path, int mode); +/** + * @brief Sets the date and time that the specified file or directory was created, last accessed, or last modified. + * @param path The path of directory or file + * @param ctime creation date (Windows Only) + * @param actime Last access date + * @param modtime Last modification date + * @return 1 if successed otherwise 0. +*/ +int fileop_set_file_time(const char* path, time_t ctime, time_t actime, time_t modtime); +#if _WIN32 +#define fileop_fdopen _fdopen +#else +#define fileop_fdopen fdopen +#endif +#if _WIN32 +#define fileop_close(fd) (!_close(fd)) +#else +#define fileop_close(fd) (!close(fd)) +#endif +#define fileop_fclose(stream) (!fclose(stream)) #ifdef __cplusplus } #endif diff --git a/cstr_util.c b/cstr_util.c index 5d74c10..9ad2009 100644 --- a/cstr_util.c +++ b/cstr_util.c @@ -2,6 +2,7 @@ #include #include +#include int cstr_util_copy_str(char** dest, const char* str) { if (!dest || !str) return 1; @@ -15,3 +16,14 @@ int cstr_util_copy_str(char** dest, const char* str) { *dest = temp; return 0; } + +int cstr_is_integer(const char* str, int allow_sign) { + if (!str) return 0; + size_t le = strlen(str), i = 0; + if (!le) return 0; + if (allow_sign && le > 1 && (str[0] == '+' || str[0] == '-')) i++; + for (; i < le; i++) { + if (!isdigit(str[i])) return 0; + } + return 1; +} diff --git a/cstr_util.h b/cstr_util.h index 277cdf9..3209316 100644 --- a/cstr_util.h +++ b/cstr_util.h @@ -10,6 +10,13 @@ extern "C" { * @return 0 if successed. `1` - args contains NULL. `2` - Out of memory. */ int cstr_util_copy_str(char** dest, const char* str); +/** + * @brief Check if a string is a integer. + * @param str String + * @param allow_sign Allow +/- at the first. + * @return 1 if is a interger otherwise 0 +*/ +int cstr_is_integer(const char* str, int allow_sign); #ifdef __cplusplus } #endif diff --git a/fileop.cpp b/fileop.cpp index da95347..b111d62 100644 --- a/fileop.cpp +++ b/fileop.cpp @@ -4,16 +4,22 @@ #include "fileop.h" +#include +#include #ifdef _WIN32 #include #include +#include +#include #else #include -#include +#include #endif #include +#include #include "err.h" #include "wchar_util.h" +#include "time_util.h" #include #ifdef _WIN32 @@ -52,12 +58,29 @@ int open_internal(wchar_t* fn, int* fd, int oflag, int shflag, int pmode) { return _wsopen_s(fd, fn, oflag, shflag, pmode); } +bool isdir_internal(wchar_t* fn, bool& result) { + struct __stat64 stats; + if (_wstat64(fn, &stats)) { + return false; + } + result = stats.st_mode & S_IFDIR; + return true; +} + +bool mkdir_internal(wchar_t* fn) { + return !_wmkdir(fn); +} + +HANDLE set_file_time_internal(wchar_t* fn) { + return CreateFileW(fn, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); +} + template T fileop_internal(const char* fname, UINT codePage, T(*callback)(wchar_t* fn, Args... args), T failed, Args... args) { int wlen; wchar_t* fn; DWORD opt = wchar_util::getMultiByteToWideCharOptions(MB_ERR_INVALID_CHARS, codePage); - wlen = MultiByteToWideChar(codePage, opt, fname, -1, NULL, 0); + wlen = MultiByteToWideChar(codePage, opt, fname, -1, nullptr, 0); if (!wlen) return failed; fn = (wchar_t*)malloc(sizeof(wchar_t) * wlen); if (!MultiByteToWideChar(codePage, opt, fname, -1, fn, wlen)) { @@ -203,3 +226,124 @@ int fileop::open(std::string fn, int& fd, int oflag, int shflag, int pmode) { return fd == -1 ? errno : 0; #endif } + +bool fileop::isabs(std::string path) { + if (!path.length()) return false; +#if _WIN32 + if (path.length() <= 2) return false; + if (isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) return true; else return false; +#else + return path[0] == '/' ? true : false; +#endif +} + +std::string fileop::join(std::string path, std::string path2) { + auto l1 = path.length(), l2 = path2.length(); + if (!l1) return path2; + if (!l2) return path; + if (isabs(path2)) return path2; +#if _WIN32 + if (l2 >= 2 && isalpha(path2[0]) && path2[1] == ':') return path2; + if (l1 >= 2 && isalpha(path[0]) && path[1] == ':') { + if (path2[0] == '/' || path2[0] == '\\') return path.substr(0, 2) + path2; + return (path[l1 - 1] == '/' || path[l1 - 1] == '\\') ? path + path2 : path + "\\" + path2; + } + if (path2[0] == '/' || path2[0] == '\\') return path2; + return (path[l1 - 1] == '/' || path[l1 - 1] == '\\') ? path + path2 : path + "\\" + path2; +#else + return path[l1 - 1] == '/' ? path + path2 : path + "/" + path2; +#endif +} + +bool fileop::isdir(std::string path, bool& result) { + if (!exists(path)) { + result = false; + return true; + } +#if _WIN32 + UINT cp[] = { CP_UTF8, CP_OEMCP, CP_ACP }; + int i; + for (i = 0; i < 3; i++) { + if (fileop_internal(path.c_str(), cp[i], &isdir_internal, false, result)) return true; + } + struct __stat64 stats; + if (_stat64(path.c_str(), &stats)) { +#else + struct stat stats; + if (stat(path.c_str(), &stats)) { +#endif + return false; + } + result = stats.st_mode & S_IFDIR; + return true; +} + +#if _WIN32 +bool fileop::isdrive(std::string path) { + auto l = path.length(); + if (l == 2 && isalpha(path[0]) && path[1] == ':') return true; + if (l == 3 && isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\')) return true; + return false; +} +#endif + +bool fileop::mkdir(std::string path, int mode) { +#if _WIN32 + UINT cp[] = { CP_UTF8, CP_OEMCP, CP_ACP }; + int i; + for (i = 0; i < 3; i++) { + if (fileop_internal(path.c_str(), cp[i], &mkdir_internal, false)) return true; + } + return !::_mkdir(path.c_str()); +#else + return !::mkdir(path.c_str(), mode); +#endif +} + +bool fileop::set_file_time(std::string path, time_t ctime, time_t actime, time_t modtime) { +#if _WIN32 + UINT cp[] = { CP_UTF8, CP_OEMCP, CP_ACP }; + int i; + HANDLE file; + for (i = 0; i < 3; i++) { + if ((file = fileop_internal(path.c_str(), cp[i], &set_file_time_internal, INVALID_HANDLE_VALUE)) != INVALID_HANDLE_VALUE) { + break; + } + } + if (file == INVALID_HANDLE_VALUE) { + file = CreateFileA(path.c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (file == INVALID_HANDLE_VALUE) return false; + } + FILETIME c, ac, mod; + time_util::time_t_to_file_time(ctime, &c); + time_util::time_t_to_file_time(actime, &ac); + time_util::time_t_to_file_time(modtime, &mod); + auto re = SetFileTime(file, &c, &ac, &mod); + CloseHandle(file); + return re ? true : false; +#else + struct utimbuf t = { actime, modtime }; + return !utime(path.c_str(), &t); +#endif +} + +FILE* fileop::fdopen(int fd, std::string mode) { +#if _WIN32 + return ::_fdopen(fd, mode.c_str()); +#else + return ::fdopen(fd, mode.c_str()); +#endif +} + +bool fileop::close(int fd) { +#if _WIN32 + return !::_close(fd); +#else + return !::close(fd); +#endif +} + +bool fileop::fclose(FILE* f) { + if (!f) return false; + return !::fclose(f); +} diff --git a/fileop.h b/fileop.h index d984431..cdc7328 100644 --- a/fileop.h +++ b/fileop.h @@ -1,6 +1,8 @@ #ifndef _UTIL_FILEOP_H #define _UTIL_FILEOP_H #include +#include +#include namespace fileop { /** @@ -52,5 +54,68 @@ namespace fileop { * @return errno */ int open(std::string fn, int& fd, int oflag, int shflag = 0x10, int pmode = 0); + /** + * @brief Check if path is absoulte path. + * @param path The path. + * @return + */ + bool isabs(std::string path); + /** + * @brief Join two more pathname components + * @param path + * @param path2 + * @return result + */ + std::string join(std::string path, std::string path2); + /** + * @brief check if path is an existing directory. + * @param path Path + * @param result true if path is an existing directory. + * @return false if error occured + */ + bool isdir(std::string path, bool& result); +#if _WIN32 + /** + * @brief Check if a path only contains drive. + * @param path Path + * @return Result + */ + bool isdrive(std::string path); +#endif + /** + * @brief Creates a new directory. + * @param path Path for a new directory. + * @param mode Directory permission. (Linux only) + * @return true if successed. + */ + bool mkdir(std::string path, int mode); + /** + * @brief Sets the date and time that the specified file or directory was created, last accessed, or last modified. + * @param path The path of directory or file + * @param ctime creation date (Windows Only) + * @param actime Last access date + * @param modtime Last modification date + * @return true if successed. + */ + bool set_file_time(std::string path, time_t ctime, time_t actime, time_t modtime); + /** + * @brief Associates a stream with a file that was previously opened. + * @param fd File descriptor of the open file. + * @param mode Type of file access. + * @return A pointer to the open stream. + */ + FILE* fdopen(int fd, std::string mode); + /** + * @brief Closes a file. + * @param fd File descriptor referring to the open file. + * @return + */ + bool close(int fd); + /** + * @brief Closes a stream + * @param f Pointer to FILE structure. + * @return true if the stream is successfully closed + */ + bool fclose(FILE* f); } #endif diff --git a/time_util.cpp b/time_util.cpp new file mode 100644 index 0000000..402e09d --- /dev/null +++ b/time_util.cpp @@ -0,0 +1,14 @@ +#include "time_util.h" + +#if _WIN32 +#include +#endif + +#if _WIN32 +void time_util::time_t_to_file_time(time_t t, LPFILETIME pft) { + ULARGE_INTEGER time_value; + time_value.QuadPart = (t * 10000000LL) + 116444736000000000LL; + pft->dwLowDateTime = time_value.LowPart; + pft->dwHighDateTime = time_value.HighPart; +} +#endif diff --git a/time_util.h b/time_util.h new file mode 100644 index 0000000..1879ab5 --- /dev/null +++ b/time_util.h @@ -0,0 +1,18 @@ +#ifndef _UTIL_TIME_UTIL_H +#define _UTIL_TIME_UTIL_H +#include +#if _WIN32 +#include +#endif + +namespace time_util { +#if _WIN32 + /** + * @brief Convert from time_t to FILETIME + * @param t UNIX Timestamp + * @param pft Result + */ + void time_t_to_file_time(time_t t, LPFILETIME pft); +#endif +} +#endif