X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2FKM_fileio.cpp;h=5a56c44cd09890c8831f4f4500e59c9e651f8844;hb=44bc524e3cf74f0903b7fbb51ca2f366f48d3495;hp=e0a83ea94ca96c4eff75d077bd9a99f5fe44e785;hpb=984de376d405e0b68e77d61558d4f798fa1170a5;p=asdcplib.git diff --git a/src/KM_fileio.cpp b/src/KM_fileio.cpp index e0a83ea..5a56c44 100644 --- a/src/KM_fileio.cpp +++ b/src/KM_fileio.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2004-2006, John Hurst +Copyright (c) 2004-2007, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -33,6 +33,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#ifdef KM_WIN32 +#include +#endif using namespace Kumu; @@ -53,6 +56,33 @@ struct iovec { typedef struct stat fstat_t; #endif +// +static void +split(const std::string& str, char separator, std::list& components) +{ + const char* pstr = str.c_str(); + const char* r = strchr(pstr, separator); + + while ( r != 0 ) + { + assert(r >= pstr); + if ( r > pstr ) + { + std::string tmp_str; + assert(r - pstr < 100); + tmp_str.assign(pstr, (r - pstr)); + components.push_back(tmp_str); + } + + pstr = r + 1; + r = strchr(pstr, separator); + } + + if( strlen(pstr) > 0 ) + components.push_back(std::string(pstr)); +} + + // static Kumu::Result_t do_stat(const char* path, fstat_t* stat_info) @@ -104,12 +134,29 @@ do_fstat(HANDLE handle, fstat_t* stat_info) // bool -Kumu::PathIsFile(const char* pathname) +Kumu::PathExists(const std::string& pathname) +{ + if ( pathname.empty() ) + return false; + + fstat_t info; + + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) + return true; + + return false; +} + +// +bool +Kumu::PathIsFile(const std::string& pathname) { - assert(pathname); + if ( pathname.empty() ) + return false; + fstat_t info; - if ( KM_SUCCESS(do_stat(pathname, &info)) ) + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) { if ( info.st_mode & ( S_IFREG|S_IFLNK ) ) return true; @@ -121,12 +168,14 @@ Kumu::PathIsFile(const char* pathname) // bool -Kumu::PathIsDirectory(const char* pathname) +Kumu::PathIsDirectory(const std::string& pathname) { - assert(pathname); + if ( pathname.empty() ) + return false; + fstat_t info; - if ( KM_SUCCESS(do_stat(pathname, &info)) ) + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) { if ( info.st_mode & S_IFDIR ) return true; @@ -135,15 +184,16 @@ Kumu::PathIsDirectory(const char* pathname) return false; } - // Kumu::fsize_t -Kumu::FileSize(const char* pathname) +Kumu::FileSize(const std::string& pathname) { - assert(pathname); + if ( pathname.empty() ) + return 0; + fstat_t info; - if ( KM_SUCCESS(do_stat(pathname, &info)) ) + if ( KM_SUCCESS(do_stat(pathname.c_str(), &info)) ) { if ( info.st_mode & ( S_IFREG|S_IFLNK ) ) return(info.st_size); @@ -152,6 +202,346 @@ Kumu::FileSize(const char* pathname) return 0; } +// +static PathCompList_t& +s_PathMakeCanonical(PathCompList_t& CList, char separator, bool is_absolute) +{ + PathCompList_t::iterator ci, ri; // component and removal iterators + + for ( ci = CList.begin(); ci != CList.end(); ci++ ) + { + if ( *ci == "." && ( CList.size() > 1 || is_absolute ) ) + { + ri = ci++; + CList.erase(ri); + } + else if ( *ci == ".." && ci != CList.begin() ) + { + ri = ci; + ri--; + + if ( *ri != ".." ) + { + CList.erase(ri); + ri = ci++; + CList.erase(ri); + } + } + } + + return CList; +} + +// +std::string +Kumu::PathMakeCanonical(const std::string& Path, char separator) +{ + PathCompList_t CList; + bool is_absolute = PathIsAbsolute(Path, separator); + s_PathMakeCanonical(PathToComponents(Path, CList, separator), separator, is_absolute); + + if ( is_absolute ) + return ComponentsToAbsolutePath(CList, separator); + + return ComponentsToPath(CList, separator); +} + +// +bool +Kumu::PathsAreEquivalent(const std::string& lhs, const std::string& rhs) +{ + return PathMakeCanonical(lhs) == PathMakeCanonical(rhs); +} + +// +Kumu::PathCompList_t& +Kumu::PathToComponents(const std::string& Path, PathCompList_t& CList, char separator) +{ + split(Path, separator, CList); + return CList; +} + +// +std::string +Kumu::ComponentsToPath(const PathCompList_t& CList, char separator) +{ + if ( CList.empty() ) + return ""; + + PathCompList_t::const_iterator ci = CList.begin(); + std::string out_path = *ci; + + for ( ci++; ci != CList.end(); ci++ ) + out_path += separator + *ci; + + return out_path; +} + +// +std::string +Kumu::ComponentsToAbsolutePath(const PathCompList_t& CList, char separator) +{ + std::string out_path; + + if ( CList.empty() ) + out_path = separator; + else + { + PathCompList_t::const_iterator ci; + + for ( ci = CList.begin(); ci != CList.end(); ci++ ) + out_path += separator + *ci; + } + + return out_path; +} + +// +bool +Kumu::PathHasComponents(const std::string& Path, char separator) +{ + if ( strchr(Path.c_str(), separator) == 0 ) + return false; + + return true; +} + +// +bool +Kumu::PathIsAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + return false; + + if ( Path[0] == separator) + return true; + + return false; +} + +// +std::string +Kumu::PathMakeAbsolute(const std::string& Path, char separator) +{ + if ( Path.empty() ) + { + std::string out_path; + out_path = separator; + return out_path; + } + + if ( PathIsAbsolute(Path, separator) ) + return Path; + + char cwd_buf [MaxFilePath]; + if ( getcwd(cwd_buf, MaxFilePath) == 0 ) + { + DefaultLogSink().Error("Error retrieving current working directory."); + return ""; + } + + PathCompList_t CList; + CList.push_back(cwd_buf); + CList.push_back(Path); + + return ComponentsToAbsolutePath(s_PathMakeCanonical(CList, separator, true), separator); +} + +// +std::string +Kumu::PathMakeLocal(const std::string& Path, const std::string& Parent) +{ + size_t pos = Path.find(Parent); + + if ( pos == 0 ) // Parent found at offset 0 + return Path.substr(Parent.size()+1); + + return Path; +} + +// +std::string +Kumu::PathBasename(const std::string& Path, char separator) +{ + PathCompList_t CList; + PathToComponents(Path, CList, separator); + + if ( CList.empty() ) + return ""; + + return CList.back(); +} + +// +std::string +Kumu::PathDirname(const std::string& Path, char separator) +{ + PathCompList_t CList; + bool is_absolute = PathIsAbsolute(Path, separator); + PathToComponents(Path, CList, separator); + + if ( CList.empty() ) + return is_absolute ? "/" : ""; + + CList.pop_back(); + + if ( is_absolute ) + return ComponentsToAbsolutePath(CList, separator); + + return ComponentsToPath(CList, separator); +} + +// +std::string +Kumu::PathGetExtension(const std::string& Path) +{ + std::string Basename = PathBasename(Path); + const char* p = strrchr(Basename.c_str(), '.'); + + if ( p++ == 0 ) + return ""; + + return p; +} + +// +std::string +Kumu::PathSetExtension(const std::string& Path, const std::string& Extension) // empty extension removes +{ + std::string Basename = PathBasename(Path); + const char* p = strrchr(Basename.c_str(), '.'); + + if ( p != 0 ) + Basename = Basename.substr(0, p - Basename.c_str()); + + if ( Extension.empty() ) + return Basename; + + return Basename + "." + Extension; +} + +// +Kumu::PathList_t& +Kumu::FindInPaths(const IPathMatch& Pattern, const Kumu::PathList_t& SearchPaths, + Kumu::PathList_t& FoundPaths, bool one_shot, char separator) +{ + PathList_t::const_iterator si; + for ( si = SearchPaths.begin(); si != SearchPaths.end(); si++ ) + { + FindInPath(Pattern, *si, FoundPaths, one_shot, separator); + + if ( one_shot && ! FoundPaths.empty() ) + break; + } + + return FoundPaths; +} + +// +Kumu::PathList_t& +Kumu::FindInPath(const IPathMatch& Pattern, const std::string& SearchDir, + Kumu::PathList_t& FoundPaths, bool one_shot, char separator) +{ + char name_buf[MaxFilePath]; + DirScanner Dir; + + if ( KM_SUCCESS(Dir.Open(SearchDir.c_str())) ) + { + while ( KM_SUCCESS(Dir.GetNext(name_buf)) ) + { + if ( name_buf[0] == '.' ) continue; // no hidden files + std::string tmp_path = SearchDir + separator + name_buf; + + if ( PathIsDirectory(tmp_path.c_str()) ) + FindInPath(Pattern, tmp_path, FoundPaths, one_shot, separator); + + else if ( Pattern.Match(name_buf) ) + { + FoundPaths.push_back(SearchDir + separator + name_buf); + if ( one_shot ) + break; + } + } + } + + return FoundPaths; +} + + +#ifndef KM_WIN32 + +// +Kumu::PathMatchRegex::PathMatchRegex(const std::string& s) +{ + int result = regcomp(&m_regex, s.c_str(), REG_NOSUB); // (REG_EXTENDED|REG_NOSUB|REG_NEWLINE)); + + if ( result ) + { + char buf[128]; + regerror(result, &m_regex, buf, 128); + DefaultLogSink().Error("PathMatchRegex: %s\n", buf); + regfree(&m_regex); + } +} + +Kumu::PathMatchRegex::PathMatchRegex(const PathMatchRegex& rhs) { + m_regex = rhs.m_regex; +} + +Kumu::PathMatchRegex::~PathMatchRegex() { + regfree(&m_regex); +} + +bool +Kumu::PathMatchRegex::Match(const std::string& s) const { + return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 ); +} + + + +// +Kumu::PathMatchGlob::PathMatchGlob(const std::string& glob) +{ + std::string regex; // convert glob to regex + + for ( const char* p = glob.c_str(); *p != 0; p++ ) + { + switch (*p) + { + case '.': regex += "\\."; break; + case '*': regex += ".*"; break; + case '?': regex += ".?"; break; + default: regex += *p; + } + } + regex += '$'; + + int result = regcomp(&m_regex, regex.c_str(), REG_NOSUB); + + if ( result ) + { + char buf[128]; + regerror(result, &m_regex, buf, 128); + DefaultLogSink().Error("PathMatchRegex: %s\n", buf); + regfree(&m_regex); + } +} + +Kumu::PathMatchGlob::PathMatchGlob(const PathMatchGlob& rhs) { + m_regex = rhs.m_regex; +} + +Kumu::PathMatchGlob::~PathMatchGlob() { + regfree(&m_regex); +} + +bool +Kumu::PathMatchGlob::Match(const std::string& s) const { + return ( regexec(&m_regex, s.c_str(), 0, 0, 0) == 0 ); +} + +#endif + //------------------------------------------------------------------------------------------ // portable aspects of the file classes @@ -204,7 +594,7 @@ Kumu::FileWriter::Writev(const byte_t* buf, ui32_t buf_len) { DefaultLogSink().Error("The iovec is full! Only %u entries allowed before a flush.\n", IOVecMaxEntries); - return RESULT_FAIL; + return RESULT_WRITEFAIL; } iov->m_iovec[iov->m_Count].iov_base = (char*)buf; // stupid iovec uses char* @@ -399,13 +789,12 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) (DWORD*)&tmp_count, NULL); - if ( wr_result == 0 ) + if ( wr_result == 0 || tmp_count != iov->m_iovec[i].iov_len) { result = Kumu::RESULT_WRITEFAIL; break; } - assert(iov->m_iovec[i].iov_len == tmp_count); *bytes_written += tmp_count; } @@ -433,7 +822,10 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written BOOL result = ::WriteFile(m_Handle, buf, buf_len, (DWORD*)bytes_written, NULL); ::SetErrorMode(prev); - return ( result == 0 ) ? Kumu::RESULT_WRITEFAIL : Kumu::RESULT_OK; + if ( result == 0 || *bytes_written != buf_len ) + return Kumu::RESULT_WRITEFAIL; + + return Kumu::RESULT_OK; } #else // KM_WIN32 @@ -570,13 +962,17 @@ Kumu::FileWriter::Writev(ui32_t* bytes_written) if ( m_Handle == -1L ) return RESULT_STATE; - int read_size = writev(m_Handle, iov->m_iovec, iov->m_Count); + int total_size = 0; + for ( int i = 0; i < iov->m_Count; i++ ) + total_size += iov->m_iovec[i].iov_len; + + int write_size = writev(m_Handle, iov->m_iovec, iov->m_Count); - if ( read_size == -1L ) + if ( write_size == -1L || write_size != total_size ) return RESULT_WRITEFAIL; iov->m_Count = 0; - *bytes_written = read_size; + *bytes_written = write_size; return RESULT_OK; } @@ -590,18 +986,15 @@ Kumu::FileWriter::Write(const byte_t* buf, ui32_t buf_len, ui32_t* bytes_written if ( bytes_written == 0 ) bytes_written = &tmp_int; - // TODO: flush iovec - - if ( m_Handle == -1L ) return RESULT_STATE; - int read_size = write(m_Handle, buf, buf_len); - - if ( read_size == -1L ) + int write_size = write(m_Handle, buf, buf_len); + + if ( write_size == -1L || (ui32_t)write_size != buf_len ) return RESULT_WRITEFAIL; - *bytes_written = read_size; + *bytes_written = write_size; return RESULT_OK; } @@ -637,7 +1030,7 @@ Kumu::ReadFileIntoString(const char* filename, std::string& outString, ui32_t ma if ( fsize == 0 ) { DefaultLogSink().Error("%s: zero file size\n", filename); - return RESULT_ALLOC; + return RESULT_READFAIL; } result = ReadBuf.Capacity((ui32_t)fsize); @@ -666,10 +1059,7 @@ Kumu::WriteStringIntoFile(const char* filename, const std::string& inString) if ( KM_SUCCESS(result) ) result = File.Write((byte_t*)inString.c_str(), inString.length(), &write_count); - if ( KM_SUCCESS(result) && write_count != inString.length() ) - return RESULT_WRITEFAIL; - - return RESULT_OK; + return result; }