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