Make case-dependent operations locale-independent

Use ASCII-only ctype operations provided by KWSys String.
These match the "C" locale in which `cmake` has long run.
This commit is contained in:
Brad King
2026-02-08 12:59:23 -05:00
parent c81909f842
commit ea47c154e5
15 changed files with 53 additions and 53 deletions

View File

@@ -4,12 +4,12 @@ file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmCPackInnoSetupGenerator.h"
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <ostream>
#include <utility>
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
#include "cmCPackComponentGroup.h"
#include "cmCPackLog.h"
@@ -116,7 +116,7 @@ int cmCPackInnoSetupGenerator::PackageFiles()
if (cmSystemTools::LowerCase(i) == "english") {
params["MessagesFile"] = "\"compiler:Default.isl\"";
} else {
i[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(i[0])));
i[0] = static_cast<char>(cmsysString_toupper(i[0]));
params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
}

View File

@@ -3,12 +3,13 @@
#include "cmCPackRPMGenerator.h"
#include <algorithm>
#include <cctype>
#include <map>
#include <ostream>
#include <utility>
#include <vector>
#include "cmsys/String.h"
#include "cmCPackComponentGroup.h"
#include "cmCPackGenerator.h"
#include "cmCPackLog.h"
@@ -143,7 +144,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
++compIt) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
[](unsigned char c) { return std::toupper(c); });
cmsysString_toupper);
if (this->IsOn("CPACK_RPM_" + compIt->first + "_DEBUGINFO_PACKAGE") ||
this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -157,7 +158,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
compGIt != this->ComponentGroups.end(); ++compGIt) {
std::string component(compGIt->first);
std::transform(component.begin(), component.end(), component.begin(),
[](unsigned char c) { return std::toupper(c); });
cmsysString_toupper);
if (this->IsOn("CPACK_RPM_" + compGIt->first + "_DEBUGINFO_PACKAGE") ||
this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -174,8 +175,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
if (!compIt->second.Group) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(),
component.begin(),
[](unsigned char c) { return std::toupper(c); });
component.begin(), cmsysString_toupper);
if (this->IsOn("CPACK_RPM_" + compIt->first +
"_DEBUGINFO_PACKAGE") ||
@@ -207,8 +207,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
std::string mainComponentUpper(mainComponent);
std::transform(mainComponentUpper.begin(), mainComponentUpper.end(),
mainComponentUpper.begin(),
[](unsigned char c) { return std::toupper(c); });
mainComponentUpper.begin(), cmsysString_toupper);
// The default behavior is to have one package by component group
// unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
@@ -220,7 +219,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
compGIt != this->ComponentGroups.end(); ++compGIt) {
std::string component(compGIt->first);
std::transform(component.begin(), component.end(), component.begin(),
[](unsigned char c) { return std::toupper(c); });
cmsysString_toupper);
if (mainComponentUpper == component) {
// main component will be handled last
@@ -242,7 +241,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
if (!compIt->second.Group) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
[](unsigned char c) { return std::toupper(c); });
cmsysString_toupper);
if (mainComponentUpper == component) {
// main component will be handled last
@@ -285,7 +284,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
++compIt) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
[](unsigned char c) { return std::toupper(c); });
cmsysString_toupper);
if (mainComponentUpper == component) {
// main component will be handled last

View File

@@ -2,12 +2,13 @@
file LICENSE.rst or https://cmake.org/licensing for details. */
#include "cmCursesColor.h"
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <unordered_map>
#include <utility>
#include "cmsys/String.h"
#include "cmCursesStandardIncludes.h"
bool cmCursesColor::HasColors()
@@ -42,7 +43,7 @@ short cmCursesColor::GetColor(char id, short fallback)
if (!initialized) {
if (auto* v = getenv("CCMAKE_COLORS")) {
while (v[0] && v[1] && v[1] == '=') {
auto const n = std::toupper(static_cast<unsigned char>(*v));
char const n = cmsysString_toupper(*v);
char buffer[12];
memset(buffer, 0, sizeof(buffer));

View File

@@ -34,6 +34,7 @@
#include "cmsys/Directory.hxx"
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
#include "cmsys/SystemInformation.hxx"
#ifndef _WIN32
# include <unistd.h> // IWYU pragma: keep
@@ -3702,8 +3703,7 @@ bool cmCTest::ConvertInstrumentationJSONFileToXML(std::string const& fpath,
bool generating_test_xml = root["role"] == "test";
if (!generating_test_xml) {
std::string element_name = root["role"].asString();
element_name[0] = static_cast<char>(
std::toupper(static_cast<unsigned char>(element_name[0])));
element_name[0] = static_cast<char>(cmsysString_toupper(element_name[0]));
xml.StartElement(element_name);
std::vector<std::string> keys = root.getMemberNames();
for (auto const& key : keys) {
@@ -3735,8 +3735,8 @@ bool cmCTest::ConvertInstrumentationJSONFileToXML(std::string const& fpath,
std::vector<std::string> keys = dynamic_information.getMemberNames();
for (auto const& key : keys) {
std::string measurement_name = key;
measurement_name[0] = static_cast<char>(
std::toupper(static_cast<unsigned char>(measurement_name[0])));
measurement_name[0] =
static_cast<char>(cmsysString_toupper(measurement_name[0]));
xml.StartElement("NamedMeasurement");
xml.Attribute("type", "numeric/double");

View File

@@ -3,7 +3,6 @@
#include "cmComputeLinkInformation.h"
#include <algorithm>
#include <cctype>
#include <sstream>
#include <utility>
@@ -13,6 +12,8 @@
#include <cmext/algorithm>
#include <cmext/string_view>
#include "cmsys/String.h"
#include "cmComputeLinkDepends.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
@@ -1556,8 +1557,8 @@ std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
ret += c;
} else {
ret += '[';
ret += static_cast<char>(tolower(static_cast<unsigned char>(c)));
ret += static_cast<char>(toupper(static_cast<unsigned char>(c)));
ret += static_cast<char>(cmsysString_tolower(c));
ret += static_cast<char>(cmsysString_toupper(c));
ret += ']';
}
}

View File

@@ -3,7 +3,6 @@
#include "cmFindLibraryCommand.h"
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <set>
@@ -13,6 +12,7 @@
#include <cm/optional>
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
#include "cmFindCommon.h"
#include "cmGlobalGenerator.h"
@@ -349,7 +349,7 @@ void cmFindLibraryHelper::RegexFromLiteral(std::string& out,
out += "\\";
}
if (dirCase == cmSystemTools::DirCase::Insensitive) {
out += static_cast<char>(tolower(static_cast<unsigned char>(ch)));
out += static_cast<char>(cmsysString_tolower(ch));
} else {
out += ch;
}

View File

@@ -12,9 +12,8 @@
#include "LexerParser/cmGccDepfileLexer.h"
#ifdef _WIN32
# include <cctype>
# include "cmsys/Encoding.h"
# include "cmsys/String.h"
#endif
bool cmGccDepfileLexerHelper::readFile(char const* filePath)
@@ -128,8 +127,7 @@ void cmGccDepfileLexerHelper::sanitizeContent()
// Some versions of GNU compilers can escape this character.
// c\:\path must be transformed to c:\path
if (pit->size() >= 3) {
auto pit0 = static_cast<char>(
std::toupper(static_cast<unsigned char>((*pit)[0])));
auto pit0 = static_cast<char>(cmsysString_toupper((*pit)[0]));
if (pit0 >= 'A' && pit0 <= 'Z' && (*pit)[1] == '\\' &&
(*pit)[2] == ':') {
pit->erase(1, 1);

View File

@@ -16,6 +16,8 @@
# include <cctype>
# include <windows.h>
# include <cmsys/String.h>
#endif
#define MAX_SYMBOLIC_LINKS 32
@@ -171,8 +173,7 @@ std::string ImplBase::GetWorkingDirectoryOnDrive(char letter)
std::string d = this->OS.GetWorkingDirectoryOnDrive(letter);
std::replace(d.begin(), d.end(), '\\', '/');
if (d.size() >= 3 &&
std::toupper(static_cast<unsigned char>(d[0])) ==
std::toupper(static_cast<unsigned char>(letter)) &&
cmsysString_toupper(d[0]) == cmsysString_toupper(letter) &&
d[1] == ':' && d[2] == '/') {
d[0] = letter;
d.push_back('/');
@@ -182,8 +183,7 @@ std::string ImplBase::GetWorkingDirectoryOnDrive(char letter)
// Use the current working directory if the drive matches.
d = this->OS.GetWorkingDirectory();
if (d.size() >= 3 &&
std::toupper(static_cast<unsigned char>(d[0])) ==
std::toupper(static_cast<unsigned char>(letter)) &&
cmsysString_toupper(d[0]) == cmsysString_toupper(letter) &&
d[1] == ':' && d[2] == '/') {
d[0] = letter;
d.push_back('/');
@@ -284,7 +284,7 @@ Control Impl<Policy>::ResolveRoot(Root root)
if (Policy::ActualCase == Options::ActualCase::Yes) {
// Normalize the drive letter to upper-case.
P[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(P[0])));
P[0] = static_cast<char>(cmsysString_toupper(P[0]));
}
// The root is a drive letter. The root '/' immediately follows.

View File

@@ -3,10 +3,11 @@
#include "cmSbomArguments.h"
#include <algorithm>
#include <cctype>
#include <cm/string_view>
#include "cmsys/String.h"
#include "cmExecutionStatus.h"
#include "cmGeneratorExpression.h"
#include "cmStringAlgorithms.h"
@@ -99,6 +100,6 @@ std::string cmSbomArguments::GetPackageFileName() const
std::string const pkgNameOnDisk = this->GetPackageDirName();
std::string format = GetSbomFileExtension(this->GetFormat());
std::transform(format.begin(), format.end(), format.begin(),
[](unsigned char c) { return std::tolower(c); });
cmsysString_tolower);
return cmStrCat(pkgNameOnDisk, format);
}

View File

@@ -8,15 +8,17 @@
#include <cstdio>
#include <cstdlib>
#include "cmsys/String.h"
bool cmStrCaseEq(cm::string_view s1, cm::string_view s2)
{
if (s1.size() != s2.size()) {
return false;
}
return std::equal(
s1.begin(), s1.end(), s2.begin(),
[](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
return std::equal(s1.begin(), s1.end(), s2.begin(), [](char a, char b) {
return cmsysString_tolower(a) == cmsysString_tolower(b);
});
}
std::string cmTrimWhitespace(cm::string_view str)

View File

@@ -101,6 +101,7 @@
#include "cmsys/Directory.hxx"
#ifdef _WIN32
# include "cmsys/Encoding.hxx"
# include "cmsys/String.h"
#endif
#include "cmsys/FStream.hxx"
#include "cmsys/RegularExpression.hxx"
@@ -1340,7 +1341,7 @@ std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
}
// Normalize to upper-case drive letter as cm::PathResolver does.
if (resolved_path.size() > 1 && resolved_path[1] == ':') {
resolved_path[0] = toupper(static_cast<unsigned char>(resolved_path[0]));
resolved_path[0] = cmsysString_toupper(resolved_path[0]);
}
return resolved_path;
#else
@@ -1362,12 +1363,10 @@ std::string cmSystemTools::GetRealPath(std::string const& path,
// limitation to otherwise preserve susbt drives.
if (resolved_path.size() >= 2 && resolved_path[1] == ':' &&
path.size() >= 2 && path[1] == ':' &&
toupper(static_cast<unsigned char>(resolved_path[0])) !=
toupper(static_cast<unsigned char>(path[0]))) {
cmsysString_toupper(resolved_path[0]) != cmsysString_toupper(path[0])) {
// FIXME: Add thread_local or mutex if we use threads.
static std::map<char, std::string> substMap;
char const drive =
static_cast<char>(toupper(static_cast<unsigned char>(path[0])));
char const drive = static_cast<char>(cmsysString_toupper(path[0]));
std::string maybe_subst = cmStrCat(drive, ":/");
auto smi = substMap.find(drive);
if (smi == substMap.end()) {

View File

@@ -4,7 +4,6 @@
#include "cmWindowsRegistry.h"
#include <cctype>
#include <cstddef>
#include <type_traits>
#include <unordered_map>
@@ -13,6 +12,7 @@
#include <cmext/string_view>
#include "cmsys/RegularExpression.hxx"
#include "cmsys/String.h"
#if defined(_WIN32) && !defined(__CYGWIN__)
# include <algorithm>
@@ -47,8 +47,8 @@ int Strucmp(cm::string_view l, cm::string_view r)
cm::string_view::size_type ri = 0;
do {
lc = std::tolower(static_cast<unsigned char>(l[li++]));
rc = std::tolower(static_cast<unsigned char>(r[ri++]));
lc = cmsysString_tolower(l[li++]);
rc = cmsysString_tolower(r[ri++]);
} while (lc == rc && li < l.size() && ri < r.size());
return lc == rc ? static_cast<int>(l.size() - r.size()) : lc - rc;

View File

@@ -5,7 +5,6 @@
#include <algorithm>
#include <cassert>
#include <cctype>
#include <climits>
#include <cstring>
#include <functional>
@@ -20,6 +19,8 @@
#include <cm3p/uv.h>
#include "cmsys/String.h"
#include "cmBuildArgs.h"
#include "cmBuildOptions.h"
#include "cmCommandLineArgument.h"
@@ -500,8 +501,7 @@ int do_build(int ac, char const* const* av)
};
auto resolvePackagesLambda = [&](std::string const& value) -> bool {
std::string v = value;
std::transform(v.begin(), v.end(), v.begin(),
[](unsigned char c) { return std::tolower(c); });
std::transform(v.begin(), v.end(), v.begin(), cmsysString_tolower);
if (v == "on") {
resolveMode = PackageResolveMode::Force;
} else if (v == "only") {

View File

@@ -9,7 +9,7 @@
#include <utility>
#ifdef _WIN32
# include <cctype>
# include <cmsys/String.h>
#endif
#include <cmsys/Status.hxx>
@@ -92,8 +92,7 @@ public:
std::string GetWorkingDirectoryOnDrive(char letter) override
{
std::string result;
auto i = this->WorkDirOnDrive.find(
std::tolower(static_cast<unsigned char>(letter)));
auto i = this->WorkDirOnDrive.find(cmsysString_tolower(letter));
if (i != this->WorkDirOnDrive.end()) {
result = i->second;
}

View File

@@ -1,4 +1,3 @@
#include <cctype>
#include <chrono>
#include <cstdlib>
#include <iostream>
@@ -7,6 +6,7 @@
#include <string>
#include <thread>
#include "cmsys/String.h"
#include "cmsys/SystemTools.hxx"
#ifdef _WIN32
@@ -41,7 +41,7 @@ int main(int argc, char** argv)
std::this_thread::sleep_for(std::chrono::milliseconds(12000));
std::string input = getStdin();
for (auto& c : input) {
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
c = static_cast<char>(cmsysString_toupper(c));
}
std::cout << input << std::flush;
std::cerr << "2" << std::flush;