TEST( PathTools, GetSlash ) { #if defined( _WIN32 ) ASSERT_EQ( '\\', Path_GetSlash() ); #else ASSERT_EQ( '/', Path_GetSlash() ); #endif }
std::string Path_RemoveTrailingSlash(const std::string & sRawPath, char slash) { if (slash == 0) slash = Path_GetSlash(); std::string sPath = sRawPath; std::string::size_type nCurrent = sRawPath.length(); if (nCurrent == 0) return sPath; int nLastFound = -1; nCurrent--; while (nCurrent != 0) { if (sRawPath[nCurrent] == slash) { nLastFound = (int)nCurrent; nCurrent--; } else { break; } } if (nLastFound >= 0) { sPath.erase(nLastFound, std::string::npos); } return sPath; }
/** returns just the filename from the provided full or relative path. */ std::string Path_StripDirectory(const std::string & sPath, char slash) { if (slash == 0) slash = Path_GetSlash(); std::string::size_type n = sPath.find_last_of(slash); if (n == std::string::npos) return sPath; else return std::string(sPath.begin() + n + 1, sPath.end()); }
/** Returns the specified path without its filename */ std::string Path_StripFilename(const std::string& sPath, char slash) { if (slash == 0) slash = Path_GetSlash(); std::string::size_type n = sPath.find_last_of(slash); if (n == std::string::npos) return sPath; else return std::string(sPath.begin(), sPath.begin() + n); }
/** Fixes the directory separators for the current platform */ std::string Path_FixSlashes(const std::string & sPath, char slash) { if (slash == 0) slash = Path_GetSlash(); std::string sFixed = sPath; for (std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++) { if (*i == '/' || *i == '\\') * i = slash; } return sFixed; }
/** Jams two paths together with the right kind of slash */ std::string Path_Join(const std::string & first, const std::string & second, char slash) { if (slash == 0) slash = Path_GetSlash(); // only insert a slash if we don't already have one std::string::size_type nLen = first.length(); if (!nLen) return second; #if defined(_WIN32) if (first.back() == '\\' || first.back() == '/') nLen--; #else char last_char = first[first.length() - 1]; if (last_char == '\\' || last_char == '/') nLen--; #endif return first.substr(0, nLen) + std::string(1, slash) + second; }
/** Removes redundant <dir>/.. elements in the path. Returns an empty path if the * specified path has a broken number of directories for its number of ..s */ std::string Path_Compact(const std::string & sRawPath, char slash) { if (slash == 0) slash = Path_GetSlash(); std::string sPath = Path_FixSlashes(sRawPath, slash); std::string sSlashString(1, slash); // strip out all /./ for (std::string::size_type i = 0; (i + 3) < sPath.length(); ) { if (sPath[i] == slash && sPath[i + 1] == '.' && sPath[i + 2] == slash) { sPath.replace(i, 3, sSlashString); } else { ++i; } } // get rid of trailing /. but leave the path separator if (sPath.length() > 2) { std::string::size_type len = sPath.length(); if (sPath[len - 1] == '.' && sPath[len - 2] == slash) { // sPath.pop_back(); sPath[len - 1] = 0; // for now, at least } } // get rid of leading ./ if (sPath.length() > 2) { if (sPath[0] == '.' && sPath[1] == slash) { sPath.replace(0, 2, ""); } } // each time we encounter .. back up until we've found the previous directory name // then get rid of both std::string::size_type i = 0; while (i < sPath.length()) { if (i > 0 && sPath.length() - i >= 2 && sPath[i] == '.' && sPath[i + 1] == '.' && (i + 2 == sPath.length() || sPath[i + 2] == slash) && sPath[i - 1] == slash) { // check if we've hit the start of the string and have a bogus path if (i == 1) return ""; // find the separator before i-1 std::string::size_type iDirStart = i - 2; while (iDirStart > 0 && sPath[iDirStart - 1] != slash) --iDirStart; // remove everything from iDirStart to i+2 sPath.replace(iDirStart, (i - iDirStart) + 3, ""); // start over i = 0; } else { ++i; } } return sPath; }