diff options
author | Eike Rathke <erack@redhat.com> | 2020-09-28 21:02:23 +0200 |
---|---|---|
committer | Eike Rathke <erack@redhat.com> | 2020-09-29 00:54:12 +0200 |
commit | 3c6177be2705303044e3de262689d593f3d0f282 (patch) | |
tree | 0bef6428be1e46c48f5d58e5ccaefcfb500f5e9f /sc/source/core | |
parent | 6e51adec109ab179f093181856959a6d8dc3d3b2 (diff) |
Resolves: tdf#137091 Use CharClass matching the formula language
... not the current locale. Specifically important for
uppercase/lowercase conversions that may yield different results
for example in Turkish i with/without dot.
Change-Id: I2aa57cdcf530d7a0697c4ffbd5dccb86bb526d8e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103588
Tested-by: Jenkins
Reviewed-by: Eike Rathke <erack@redhat.com>
Diffstat (limited to 'sc/source/core')
-rw-r--r-- | sc/source/core/tool/compiler.cxx | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 9ab2b6107cf5..2050a2100579 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -22,6 +22,7 @@ #include <compiler.hxx> #include <vcl/svapp.hxx> +#include <vcl/settings.hxx> #include <sfx2/app.hxx> #include <sfx2/objsh.hxx> #include <basic/sbmeth.hxx> @@ -79,7 +80,8 @@ using namespace formula; using namespace ::com::sun::star; using ::std::vector; -CharClass* ScCompiler::pCharClassEnglish = nullptr; +const CharClass* ScCompiler::pCharClassEnglish = nullptr; +const CharClass* ScCompiler::pCharClassLocalized = nullptr; const ScCompiler::Convention* ScCompiler::pConventions[ ] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; namespace { @@ -173,12 +175,17 @@ void ScCompiler::DeInit() delete pCharClassEnglish; pCharClassEnglish = nullptr; } + if (pCharClassLocalized) + { + delete pCharClassLocalized; + pCharClassLocalized = nullptr; + } } bool ScCompiler::IsEnglishSymbol( const OUString& rName ) { // function names are always case-insensitive - OUString aUpper = ScGlobal::getCharClassPtr()->uppercase(rName); + OUString aUpper = GetCharClassEnglish()->uppercase(rName); // 1. built-in function name formula::FormulaCompiler aCompiler; @@ -198,11 +205,27 @@ bool ScCompiler::IsEnglishSymbol( const OUString& rName ) return !aIntName.isEmpty(); // no valid function name } -void ScCompiler::InitCharClassEnglish() +const CharClass* ScCompiler::GetCharClassEnglish() { - css::lang::Locale aLocale( "en", "US", ""); - pCharClassEnglish = new CharClass( - ::comphelper::getProcessComponentContext(), LanguageTag( aLocale)); + if (!pCharClassEnglish) + { + css::lang::Locale aLocale( "en", "US", ""); + pCharClassEnglish = new CharClass( + ::comphelper::getProcessComponentContext(), LanguageTag( aLocale)); + } + return pCharClassEnglish; +} + +const CharClass* ScCompiler::GetCharClassLocalized() +{ + if (!pCharClassLocalized) + { + // Switching UI language requires restart; if not, we would have to + // keep track of that. + pCharClassLocalized = new CharClass( + ::comphelper::getProcessComponentContext(), Application::GetSettings().GetUILanguageTag()); + } + return pCharClassLocalized; } void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar ) @@ -268,13 +291,9 @@ void ScCompiler::SetFormulaLanguage( const ScCompiler::OpCodeMapPtr & xMap ) mxSymbols = xMap; if (mxSymbols->isEnglish()) - { - if (!pCharClassEnglish) - InitCharClassEnglish(); - pCharClass = pCharClassEnglish; - } + pCharClass = GetCharClassEnglish(); else - pCharClass = ScGlobal::getCharClassPtr(); + pCharClass = GetCharClassLocalized(); SetGrammarAndRefConvention( mxSymbols->getGrammar(), GetGrammar()); } @@ -4174,9 +4193,9 @@ void ScCompiler::AutoCorrectParsedSymbol() } } -static bool lcl_UpperAsciiOrI18n( OUString& rUpper, const OUString& rOrg, FormulaGrammar::Grammar eGrammar ) +bool ScCompiler::ToUpperAsciiOrI18nIsAscii( OUString& rUpper, const OUString& rOrg ) const { - if (FormulaGrammar::isODFF( eGrammar )) + if (FormulaGrammar::isODFF( meGrammar )) { // ODFF has a defined set of English function names, avoid i18n // overhead. @@ -4185,7 +4204,8 @@ static bool lcl_UpperAsciiOrI18n( OUString& rUpper, const OUString& rOrg, Formul } else { - rUpper = ScGlobal::getCharClassPtr()->uppercase(rOrg); + // One of localized or English. + rUpper = pCharClass->uppercase(rOrg); return false; } } @@ -4279,7 +4299,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) else { OUString aTmpStr( cSymbol[0] ); - bMayBeFuncName = ScGlobal::getCharClassPtr()->isLetter( aTmpStr, 0 ); + bMayBeFuncName = pCharClass->isLetter( aTmpStr, 0 ); bAsciiNonAlnum = false; } @@ -4330,7 +4350,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) if (bAsciiNonAlnum) { - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + bAsciiUpper = ToUpperAsciiOrI18nIsAscii( aUpper, aOrg); if (cSymbol[0] == '#') { // Check for TableRef item specifiers first. @@ -4356,7 +4376,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) if (bMayBeFuncName) { if (aUpper.isEmpty()) - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + bAsciiUpper = ToUpperAsciiOrI18nIsAscii( aUpper, aOrg); if (IsOpCode( aUpper, bInArray )) return true; } @@ -4380,7 +4400,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) } if (aUpper.isEmpty()) - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + bAsciiUpper = ToUpperAsciiOrI18nIsAscii( aUpper, aOrg); // IsBoolean() before IsValue() to catch inline bools without the kludge // for inline arrays. @@ -4392,7 +4412,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) // User defined names and such do need i18n upper also in ODF. if (bAsciiUpper) - aUpper = ScGlobal::getCharClassPtr()->uppercase( aOrg ); + aUpper = pCharClass->uppercase( aOrg ); if (IsNamedRange( aUpper )) return true; @@ -4450,7 +4470,7 @@ bool ScCompiler::NextNewToken( bool bInArray ) // Provide single token information and continue. Do not set an error, that // would prematurely end compilation. Simple unknown names are handled by // the interpreter. - aUpper = ScGlobal::getCharClassPtr()->lowercase( aUpper ); + aUpper = pCharClass->lowercase( aUpper ); svl::SharedString aSS = rDoc.GetSharedStringPool().intern(aUpper); maRawToken.SetString(aSS.getData(), aSS.getDataIgnoreCase()); maRawToken.NewOpCode( ocBad ); |