1*c25918c1SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*c25918c1SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*c25918c1SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*c25918c1SAndrew Rist  * distributed with this work for additional information
6*c25918c1SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*c25918c1SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*c25918c1SAndrew Rist  * "License"); you may not use this file except in compliance
9*c25918c1SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*c25918c1SAndrew Rist  *
11*c25918c1SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*c25918c1SAndrew Rist  *
13*c25918c1SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*c25918c1SAndrew Rist  * software distributed under the License is distributed on an
15*c25918c1SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*c25918c1SAndrew Rist  * KIND, either express or implied.  See the License for the
17*c25918c1SAndrew Rist  * specific language governing permissions and limitations
18*c25918c1SAndrew Rist  * under the License.
19*c25918c1SAndrew Rist  *
20*c25918c1SAndrew Rist  *************************************************************/
21*c25918c1SAndrew Rist 
22*c25918c1SAndrew Rist 
23cdf0e10cSrcweir #include "precompiled_formula.hxx"
24cdf0e10cSrcweir 
25cdf0e10cSrcweir #include "formula/formulahelper.hxx"
26cdf0e10cSrcweir #include <unotools/charclass.hxx>
27cdf0e10cSrcweir #include <unotools/syslocale.hxx>
28cdf0e10cSrcweir 
29cdf0e10cSrcweir namespace formula
30cdf0e10cSrcweir {
31cdf0e10cSrcweir 
32cdf0e10cSrcweir     namespace
33cdf0e10cSrcweir     {
34cdf0e10cSrcweir         //============================================================================
35cdf0e10cSrcweir         class OEmptyFunctionDescription : public IFunctionDescription
36cdf0e10cSrcweir         {
37cdf0e10cSrcweir         public:
OEmptyFunctionDescription()38cdf0e10cSrcweir             OEmptyFunctionDescription(){}
~OEmptyFunctionDescription()39cdf0e10cSrcweir             virtual ~OEmptyFunctionDescription(){}
40cdf0e10cSrcweir 
getFunctionName() const41cdf0e10cSrcweir             virtual ::rtl::OUString getFunctionName() const { return ::rtl::OUString(); }
getCategory() const42cdf0e10cSrcweir             virtual const IFunctionCategory* getCategory() const { return NULL; }
getDescription() const43cdf0e10cSrcweir             virtual ::rtl::OUString getDescription() const { return ::rtl::OUString(); }
getSuppressedArgumentCount() const44cdf0e10cSrcweir             virtual xub_StrLen getSuppressedArgumentCount() const { return 0; }
getFormula(const::std::vector<::rtl::OUString> &) const45cdf0e10cSrcweir             virtual ::rtl::OUString getFormula(const ::std::vector< ::rtl::OUString >& ) const { return ::rtl::OUString(); }
fillVisibleArgumentMapping(::std::vector<sal_uInt16> &) const46cdf0e10cSrcweir             virtual void fillVisibleArgumentMapping(::std::vector<sal_uInt16>& ) const {}
initArgumentInfo() const47cdf0e10cSrcweir             virtual void initArgumentInfo()  const {}
getSignature() const48cdf0e10cSrcweir             virtual ::rtl::OUString getSignature() const { return ::rtl::OUString(); }
getHelpId() const49cdf0e10cSrcweir             virtual rtl::OString getHelpId() const { return ""; }
getParameterCount() const50cdf0e10cSrcweir             virtual sal_uInt32 getParameterCount() const { return 0; }
getParameterName(sal_uInt32) const51cdf0e10cSrcweir             virtual ::rtl::OUString getParameterName(sal_uInt32 ) const { return ::rtl::OUString(); }
getParameterDescription(sal_uInt32) const52cdf0e10cSrcweir             virtual ::rtl::OUString getParameterDescription(sal_uInt32 ) const { return ::rtl::OUString(); }
isParameterOptional(sal_uInt32) const53cdf0e10cSrcweir             virtual bool isParameterOptional(sal_uInt32 ) const { return sal_False; }
54cdf0e10cSrcweir         };
55cdf0e10cSrcweir     }
56cdf0e10cSrcweir //===================================================================
57cdf0e10cSrcweir //	class FormulaHelper - statische Methoden
58cdf0e10cSrcweir //===================================================================
59cdf0e10cSrcweir 
60cdf0e10cSrcweir #define FUNC_NOTFOUND 0xffff
61cdf0e10cSrcweir 
FormulaHelper(const IFunctionManager * _pFunctionManager)62cdf0e10cSrcweir FormulaHelper::FormulaHelper(const IFunctionManager* _pFunctionManager)
63cdf0e10cSrcweir     :m_pSysLocale(new SvtSysLocale)
64cdf0e10cSrcweir     ,m_pFunctionManager(_pFunctionManager)
65cdf0e10cSrcweir     ,open(_pFunctionManager->getSingleToken(IFunctionManager::eOk))
66cdf0e10cSrcweir     ,close(_pFunctionManager->getSingleToken(IFunctionManager::eClose))
67cdf0e10cSrcweir     ,sep(_pFunctionManager->getSingleToken(IFunctionManager::eSep))
68cdf0e10cSrcweir     ,arrayOpen(_pFunctionManager->getSingleToken(IFunctionManager::eArrayOpen))
69cdf0e10cSrcweir     ,arrayClose(_pFunctionManager->getSingleToken(IFunctionManager::eArrayClose))
70cdf0e10cSrcweir {
71cdf0e10cSrcweir     m_pCharClass = m_pSysLocale->GetCharClassPtr();
72cdf0e10cSrcweir }
GetNextFunc(const String & rFormula,sal_Bool bBack,xub_StrLen & rFStart,xub_StrLen * pFEnd,const IFunctionDescription ** ppFDesc,::std::vector<::rtl::OUString> * pArgs) const73cdf0e10cSrcweir sal_Bool FormulaHelper::GetNextFunc( const String&	rFormula,
74cdf0e10cSrcweir 								 sal_Bool			bBack,
75cdf0e10cSrcweir 								 xub_StrLen&	rFStart,   // Ein- und Ausgabe
76cdf0e10cSrcweir 								 xub_StrLen*	pFEnd, 	   // = NULL
77cdf0e10cSrcweir 								 const IFunctionDescription**	ppFDesc,   // = NULL
78cdf0e10cSrcweir                                  ::std::vector< ::rtl::OUString>*	pArgs )  const // = NULL
79cdf0e10cSrcweir {
80cdf0e10cSrcweir 	sal_Bool		bFound = sal_False;
81cdf0e10cSrcweir 	xub_StrLen	nOldStart = rFStart;
82cdf0e10cSrcweir 	String		aFname;
83cdf0e10cSrcweir 
84cdf0e10cSrcweir 	rFStart = GetFunctionStart( rFormula, rFStart, bBack, ppFDesc ? &aFname : NULL );
85cdf0e10cSrcweir 	bFound  = ( rFStart != FUNC_NOTFOUND );
86cdf0e10cSrcweir 
87cdf0e10cSrcweir 	if ( bFound )
88cdf0e10cSrcweir 	{
89cdf0e10cSrcweir 		if ( pFEnd )
90cdf0e10cSrcweir 			*pFEnd = GetFunctionEnd( rFormula, rFStart );
91cdf0e10cSrcweir 
92cdf0e10cSrcweir 		if ( ppFDesc )
93cdf0e10cSrcweir 		{
94cdf0e10cSrcweir             *ppFDesc = NULL;
95cdf0e10cSrcweir             const ::rtl::OUString sTemp( aFname );
96cdf0e10cSrcweir             const sal_uInt32 nCategoryCount = m_pFunctionManager->getCount();
97cdf0e10cSrcweir             for(sal_uInt32 j= 0; j < nCategoryCount && !*ppFDesc; ++j)
98cdf0e10cSrcweir             {
99cdf0e10cSrcweir                 const IFunctionCategory* pCategory = m_pFunctionManager->getCategory(j);
100cdf0e10cSrcweir                 const sal_uInt32 nCount = pCategory->getCount();
101cdf0e10cSrcweir                 for(sal_uInt32 i = 0 ; i < nCount; ++i)
102cdf0e10cSrcweir                 {
103cdf0e10cSrcweir                     const IFunctionDescription* pCurrent = pCategory->getFunction(i);
104cdf0e10cSrcweir 	                if ( pCurrent->getFunctionName().equalsIgnoreAsciiCase(sTemp) )
105cdf0e10cSrcweir                     {
106cdf0e10cSrcweir                         *ppFDesc = pCurrent;
107cdf0e10cSrcweir                         break;
108cdf0e10cSrcweir                     }
109cdf0e10cSrcweir                 } // for(sal_uInt32 i = 0 ; i < nCount; ++i)
110cdf0e10cSrcweir             }
111cdf0e10cSrcweir 			if ( *ppFDesc && pArgs )
112cdf0e10cSrcweir 			{
113cdf0e10cSrcweir 				GetArgStrings( *pArgs,rFormula, rFStart, static_cast<sal_uInt16>((*ppFDesc)->getParameterCount() ));
114cdf0e10cSrcweir 			}
115cdf0e10cSrcweir             else
116cdf0e10cSrcweir             {
117cdf0e10cSrcweir                 static OEmptyFunctionDescription s_aFunctionDescription;
118cdf0e10cSrcweir                 *ppFDesc = &s_aFunctionDescription;
119cdf0e10cSrcweir             }
120cdf0e10cSrcweir 		}
121cdf0e10cSrcweir 	}
122cdf0e10cSrcweir 	else
123cdf0e10cSrcweir 		rFStart = nOldStart;
124cdf0e10cSrcweir 
125cdf0e10cSrcweir 	return bFound;
126cdf0e10cSrcweir }
127cdf0e10cSrcweir 
128cdf0e10cSrcweir //------------------------------------------------------------------------
129cdf0e10cSrcweir 
FillArgStrings(const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs,::std::vector<::rtl::OUString> & _rArgs) const130cdf0e10cSrcweir void FormulaHelper::FillArgStrings( const String&	rFormula,
131cdf0e10cSrcweir 									xub_StrLen		nFuncPos,
132cdf0e10cSrcweir 									sal_uInt16			nArgs,
133cdf0e10cSrcweir 									::std::vector< ::rtl::OUString >& _rArgs ) const
134cdf0e10cSrcweir {
135cdf0e10cSrcweir 	xub_StrLen	nStart	= 0;
136cdf0e10cSrcweir 	xub_StrLen	nEnd	= 0;
137cdf0e10cSrcweir 	sal_uInt16		i;
138cdf0e10cSrcweir 	sal_Bool		bLast	= sal_False;
139cdf0e10cSrcweir 
140cdf0e10cSrcweir 	for ( i=0; i<nArgs && !bLast; i++ )
141cdf0e10cSrcweir 	{
142cdf0e10cSrcweir 		nStart = GetArgStart( rFormula, nFuncPos, i );
143cdf0e10cSrcweir 
144cdf0e10cSrcweir 		if ( i+1<nArgs ) // letztes Argument?
145cdf0e10cSrcweir 		{
146cdf0e10cSrcweir 			nEnd = GetArgStart( rFormula, nFuncPos, i+1 );
147cdf0e10cSrcweir 
148cdf0e10cSrcweir 			if ( nEnd != nStart )
149cdf0e10cSrcweir                 _rArgs.push_back(rFormula.Copy( nStart, nEnd-1-nStart ));
150cdf0e10cSrcweir 			else
151cdf0e10cSrcweir 				_rArgs.push_back(String()), bLast = sal_True;
152cdf0e10cSrcweir 		}
153cdf0e10cSrcweir 		else
154cdf0e10cSrcweir 		{
155cdf0e10cSrcweir 			nEnd = GetFunctionEnd( rFormula, nFuncPos )-1;
156cdf0e10cSrcweir 			if ( nStart < nEnd )
157cdf0e10cSrcweir 				_rArgs.push_back( rFormula.Copy( nStart, nEnd-nStart ) );
158cdf0e10cSrcweir 			else
159cdf0e10cSrcweir 				_rArgs.push_back(String());
160cdf0e10cSrcweir 		}
161cdf0e10cSrcweir 	}
162cdf0e10cSrcweir 
163cdf0e10cSrcweir 	if ( bLast )
164cdf0e10cSrcweir 		for ( ; i<nArgs; i++ )
165cdf0e10cSrcweir 			_rArgs.push_back(String());
166cdf0e10cSrcweir }
167cdf0e10cSrcweir 
168cdf0e10cSrcweir //------------------------------------------------------------------------
169cdf0e10cSrcweir 
GetArgStrings(::std::vector<::rtl::OUString> & _rArgs,const String & rFormula,xub_StrLen nFuncPos,sal_uInt16 nArgs) const170cdf0e10cSrcweir void FormulaHelper::GetArgStrings( ::std::vector< ::rtl::OUString >& _rArgs
171cdf0e10cSrcweir                                       ,const String& rFormula,
172cdf0e10cSrcweir 									   xub_StrLen nFuncPos,
173cdf0e10cSrcweir 									   sal_uInt16 nArgs ) const
174cdf0e10cSrcweir {
175cdf0e10cSrcweir 	if (nArgs)
176cdf0e10cSrcweir 	{
177cdf0e10cSrcweir 		FillArgStrings( rFormula, nFuncPos, nArgs, _rArgs );
178cdf0e10cSrcweir 	}
179cdf0e10cSrcweir }
180cdf0e10cSrcweir 
181cdf0e10cSrcweir //------------------------------------------------------------------------
182cdf0e10cSrcweir 
IsFormulaText(const CharClass * _pCharClass,const String & rStr,xub_StrLen nPos)183cdf0e10cSrcweir inline sal_Bool IsFormulaText( const CharClass* _pCharClass,const String& rStr, xub_StrLen nPos )
184cdf0e10cSrcweir {
185cdf0e10cSrcweir 	if( _pCharClass->isLetterNumeric( rStr, nPos ) )
186cdf0e10cSrcweir 		return sal_True;
187cdf0e10cSrcweir 	else
188cdf0e10cSrcweir 	{	// In internationalized versions function names may contain a dot
189cdf0e10cSrcweir 		//  and in every version also an underscore... ;-)
190cdf0e10cSrcweir 		sal_Unicode c = rStr.GetChar(nPos);
191cdf0e10cSrcweir 		return c == '.' || c == '_';
192cdf0e10cSrcweir 	}
193cdf0e10cSrcweir 
194cdf0e10cSrcweir }
195cdf0e10cSrcweir 
GetFunctionStart(const String & rFormula,xub_StrLen nStart,sal_Bool bBack,String * pFuncName) const196cdf0e10cSrcweir xub_StrLen FormulaHelper::GetFunctionStart( const String&	rFormula,
197cdf0e10cSrcweir 										xub_StrLen		nStart,
198cdf0e10cSrcweir 										sal_Bool			bBack,
199cdf0e10cSrcweir 										String*			pFuncName ) const
200cdf0e10cSrcweir {
201cdf0e10cSrcweir 	xub_StrLen nStrLen = rFormula.Len();
202cdf0e10cSrcweir 
203cdf0e10cSrcweir 	if ( nStrLen < nStart )
204cdf0e10cSrcweir 		return nStart;
205cdf0e10cSrcweir 
206cdf0e10cSrcweir 	xub_StrLen	nFStart = FUNC_NOTFOUND;
207cdf0e10cSrcweir 	xub_StrLen	nParPos	= nStart;
208cdf0e10cSrcweir 
209cdf0e10cSrcweir 	sal_Bool bRepeat, bFound;
210cdf0e10cSrcweir 	do
211cdf0e10cSrcweir 	{
212cdf0e10cSrcweir 		bFound  = sal_False;
213cdf0e10cSrcweir 		bRepeat = sal_False;
214cdf0e10cSrcweir 
215cdf0e10cSrcweir 		if ( bBack )
216cdf0e10cSrcweir 		{
217cdf0e10cSrcweir 			while ( !bFound && (nParPos > 0) )
218cdf0e10cSrcweir 			{
219cdf0e10cSrcweir 				if ( rFormula.GetChar(nParPos) == '"' )
220cdf0e10cSrcweir 				{
221cdf0e10cSrcweir 					nParPos--;
222cdf0e10cSrcweir 					while ( (nParPos > 0) && rFormula.GetChar(nParPos) != '"' )
223cdf0e10cSrcweir 						nParPos--;
224cdf0e10cSrcweir 					if (nParPos > 0)
225cdf0e10cSrcweir 						nParPos--;
226cdf0e10cSrcweir 				}
227cdf0e10cSrcweir                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
228cdf0e10cSrcweir 					nParPos--;
229cdf0e10cSrcweir 			}
230cdf0e10cSrcweir 		}
231cdf0e10cSrcweir 		else
232cdf0e10cSrcweir 		{
233cdf0e10cSrcweir 			while ( !bFound && (nParPos < nStrLen) )
234cdf0e10cSrcweir 			{
235cdf0e10cSrcweir 				if ( rFormula.GetChar(nParPos) == '"' )
236cdf0e10cSrcweir 				{
237cdf0e10cSrcweir 					nParPos++;
238cdf0e10cSrcweir 					while ( (nParPos < nStrLen) && rFormula.GetChar(nParPos) != '"' )
239cdf0e10cSrcweir 						nParPos++;
240cdf0e10cSrcweir 					nParPos++;
241cdf0e10cSrcweir 				}
242cdf0e10cSrcweir                 else if ( (bFound = ( rFormula.GetChar(nParPos) == '(' ) ) == sal_False )
243cdf0e10cSrcweir 					nParPos++;
244cdf0e10cSrcweir 			}
245cdf0e10cSrcweir 		}
246cdf0e10cSrcweir 
247cdf0e10cSrcweir 		if ( bFound && (nParPos > 0) )
248cdf0e10cSrcweir 		{
249cdf0e10cSrcweir 			nFStart = nParPos-1;
250cdf0e10cSrcweir 
251cdf0e10cSrcweir 			while ( (nFStart > 0) && IsFormulaText(m_pCharClass, rFormula, nFStart ))
252cdf0e10cSrcweir 				nFStart--;
253cdf0e10cSrcweir 		}
254cdf0e10cSrcweir 
255cdf0e10cSrcweir 		nFStart++;
256cdf0e10cSrcweir 
257cdf0e10cSrcweir 		if ( bFound )
258cdf0e10cSrcweir 		{
259cdf0e10cSrcweir 			if ( IsFormulaText( m_pCharClass,rFormula, nFStart ) )
260cdf0e10cSrcweir 			{
261cdf0e10cSrcweir 									//	Funktion gefunden
262cdf0e10cSrcweir 				if ( pFuncName )
263cdf0e10cSrcweir 					*pFuncName = rFormula.Copy( nFStart, nParPos-nFStart );
264cdf0e10cSrcweir 			}
265cdf0e10cSrcweir 			else					// Klammern ohne Funktion -> weitersuchen
266cdf0e10cSrcweir 			{
267cdf0e10cSrcweir 				bRepeat = sal_True;
268cdf0e10cSrcweir 				if ( !bBack )
269cdf0e10cSrcweir 					nParPos++;
270cdf0e10cSrcweir 				else if (nParPos > 0)
271cdf0e10cSrcweir 					nParPos--;
272cdf0e10cSrcweir 				else
273cdf0e10cSrcweir 					bRepeat = sal_False;
274cdf0e10cSrcweir 			}
275cdf0e10cSrcweir 		}
276cdf0e10cSrcweir 		else						// keine Klammern gefunden
277cdf0e10cSrcweir 		{
278cdf0e10cSrcweir 			nFStart = FUNC_NOTFOUND;
279cdf0e10cSrcweir 			if ( pFuncName )
280cdf0e10cSrcweir 				pFuncName->Erase();
281cdf0e10cSrcweir 		}
282cdf0e10cSrcweir 	}
283cdf0e10cSrcweir 	while(bRepeat);
284cdf0e10cSrcweir 
285cdf0e10cSrcweir 	return nFStart;
286cdf0e10cSrcweir }
287cdf0e10cSrcweir 
288cdf0e10cSrcweir //------------------------------------------------------------------------
289cdf0e10cSrcweir 
GetFunctionEnd(const String & rStr,xub_StrLen nStart) const290cdf0e10cSrcweir xub_StrLen	FormulaHelper::GetFunctionEnd( const String& rStr, xub_StrLen nStart ) const
291cdf0e10cSrcweir {
292cdf0e10cSrcweir 	xub_StrLen nStrLen = rStr.Len();
293cdf0e10cSrcweir 
294cdf0e10cSrcweir 	if ( nStrLen < nStart )
295cdf0e10cSrcweir 		return nStart;
296cdf0e10cSrcweir 
297cdf0e10cSrcweir 	short	nParCount = 0;
298cdf0e10cSrcweir     bool    bInArray = false;
299cdf0e10cSrcweir 	sal_Bool	bFound = sal_False;
300cdf0e10cSrcweir 
301cdf0e10cSrcweir 	while ( !bFound && (nStart < nStrLen) )
302cdf0e10cSrcweir 	{
303cdf0e10cSrcweir 		sal_Unicode c = rStr.GetChar(nStart);
304cdf0e10cSrcweir 
305cdf0e10cSrcweir 		if ( c == '"' )
306cdf0e10cSrcweir 		{
307cdf0e10cSrcweir 			nStart++;
308cdf0e10cSrcweir 			while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
309cdf0e10cSrcweir 				nStart++;
310cdf0e10cSrcweir 		}
311cdf0e10cSrcweir 		else if ( c == open )
312cdf0e10cSrcweir 			nParCount++;
313cdf0e10cSrcweir 		else if ( c == close )
314cdf0e10cSrcweir 		{
315cdf0e10cSrcweir 			nParCount--;
316cdf0e10cSrcweir 			if ( nParCount == 0 )
317cdf0e10cSrcweir 				bFound = sal_True;
318cdf0e10cSrcweir 			else if ( nParCount < 0 )
319cdf0e10cSrcweir 			{
320cdf0e10cSrcweir 				bFound = sal_True;
321cdf0e10cSrcweir 				nStart--;	// einen zu weit gelesen
322cdf0e10cSrcweir 			}
323cdf0e10cSrcweir 		}
324cdf0e10cSrcweir         else if ( c == arrayOpen )
325cdf0e10cSrcweir         {
326cdf0e10cSrcweir             bInArray = true;
327cdf0e10cSrcweir         }
328cdf0e10cSrcweir         else if ( c == arrayClose )
329cdf0e10cSrcweir         {
330cdf0e10cSrcweir             bInArray = false;
331cdf0e10cSrcweir         }
332cdf0e10cSrcweir 		else if ( c == sep )
333cdf0e10cSrcweir 		{
334cdf0e10cSrcweir 			if ( !bInArray && nParCount == 0 )
335cdf0e10cSrcweir 			{
336cdf0e10cSrcweir 				bFound = sal_True;
337cdf0e10cSrcweir 				nStart--;	// einen zu weit gelesen
338cdf0e10cSrcweir 			}
339cdf0e10cSrcweir 		}
340cdf0e10cSrcweir 		nStart++; // hinter gefundene Position stellen
341cdf0e10cSrcweir 	}
342cdf0e10cSrcweir 
343cdf0e10cSrcweir 	return nStart;
344cdf0e10cSrcweir }
345cdf0e10cSrcweir 
346cdf0e10cSrcweir //------------------------------------------------------------------
347cdf0e10cSrcweir 
GetArgStart(const String & rStr,xub_StrLen nStart,sal_uInt16 nArg) const348cdf0e10cSrcweir xub_StrLen FormulaHelper::GetArgStart( const String& rStr, xub_StrLen nStart, sal_uInt16 nArg ) const
349cdf0e10cSrcweir {
350cdf0e10cSrcweir 	xub_StrLen nStrLen = rStr.Len();
351cdf0e10cSrcweir 
352cdf0e10cSrcweir 	if ( nStrLen < nStart )
353cdf0e10cSrcweir 		return nStart;
354cdf0e10cSrcweir 
355cdf0e10cSrcweir 	short	nParCount	= 0;
356cdf0e10cSrcweir     bool    bInArray    = false;
357cdf0e10cSrcweir 	sal_Bool	bFound		= sal_False;
358cdf0e10cSrcweir 
359cdf0e10cSrcweir 	while ( !bFound && (nStart < nStrLen) )
360cdf0e10cSrcweir 	{
361cdf0e10cSrcweir 		sal_Unicode c = rStr.GetChar(nStart);
362cdf0e10cSrcweir 
363cdf0e10cSrcweir 		if ( c == '"' )
364cdf0e10cSrcweir 		{
365cdf0e10cSrcweir 			nStart++;
366cdf0e10cSrcweir 			while ( (nStart < nStrLen) && rStr.GetChar(nStart) != '"' )
367cdf0e10cSrcweir 				nStart++;
368cdf0e10cSrcweir 		}
369cdf0e10cSrcweir 		else if ( c == open )
370cdf0e10cSrcweir 		{
371cdf0e10cSrcweir 			bFound = ( nArg == 0 );
372cdf0e10cSrcweir 			nParCount++;
373cdf0e10cSrcweir 		}
374cdf0e10cSrcweir 		else if ( c == close )
375cdf0e10cSrcweir 		{
376cdf0e10cSrcweir 			nParCount--;
377cdf0e10cSrcweir 			bFound = ( nParCount == 0 );
378cdf0e10cSrcweir 		}
379cdf0e10cSrcweir         else if ( c == arrayOpen )
380cdf0e10cSrcweir         {
381cdf0e10cSrcweir             bInArray = true;
382cdf0e10cSrcweir         }
383cdf0e10cSrcweir         else if ( c == arrayClose )
384cdf0e10cSrcweir         {
385cdf0e10cSrcweir             bInArray = false;
386cdf0e10cSrcweir         }
387cdf0e10cSrcweir 		else if ( c == sep )
388cdf0e10cSrcweir 		{
389cdf0e10cSrcweir 			if ( !bInArray && nParCount == 1 )
390cdf0e10cSrcweir 			{
391cdf0e10cSrcweir 				nArg--;
392cdf0e10cSrcweir 				bFound = ( nArg == 0  );
393cdf0e10cSrcweir 			}
394cdf0e10cSrcweir 		}
395cdf0e10cSrcweir 		nStart++;
396cdf0e10cSrcweir 	}
397cdf0e10cSrcweir 
398cdf0e10cSrcweir 	return nStart;
399cdf0e10cSrcweir }
400cdf0e10cSrcweir // =============================================================================
401cdf0e10cSrcweir } // formula
402cdf0e10cSrcweir // =============================================================================
403