Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/elfmz/far2l.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelfmz <fenix1905@tut.by>2022-09-03 16:39:10 +0300
committerelfmz <fenix1905@tut.by>2022-09-03 16:39:10 +0300
commit8fb5855053a33cfe8d20e5e8dd8ae141390a4971 (patch)
tree5a8eda268d75875a309c77a531dd3c44ee31f6b4
parent09e9fa095dbfed0eea24b06c09371a6ca08673d3 (diff)
KeyFileHelper: optional case-insensitivity
-rw-r--r--utils/include/KeyFileHelper.h28
-rw-r--r--utils/include/utils.h1
-rw-r--r--utils/src/KeyFileHelper.cpp60
-rw-r--r--utils/src/utils.cpp5
4 files changed, 80 insertions, 14 deletions
diff --git a/utils/include/KeyFileHelper.h b/utils/include/KeyFileHelper.h
index b1a9487f..5089c3d9 100644
--- a/utils/include/KeyFileHelper.h
+++ b/utils/include/KeyFileHelper.h
@@ -4,8 +4,20 @@
#include <vector>
#include <map>
-struct KeyFileValues : std::map<std::string, std::string>
+struct KeyFileCmp
{
+ inline KeyFileCmp(bool case_insensitive = false) : _case_insensitive(case_insensitive) {}
+
+ bool operator()(const std::string& a, const std::string& b) const;
+
+private:
+ bool _case_insensitive = false;
+};
+
+struct KeyFileValues : std::map<std::string, std::string, KeyFileCmp>
+{
+ KeyFileValues(bool case_insensitive = false);
+
bool HasKey(const std::string &name) const;
std::string GetString(const std::string &name, const char *def = "") const;
std::wstring GetString(const std::string &name, const wchar_t *def) const;
@@ -24,7 +36,7 @@ class KeyFileReadSection : public KeyFileValues
bool _section_loaded;
public:
- KeyFileReadSection(const std::string &filename, const std::string &section);
+ KeyFileReadSection(const std::string &filename, const std::string &section, bool case_insensitive = false);
bool SectionLoaded() const { return _section_loaded; }
};
@@ -32,12 +44,18 @@ public:
class KeyFileReadHelper
{
protected:
- struct Sections : std::map<std::string, KeyFileValues> {} _kf;
+ struct Sections : std::map<std::string, KeyFileValues, KeyFileCmp> {
+ inline Sections(bool case_insensitive) :
+ std::map<std::string, KeyFileValues, KeyFileCmp>(KeyFileCmp(case_insensitive))
+ { }
+ } _kf;
+
struct stat _filestat {};
bool _loaded = false;
+ bool _case_insensitive;
public:
- KeyFileReadHelper(const std::string &filename, const char *load_only_section = nullptr);
+ KeyFileReadHelper(const std::string &filename, const char *load_only_section = nullptr, bool case_insensitive = false);
bool IsLoaded() const { return _loaded; }
@@ -69,7 +87,7 @@ class KeyFileHelper : public KeyFileReadHelper
bool _dirty;
public:
- KeyFileHelper(const std::string &filename, bool load = true);
+ KeyFileHelper(const std::string &filename, bool load = true, bool case_insensitive = false);
~KeyFileHelper();
bool Save(bool only_if_dirty = true);
diff --git a/utils/include/utils.h b/utils/include/utils.h
index b91b6f8f..51deb428 100644
--- a/utils/include/utils.h
+++ b/utils/include/utils.h
@@ -276,6 +276,7 @@ template <typename HaystackIT, typename NeedlesT>
return nullptr;
}
+bool CaseIgnoreEngStrMatch(const std::string &str1, const std::string &str2);
bool CaseIgnoreEngStrMatch(const char *str1, const char *str2, size_t len);
const char *CaseIgnoreEngStrChr(const char c, const char *str, size_t len);
diff --git a/utils/src/KeyFileHelper.cpp b/utils/src/KeyFileHelper.cpp
index 06394ee5..fe5daacb 100644
--- a/utils/src/KeyFileHelper.cpp
+++ b/utils/src/KeyFileHelper.cpp
@@ -17,6 +17,41 @@
// KeyFileHelper to tell KeyFileReadHelper don't load anything
static char sDontLoadLiteral[] = "][";
+// This predicate causes std::map elements to be sorted either in semi-case-insensitive mode,
+// i.e. elements that differ by character case only will be together.
+// Either in fully case-insensitive mode.
+
+bool FN_NOINLINE KeyFileCmp::operator()(const std::string& a, const std::string& b) const
+{
+ int case_sensitive_diff = 0;
+ const char *pa = a.c_str();
+ const char *pb = b.c_str();
+ for (size_t i = 0;; ++i) {
+ auto ca = pa[i];
+ auto cb = pb[i];
+ if (ca != cb) {
+ if (case_sensitive_diff == 0) {
+ case_sensitive_diff = (ca < cb) ? -1 : 1;
+ }
+ if (ca >= 'a' && ca <= 'z') {
+ ca-= 'a' - 'A';
+ }
+ if (cb >= 'a' && cb <= 'z') {
+ cb-= 'a' - 'A';
+ }
+ if (ca != cb) {
+ return ca < cb;
+ }
+ }
+ if (UNLIKELY(i == a.size() || i == b.size())) {
+ if ((_case_insensitive || case_sensitive_diff == 0) && a.size() != b.size()) {
+ return a.size() < b.size();
+ }
+ return _case_insensitive ? false : (case_sensitive_diff < 0);
+ }
+ }
+}
+
class KFEscaping
{
std::string _result;
@@ -125,6 +160,10 @@ public:
////////////////////////////////////////////////////////////////
+KeyFileValues::KeyFileValues(bool case_insensitive)
+ : std::map<std::string, std::string, KeyFileCmp>(KeyFileCmp(case_insensitive))
+{
+}
bool KeyFileValues::HasKey(const std::string &name) const
{
@@ -363,7 +402,7 @@ static bool LoadKeyFile(const std::string &filename, struct stat &filestat, Valu
///////////////////////////////////////////
-KeyFileReadSection::KeyFileReadSection(const std::string &filename, const std::string &section)
+KeyFileReadSection::KeyFileReadSection(const std::string &filename, const std::string &section, bool case_insensitive)
:
_section_loaded(false)
{
@@ -371,7 +410,7 @@ KeyFileReadSection::KeyFileReadSection(const std::string &filename, const std::s
LoadKeyFile(filename, filestat,
[&] (const std::string &section_name)->KeyFileValues *
{
- if (section_name == section) {
+ if (section_name == section || (case_insensitive && CaseIgnoreEngStrMatch(section_name, section))) {
_section_loaded = true;
return this;
}
@@ -383,7 +422,8 @@ KeyFileReadSection::KeyFileReadSection(const std::string &filename, const std::s
///////////////////////////////////
-KeyFileReadHelper::KeyFileReadHelper(const std::string &filename, const char *load_only_section)
+KeyFileReadHelper::KeyFileReadHelper(const std::string &filename, const char *load_only_section, bool case_insensitive)
+ : _kf(case_insensitive), _case_insensitive(case_insensitive)
{
// intentially comparing pointer values
if (load_only_section == &sDontLoadLiteral[0]) {
@@ -393,7 +433,8 @@ KeyFileReadHelper::KeyFileReadHelper(const std::string &filename, const char *lo
_loaded = LoadKeyFile(filename, _filestat,
[&] (const std::string &section_name)->KeyFileValues *
{
- if (load_only_section == nullptr || section_name == load_only_section) {
+ if (load_only_section == nullptr || section_name == load_only_section
+ || (case_insensitive && CaseIgnoreEngStrMatch(section_name, load_only_section))) {
return &_kf[section_name];
}
@@ -436,7 +477,8 @@ std::vector<std::string> KeyFileReadHelper::EnumSectionsAt(const std::string &pa
std::vector<std::string> out;
for (const auto &s : _kf) {
if (s.first.size() > prefix.size()
- && memcmp(s.first.c_str(), prefix.c_str(), prefix.size()) == 0
+ && ( (!_case_insensitive && memcmp(s.first.c_str(), prefix.c_str(), prefix.size()) == 0) ||
+ (_case_insensitive && CaseIgnoreEngStrMatch(s.first.c_str(), prefix.c_str(), prefix.size())) )
&& (recursed || strchr(s.first.c_str() + prefix.size(), '/') == nullptr)) {
out.push_back(s.first);
@@ -559,9 +601,9 @@ bool KeyFileReadHelper::GetBytes(std::vector<unsigned char> &out, const std::str
/////////////////////////////////////////////////////////////
-KeyFileHelper::KeyFileHelper(const std::string &filename, bool load)
+KeyFileHelper::KeyFileHelper(const std::string &filename, bool load, bool case_insensitive)
:
- KeyFileReadHelper(filename, load ? nullptr : &sDontLoadLiteral[0]),
+ KeyFileReadHelper(filename, load ? nullptr : &sDontLoadLiteral[0], case_insensitive),
_filename(filename),
_dirty(!load)
{
@@ -649,9 +691,9 @@ bool KeyFileHelper::RemoveSection(const std::string &section)
{
if (_kf.erase(section) != 0) {
_dirty = true;
- return 1;
+ return true;
}
- return 0;
+ return false;
}
size_t KeyFileHelper::RemoveSectionsAt(const std::string &parent_section)
diff --git a/utils/src/utils.cpp b/utils/src/utils.cpp
index 4df46fd4..66e95fb3 100644
--- a/utils/src/utils.cpp
+++ b/utils/src/utils.cpp
@@ -287,6 +287,11 @@ static inline bool CaseIgnoreEngChrMatch(const char c1, const char c2)
return true;
}
+bool CaseIgnoreEngStrMatch(const std::string &str1, const std::string &str2)
+{
+ return str1.size() == str2.size() && CaseIgnoreEngStrMatch(str1.c_str(), str2.c_str(), str1.size());
+}
+
bool CaseIgnoreEngStrMatch(const char *str1, const char *str2, size_t len)
{
for (size_t i = 0; i != len; ++i) {