From d7dedcfc755bf3341d536f8ddf186f2e8483417a Mon Sep 17 00:00:00 2001 From: JamesAC Date: Fri, 29 Jul 2011 11:49:46 +0000 Subject: [PATCH] Adding support for RegExp in Substitute strings when RegExpSubstitute=1 is set. --- Library/Library.vcxproj | 32 ++++++- Library/Library.vcxproj.filters | 75 ++++++++++++++++ Library/Litestep.cpp | 40 +++++++++ Library/Litestep.h | 2 + Library/Measure.cpp | 146 +++++++++++++++++++++++++++----- Library/Measure.h | 4 +- 6 files changed, 272 insertions(+), 27 deletions(-) diff --git a/Library/Library.vcxproj b/Library/Library.vcxproj index 91980737..580132ee 100644 --- a/Library/Library.vcxproj +++ b/Library/Library.vcxproj @@ -95,7 +95,7 @@ Disabled lua/include;lua/lua;lua/tolua++;lua/glue;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;SUPPORT_UTF8;LIBRARY_EXPORTS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL true @@ -138,7 +138,7 @@ Disabled lua/include;lua/lua;lua/tolua++;lua/glue;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;HAVE_CONFIG_H;SUPPORT_UTF8;LIBRARY_EXPORTS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL true @@ -182,7 +182,7 @@ MaxSpeed OnlyExplicitInline lua/include;lua/lua;lua/tolua++;lua/glue;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;HAVE_CONFIG_H;SUPPORT_UTF8;_SECURE_SCL=0;%(PreprocessorDefinitions) true MultiThreadedDLL true @@ -232,7 +232,7 @@ MaxSpeed Default lua/include;lua/lua;lua/tolua++;lua/glue;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;_SECURE_SCL=0;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBRARY_EXPORTS;HAVE_CONFIG_H;SUPPORT_UTF8;_SECURE_SCL=0;%(PreprocessorDefinitions) true MultiThreadedDLL true @@ -611,6 +611,26 @@ MaxSpeed Use + + + + + + + + + + + + + + + + + + + + Disabled EnableFastChecks @@ -855,6 +875,10 @@ + + + + diff --git a/Library/Library.vcxproj.filters b/Library/Library.vcxproj.filters index d5031ce5..abf2c2d2 100644 --- a/Library/Library.vcxproj.filters +++ b/Library/Library.vcxproj.filters @@ -31,6 +31,9 @@ {c8550e7b-009b-4e12-a55a-ed458d05bdad} + + {5866a61e-ec27-469c-a8f0-2a45ce141f60} + @@ -294,6 +297,66 @@ Lua\Lua + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + + + pcre + @@ -526,6 +589,18 @@ Lua\Lua + + pcre + + + pcre + + + pcre + + + pcre + diff --git a/Library/Litestep.cpp b/Library/Litestep.cpp index c5d1709a..a2d0d669 100644 --- a/Library/Litestep.cpp +++ b/Library/Litestep.cpp @@ -500,6 +500,46 @@ std::wstring ConvertToWide(LPCSTR str) return szWide; } +std::string ConvertToUTF8(LPCWSTR str) +{ + std::string szAscii; + + if (str && *str) + { + int strLen = (int)wcslen(str) + 1; + int bufLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL, NULL); + if (bufLen > 0) + { + char* tmpSz = new char[bufLen]; + tmpSz[0] = 0; + WideCharToMultiByte(CP_UTF8, 0, str, strLen, tmpSz, bufLen, NULL, NULL); + szAscii = tmpSz; + delete [] tmpSz; + } + } + return szAscii; +} + +std::wstring ConvertUTF8ToWide(LPCSTR str) +{ + std::wstring szWide; + + if (str && *str) + { + int strLen = (int)strlen(str) + 1; + int bufLen = MultiByteToWideChar(CP_UTF8, 0, str, strLen, NULL, 0); + if (bufLen > 0) + { + WCHAR* wideSz = new WCHAR[bufLen]; + wideSz[0] = 0; + MultiByteToWideChar(CP_UTF8, 0, str, strLen, wideSz, bufLen); + szWide = wideSz; + delete [] wideSz; + } + } + return szWide; +} + BOOL LSLog(int nLevel, LPCTSTR pszModule, LPCTSTR pszMessage) { CRainmeter::LOG_INFO logInfo; diff --git a/Library/Litestep.h b/Library/Litestep.h index f1f8f9b3..ab35663b 100644 --- a/Library/Litestep.h +++ b/Library/Litestep.h @@ -56,6 +56,8 @@ void ResetLoggingFlag(); std::string ConvertToAscii(LPCTSTR str); std::wstring ConvertToWide(LPCSTR str); +std::string ConvertToUTF8(LPCWSTR str); +std::wstring ConvertUTF8ToWide(LPCSTR str); HINSTANCE LSExecuteAsAdmin(HWND Owner, LPCTSTR szCommand, int nShowCmd); HINSTANCE ExecuteCommand(HWND Owner, LPCTSTR szCommand, int nShowCmd, LPCTSTR szVerb); diff --git a/Library/Measure.cpp b/Library/Measure.cpp index 6d45715a..228e145d 100644 --- a/Library/Measure.cpp +++ b/Library/Measure.cpp @@ -35,6 +35,10 @@ #include "Rainmeter.h" #include "Error.h" #include "Litestep.h" +#include "pcre-8.10/config.h" +#include "pcre-8.10/pcre.h" + +#define OVECCOUNT 300 // Should be a multiple of 3 enum AUTOSCALE_INDEX { @@ -74,6 +78,7 @@ CMeasure::CMeasure(CMeterWindow* meterWindow, const WCHAR* name) : m_MeterWindow m_MinValue(), m_MaxValue(1.0), m_Value(), + m_RegExpSubstitute(false), m_MedianPos(), m_AveragePos(), m_AverageSize(), @@ -165,6 +170,7 @@ void CMeasure::ReadConfig(CConfigParser& parser, const WCHAR* section) m_DynamicVariables = 0!=parser.ReadInt(section, L"DynamicVariables", 0); + m_RegExpSubstitute = 0!=parser.ReadInt(section, L"RegExpSubstitute", 0); std::wstring subs = parser.ReadString(section, L"Substitute", L""); if (!subs.empty() && (subs[0] != L'\"' || subs[subs.length() - 1] != L'\'') && @@ -183,6 +189,29 @@ void CMeasure::ReadConfig(CConfigParser& parser, const WCHAR* section) InitializeGroup(group); } +/* +** MakePlainSubstitute +** +** Substitues text using a straight find and replace method +*/ +bool CMeasure::MakePlainSubstitute(std::wstring& str, size_t index) +{ + size_t start = 0; + size_t pos = std::wstring::npos; + + do + { + pos = str.find(m_Substitute[index].first, start); + if (pos != std::wstring::npos) + { + str.replace(pos, m_Substitute[index].first.length(), m_Substitute[index].second); + start = pos + m_Substitute[index].second.length(); + } + } while (pos != std::wstring::npos); + + return true; +} + /* ** CheckSubstitute ** @@ -194,31 +223,105 @@ const WCHAR* CMeasure::CheckSubstitute(const WCHAR* buffer) if (!m_Substitute.empty()) { - str = buffer; - - for (size_t i = 0, isize = m_Substitute.size(); i < isize; i += 2) + if (!m_RegExpSubstitute) // Plain Substitutions only { - if (str.empty() && m_Substitute[i].empty()) - { - // Empty result and empty substitute -> use second - str = m_Substitute[i + 1]; - } - else if (!m_Substitute[i].empty()) - { - size_t start = 0; - size_t pos = std::wstring::npos; + str = buffer; - do + for (size_t i = 0, isize = m_Substitute.size(); i < isize; i++) + { + if (str.empty() && m_Substitute[i].first.empty()) { - pos = str.find(m_Substitute[i], start); - if (pos != std::wstring::npos) - { - str.replace(pos, m_Substitute[i].length(), m_Substitute[i + 1]); - start = pos + m_Substitute[i + 1].length(); - } - } while (pos != std::wstring::npos); + // Empty result and empty substitute -> use second + str = m_Substitute[i].second; + } + else if (!m_Substitute[i].first.empty()) + { + MakePlainSubstitute(str, i); + } } } + else // Contains a RegEx + { + std::string utf8str = ConvertToUTF8(buffer); + + for (size_t i = 0, isize = m_Substitute.size() ; i < isize ; i++) + { + pcre* re; + const char* error; + int erroffset; + int ovector[OVECCOUNT]; + int rc; + int flags = PCRE_UTF8; + int offset = 0; + + re = pcre_compile( + ConvertToUTF8(m_Substitute[i].first.c_str()).c_str(), // the pattern + flags, // default options + &error, // for error message + &erroffset, // for error offset + NULL); // use default character tables + + if (re == NULL) + { + MakePlainSubstitute(str, i); + Log(LOG_NOTICE, ConvertToWide(error).c_str()); + } + else + { + do + { + rc = pcre_exec( + re, // the compiled pattern + NULL, // no extra data - we didn't study the pattern + utf8str.c_str(), // the subject string + utf8str.length(), // the length of the subject + offset, // start at offset 0 in the subject + 0, // default options + ovector, // output vector for substring information + OVECCOUNT); // number of elements in the output vector + + if (rc <= 0) + { + break; + } + else + { + std::string result = ConvertToUTF8(m_Substitute[i].second.c_str()); + + if (rc > 1) + { + for (int j = rc - 1 ; j > 0 ; j--) + { + size_t new_start = ovector[2*j]; + size_t in_length = ovector[2*j+1] - ovector[2*j]; + + char tmpName[64]; + _snprintf_s(tmpName, _TRUNCATE, "\\%i", j); + + size_t cut_length = strlen(tmpName); + size_t pos = result.find(tmpName); + while (pos != std::string::npos) + { + result.replace(pos, cut_length, utf8str, new_start, in_length); + pos = result.find(tmpName, pos + in_length); + } + } + } + + size_t start = ovector[0]; + size_t length = ovector[1] - ovector[0]; + utf8str.replace(start, length, result); + offset = start + result.length(); + } + } while (true); + + // Release memory used for the compiled pattern + pcre_free(re); + } + } + + str = ConvertUTF8ToWide(utf8str.c_str()); + } return str.c_str(); } @@ -247,8 +350,7 @@ bool CMeasure::ParseSubstitute(std::wstring buffer) if (word1 != word2) { - m_Substitute.push_back(word1); - m_Substitute.push_back(word2); + m_Substitute.push_back(std::pair(word1, word2)); } sep = ExtractWord(buffer); diff --git a/Library/Measure.h b/Library/Measure.h index 54d12474..fd67ff9a 100644 --- a/Library/Measure.h +++ b/Library/Measure.h @@ -92,6 +92,7 @@ protected: bool ParseSubstitute(std::wstring buffer); std::wstring ExtractWord(std::wstring& buffer); const WCHAR* CheckSubstitute(const WCHAR* buffer); + bool MakePlainSubstitute(std::wstring& str, size_t index); bool m_DynamicVariables; // If true, the measure contains dynamic variables bool m_Invert; // If true, the value should be inverted @@ -102,7 +103,8 @@ protected: const std::wstring m_Name; // Name of this Measure const std::string m_ANSIName; // Name of this Measure in ANSI - std::vector m_Substitute; // Vec of substitute strings + std::vector< std::pair > m_Substitute; // Vec of substitute strings + bool m_RegExpSubstitute; std::vector m_MedianMaxValues; // The values for the median filtering std::vector m_MedianMinValues; // The values for the median filtering