Merge topic 'update-kwsys'

f442561af3 Merge branch 'upstream-KWSys' into update-kwsys
e02ccf40f3 KWSys 2026-08-01 (786ec914)

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !12353
This commit is contained in:
Brad King
2026-08-01 11:16:00 +00:00
committed by Kitware Robot
2 changed files with 80 additions and 149 deletions

View File

@@ -495,112 +495,36 @@ public:
}
};
#ifdef _WIN32
/**
* SystemTools static variables singleton class.
*/
class SystemToolsStatic
{
public:
#ifdef _WIN32
static std::string GetCasePathName(std::string const& pathIn);
static char const* GetEnvBuffered(char const* key);
// This map exists so that the encoding conversion performed on Windows has a
// storage location which behaves like the global environment. Note that if
// an environment variable is set, previously returned values of that
// variable's value may be invalidated (and it is just as hazardous as
// keeping `getenv` results across `setenv` calls on POSIX platforms).
std::map<std::string, std::string> EnvMap;
#endif
/**
* Actual implementation of ReplaceString.
*/
static void ReplaceString(std::string& source, char const* replace,
size_t replaceSize, std::string const& with);
/**
* Actual implementation of FileIsFullPath.
*/
static bool FileIsFullPath(char const*, size_t);
/**
* Find a filename (file or directory) in the system PATH, with
* optional extra paths.
*/
static std::string FindName(
std::string const& name,
std::vector<std::string> const& userPaths = std::vector<std::string>(),
bool no_system_path = false);
};
// Do NOT initialize. Default initialization to zero is necessary.
static SystemToolsStatic* SystemToolsStatics;
#ifdef _WIN32
std::string SystemToolsStatic::GetCasePathName(std::string const& pathIn)
char const* SystemToolsStatic::GetEnvBuffered(char const* key)
{
std::string casePath;
// First check if the file is relative. We don't fix relative paths since the
// real case depends on the root directory and the given path fragment may
// have meaning elsewhere in the project.
if (!SystemTools::FileIsFullPath(pathIn)) {
// This looks unnecessary, but it allows for the return value optimization
// since all return paths return the same local variable.
casePath = pathIn;
return casePath;
}
std::vector<std::string> path_components;
SystemTools::SplitPath(pathIn, path_components);
// Start with root component.
std::vector<std::string>::size_type idx = 0;
casePath = path_components[idx++];
// make sure drive letter is always upper case
if (casePath.size() > 1 && casePath[1] == ':') {
casePath[0] = kwsysString_toupper(casePath[0]);
}
char const* sep = "";
// If network path, fill casePath with server/share so FindFirstFile
// will work after that. Maybe someday call other APIs to get
// actual case of servers and shares.
if (path_components.size() > 2 && path_components[0] == "//") {
casePath += path_components[idx++];
casePath += '/';
casePath += path_components[idx++];
sep = "/";
}
// Convert case of all components that exist.
bool converting = true;
for (; idx < path_components.size(); idx++) {
casePath += sep;
sep = "/";
if (converting) {
// If path component contains wildcards, we skip matching
// because these filenames are not allowed on windows,
// and we do not want to match a different file.
if (path_components[idx].find('*') != std::string::npos ||
path_components[idx].find('?') != std::string::npos) {
converting = false;
} else {
std::string test_str = casePath;
test_str += path_components[idx];
WIN32_FIND_DATAW findData;
HANDLE hFind =
::FindFirstFileW(Encoding::ToWide(test_str).c_str(), &findData);
if (INVALID_HANDLE_VALUE != hFind) {
auto case_file_name = Encoding::ToNarrow(findData.cFileName);
path_components[idx] = std::move(case_file_name);
::FindClose(hFind);
} else {
converting = false;
}
}
std::string env;
if (SystemTools::GetEnv(key, env)) {
std::string& menv = SystemToolsStatics->EnvMap[key];
if (menv != env) {
menv = std::move(env);
}
casePath += path_components[idx];
return menv.c_str();
}
return casePath;
return nullptr;
}
#endif
@@ -641,21 +565,6 @@ void SystemTools::GetPath(std::vector<std::string>& path, char const* env)
}
}
#if defined(_WIN32)
char const* SystemToolsStatic::GetEnvBuffered(char const* key)
{
std::string env;
if (SystemTools::GetEnv(key, env)) {
std::string& menv = SystemToolsStatics->EnvMap[key];
if (menv != env) {
menv = std::move(env);
}
return menv.c_str();
}
return nullptr;
}
#endif
char const* SystemTools::GetEnv(char const* key)
{
#if defined(_WIN32)
@@ -972,8 +881,8 @@ void SystemTools::ReplaceString(std::string& source,
return;
}
SystemToolsStatic::ReplaceString(source, replace.c_str(), replace.size(),
with);
SystemTools::ReplaceStringImpl(source, replace.c_str(), replace.size(),
with);
}
void SystemTools::ReplaceString(std::string& source, char const* replace,
@@ -984,13 +893,13 @@ void SystemTools::ReplaceString(std::string& source, char const* replace,
return;
}
SystemToolsStatic::ReplaceString(source, replace, strlen(replace),
with ? with : "");
SystemTools::ReplaceStringImpl(source, replace, strlen(replace),
with ? with : "");
}
void SystemToolsStatic::ReplaceString(std::string& source, char const* replace,
size_t replaceSize,
std::string const& with)
void SystemTools::ReplaceStringImpl(std::string& source, char const* replace,
size_t replaceSize,
std::string const& with)
{
char const* src = source.c_str();
char* searchPos = const_cast<char*>(strstr(src, replace));
@@ -2880,7 +2789,7 @@ size_t SystemTools::GetMaximumFilePathLength()
* the system search path. Returns the full path to the file if it is
* found. Otherwise, the empty string is returned.
*/
std::string SystemToolsStatic::FindName(
std::string SystemTools::FindNameImpl(
std::string const& name, std::vector<std::string> const& userPaths,
bool no_system_path)
{
@@ -2918,7 +2827,7 @@ std::string SystemTools::FindFile(std::string const& name,
bool no_system_path)
{
std::string tryPath =
SystemToolsStatic::FindName(name, userPaths, no_system_path);
SystemTools::FindNameImpl(name, userPaths, no_system_path);
if (!tryPath.empty() && !SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -2936,7 +2845,7 @@ std::string SystemTools::FindDirectory(
bool no_system_path)
{
std::string tryPath =
SystemToolsStatic::FindName(name, userPaths, no_system_path);
SystemTools::FindNameImpl(name, userPaths, no_system_path);
if (!tryPath.empty() && SystemTools::FileIsDirectory(tryPath)) {
return SystemTools::CollapseFullPath(tryPath);
}
@@ -3464,15 +3373,6 @@ std::string SystemTools::RelativePath(std::string const& local,
return relativePath;
}
std::string SystemTools::GetActualCaseForPath(std::string const& p)
{
#ifdef _WIN32
return SystemToolsStatic::GetCasePathName(p);
#else
return p;
#endif
}
char const* SystemTools::SplitPathRootComponent(std::string const& p,
std::string* root)
{
@@ -3989,18 +3889,8 @@ bool SystemTools::LocateFileInDir(char const* filename, char const* dir,
return res;
}
bool SystemTools::FileIsFullPath(std::string const& in_name)
{
return SystemToolsStatic::FileIsFullPath(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(char const* in_name)
{
return SystemToolsStatic::FileIsFullPath(
in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
bool SystemToolsStatic::FileIsFullPath(char const* in_name, size_t len)
namespace {
bool FileIsFullPathImpl(char const* in_name, size_t len)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
// On Windows, the name must be at least two characters long.
@@ -4032,6 +3922,17 @@ bool SystemToolsStatic::FileIsFullPath(char const* in_name, size_t len)
}
return false;
}
}
bool SystemTools::FileIsFullPath(std::string const& in_name)
{
return FileIsFullPathImpl(in_name.c_str(), in_name.size());
}
bool SystemTools::FileIsFullPath(char const* in_name)
{
return FileIsFullPathImpl(in_name, in_name[0] ? (in_name[1] ? 2 : 1) : 0);
}
Status SystemTools::GetShortPath(std::string const& path,
std::string& shortPath)
@@ -4654,6 +4555,13 @@ std::string SystemTools::DecodeURL(std::string const& url)
return ret;
}
#if defined(__VMS) || defined(_WIN32)
# define KWSYS_NEED_SYSTEM_TOOLS_MANAGER 1
#else
# define KWSYS_NEED_SYSTEM_TOOLS_MANAGER 0
#endif
#if KWSYS_NEED_SYSTEM_TOOLS_MANAGER
// ----------------------------------------------------------------------
// Do NOT initialize. Default initialization to zero is necessary.
static unsigned int SystemToolsManagerCount;
@@ -4678,7 +4586,7 @@ SystemToolsManager::~SystemToolsManager()
}
}
#if defined(__VMS)
# if defined(__VMS)
// On VMS we configure the run time C library to be more UNIX like.
// https://h71000.www7.hp.com/doc/732final/5763/5763pro_004.html
extern "C" int decc$feature_get_index(char* name);
@@ -4690,22 +4598,27 @@ static int SetVMSFeature(char* name, int value)
i = decc$feature_get_index(name);
return i >= 0 && (decc$feature_set_value(i, 1, value) >= 0 || errno == 0);
}
#endif
# endif
void SystemTools::ClassInitialize()
{
#ifdef __VMS
# ifdef __VMS
SetVMSFeature("DECC$FILENAME_UNIX_ONLY", 1);
#endif
# endif
# ifdef _WIN32
// Create statics singleton instance
SystemToolsStatics = new SystemToolsStatic;
# endif
}
void SystemTools::ClassFinalize()
{
# ifdef _WIN32
delete SystemToolsStatics;
# endif
}
#endif
} // namespace KWSYS_NAMESPACE

View File

@@ -43,8 +43,17 @@ typedef @KWSYS_NAMESPACE@_VA_LIST::hack_va_list va_list;
namespace @KWSYS_NAMESPACE@ {
#ifdef _WIN32
class SystemToolsStatic;
#endif
#if defined(__VMS) || defined(_WIN32)
# define @KWSYS_NAMESPACE@_NEED_SYSTEM_TOOLS_MANAGER 1
#else
# define @KWSYS_NAMESPACE@_NEED_SYSTEM_TOOLS_MANAGER 0
#endif
#if @KWSYS_NAMESPACE@_NEED_SYSTEM_TOOLS_MANAGER
/** \class SystemToolsManager
* \brief Use to make sure SystemTools is initialized before it is used
* and is the last static object destroyed
@@ -63,6 +72,7 @@ public:
// SystemTools. It will make sure SystemTools is initialized
// before it is used and is the last static object destroyed.
static SystemToolsManager SystemToolsManagerInstance;
#endif
// Flags for use with TestFileAccess. Use a typedef in case any operating
// system in the future needs a special type. These are flags that may be
@@ -361,15 +371,6 @@ public:
*/
static char const* GetExecutableExtension();
/**
* Given a path on a Windows machine, return the actual case of
* the path as it exists on disk. Path components that do not
* exist on disk are returned unchanged. Relative paths are always
* returned unchanged. Drive letters are always made upper case.
* This does nothing on non-Windows systems but return the path.
*/
static std::string GetActualCaseForPath(std::string const& path);
/**
* Given the path to a program executable, get the directory part of
* the path with the file stripped off. If there is no directory
@@ -1017,6 +1018,7 @@ public:
static std::string DecodeURL(std::string const& url);
private:
#if @KWSYS_NAMESPACE@_NEED_SYSTEM_TOOLS_MANAGER
static void ClassInitialize();
static void ClassFinalize();
@@ -1027,9 +1029,25 @@ private:
{
return &SystemToolsManagerInstance;
}
#endif
static void ReplaceStringImpl(std::string& source, char const* replace,
size_t replaceSize, std::string const& with);
/**
* Find a filename (file or directory) in the system PATH, with
* optional extra paths.
*/
static std::string FindNameImpl(
std::string const& name,
std::vector<std::string> const& userPaths = std::vector<std::string>(),
bool no_system_path = false);
#ifdef _WIN32
friend class SystemToolsStatic;
#endif
#if @KWSYS_NAMESPACE@_NEED_SYSTEM_TOOLS_MANAGER
friend class SystemToolsManager;
#endif
};
} // namespace @KWSYS_NAMESPACE@