Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <config_features.h>
21 :
22 : #include <calc.hxx>
23 : #include <cctype>
24 : #include <cfloat>
25 : #include <climits>
26 : #include <comphelper/processfactory.hxx>
27 : #include <comphelper/string.hxx>
28 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 : #include <cstdlib>
30 : #include <dbfld.hxx>
31 : #include <dbmgr.hxx>
32 : #include <docfld.hxx>
33 : #include <docstat.hxx>
34 : #include <doc.hxx>
35 : #include <IDocumentFieldsAccess.hxx>
36 : #include <IDocumentStatistics.hxx>
37 : #include <editeng/langitem.hxx>
38 : #include <editeng/scripttypeitem.hxx>
39 : #include <editeng/unolingu.hxx>
40 : #include <expfld.hxx>
41 : #include <hintids.hxx>
42 : #include <osl/diagnose.hxx>
43 : #include <rtl/math.hxx>
44 : #include <shellres.hxx>
45 : #include <svl/zforlist.hxx>
46 : #include <swmodule.hxx>
47 : #include <swtypes.hxx>
48 : #include <unotools/charclass.hxx>
49 : #include <unotools/localedatawrapper.hxx>
50 : #include <unotools/useroptions.hxx>
51 : #include <usrfld.hxx>
52 : #include <viewsh.hxx>
53 : #include <boost/scoped_ptr.hpp>
54 :
55 : using namespace ::com::sun::star;
56 :
57 : // shortcut
58 : #define RESOURCE SwViewShell::GetShellRes()
59 :
60 : const sal_Char sCalc_Add[] = "add";
61 : const sal_Char sCalc_Sub[] = "sub";
62 : const sal_Char sCalc_Mul[] = "mul";
63 : const sal_Char sCalc_Div[] = "div";
64 : const sal_Char sCalc_Phd[] = "phd";
65 : const sal_Char sCalc_Sqrt[] = "sqrt";
66 : const sal_Char sCalc_Pow[] = "pow";
67 : const sal_Char sCalc_Or[] = "or";
68 : const sal_Char sCalc_Xor[] = "xor";
69 : const sal_Char sCalc_And[] = "and";
70 : const sal_Char sCalc_Not[] = "not";
71 : const sal_Char sCalc_Eq[] = "eq";
72 : const sal_Char sCalc_Neq[] = "neq";
73 : const sal_Char sCalc_Leq[] = "leq";
74 : const sal_Char sCalc_Geq[] = "geq";
75 : const sal_Char sCalc_L[] = "l";
76 : const sal_Char sCalc_G[] = "g";
77 : const sal_Char sCalc_Sum[] = "sum";
78 : const sal_Char sCalc_Mean[] = "mean";
79 : const sal_Char sCalc_Min[] = "min";
80 : const sal_Char sCalc_Max[] = "max";
81 : const sal_Char sCalc_Sin[] = "sin";
82 : const sal_Char sCalc_Cos[] = "cos";
83 : const sal_Char sCalc_Tan[] = "tan";
84 : const sal_Char sCalc_Asin[] = "asin";
85 : const sal_Char sCalc_Acos[] = "acos";
86 : const sal_Char sCalc_Atan[] = "atan";
87 : const sal_Char sCalc_Round[]= "round";
88 : const sal_Char sCalc_Date[] = "date";
89 :
90 : // ATTENTION: sorted list of all operators
91 : struct _CalcOp
92 : {
93 : union{
94 : const sal_Char* pName;
95 : const OUString* pUName;
96 : };
97 : SwCalcOper eOp;
98 : };
99 :
100 : _CalcOp const aOpTable[] = {
101 : /* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arc cosine
102 : /* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
103 : /* AND */ {{sCalc_And}, CALC_AND}, // log. AND
104 : /* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arc sine
105 : /* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arc tangent
106 : /* COS */ {{sCalc_Cos}, CALC_COS}, // Cosine
107 : /* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
108 : /* DIV */ {{sCalc_Div}, CALC_DIV}, // Division
109 : /* EQ */ {{sCalc_Eq}, CALC_EQ}, // Equality
110 : /* G */ {{sCalc_G}, CALC_GRE}, // Greater than
111 : /* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // Greater or equal
112 : /* L */ {{sCalc_L}, CALC_LES}, // Less than
113 : /* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // Less or equal
114 : /* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximum value
115 : /* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mean
116 : /* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimum value
117 : /* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplication
118 : /* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // Not equal
119 : /* NOT */ {{sCalc_Not}, CALC_NOT}, // log. NOT
120 : /* OR */ {{sCalc_Or}, CALC_OR}, // log. OR
121 : /* PHD */ {{sCalc_Phd}, CALC_PHD}, // Percentage
122 : /* POW */ {{sCalc_Pow}, CALC_POW}, // Exponentiation
123 : /* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Rounding
124 : /* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sine
125 : /* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Square root
126 : /* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraction
127 : /* SUM */ {{sCalc_Sum}, CALC_SUM}, // Sum
128 : /* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangent
129 : /* XOR */ {{sCalc_Xor}, CALC_XOR} // log. XOR
130 : };
131 :
132 : double const nRoundVal[] = {
133 : 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
134 : 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
135 : 0.5e-15,0.5e-16
136 : };
137 :
138 : // First character may be any alphabetic or underscore.
139 : const sal_Int32 coStartFlags =
140 : i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
141 : i18n::KParseTokens::ASC_UNDERSCORE |
142 : i18n::KParseTokens::IGNORE_LEADING_WS;
143 :
144 : // Continuing characters may be any alphanumeric, underscore, or dot.
145 : const sal_Int32 coContFlags =
146 : ( coStartFlags | i18n::KParseTokens::ASC_DOT )
147 : & ~i18n::KParseTokens::IGNORE_LEADING_WS;
148 :
149 : extern "C" {
150 240 : static int SAL_CALL OperatorCompare( const void *pFirst, const void *pSecond)
151 : {
152 240 : int nRet = 0;
153 240 : if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
154 : {
155 240 : if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
156 : nRet = ((_CalcOp*)pFirst)->pUName->compareTo(
157 0 : *((_CalcOp*)pSecond)->pUName );
158 : else
159 : nRet = ((_CalcOp*)pFirst)->pUName->compareToAscii(
160 240 : ((_CalcOp*)pSecond)->pName );
161 : }
162 : else
163 : {
164 0 : if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
165 : nRet = -1 * ((_CalcOp*)pSecond)->pUName->compareToAscii(
166 0 : ((_CalcOp*)pFirst)->pName );
167 : else
168 : nRet = strcmp( ((_CalcOp*)pFirst)->pName,
169 0 : ((_CalcOp*)pSecond)->pName );
170 : }
171 240 : return nRet;
172 : }
173 : }// extern "C"
174 :
175 48 : _CalcOp* FindOperator( const OUString& rSrch )
176 : {
177 : _CalcOp aSrch;
178 48 : aSrch.pUName = &rSrch;
179 48 : aSrch.eOp = CALC_NAME;
180 :
181 : return (_CalcOp*)bsearch( (void*) &aSrch,
182 : (void*) aOpTable,
183 : sizeof( aOpTable ) / sizeof( _CalcOp ),
184 : sizeof( _CalcOp ),
185 48 : OperatorCompare );
186 : }
187 :
188 214 : SwHash* Find( const OUString& rStr, SwHash** ppTable,
189 : sal_uInt16 nTblSize, sal_uInt16* pPos )
190 : {
191 214 : sal_uLong ii = 0;
192 2756 : for( sal_Int32 n = 0; n < rStr.getLength(); ++n )
193 : {
194 2542 : ii = ii << 1 ^ rStr[n];
195 : }
196 214 : ii %= nTblSize;
197 :
198 214 : if( pPos )
199 212 : *pPos = (sal_uInt16)ii;
200 :
201 264 : for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
202 : {
203 64 : if( rStr == pEntry->aStr )
204 : {
205 14 : return pEntry;
206 : }
207 : }
208 200 : return 0;
209 : }
210 :
211 484 : inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
212 : {
213 : return ((SvxLanguageItem&)rDoc.GetDefault(
214 : GetWhichOfScript( RES_CHRATR_LANGUAGE,
215 484 : GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ))
216 484 : )).GetLanguage();
217 : }
218 :
219 0 : static double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
220 : {
221 0 : double nRet = 0;
222 0 : SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
223 0 : if( pFormatter )
224 : {
225 0 : Date* pNull = pFormatter->GetNullDate();
226 0 : Date aDate( nDate >> 24, (nDate& 0x00FF0000) >> 16, nDate& 0x0000FFFF );
227 0 : nRet = aDate - *pNull;
228 : }
229 0 : return nRet;
230 : }
231 :
232 42 : SwCalc::SwCalc( SwDoc& rD )
233 : : aErrExpr( OUString(), SwSbxValue(), 0 )
234 : , nCommandPos(0)
235 : , rDoc( rD )
236 42 : , pLclData( m_aSysLocale.GetLocaleDataPtr() )
237 42 : , pCharClass( &GetAppCharClass() )
238 : , nListPor( 0 )
239 : , eCurrOper( CALC_NAME )
240 : , eCurrListOper( CALC_NAME )
241 126 : , eError( CALC_NOERR )
242 : {
243 42 : aErrExpr.aStr = "~C_ERR~";
244 42 : memset( VarTable, 0, sizeof(VarTable) );
245 42 : LanguageType eLang = GetDocAppScriptLang( rDoc );
246 :
247 68 : if( eLang != pLclData->getLanguageTag().getLanguageType() ||
248 26 : eLang != pCharClass->getLanguageTag().getLanguageType() )
249 : {
250 16 : LanguageTag aLanguageTag( eLang );
251 16 : pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), aLanguageTag );
252 16 : pLclData = new LocaleDataWrapper( aLanguageTag );
253 : }
254 :
255 42 : sCurrSym = comphelper::string::strip(pLclData->getCurrSymbol(), ' ');
256 42 : sCurrSym = pCharClass->lowercase( sCurrSym );
257 :
258 : static sal_Char const
259 : sNType0[] = "false",
260 : sNType1[] = "true",
261 : sNType2[] = "pi",
262 : sNType3[] = "e",
263 : sNType4[] = "tables",
264 : sNType5[] = "graf",
265 : sNType6[] = "ole",
266 : sNType7[] = "page",
267 : sNType8[] = "para",
268 : sNType9[] = "word",
269 : sNType10[]= "char",
270 :
271 : sNType11[] = "user_firstname" ,
272 : sNType12[] = "user_lastname" ,
273 : sNType13[] = "user_initials" ,
274 : sNType14[] = "user_company" ,
275 : sNType15[] = "user_street" ,
276 : sNType16[] = "user_country" ,
277 : sNType17[] = "user_zipcode" ,
278 : sNType18[] = "user_city" ,
279 : sNType19[] = "user_title" ,
280 : sNType20[] = "user_position" ,
281 : sNType21[] = "user_tel_work" ,
282 : sNType22[] = "user_tel_home" ,
283 : sNType23[] = "user_fax" ,
284 : sNType24[] = "user_email" ,
285 : sNType25[] = "user_state" ,
286 : sNType26[] = "graph"
287 : ;
288 : static const sal_Char* const sNTypeTab[ 27 ] =
289 : {
290 : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
291 : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
292 : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
293 : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
294 : sNType24,
295 :
296 : // those have two HashIds
297 : sNType25, sNType26
298 : };
299 : static sal_uInt16 const aHashValue[ 27 ] =
300 : {
301 : 34, 38, 43, 7, 18, 32, 22, 29, 30, 33, 3,
302 : 28, 24, 40, 9, 11, 26, 45, 4, 23, 36, 44, 19, 5, 1,
303 : // those have two HashIds
304 : 11, 38
305 : };
306 : static sal_uInt16 const aAdrToken[ 12 ] =
307 : {
308 : USER_OPT_COMPANY, USER_OPT_STREET, USER_OPT_COUNTRY, USER_OPT_ZIP,
309 : USER_OPT_CITY, USER_OPT_TITLE, USER_OPT_POSITION, USER_OPT_TELEPHONEWORK,
310 : USER_OPT_TELEPHONEHOME, USER_OPT_FAX, USER_OPT_EMAIL, USER_OPT_STATE
311 : };
312 :
313 : static sal_uInt16 SwDocStat::* const aDocStat1[ 3 ] =
314 : {
315 : &SwDocStat::nTbl, &SwDocStat::nGrf, &SwDocStat::nOLE
316 : };
317 : static sal_uLong SwDocStat::* const aDocStat2[ 4 ] =
318 : {
319 : &SwDocStat::nPage, &SwDocStat::nPara,
320 : &SwDocStat::nWord, &SwDocStat::nChar
321 : };
322 :
323 : #if TBLSZ != 47
324 : #error Did you adjust all hash values?
325 : #endif
326 :
327 42 : const SwDocStat& rDocStat = rDoc.getIDocumentStatistics().GetDocStat();
328 :
329 42 : SwSbxValue nVal;
330 84 : OUString sTmpStr;
331 : sal_uInt16 n;
332 :
333 1092 : for( n = 0; n < 25; ++n )
334 : {
335 1050 : sTmpStr = OUString::createFromAscii(sNTypeTab[n]);
336 1050 : VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
337 : }
338 :
339 42 : ((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( false );
340 42 : ((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( true );
341 42 : ((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
342 42 : ((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
343 :
344 168 : for( n = 0; n < 3; ++n )
345 126 : ((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
346 210 : for( n = 0; n < 4; ++n )
347 168 : ((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
348 :
349 42 : SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
350 :
351 42 : ((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( rUserOptions.GetFirstName() );
352 42 : ((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( rUserOptions.GetLastName() );
353 42 : ((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( rUserOptions.GetID() );
354 :
355 504 : for( n = 0; n < 11; ++n )
356 924 : ((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
357 1386 : rUserOptions.GetToken( aAdrToken[ n ] ));
358 :
359 42 : nVal.PutString( rUserOptions.GetToken( aAdrToken[ 11 ] ));
360 42 : sTmpStr = OUString::createFromAscii(sNTypeTab[25]);
361 84 : VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
362 :
363 42 : } // SwCalc::SwCalc
364 :
365 84 : SwCalc::~SwCalc()
366 : {
367 2016 : for( sal_uInt16 n = 0; n < TBLSZ; ++n )
368 1974 : delete VarTable[n];
369 :
370 42 : if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
371 16 : delete pLclData;
372 42 : if( pCharClass != &GetAppCharClass() )
373 16 : delete pCharClass;
374 42 : }
375 :
376 38 : SwSbxValue SwCalc::Calculate( const OUString& rStr )
377 : {
378 38 : eError = CALC_NOERR;
379 38 : SwSbxValue nResult;
380 :
381 38 : if( rStr.isEmpty() )
382 0 : return nResult;
383 :
384 38 : nListPor = 0;
385 38 : eCurrListOper = CALC_PLUS; // default: sum
386 :
387 38 : sCommand = rStr;
388 38 : nCommandPos = 0;
389 :
390 114 : while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
391 38 : nResult = Expr();
392 :
393 38 : if( eError )
394 0 : nResult.PutDouble( DBL_MAX );
395 :
396 38 : return nResult;
397 : }
398 :
399 : //TODO: provide documentation
400 : /** ???
401 :
402 : @param rVal ???
403 : @param bRound In previous times <bRound> had a default value of <sal_True>.
404 : There it should be only changed when calculating table cells,
405 : so that no rounding errors would occur while composing a formula.
406 : Now this parameter is ignored.
407 : @return ???
408 : */
409 0 : OUString SwCalc::GetStrResult( const SwSbxValue& rVal, bool bRound )
410 : {
411 0 : if( !rVal.IsDouble() )
412 : {
413 0 : return rVal.GetOUString();
414 : }
415 0 : return GetStrResult( rVal.GetDouble(), bRound );
416 : }
417 :
418 0 : OUString SwCalc::GetStrResult( double nValue, bool )
419 : {
420 0 : if( nValue >= DBL_MAX )
421 0 : switch( eError )
422 : {
423 0 : case CALC_SYNTAX : return RESOURCE->aCalc_Syntax;
424 0 : case CALC_ZERODIV : return RESOURCE->aCalc_ZeroDiv;
425 0 : case CALC_BRACK : return RESOURCE->aCalc_Brack;
426 0 : case CALC_POWERR : return RESOURCE->aCalc_Pow;
427 0 : case CALC_VARNFND : return RESOURCE->aCalc_VarNFnd;
428 0 : case CALC_OVERFLOW : return RESOURCE->aCalc_Overflow;
429 0 : case CALC_WRONGTIME : return RESOURCE->aCalc_WrongTime;
430 0 : default : return RESOURCE->aCalc_Default;
431 : }
432 :
433 0 : sal_uInt16 nDec = 15;
434 : OUString aRetStr( ::rtl::math::doubleToUString(
435 : nValue,
436 : rtl_math_StringFormat_Automatic,
437 : nDec,
438 0 : pLclData->getNumDecimalSep()[0],
439 0 : true ));
440 0 : return aRetStr;
441 : }
442 :
443 4 : SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
444 : {
445 4 : OUString aStr = pCharClass->lowercase( rStr );
446 4 : return VarLook( aStr, 1 );
447 : }
448 :
449 38 : SwCalcExp* SwCalc::VarLook( const OUString& rStr, sal_uInt16 ins )
450 : {
451 38 : aErrExpr.nValue.SetVoidValue(false);
452 :
453 38 : sal_uInt16 ii = 0;
454 38 : OUString aStr = pCharClass->lowercase( rStr );
455 :
456 38 : SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
457 :
458 38 : if( !pFnd )
459 : {
460 : // then check doc
461 30 : SwHash** ppDocTbl = rDoc.getIDocumentFieldsAccess().GetUpdtFlds().GetFldTypeTable();
462 30 : for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
463 : {
464 10 : if( aStr == pEntry->aStr )
465 : {
466 : // then insert here
467 : pFnd = new SwCalcExp( aStr, SwSbxValue(),
468 10 : ((SwCalcFldType*)pEntry)->pFldType );
469 10 : pFnd->pNext = *(VarTable+ii);
470 10 : *(VarTable+ii) = pFnd;
471 10 : break;
472 : }
473 : }
474 : }
475 :
476 38 : if( pFnd )
477 : {
478 18 : SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
479 :
480 18 : if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
481 : {
482 4 : SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
483 4 : if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
484 : {
485 4 : pFndExp->nValue.PutString( pUFld->GetContent() );
486 : }
487 0 : else if( !pUFld->IsValid() )
488 : {
489 : // Save the current values...
490 0 : sal_uInt16 nOld_ListPor = nListPor;
491 0 : SwSbxValue nOld_LastLeft = nLastLeft;
492 0 : SwSbxValue nOld_NumberValue = nNumberValue;
493 0 : sal_Int32 nOld_CommandPos = nCommandPos;
494 0 : SwCalcOper eOld_CurrOper = eCurrOper;
495 0 : SwCalcOper eOld_CurrListOper = eCurrListOper;
496 :
497 0 : pFndExp->nValue.PutDouble( pUFld->GetValue( *this ) );
498 :
499 : // ...and write them back.
500 0 : nListPor = nOld_ListPor;
501 0 : nLastLeft = nOld_LastLeft;
502 0 : nNumberValue = nOld_NumberValue;
503 0 : nCommandPos = nOld_CommandPos;
504 0 : eCurrOper = eOld_CurrOper;
505 0 : eCurrListOper = eOld_CurrListOper;
506 : }
507 : else
508 : {
509 0 : pFndExp->nValue.PutDouble( pUFld->GetValue() );
510 : }
511 : }
512 18 : return pFndExp;
513 : }
514 :
515 : // At this point the "real" case variable has to be used
516 40 : OUString const sTmpName( ::ReplacePoint(rStr) );
517 :
518 20 : if( !ins )
519 : {
520 : #if HAVE_FEATURE_DBCONNECTIVITY
521 20 : SwDBManager *pMgr = rDoc.GetDBManager();
522 :
523 20 : OUString sDBName(GetDBName( sTmpName ));
524 40 : OUString sSourceName(sDBName.getToken(0, DB_DELIM));
525 40 : OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
526 20 : if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
527 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
528 : {
529 0 : OUString sColumnName( GetColumnName( sTmpName ));
530 : OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name");
531 :
532 0 : OUString sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
533 0 : sDBNum = pCharClass->lowercase(sDBNum);
534 :
535 : // Initialize again because this doesn't happen in docfld anymore for
536 : // elements != RES_DBFLD. E.g. if there is an expression field before
537 : // an DB_Field in a document.
538 0 : VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
539 :
540 0 : if( sDBNum.equalsIgnoreAsciiCase(sColumnName) )
541 : {
542 0 : aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
543 0 : return &aErrExpr;
544 : }
545 :
546 0 : sal_uLong nTmpRec = 0;
547 0 : if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
548 0 : nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
549 :
550 0 : OUString sResult;
551 0 : double nNumber = DBL_MAX;
552 :
553 0 : long nLang = pLclData->getLanguageTag().getLanguageType();
554 0 : if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
555 0 : nTmpRec, nLang, sResult, &nNumber ))
556 : {
557 0 : if (nNumber != DBL_MAX)
558 0 : aErrExpr.nValue.PutDouble( nNumber );
559 : else
560 0 : aErrExpr.nValue.PutString( sResult );
561 :
562 0 : return &aErrExpr;
563 0 : }
564 : }
565 : else
566 : #endif
567 : {
568 : //data source was not available - set return to "NoValue"
569 20 : aErrExpr.nValue.SetVoidValue(true);
570 : }
571 : // NEVER save!
572 40 : return &aErrExpr;
573 : }
574 :
575 0 : SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
576 0 : pNewExp->pNext = VarTable[ ii ];
577 0 : VarTable[ ii ] = pNewExp;
578 :
579 0 : OUString sColumnName( GetColumnName( sTmpName ));
580 : OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
581 0 : if( sColumnName.equalsIgnoreAsciiCase(
582 0 : SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
583 : {
584 : #if HAVE_FEATURE_DBCONNECTIVITY
585 0 : SwDBManager *pMgr = rDoc.GetDBManager();
586 0 : OUString sDBName(GetDBName( sTmpName ));
587 0 : OUString sSourceName(sDBName.getToken(0, DB_DELIM));
588 0 : OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
589 0 : if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
590 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
591 0 : !pMgr->IsInMerge())
592 : {
593 0 : pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
594 : }
595 : else
596 : #endif
597 : {
598 0 : pNewExp->nValue.SetVoidValue(true);
599 0 : }
600 : }
601 :
602 38 : return pNewExp;
603 : }
604 :
605 28 : void SwCalc::VarChange( const OUString& rStr, double nValue )
606 : {
607 28 : SwSbxValue aVal( nValue );
608 28 : VarChange( rStr, aVal );
609 28 : }
610 :
611 32 : void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
612 : {
613 32 : OUString aStr = pCharClass->lowercase( rStr );
614 :
615 32 : sal_uInt16 nPos = 0;
616 32 : SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
617 :
618 32 : if( !pFnd )
619 : {
620 32 : pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
621 32 : pFnd->pNext = VarTable[ nPos ];
622 32 : VarTable[ nPos ] = pFnd;
623 : }
624 : else
625 : {
626 0 : pFnd->nValue = rValue;
627 32 : }
628 32 : }
629 :
630 0 : bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
631 : {
632 0 : if( aRekurStk.end() != std::find(aRekurStk.begin(), aRekurStk.end(), pUserFieldType ) )
633 0 : return false;
634 :
635 0 : aRekurStk.push_back( pUserFieldType );
636 0 : return true;
637 : }
638 :
639 0 : void SwCalc::Pop()
640 : {
641 : OSL_ENSURE( aRekurStk.size(), "SwCalc: Pop on an invalid pointer" );
642 :
643 0 : aRekurStk.pop_back();
644 0 : }
645 :
646 150 : SwCalcOper SwCalc::GetToken()
647 : {
648 : #if OSL_DEBUG_LEVEL > 1
649 : // static for switch back to the "old" implementation of the calculator
650 : // which doesn't use the I18N routines.
651 : static int nUseOld = 0;
652 : if( !nUseOld )
653 : {
654 : #endif
655 :
656 150 : if( nCommandPos >= sCommand.getLength() )
657 76 : return eCurrOper = CALC_ENDCALC;
658 :
659 : using namespace ::com::sun::star::i18n;
660 : {
661 : // Parse any token.
662 : ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
663 : coStartFlags, OUString(),
664 74 : coContFlags, OUString());
665 :
666 74 : bool bSetError = true;
667 74 : sal_Int32 nRealStt = nCommandPos + aRes.LeadingWhiteSpace;
668 74 : if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
669 : {
670 10 : nNumberValue.PutDouble( aRes.Value );
671 10 : eCurrOper = CALC_NUMBER;
672 10 : bSetError = false;
673 : }
674 64 : else if( aRes.TokenType & KParseType::IDENTNAME )
675 : {
676 : OUString aName( sCommand.copy( nRealStt,
677 48 : aRes.EndPos - nRealStt ) );
678 : //#101436#: The variable may contain a database name. It must not be
679 : // converted to lower case! Instead all further comparisons must be
680 : // done case-insensitive
681 86 : OUString sLowerCaseName = pCharClass->lowercase( aName );
682 : // catch currency symbol
683 48 : if( sLowerCaseName == sCurrSym )
684 : {
685 0 : nCommandPos = aRes.EndPos;
686 0 : return GetToken(); // call again
687 : }
688 :
689 : // catch operators
690 48 : _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
691 48 : if( pFnd )
692 : {
693 10 : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
694 : {
695 : case CALC_SUM:
696 : case CALC_MEAN:
697 0 : eCurrListOper = CALC_PLUS;
698 0 : break;
699 : case CALC_MIN:
700 0 : eCurrListOper = CALC_MIN_IN;
701 0 : break;
702 : case CALC_MAX:
703 0 : eCurrListOper = CALC_MAX_IN;
704 0 : break;
705 : case CALC_DATE:
706 0 : eCurrListOper = CALC_MONTH;
707 0 : break;
708 : default:
709 10 : break;
710 : }
711 10 : nCommandPos = aRes.EndPos;
712 10 : return eCurrOper;
713 : }
714 38 : aVarName = aName;
715 38 : eCurrOper = CALC_NAME;
716 76 : bSetError = false;
717 : }
718 16 : else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
719 : {
720 8 : nNumberValue.PutString( aRes.DequotedNameOrString );
721 8 : eCurrOper = CALC_NUMBER;
722 8 : bSetError = false;
723 : }
724 8 : else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
725 : {
726 : OUString aName( sCommand.copy( nRealStt,
727 8 : aRes.EndPos - nRealStt ));
728 8 : if( 1 == aName.getLength() )
729 : {
730 8 : bSetError = false;
731 8 : sal_Unicode ch = aName[0];
732 8 : switch( ch )
733 : {
734 : case ';':
735 0 : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
736 : {
737 0 : eCurrOper = eCurrListOper;
738 0 : break;
739 : }
740 :
741 : case '\n':
742 0 : eCurrOper = CALC_PRINT;
743 0 : break;
744 :
745 : case '%':
746 : case '^':
747 : case '*':
748 : case '/':
749 : case '+':
750 : case '-':
751 : case '(':
752 : case ')':
753 0 : eCurrOper = SwCalcOper(ch);
754 0 : break;
755 :
756 : case '=':
757 : case '!':
758 : {
759 : SwCalcOper eTmp2;
760 8 : if( '=' == ch )
761 8 : eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
762 : else
763 0 : eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
764 :
765 16 : if( aRes.EndPos < sCommand.getLength() &&
766 8 : '=' == sCommand[aRes.EndPos] )
767 : {
768 4 : eCurrOper = eTmp2;
769 4 : ++aRes.EndPos;
770 : }
771 : }
772 8 : break;
773 :
774 : case cListDelim:
775 0 : eCurrOper = eCurrListOper;
776 0 : break;
777 :
778 : case '[':
779 0 : if( aRes.EndPos < sCommand.getLength() )
780 : {
781 0 : aVarName = "";
782 0 : sal_Int32 nFndPos = aRes.EndPos,
783 0 : nSttPos = nFndPos;
784 :
785 0 : do {
786 0 : if( -1 != ( nFndPos =
787 0 : sCommand.indexOf( ']', nFndPos )) )
788 : {
789 : // ignore the ]
790 0 : if ('\\' == sCommand[nFndPos-1])
791 : {
792 0 : aVarName += sCommand.copy( nSttPos,
793 0 : nFndPos - nSttPos - 1 );
794 0 : nSttPos = ++nFndPos;
795 : }
796 : else
797 0 : break;
798 : }
799 : } while( nFndPos != -1 );
800 :
801 0 : if( nFndPos != -1 )
802 : {
803 0 : if( nSttPos != nFndPos )
804 0 : aVarName += sCommand.copy( nSttPos,
805 0 : nFndPos - nSttPos );
806 0 : aRes.EndPos = nFndPos + 1;
807 0 : eCurrOper = CALC_NAME;
808 : }
809 : else
810 0 : bSetError = true;
811 : }
812 : else
813 : {
814 0 : bSetError = true;
815 : }
816 0 : break;
817 :
818 : default:
819 0 : bSetError = true;
820 0 : break;
821 : }
822 8 : }
823 : }
824 0 : else if( aRes.TokenType & KParseType::BOOLEAN )
825 : {
826 : OUString aName( sCommand.copy( nRealStt,
827 0 : aRes.EndPos - nRealStt ));
828 0 : if( !aName.isEmpty() )
829 : {
830 0 : sal_Unicode ch = aName[0];
831 :
832 0 : bSetError = true;
833 0 : if ('<' == ch || '>' == ch)
834 : {
835 0 : bSetError = false;
836 :
837 0 : SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
838 0 : eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
839 :
840 0 : if( 2 == aName.getLength() && '=' == aName[1] )
841 0 : eCurrOper = eTmp2;
842 0 : else if( 1 != aName.getLength() )
843 0 : bSetError = true;
844 : }
845 0 : }
846 : }
847 0 : else if( nRealStt == sCommand.getLength() )
848 : {
849 0 : eCurrOper = CALC_ENDCALC;
850 0 : bSetError = false;
851 : }
852 :
853 64 : if( bSetError )
854 : {
855 0 : eError = CALC_SYNTAX;
856 0 : eCurrOper = CALC_PRINT;
857 : }
858 64 : nCommandPos = aRes.EndPos;
859 : };
860 :
861 : #if OSL_DEBUG_LEVEL > 1
862 : #define NextCh( s, n ) (nCommandPos < sCommand.getLength() ? sCommand[nCommandPos++] : 0)
863 :
864 : }
865 : else
866 : {
867 : sal_Unicode ch;
868 : sal_Unicode cTSep = pLclData->getNumThousandSep()[0],
869 : cDSep = pLclData->getNumDecimalSep()[0];
870 :
871 : do {
872 : if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
873 : return eCurrOper = CALC_ENDCALC;
874 : } while ( ch == '\t' || ch == ' ' || ch == cTSep );
875 :
876 : if( ch == cDSep )
877 : ch = '.';
878 :
879 : switch( ch )
880 : {
881 : case ';':
882 : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
883 : {
884 : eCurrOper = eCurrListOper;
885 : break;
886 : } // else .. no break
887 : case '\n':
888 : {
889 : sal_Unicode c;
890 : while( nCommandPos < sCommand.getLength() &&
891 : ( ( c = sCommand[nCommandPos] ) == ' ' ||
892 : c == '\t' || c == '\x0a' || c == '\x0d' ))
893 : {
894 : ++nCommandPos;
895 : }
896 : eCurrOper = CALC_PRINT;
897 : }
898 : break;
899 :
900 : case '%':
901 : case '^':
902 : case '*':
903 : case '/':
904 : case '+':
905 : case '-':
906 : case '(':
907 : case ')':
908 : eCurrOper = SwCalcOper(ch);
909 : break;
910 :
911 : case '=':
912 : if( '=' == sCommand[nCommandPos] )
913 : {
914 : ++nCommandPos;
915 : eCurrOper = CALC_EQ;
916 : }
917 : else
918 : {
919 : eCurrOper = SwCalcOper(ch);
920 : }
921 : break;
922 :
923 : case '!':
924 : if( '=' == sCommand[nCommandPos] )
925 : {
926 : ++nCommandPos;
927 : eCurrOper = CALC_NEQ;
928 : }
929 : else
930 : {
931 : eCurrOper = CALC_NOT;
932 : }
933 : break;
934 :
935 : case '>':
936 : case '<':
937 : eCurrOper = '>' == ch ? CALC_GRE : CALC_LES;
938 : if( '=' == (ch = sCommand[nCommandPos] ) )
939 : {
940 : ++nCommandPos;
941 : eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
942 : }
943 : else if( ' ' != ch )
944 : {
945 : eError = CALC_SYNTAX;
946 : eCurrOper = CALC_PRINT;
947 : }
948 : break;
949 :
950 : case cListDelim :
951 : eCurrOper = eCurrListOper;
952 : break;
953 :
954 : case '0': case '1': case '2': case '3': case '4':
955 : case '5': case '6': case '7': case '8': case '9':
956 : case ',':
957 : case '.':
958 : {
959 : double nVal;
960 : --nCommandPos; // back to the first char
961 : if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
962 : {
963 : nNumberValue.PutDouble( nVal );
964 : eCurrOper = CALC_NUMBER;
965 : }
966 : else
967 : {
968 : // erroneous number
969 : eError = CALC_SYNTAX;
970 : eCurrOper = CALC_PRINT;
971 : }
972 : }
973 : break;
974 :
975 : case '[':
976 : {
977 : OUString aStr;
978 : bool bIgnore = false;
979 : do {
980 : while( 0 != ( ch = NextCh( sCommand, nCommandPos )) &&
981 : ch != ']' )
982 : {
983 : if( !bIgnore && '\\' == ch )
984 : bIgnore = true;
985 : else if( bIgnore )
986 : bIgnore = false;
987 : aStr += OUString(ch);
988 : }
989 :
990 : if( !bIgnore )
991 : break;
992 :
993 : aStr = aStr.replaceAt(aStr.getLength() - 1, 1, OUString(ch));
994 : } while( ch );
995 :
996 : aVarName = aStr;
997 : eCurrOper = CALC_NAME;
998 : }
999 : break;
1000 :
1001 : case '"':
1002 : {
1003 : sal_Int32 nStt = nCommandPos;
1004 : while( 0 != ( ch = NextCh( sCommand, nCommandPos ) ) &&
1005 : '"' != ch )
1006 : {
1007 : ;
1008 : }
1009 :
1010 : sal_Int32 nLen = nCommandPos - nStt;
1011 : if( '"' == ch )
1012 : --nLen;
1013 : nNumberValue.PutString( sCommand.copy( nStt, nLen ));
1014 : eCurrOper = CALC_NUMBER;
1015 : }
1016 : break;
1017 :
1018 : default:
1019 : if (ch && (pCharClass->isLetter( sCommand, nCommandPos - 1) ||
1020 : '_' == ch))
1021 : {
1022 : sal_Int32 nStt = nCommandPos-1;
1023 : while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
1024 : (pCharClass->isLetterNumeric( sCommand, nCommandPos - 1) ||
1025 : ch == '_' || ch == '.' ) )
1026 : {
1027 : ;
1028 : }
1029 :
1030 : if( ch )
1031 : --nCommandPos;
1032 :
1033 : OUString aStr( sCommand.copy( nStt, nCommandPos-nStt ));
1034 : aStr = pCharClass->lowercase( aStr );
1035 :
1036 : // catch currency symbol
1037 : if( aStr == sCurrSym )
1038 : return GetToken(); // call again
1039 :
1040 : // catch operators
1041 : _CalcOp* pFnd = ::FindOperator( aStr );
1042 : if( pFnd )
1043 : {
1044 : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
1045 : {
1046 : case CALC_SUM :
1047 : case CALC_MEAN :
1048 : eCurrListOper = CALC_PLUS;
1049 : break;
1050 : case CALC_MIN :
1051 : eCurrListOper = CALC_MIN_IN;
1052 : break;
1053 : case CALC_MAX :
1054 : eCurrListOper = CALC_MAX_IN;
1055 : break;
1056 : case CALC_DATE :
1057 : eCurrListOper = CALC_MONTH;
1058 : break;
1059 : default :
1060 : break;
1061 : }
1062 : return eCurrOper;
1063 : }
1064 : aVarName = aStr;
1065 : eCurrOper = CALC_NAME;
1066 : }
1067 : else
1068 : {
1069 : eError = CALC_SYNTAX;
1070 : eCurrOper = CALC_PRINT;
1071 : }
1072 : break;
1073 : }
1074 : }
1075 : #endif
1076 64 : return eCurrOper;
1077 : }
1078 :
1079 42 : SwSbxValue SwCalc::Term()
1080 : {
1081 42 : SwSbxValue left( Prim() );
1082 42 : nLastLeft = left;
1083 : for(;;)
1084 : {
1085 56 : sal_uInt16 nSbxOper = USHRT_MAX;
1086 :
1087 56 : switch( eCurrOper )
1088 : {
1089 : case CALC_AND:
1090 : {
1091 0 : GetToken();
1092 0 : bool bB = Prim().GetBool();
1093 0 : left.PutBool( left.GetBool() && bB );
1094 : }
1095 0 : break;
1096 : case CALC_OR:
1097 : {
1098 0 : GetToken();
1099 0 : bool bB = Prim().GetBool();
1100 0 : left.PutBool( left.GetBool() || bB );
1101 : }
1102 0 : break;
1103 : case CALC_XOR:
1104 : {
1105 0 : GetToken();
1106 0 : bool bR = Prim().GetBool();
1107 0 : bool bL = left.GetBool();
1108 0 : left.PutBool( (bL && !bR) || (!bL && bR) );
1109 : }
1110 0 : break;
1111 :
1112 10 : case CALC_EQ: nSbxOper = SbxEQ; break;
1113 4 : case CALC_NEQ: nSbxOper = SbxNE; break;
1114 0 : case CALC_LEQ: nSbxOper = SbxLE; break;
1115 0 : case CALC_GEQ: nSbxOper = SbxGE; break;
1116 0 : case CALC_GRE: nSbxOper = SbxGT; break;
1117 0 : case CALC_LES: nSbxOper = SbxLT; break;
1118 :
1119 0 : case CALC_MUL: nSbxOper = SbxMUL; break;
1120 0 : case CALC_DIV: nSbxOper = SbxDIV; break;
1121 :
1122 : case CALC_MIN_IN:
1123 : {
1124 0 : GetToken();
1125 0 : SwSbxValue e = Prim();
1126 0 : left = left.GetDouble() < e.GetDouble() ? left : e;
1127 : }
1128 0 : break;
1129 : case CALC_MAX_IN:
1130 : {
1131 0 : GetToken();
1132 0 : SwSbxValue e = Prim();
1133 0 : left = left.GetDouble() > e.GetDouble() ? left : e;
1134 : }
1135 0 : break;
1136 : case CALC_MONTH:
1137 : {
1138 0 : GetToken();
1139 0 : SwSbxValue e = Prim();
1140 0 : sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
1141 0 : nYear = nYear & 0x0000FFFF;
1142 0 : sal_Int32 nMonth = (sal_Int32) floor( e.GetDouble() );
1143 0 : nMonth = ( nMonth & 0x000000FF ) << 16;
1144 0 : left.PutLong( nMonth + nYear );
1145 0 : eCurrOper = CALC_DAY;
1146 : }
1147 0 : break;
1148 : case CALC_DAY:
1149 : {
1150 0 : GetToken();
1151 0 : SwSbxValue e = Prim();
1152 0 : sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
1153 0 : nYearMonth = nYearMonth & 0x00FFFFFF;
1154 0 : sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
1155 0 : nDay = ( nDay & 0x000000FF ) << 24;
1156 0 : left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
1157 : }
1158 0 : break;
1159 : case CALC_ROUND:
1160 : {
1161 0 : GetToken();
1162 0 : SwSbxValue e = Prim();
1163 :
1164 0 : double fVal = 0;
1165 0 : double fFac = 1;
1166 0 : sal_Int32 nDec = (sal_Int32) floor( e.GetDouble() );
1167 0 : if( nDec < -20 || nDec > 20 )
1168 : {
1169 0 : eError = CALC_OVERFLOW;
1170 0 : left.Clear();
1171 0 : return left;
1172 : }
1173 0 : fVal = left.GetDouble();
1174 : sal_uInt16 i;
1175 0 : if( nDec >= 0)
1176 : {
1177 0 : for (i = 0; i < (sal_uInt16) nDec; ++i )
1178 0 : fFac *= 10.0;
1179 : }
1180 : else
1181 : {
1182 0 : for (i = 0; i < (sal_uInt16) -nDec; ++i )
1183 0 : fFac /= 10.0;
1184 : }
1185 :
1186 0 : fVal *= fFac;
1187 : bool bSign;
1188 0 : if (fVal < 0.0)
1189 : {
1190 0 : fVal *= -1.0;
1191 0 : bSign = true;
1192 : }
1193 : else
1194 : {
1195 0 : bSign = false;
1196 : }
1197 :
1198 : // rounding
1199 0 : double fNum = fVal; // find the exponent
1200 0 : int nExp = 0;
1201 0 : if( fNum > 0 )
1202 : {
1203 0 : while( fNum < 1.0 )
1204 0 : fNum *= 10.0, --nExp;
1205 0 : while( fNum >= 10.0 )
1206 0 : fNum /= 10.0, ++nExp;
1207 : }
1208 0 : nExp = 15 - nExp;
1209 0 : if( nExp > 15 )
1210 0 : nExp = 15;
1211 0 : else if( nExp <= 1 )
1212 0 : nExp = 0;
1213 0 : fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1214 :
1215 0 : if (bSign)
1216 0 : fVal *= -1.0;
1217 :
1218 0 : fVal /= fFac;
1219 :
1220 0 : left.PutDouble( fVal );
1221 : }
1222 0 : break;
1223 :
1224 : //#77448# (=2*3^2 != 18)
1225 :
1226 : default:
1227 42 : return left;
1228 : }
1229 :
1230 14 : if( USHRT_MAX != nSbxOper )
1231 : {
1232 : // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1233 14 : SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1234 :
1235 14 : GetToken();
1236 14 : if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1237 : {
1238 14 : left.PutBool( left.Compare( eSbxOper, Prim() ));
1239 : }
1240 : else
1241 : {
1242 0 : SwSbxValue aRight( Prim() );
1243 0 : aRight.MakeDouble();
1244 0 : left.MakeDouble();
1245 :
1246 0 : if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1247 0 : eError = CALC_ZERODIV;
1248 : else
1249 0 : left.Compute( eSbxOper, aRight );
1250 : }
1251 : }
1252 14 : }
1253 : }
1254 :
1255 : extern "C" typedef double (*pfCalc)( double );
1256 :
1257 56 : SwSbxValue SwCalc::Prim()
1258 : {
1259 56 : SwSbxValue nErg;
1260 :
1261 56 : pfCalc pFnc = 0;
1262 :
1263 56 : bool bChkTrig = false, bChkPow = false;
1264 :
1265 56 : switch( eCurrOper )
1266 : {
1267 0 : case CALC_SIN: pFnc = &sin; break;
1268 0 : case CALC_COS: pFnc = &cos; break;
1269 0 : case CALC_TAN: pFnc = &tan; break;
1270 0 : case CALC_ATAN: pFnc = &atan; break;
1271 0 : case CALC_ASIN: pFnc = &asin; bChkTrig = true; break;
1272 0 : case CALC_ACOS: pFnc = &acos; bChkTrig = true; break;
1273 :
1274 : case CALC_NOT:
1275 : {
1276 0 : GetToken();
1277 0 : nErg = Prim();
1278 0 : if( SbxSTRING == nErg.GetType() )
1279 : {
1280 0 : nErg.PutBool( nErg.GetOUString().isEmpty() );
1281 : }
1282 0 : else if(SbxBOOL == nErg.GetType() )
1283 : {
1284 0 : nErg.PutBool(!nErg.GetBool());
1285 : }
1286 : // Evaluate arguments manually so that the binary NOT below does not
1287 : // get called. We want a BOOLEAN NOT.
1288 0 : else if (nErg.IsNumeric())
1289 : {
1290 0 : nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1291 : }
1292 : else
1293 : {
1294 : OSL_FAIL( "unexpected case. computing binary NOT" );
1295 : //!! computes a binary NOT
1296 0 : nErg.Compute( SbxNOT, nErg );
1297 : }
1298 : }
1299 0 : break;
1300 :
1301 : case CALC_NUMBER:
1302 18 : if( GetToken() == CALC_PHD )
1303 : {
1304 0 : double aTmp = nNumberValue.GetDouble();
1305 0 : aTmp *= 0.01;
1306 0 : nErg.PutDouble( aTmp );
1307 0 : GetToken();
1308 : }
1309 18 : else if( eCurrOper == CALC_NAME )
1310 : {
1311 0 : eError = CALC_SYNTAX;
1312 : }
1313 : else
1314 : {
1315 18 : nErg = nNumberValue;
1316 18 : bChkPow = true;
1317 : }
1318 18 : break;
1319 :
1320 : case CALC_NAME:
1321 38 : if( GetToken() == CALC_ASSIGN )
1322 : {
1323 4 : SwCalcExp* n = VarInsert( aVarName );
1324 4 : GetToken();
1325 4 : nErg = n->nValue = Expr();
1326 : }
1327 : else
1328 : {
1329 34 : nErg = VarLook( aVarName )->nValue;
1330 34 : bChkPow = true;
1331 : }
1332 38 : break;
1333 :
1334 : case CALC_MINUS:
1335 0 : GetToken();
1336 0 : nErg.PutDouble( -(Prim().GetDouble()) );
1337 0 : break;
1338 :
1339 : case CALC_LP:
1340 : {
1341 0 : GetToken();
1342 0 : nErg = Expr();
1343 0 : if( eCurrOper != CALC_RP )
1344 : {
1345 0 : eError = CALC_BRACK;
1346 : }
1347 : else
1348 : {
1349 0 : GetToken();
1350 0 : bChkPow = true; // in order for =(7)^2 to work
1351 : }
1352 : }
1353 0 : break;
1354 :
1355 : case CALC_MEAN:
1356 : {
1357 0 : nListPor = 1;
1358 0 : GetToken();
1359 0 : nErg = Expr();
1360 0 : double aTmp = nErg.GetDouble();
1361 0 : aTmp /= nListPor;
1362 0 : nErg.PutDouble( aTmp );
1363 : }
1364 0 : break;
1365 :
1366 : case CALC_SQRT:
1367 : {
1368 0 : GetToken();
1369 0 : nErg = Prim();
1370 0 : if( nErg.GetDouble() < 0 )
1371 0 : eError = CALC_OVERFLOW;
1372 : else
1373 0 : nErg.PutDouble( sqrt( nErg.GetDouble() ));
1374 : }
1375 0 : break;
1376 :
1377 : case CALC_SUM:
1378 : case CALC_DATE:
1379 : case CALC_MIN:
1380 : case CALC_MAX:
1381 0 : GetToken();
1382 0 : nErg = Expr();
1383 0 : break;
1384 :
1385 : case CALC_ENDCALC:
1386 0 : nErg.Clear();
1387 0 : break;
1388 :
1389 : default:
1390 0 : eError = CALC_SYNTAX;
1391 0 : break;
1392 : }
1393 :
1394 56 : if( pFnc )
1395 : {
1396 0 : GetToken();
1397 0 : double nVal = Prim().GetDouble();
1398 0 : if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1399 0 : nErg.PutDouble( (*pFnc)( nVal ) );
1400 : else
1401 0 : eError = CALC_OVERFLOW;
1402 : }
1403 :
1404 56 : if( bChkPow && eCurrOper == CALC_POW )
1405 : {
1406 0 : double dleft = nErg.GetDouble();
1407 0 : GetToken();
1408 0 : double right = Prim().GetDouble();
1409 :
1410 : double fraction, integer;
1411 0 : fraction = modf( right, &integer );
1412 0 : if( ( dleft < 0.0 && 0.0 != fraction ) ||
1413 0 : ( 0.0 == dleft && right < 0.0 ) )
1414 : {
1415 0 : eError = CALC_OVERFLOW;
1416 0 : nErg.Clear();
1417 : }
1418 : else
1419 : {
1420 0 : dleft = pow(dleft, right );
1421 0 : if( dleft == HUGE_VAL )
1422 : {
1423 0 : eError = CALC_POWERR;
1424 0 : nErg.Clear();
1425 : }
1426 : else
1427 : {
1428 0 : nErg.PutDouble( dleft );
1429 : }
1430 : }
1431 : }
1432 :
1433 56 : return nErg;
1434 : }
1435 :
1436 42 : SwSbxValue SwCalc::Expr()
1437 : {
1438 84 : SwSbxValue left = Term(), right;
1439 42 : nLastLeft = left;
1440 : for(;;)
1441 : {
1442 42 : switch(eCurrOper)
1443 : {
1444 : case CALC_PLUS:
1445 0 : GetToken();
1446 0 : left.MakeDouble();
1447 0 : ( right = Term() ).MakeDouble();
1448 0 : left.Compute( SbxPLUS, right );
1449 0 : nListPor++;
1450 0 : break;
1451 :
1452 : case CALC_MINUS:
1453 0 : GetToken();
1454 0 : left.MakeDouble();
1455 0 : ( right = Term() ).MakeDouble();
1456 0 : left.Compute( SbxMINUS, right );
1457 0 : break;
1458 :
1459 : default:
1460 84 : return left;
1461 : }
1462 : }
1463 : }
1464 :
1465 0 : OUString SwCalc::GetColumnName(const OUString& rName)
1466 : {
1467 0 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1468 0 : if( -1 != nPos )
1469 : {
1470 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1471 :
1472 0 : if( -1 != nPos )
1473 0 : return rName.copy(nPos + 1);
1474 : }
1475 0 : return rName;
1476 : }
1477 :
1478 20 : OUString SwCalc::GetDBName(const OUString& rName)
1479 : {
1480 20 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1481 20 : if( -1 != nPos )
1482 : {
1483 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1484 :
1485 0 : if( -1 != nPos )
1486 0 : return rName.copy( 0, nPos );
1487 : }
1488 20 : SwDBData aData = rDoc.GetDBData();
1489 40 : OUString sRet = aData.sDataSource;
1490 20 : sRet += OUString(DB_DELIM);
1491 20 : sRet += aData.sCommand;
1492 40 : return sRet;
1493 : }
1494 :
1495 : namespace
1496 : {
1497 442 : static bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1498 : double& rVal,
1499 : const LocaleDataWrapper* const pLclData )
1500 : {
1501 : OSL_ASSERT(pLclData);
1502 442 : const sal_Unicode nCurrCmdPos = rCommandPos;
1503 : rtl_math_ConversionStatus eStatus;
1504 : const sal_Unicode* pEnd;
1505 442 : rVal = rtl_math_uStringToDouble( rCommand.getStr() + rCommandPos,
1506 442 : rCommand.getStr() + rCommand.getLength(),
1507 442 : pLclData->getNumDecimalSep()[0],
1508 442 : pLclData->getNumThousandSep()[0],
1509 : &eStatus,
1510 1768 : &pEnd );
1511 442 : rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1512 :
1513 884 : return rtl_math_ConversionStatus_Ok == eStatus &&
1514 884 : nCurrCmdPos != rCommandPos;
1515 : }
1516 : }
1517 :
1518 0 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1519 : double& rVal, const LocaleDataWrapper* const pLclData )
1520 : {
1521 0 : const SvtSysLocale aSysLocale;
1522 : return lcl_Str2Double( rCommand, rCommandPos, rVal,
1523 0 : pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
1524 : }
1525 :
1526 442 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1527 : double& rVal, SwDoc* const pDoc )
1528 : {
1529 442 : const SvtSysLocale aSysLocale;
1530 884 : boost::scoped_ptr<const LocaleDataWrapper> pLclD;
1531 442 : if( pDoc )
1532 : {
1533 442 : LanguageType eLang = GetDocAppScriptLang( *pDoc );
1534 442 : if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1535 : {
1536 224 : pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1537 : }
1538 : }
1539 :
1540 : bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
1541 442 : (pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
1542 :
1543 884 : return bRet;
1544 : }
1545 :
1546 0 : bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1547 : {
1548 0 : bool bRet = false;
1549 : using namespace ::com::sun::star::i18n;
1550 : {
1551 : // Parse any token.
1552 0 : ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1553 : coStartFlags, OUString(),
1554 0 : coContFlags, OUString() );
1555 :
1556 0 : if( aRes.TokenType & KParseType::IDENTNAME )
1557 : {
1558 0 : bRet = aRes.EndPos == rStr.getLength();
1559 0 : if( pValidName )
1560 : {
1561 0 : *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1562 0 : aRes.EndPos - aRes.LeadingWhiteSpace );
1563 : }
1564 : }
1565 0 : else if( pValidName )
1566 0 : *pValidName = OUString();
1567 : }
1568 0 : return bRet;
1569 : }
1570 :
1571 1312 : SwHash::SwHash(const OUString& rStr)
1572 : : aStr(rStr)
1573 1312 : , pNext(0)
1574 : {
1575 1312 : }
1576 :
1577 2624 : SwHash::~SwHash()
1578 : {
1579 1312 : delete pNext;
1580 1312 : }
1581 :
1582 22 : void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
1583 : {
1584 848 : for ( sal_uInt16 i = 0; i < nCount; ++i )
1585 826 : delete *(ppHashTable+i);
1586 22 : delete [] ppHashTable;
1587 22 : }
1588 :
1589 1176 : SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1590 : const SwFieldType* pType)
1591 : : SwHash(rStr)
1592 : , nValue(rVal)
1593 1176 : , pFldType(pType)
1594 : {
1595 1176 : }
1596 :
1597 1554 : SwSbxValue::~SwSbxValue()
1598 : {
1599 1554 : }
1600 :
1601 28 : bool SwSbxValue::GetBool() const
1602 : {
1603 56 : return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1604 84 : : SbxValue::GetBool();
1605 : }
1606 :
1607 4 : double SwSbxValue::GetDouble() const
1608 : {
1609 : double nRet;
1610 4 : if( SbxSTRING == GetType() )
1611 : {
1612 0 : sal_Int32 nStt = 0;
1613 0 : SwCalc::Str2Double( GetOUString(), nStt, nRet );
1614 : }
1615 4 : else if (IsBool())
1616 : {
1617 0 : nRet = GetBool() ? 1.0 : 0.0;
1618 : }
1619 : else
1620 : {
1621 4 : nRet = SbxValue::GetDouble();
1622 : }
1623 4 : return nRet;
1624 : }
1625 :
1626 0 : SwSbxValue& SwSbxValue::MakeDouble()
1627 : {
1628 0 : if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1629 0 : PutDouble( GetDouble() );
1630 0 : return *this;
1631 270 : }
1632 :
1633 : #ifdef STANDALONE_HASHCALC
1634 :
1635 : // this is example code how to create hash values in the CTOR:
1636 :
1637 : #include <stdio.h>
1638 : void main()
1639 : {
1640 : static sal_Char
1641 : sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1642 : sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1643 : sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1644 : sNType9[] = "word", sNType10[]= "char",
1645 : sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1646 : sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1647 : sNType15[] = "user_street" , sNType16[] = "user_country" ,
1648 : sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1649 : sNType19[] = "user_title" , sNType20[] = "user_position" ,
1650 : sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1651 : sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1652 : sNType25[] = "user_state", sNType26[] = "graph"
1653 : ;
1654 :
1655 : static const sal_Char* sNTypeTab[ 27 ] =
1656 : {
1657 : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1658 : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1659 : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1660 : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1661 : sNType24, sNType25, sNType26
1662 : };
1663 :
1664 : const unsigned short nTblSize = 47;
1665 : int aArr[ nTblSize ] = { 0 };
1666 : sal_Char ch;
1667 :
1668 : for( int n = 0; n < 27; ++n )
1669 : {
1670 : unsigned long ii = 0;
1671 : const sal_Char* pp = sNTypeTab[ n ];
1672 :
1673 : while( *pp )
1674 : {
1675 : ii = ii << 1 ^ *pp++;
1676 : }
1677 : ii %= nTblSize;
1678 :
1679 : ch = aArr[ ii ] ? 'X' : ' ';
1680 : aArr[ ii ] = 1;
1681 : printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1682 : }
1683 : }
1684 :
1685 : #endif
1686 :
1687 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|