/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include namespace formula { namespace { class OEmptyFunctionDescription : public IFunctionDescription { public: OEmptyFunctionDescription(){} virtual ~OEmptyFunctionDescription(){} virtual OUString getFunctionName() const override { return OUString(); } virtual const IFunctionCategory* getCategory() const override { return nullptr; } virtual OUString getDescription() const override { return OUString(); } virtual sal_Int32 getSuppressedArgumentCount() const override { return 0; } virtual OUString getFormula(const ::std::vector< OUString >& ) const override { return OUString(); } virtual void fillVisibleArgumentMapping(::std::vector& ) const override {} virtual void initArgumentInfo() const override {} virtual OUString getSignature() const override { return OUString(); } virtual OUString getHelpId() const override { return ""; } virtual bool isHidden() const override { return false; } virtual sal_uInt32 getParameterCount() const override { return 0; } virtual sal_uInt32 getVarArgsStart() const override { return 0; } virtual sal_uInt32 getVarArgsLimit() const override { return 0; } virtual OUString getParameterName(sal_uInt32 ) const override { return OUString(); } virtual OUString getParameterDescription(sal_uInt32 ) const override { return OUString(); } virtual bool isParameterOptional(sal_uInt32 ) const override { return false; } }; } // class FormulaHelper - static Method #define FUNC_NOTFOUND -1 FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager) :m_rCharClass(m_aSysLocale.GetCharClass()) ,m_pFunctionManager(_pFunctionManager) ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk)) ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose)) ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep)) ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen)) ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose)) { } sal_Int32 FormulaHelper::GetCategoryCount() const { return m_pFunctionManager->getCount(); } bool FormulaHelper::GetNextFunc( const OUString& rFormula, bool bBack, sal_Int32& rFStart, // Input and output sal_Int32* pFEnd, // = NULL const IFunctionDescription** ppFDesc, // = NULL ::std::vector< OUString>* pArgs ) const // = NULL { sal_Int32 nOldStart = rFStart; OUString aFname; rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : nullptr ); bool bFound = ( rFStart != FUNC_NOTFOUND ); if ( bFound ) { if ( pFEnd ) *pFEnd = GetFunctionEnd( rFormula, rFStart ); if ( ppFDesc ) { *ppFDesc = nullptr; const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount(); for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j) { const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j); const sal_uInt32 nCount = pCategory->getCount(); for(sal_uInt32 i = 0 ; i < nCount; ++i) { const IFunctionDescription* pCurrent = pCategory->getFunction(i); if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(aFname) ) { *ppFDesc = pCurrent; break; } }// for(sal_uInt32 i = 0 ; i < nCount; ++i) } if ( *ppFDesc && pArgs ) { GetArgStrings( *pArgs,rFormula, rFStart, static_cast((*ppFDesc)->getParameterCount() )); } else { static OEmptyFunctionDescription s_aFunctionDescription; *ppFDesc = &s_aFunctionDescription; } } } else rFStart = nOldStart; return bFound; } void FormulaHelper::FillArgStrings( std::u16string_view rFormula, sal_Int32 nFuncPos, sal_uInt16 nArgs, ::std::vector< OUString >& _rArgs ) const { sal_Int32 nStart = 0; sal_Int32 nEnd = 0; sal_uInt16 i; bool bLast = false; for ( i=0; i& _rArgs, std::u16string_view rFormula, sal_Int32 nFuncPos, sal_uInt16 nArgs ) const { if (nArgs) { FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs ); } } static bool IsFormulaText(const CharClass& rCharClass, const OUString& rStr, sal_Int32 nPos) { if( rCharClass.isLetterNumeric( rStr, nPos ) ) return true; else { // In internationalized versions function names may contain a dot // and in every version also an underscore... ;-) sal_Unicode c = rStr[nPos]; return c == '.' || c == '_'; } } sal_Int32 FormulaHelper::GetFunctionStart( const OUString& rFormula, sal_Int32 nStart, bool bBack, OUString* pFuncName ) const { sal_Int32 nStrLen = rFormula.getLength(); if ( nStrLen < nStart ) return nStart; sal_Int32 nFStart = FUNC_NOTFOUND; sal_Int32 nParPos = bBack ? ::std::min( nStart, nStrLen - 1) : nStart; bool bRepeat; do { bool bFound = false; bRepeat = false; if ( bBack ) { while ( !bFound && (nParPos > 0) ) { if ( rFormula[nParPos] == '"' ) { nParPos--; while ( (nParPos > 0) && rFormula[nParPos] != '"' ) nParPos--; if (nParPos > 0) nParPos--; } else { bFound = rFormula[nParPos] == '('; if ( !bFound ) nParPos--; } } } else { while ( !bFound && (0 <= nParPos && nParPos < nStrLen) ) { if ( rFormula[nParPos] == '"' ) { nParPos++; while ( (nParPos < nStrLen) && rFormula[nParPos] != '"' ) nParPos++; nParPos++; } else { bFound = rFormula[nParPos] == '('; if ( !bFound ) nParPos++; } } } if ( bFound && (nParPos > 0) ) { nFStart = nParPos-1; while ( (nFStart > 0) && IsFormulaText(m_rCharClass, rFormula, nFStart )) nFStart--; } nFStart++; if ( bFound ) { if ( IsFormulaText( m_rCharClass, rFormula, nFStart ) ) { // Function found if ( pFuncName ) *pFuncName = rFormula.copy( nFStart, nParPos-nFStart ); } else // Brackets without function -> keep searching { bRepeat = true; if ( !bBack ) nParPos++; else if (nParPos > 0) nParPos--; else bRepeat = false; } } else // No brackets found { nFStart = FUNC_NOTFOUND; if ( pFuncName ) pFuncName->clear(); } } while(bRepeat); return nFStart; } sal_Int32 FormulaHelper::GetFunctionEnd( std::u16string_view rStr, sal_Int32 nStart ) const { sal_Int32 nStrLen = rStr.size(); if ( nStrLen < nStart ) return nStart; short nParCount = 0; bool bInArray = false; bool bFound = false; while ( !bFound && (nStart < nStrLen) ) { sal_Unicode c = rStr[nStart]; if ( c == '"' ) { nStart++; while ( (nStart < nStrLen) && rStr[nStart] != '"' ) nStart++; } else if ( c == open ) nParCount++; else if ( c == close ) { nParCount--; if ( nParCount == 0 ) bFound = true; else if ( nParCount < 0 ) { bFound = true; nStart--; // read one too far } } else if ( c == arrayOpen ) { bInArray = true; } else if ( c == arrayClose ) { bInArray = false; } else if ( c == sep ) { if ( !bInArray && nParCount == 0 ) { bFound = true; nStart--; // read one too far } } nStart++; // Set behind found position } // nStart > nStrLen can happen if there was an unclosed quote; instead of // checking that in every loop iteration check it once here. return std::min(nStart, nStrLen); } sal_Int32 FormulaHelper::GetArgStart( std::u16string_view rStr, sal_Int32 nStart, sal_uInt16 nArg ) const { sal_Int32 nStrLen = rStr.size(); if ( nStrLen < nStart ) return nStart; short nParCount = 0; bool bInArray = false; bool bFound = false; while ( !bFound && (nStart < nStrLen) ) { sal_Unicode c = rStr[nStart]; if ( c == '"' ) { nStart++; while ( (nStart < nStrLen) && rStr[nStart] != '"' ) nStart++; } else if ( c == open ) { bFound = ( nArg == 0 ); nParCount++; } else if ( c == close ) { nParCount--; bFound = ( nParCount == 0 ); } else if ( c == arrayOpen ) { bInArray = true; } else if ( c == arrayClose ) { bInArray = false; } else if ( c == sep ) { if ( !bInArray && nParCount == 1 ) { nArg--; bFound = ( nArg == 0 ); } } nStart++; } return nStart; } } // formula /* vim:set shiftwidth=4 softtabstop=4 expandtab: */