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 : #if defined(MACOSX)
21 : #include <stdlib.h>
22 : #endif
23 :
24 : #include <calc.hxx>
25 : #include <cctype>
26 : #include <cfloat>
27 : #include <climits>
28 : #include <comphelper/processfactory.hxx>
29 : #include <comphelper/string.hxx>
30 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 : #include <cstdlib>
32 : #include <dbfld.hxx>
33 : #include <dbmgr.hxx>
34 : #include <docfld.hxx>
35 : #include <docstat.hxx>
36 : #include <doc.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 110 : static int SAL_CALL OperatorCompare( const void *pFirst, const void *pSecond)
151 : {
152 110 : int nRet = 0;
153 110 : if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
154 : {
155 110 : 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 110 : ((_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 110 : return nRet;
172 : }
173 : }// extern "C"
174 :
175 22 : _CalcOp* FindOperator( const OUString& rSrch )
176 : {
177 : _CalcOp aSrch;
178 22 : aSrch.pUName = &rSrch;
179 22 : aSrch.eOp = CALC_NAME;
180 :
181 : return (_CalcOp*)bsearch( (void*) &aSrch,
182 : (void*) aOpTable,
183 : sizeof( aOpTable ) / sizeof( _CalcOp ),
184 : sizeof( _CalcOp ),
185 22 : OperatorCompare );
186 : }
187 :
188 58 : SwHash* Find( const OUString& rStr, SwHash** ppTable,
189 : sal_uInt16 nTblSize, sal_uInt16* pPos )
190 : {
191 58 : sal_uLong ii = 0;
192 437 : for( sal_Int32 n = 0; n < rStr.getLength(); ++n )
193 : {
194 379 : ii = ii << 1 ^ rStr[n];
195 : }
196 58 : ii %= nTblSize;
197 :
198 58 : if( pPos )
199 57 : *pPos = (sal_uInt16)ii;
200 :
201 66 : for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
202 : {
203 12 : if( rStr == pEntry->aStr )
204 : {
205 4 : return pEntry;
206 : }
207 : }
208 54 : return 0;
209 : }
210 :
211 219 : inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
212 : {
213 : return ((SvxLanguageItem&)rDoc.GetDefault(
214 : GetWhichOfScript( RES_CHRATR_LANGUAGE,
215 219 : GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ))
216 219 : )).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 15 : SwCalc::SwCalc( SwDoc& rD )
233 : : aErrExpr( OUString(), SwSbxValue(), 0 )
234 : , nCommandPos(0)
235 : , rDoc( rD )
236 15 : , pLclData( m_aSysLocale.GetLocaleDataPtr() )
237 15 : , pCharClass( &GetAppCharClass() )
238 : , nListPor( 0 )
239 : , eCurrOper( CALC_NAME )
240 : , eCurrListOper( CALC_NAME )
241 45 : , eError( CALC_NOERR )
242 : {
243 15 : aErrExpr.aStr = "~C_ERR~";
244 15 : memset( VarTable, 0, sizeof(VarTable) );
245 15 : LanguageType eLang = GetDocAppScriptLang( rDoc );
246 :
247 26 : if( eLang != pLclData->getLanguageTag().getLanguageType() ||
248 11 : eLang != pCharClass->getLanguageTag().getLanguageType() )
249 : {
250 4 : LanguageTag aLanguageTag( eLang );
251 4 : pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), aLanguageTag );
252 4 : pLclData = new LocaleDataWrapper( aLanguageTag );
253 : }
254 :
255 15 : sCurrSym = comphelper::string::strip(pLclData->getCurrSymbol(), ' ');
256 15 : 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 15 : const SwDocStat& rDocStat = rDoc.GetDocStat();
328 :
329 15 : SwSbxValue nVal;
330 30 : OUString sTmpStr;
331 : sal_uInt16 n;
332 :
333 390 : for( n = 0; n < 25; ++n )
334 : {
335 375 : sTmpStr = OUString::createFromAscii(sNTypeTab[n]);
336 375 : VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
337 : }
338 :
339 15 : ((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( false );
340 15 : ((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( true );
341 15 : ((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
342 15 : ((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
343 :
344 60 : for( n = 0; n < 3; ++n )
345 45 : ((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
346 75 : for( n = 0; n < 4; ++n )
347 60 : ((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
348 :
349 15 : SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
350 :
351 15 : ((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( rUserOptions.GetFirstName() );
352 15 : ((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( rUserOptions.GetLastName() );
353 15 : ((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( rUserOptions.GetID() );
354 :
355 180 : for( n = 0; n < 11; ++n )
356 330 : ((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
357 495 : rUserOptions.GetToken( aAdrToken[ n ] ));
358 :
359 15 : nVal.PutString( rUserOptions.GetToken( aAdrToken[ 11 ] ));
360 15 : sTmpStr = OUString::createFromAscii(sNTypeTab[25]);
361 30 : VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
362 :
363 15 : } // SwCalc::SwCalc
364 :
365 30 : SwCalc::~SwCalc()
366 : {
367 720 : for( sal_uInt16 n = 0; n < TBLSZ; ++n )
368 705 : delete VarTable[n];
369 :
370 15 : if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
371 4 : delete pLclData;
372 15 : if( pCharClass != &GetAppCharClass() )
373 4 : delete pCharClass;
374 15 : }
375 :
376 17 : SwSbxValue SwCalc::Calculate( const OUString& rStr )
377 : {
378 17 : eError = CALC_NOERR;
379 17 : SwSbxValue nResult;
380 :
381 17 : if( rStr.isEmpty() )
382 0 : return nResult;
383 :
384 17 : nListPor = 0;
385 17 : eCurrListOper = CALC_PLUS; // default: sum
386 :
387 17 : sCommand = rStr;
388 17 : nCommandPos = 0;
389 :
390 51 : while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
391 17 : nResult = Expr();
392 :
393 17 : if( eError )
394 0 : nResult.PutDouble( DBL_MAX );
395 :
396 17 : 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, sal_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, sal_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 2 : SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
444 : {
445 2 : OUString aStr = pCharClass->lowercase( rStr );
446 2 : return VarLook( aStr, 1 );
447 : }
448 :
449 17 : SwCalcExp* SwCalc::VarLook( const OUString& rStr, sal_uInt16 ins )
450 : {
451 17 : aErrExpr.nValue.SetVoidValue(false);
452 :
453 17 : sal_uInt16 ii = 0;
454 17 : OUString aStr = pCharClass->lowercase( rStr );
455 :
456 17 : SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
457 :
458 17 : if( !pFnd )
459 : {
460 : // then check doc
461 13 : SwHash** ppDocTbl = rDoc.GetUpdtFlds().GetFldTypeTable();
462 13 : for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
463 : {
464 5 : if( aStr == pEntry->aStr )
465 : {
466 : // then insert here
467 : pFnd = new SwCalcExp( aStr, SwSbxValue(),
468 5 : ((SwCalcFldType*)pEntry)->pFldType );
469 5 : pFnd->pNext = *(VarTable+ii);
470 5 : *(VarTable+ii) = pFnd;
471 5 : break;
472 : }
473 : }
474 : }
475 :
476 17 : if( pFnd )
477 : {
478 9 : SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
479 :
480 9 : if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
481 : {
482 2 : SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
483 2 : if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
484 : {
485 2 : 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 9 : return pFndExp;
513 : }
514 :
515 : // At this point the "real" case variable has to be used
516 16 : OUString const sTmpName( ::ReplacePoint(rStr) );
517 :
518 8 : if( !ins )
519 : {
520 8 : SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
521 :
522 8 : OUString sDBName(GetDBName( sTmpName ));
523 16 : OUString sSourceName(sDBName.getToken(0, DB_DELIM));
524 16 : OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
525 8 : if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
526 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
527 : {
528 0 : OUString sColumnName( GetColumnName( sTmpName ));
529 : OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name");
530 :
531 0 : OUString sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
532 0 : sDBNum = pCharClass->lowercase(sDBNum);
533 :
534 : // Initialize again because this doesn't happen in docfld anymore for
535 : // elements != RES_DBFLD. E.g. if there is an expression field before
536 : // an DB_Field in a document.
537 0 : VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
538 :
539 0 : if( sDBNum.equalsIgnoreAsciiCase(sColumnName) )
540 : {
541 0 : aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
542 0 : return &aErrExpr;
543 : }
544 :
545 0 : sal_uLong nTmpRec = 0;
546 0 : if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
547 0 : nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
548 :
549 0 : OUString sResult;
550 0 : double nNumber = DBL_MAX;
551 :
552 0 : long nLang = pLclData->getLanguageTag().getLanguageType();
553 0 : if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
554 0 : nTmpRec, nLang, sResult, &nNumber ))
555 : {
556 0 : if (nNumber != DBL_MAX)
557 0 : aErrExpr.nValue.PutDouble( nNumber );
558 : else
559 0 : aErrExpr.nValue.PutString( sResult );
560 :
561 0 : return &aErrExpr;
562 0 : }
563 : }
564 : else
565 : {
566 : //data source was not available - set return to "NoValue"
567 8 : aErrExpr.nValue.SetVoidValue(true);
568 : }
569 : // NEVER save!
570 16 : return &aErrExpr;
571 : }
572 :
573 0 : SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
574 0 : pNewExp->pNext = VarTable[ ii ];
575 0 : VarTable[ ii ] = pNewExp;
576 :
577 0 : OUString sColumnName( GetColumnName( sTmpName ));
578 : OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
579 0 : if( sColumnName.equalsIgnoreAsciiCase(
580 0 : SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
581 : {
582 0 : SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
583 0 : OUString sDBName(GetDBName( sTmpName ));
584 0 : OUString sSourceName(sDBName.getToken(0, DB_DELIM));
585 0 : OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
586 0 : if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
587 0 : pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
588 0 : !pMgr->IsInMerge())
589 : {
590 0 : pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
591 : }
592 : else
593 : {
594 0 : pNewExp->nValue.SetVoidValue(true);
595 0 : }
596 : }
597 :
598 17 : return pNewExp;
599 : }
600 :
601 0 : void SwCalc::VarChange( const OUString& rStr, double nValue )
602 : {
603 0 : SwSbxValue aVal( nValue );
604 0 : VarChange( rStr, aVal );
605 0 : }
606 :
607 2 : void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
608 : {
609 2 : OUString aStr = pCharClass->lowercase( rStr );
610 :
611 2 : sal_uInt16 nPos = 0;
612 2 : SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
613 :
614 2 : if( !pFnd )
615 : {
616 2 : pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
617 2 : pFnd->pNext = VarTable[ nPos ];
618 2 : VarTable[ nPos ] = pFnd;
619 : }
620 : else
621 : {
622 0 : pFnd->nValue = rValue;
623 2 : }
624 2 : }
625 :
626 0 : bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
627 : {
628 0 : if( aRekurStk.end() != std::find(aRekurStk.begin(), aRekurStk.end(), pUserFieldType ) )
629 0 : return false;
630 :
631 0 : aRekurStk.push_back( pUserFieldType );
632 0 : return true;
633 : }
634 :
635 0 : void SwCalc::Pop()
636 : {
637 : OSL_ENSURE( aRekurStk.size(), "SwCalc: Pop on an invalid pointer" );
638 :
639 0 : aRekurStk.pop_back();
640 0 : }
641 :
642 69 : SwCalcOper SwCalc::GetToken()
643 : {
644 : #if OSL_DEBUG_LEVEL > 1
645 : // static for switch back to the "old" implementation of the calculator
646 : // which doesn't use the I18N routines.
647 : static int nUseOld = 0;
648 : if( !nUseOld )
649 : {
650 : #endif
651 :
652 69 : if( nCommandPos >= sCommand.getLength() )
653 34 : return eCurrOper = CALC_ENDCALC;
654 :
655 : using namespace ::com::sun::star::i18n;
656 : {
657 : // Parse any token.
658 : ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
659 : coStartFlags, OUString(),
660 35 : coContFlags, OUString());
661 :
662 35 : bool bSetError = true;
663 35 : sal_Int32 nRealStt = nCommandPos + aRes.LeadingWhiteSpace;
664 35 : if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
665 : {
666 5 : nNumberValue.PutDouble( aRes.Value );
667 5 : eCurrOper = CALC_NUMBER;
668 5 : bSetError = false;
669 : }
670 30 : else if( aRes.TokenType & KParseType::IDENTNAME )
671 : {
672 : OUString aName( sCommand.copy( nRealStt,
673 22 : aRes.EndPos - nRealStt ) );
674 : //#101436#: The variable may contain a database name. It must not be
675 : // converted to lower case! Instead all further comparisons must be
676 : // done case-insensitive
677 39 : OUString sLowerCaseName = pCharClass->lowercase( aName );
678 : // catch currency symbol
679 22 : if( sLowerCaseName == sCurrSym )
680 : {
681 0 : nCommandPos = aRes.EndPos;
682 0 : return GetToken(); // call again
683 : }
684 :
685 : // catch operators
686 22 : _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
687 22 : if( pFnd )
688 : {
689 5 : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
690 : {
691 : case CALC_SUM:
692 : case CALC_MEAN:
693 0 : eCurrListOper = CALC_PLUS;
694 0 : break;
695 : case CALC_MIN:
696 0 : eCurrListOper = CALC_MIN_IN;
697 0 : break;
698 : case CALC_MAX:
699 0 : eCurrListOper = CALC_MAX_IN;
700 0 : break;
701 : case CALC_DATE:
702 0 : eCurrListOper = CALC_MONTH;
703 0 : break;
704 : default:
705 5 : break;
706 : }
707 5 : nCommandPos = aRes.EndPos;
708 5 : return eCurrOper;
709 : }
710 17 : aVarName = aName;
711 17 : eCurrOper = CALC_NAME;
712 34 : bSetError = false;
713 : }
714 8 : else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
715 : {
716 4 : nNumberValue.PutString( aRes.DequotedNameOrString );
717 4 : eCurrOper = CALC_NUMBER;
718 4 : bSetError = false;
719 : }
720 4 : else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
721 : {
722 : OUString aName( sCommand.copy( nRealStt,
723 4 : aRes.EndPos - nRealStt ));
724 4 : if( 1 == aName.getLength() )
725 : {
726 4 : bSetError = false;
727 4 : sal_Unicode ch = aName[0];
728 4 : switch( ch )
729 : {
730 : case ';':
731 0 : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
732 : {
733 0 : eCurrOper = eCurrListOper;
734 0 : break;
735 : }
736 :
737 : case '\n':
738 0 : eCurrOper = CALC_PRINT;
739 0 : break;
740 :
741 : case '%':
742 : case '^':
743 : case '*':
744 : case '/':
745 : case '+':
746 : case '-':
747 : case '(':
748 : case ')':
749 0 : eCurrOper = SwCalcOper(ch);
750 0 : break;
751 :
752 : case '=':
753 : case '!':
754 : {
755 : SwCalcOper eTmp2;
756 4 : if( '=' == ch )
757 4 : eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
758 : else
759 0 : eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
760 :
761 8 : if( aRes.EndPos < sCommand.getLength() &&
762 4 : '=' == sCommand[aRes.EndPos] )
763 : {
764 2 : eCurrOper = eTmp2;
765 2 : ++aRes.EndPos;
766 : }
767 : }
768 4 : break;
769 :
770 : case cListDelim:
771 0 : eCurrOper = eCurrListOper;
772 0 : break;
773 :
774 : case '[':
775 0 : if( aRes.EndPos < sCommand.getLength() )
776 : {
777 0 : aVarName = "";
778 0 : sal_Int32 nFndPos = aRes.EndPos,
779 0 : nSttPos = nFndPos;
780 :
781 0 : do {
782 0 : if( -1 != ( nFndPos =
783 0 : sCommand.indexOf( ']', nFndPos )) )
784 : {
785 : // ignore the ]
786 0 : if ('\\' == sCommand[nFndPos-1])
787 : {
788 0 : aVarName += sCommand.copy( nSttPos,
789 0 : nFndPos - nSttPos - 1 );
790 0 : nSttPos = ++nFndPos;
791 : }
792 : else
793 0 : break;
794 : }
795 : } while( nFndPos != -1 );
796 :
797 0 : if( nFndPos != -1 )
798 : {
799 0 : if( nSttPos != nFndPos )
800 0 : aVarName += sCommand.copy( nSttPos,
801 0 : nFndPos - nSttPos );
802 0 : aRes.EndPos = nFndPos + 1;
803 0 : eCurrOper = CALC_NAME;
804 : }
805 : else
806 0 : bSetError = true;
807 : }
808 : else
809 : {
810 0 : bSetError = true;
811 : }
812 0 : break;
813 :
814 : default:
815 0 : bSetError = true;
816 0 : break;
817 : }
818 4 : }
819 : }
820 0 : else if( aRes.TokenType & KParseType::BOOLEAN )
821 : {
822 : OUString aName( sCommand.copy( nRealStt,
823 0 : aRes.EndPos - nRealStt ));
824 0 : if( !aName.isEmpty() )
825 : {
826 0 : sal_Unicode ch = aName[0];
827 :
828 0 : bSetError = true;
829 0 : if ('<' == ch || '>' == ch)
830 : {
831 0 : bSetError = false;
832 :
833 0 : SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
834 0 : eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
835 :
836 0 : if( 2 == aName.getLength() && '=' == aName[1] )
837 0 : eCurrOper = eTmp2;
838 0 : else if( 1 != aName.getLength() )
839 0 : bSetError = true;
840 : }
841 0 : }
842 : }
843 0 : else if( nRealStt == sCommand.getLength() )
844 : {
845 0 : eCurrOper = CALC_ENDCALC;
846 0 : bSetError = false;
847 : }
848 :
849 30 : if( bSetError )
850 : {
851 0 : eError = CALC_SYNTAX;
852 0 : eCurrOper = CALC_PRINT;
853 : }
854 30 : nCommandPos = aRes.EndPos;
855 : };
856 :
857 : #if OSL_DEBUG_LEVEL > 1
858 : #define NextCh( s, n ) (nCommandPos < sCommand.getLength() ? sCommand[nCommandPos++] : 0)
859 :
860 : }
861 : else
862 : {
863 : sal_Unicode ch;
864 : sal_Unicode cTSep = pLclData->getNumThousandSep()[0],
865 : cDSep = pLclData->getNumDecimalSep()[0];
866 :
867 : do {
868 : if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
869 : return eCurrOper = CALC_ENDCALC;
870 : } while ( ch == '\t' || ch == ' ' || ch == cTSep );
871 :
872 : if( ch == cDSep )
873 : ch = '.';
874 :
875 : switch( ch )
876 : {
877 : case ';':
878 : if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
879 : {
880 : eCurrOper = eCurrListOper;
881 : break;
882 : } // else .. no break
883 : case '\n':
884 : {
885 : sal_Unicode c;
886 : while( nCommandPos < sCommand.getLength() &&
887 : ( ( c = sCommand[nCommandPos] ) == ' ' ||
888 : c == '\t' || c == '\x0a' || c == '\x0d' ))
889 : {
890 : ++nCommandPos;
891 : }
892 : eCurrOper = CALC_PRINT;
893 : }
894 : break;
895 :
896 : case '%':
897 : case '^':
898 : case '*':
899 : case '/':
900 : case '+':
901 : case '-':
902 : case '(':
903 : case ')':
904 : eCurrOper = SwCalcOper(ch);
905 : break;
906 :
907 : case '=':
908 : if( '=' == sCommand[nCommandPos] )
909 : {
910 : ++nCommandPos;
911 : eCurrOper = CALC_EQ;
912 : }
913 : else
914 : {
915 : eCurrOper = SwCalcOper(ch);
916 : }
917 : break;
918 :
919 : case '!':
920 : if( '=' == sCommand[nCommandPos] )
921 : {
922 : ++nCommandPos;
923 : eCurrOper = CALC_NEQ;
924 : }
925 : else
926 : {
927 : eCurrOper = CALC_NOT;
928 : }
929 : break;
930 :
931 : case '>':
932 : case '<':
933 : eCurrOper = '>' == ch ? CALC_GRE : CALC_LES;
934 : if( '=' == (ch = sCommand[nCommandPos] ) )
935 : {
936 : ++nCommandPos;
937 : eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
938 : }
939 : else if( ' ' != ch )
940 : {
941 : eError = CALC_SYNTAX;
942 : eCurrOper = CALC_PRINT;
943 : }
944 : break;
945 :
946 : case cListDelim :
947 : eCurrOper = eCurrListOper;
948 : break;
949 :
950 : case '0': case '1': case '2': case '3': case '4':
951 : case '5': case '6': case '7': case '8': case '9':
952 : case ',':
953 : case '.':
954 : {
955 : double nVal;
956 : --nCommandPos; // back to the first char
957 : if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
958 : {
959 : nNumberValue.PutDouble( nVal );
960 : eCurrOper = CALC_NUMBER;
961 : }
962 : else
963 : {
964 : // erroneous number
965 : eError = CALC_SYNTAX;
966 : eCurrOper = CALC_PRINT;
967 : }
968 : }
969 : break;
970 :
971 : case '[':
972 : {
973 : OUString aStr;
974 : bool bIgnore = false;
975 : do {
976 : while( 0 != ( ch = NextCh( sCommand, nCommandPos )) &&
977 : ch != ']' )
978 : {
979 : if( !bIgnore && '\\' == ch )
980 : bIgnore = true;
981 : else if( bIgnore )
982 : bIgnore = false;
983 : aStr += OUString(ch);
984 : }
985 :
986 : if( !bIgnore )
987 : break;
988 :
989 : aStr = aStr.replaceAt(aStr.getLength() - 1, 1, OUString(ch));
990 : } while( ch );
991 :
992 : aVarName = aStr;
993 : eCurrOper = CALC_NAME;
994 : }
995 : break;
996 :
997 : case '"':
998 : {
999 : sal_Int32 nStt = nCommandPos;
1000 : while( 0 != ( ch = NextCh( sCommand, nCommandPos ) ) &&
1001 : '"' != ch )
1002 : {
1003 : ;
1004 : }
1005 :
1006 : sal_Int32 nLen = nCommandPos - nStt;
1007 : if( '"' == ch )
1008 : --nLen;
1009 : nNumberValue.PutString( sCommand.copy( nStt, nLen ));
1010 : eCurrOper = CALC_NUMBER;
1011 : }
1012 : break;
1013 :
1014 : default:
1015 : if (ch && (pCharClass->isLetter( sCommand, nCommandPos - 1) ||
1016 : '_' == ch))
1017 : {
1018 : sal_Int32 nStt = nCommandPos-1;
1019 : while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
1020 : (pCharClass->isLetterNumeric( sCommand, nCommandPos - 1) ||
1021 : ch == '_' || ch == '.' ) )
1022 : {
1023 : ;
1024 : }
1025 :
1026 : if( ch )
1027 : --nCommandPos;
1028 :
1029 : OUString aStr( sCommand.copy( nStt, nCommandPos-nStt ));
1030 : aStr = pCharClass->lowercase( aStr );
1031 :
1032 : // catch currency symbol
1033 : if( aStr == sCurrSym )
1034 : return GetToken(); // call again
1035 :
1036 : // catch operators
1037 : _CalcOp* pFnd = ::FindOperator( aStr );
1038 : if( pFnd )
1039 : {
1040 : switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
1041 : {
1042 : case CALC_SUM :
1043 : case CALC_MEAN :
1044 : eCurrListOper = CALC_PLUS;
1045 : break;
1046 : case CALC_MIN :
1047 : eCurrListOper = CALC_MIN_IN;
1048 : break;
1049 : case CALC_MAX :
1050 : eCurrListOper = CALC_MAX_IN;
1051 : break;
1052 : case CALC_DATE :
1053 : eCurrListOper = CALC_MONTH;
1054 : break;
1055 : default :
1056 : break;
1057 : }
1058 : return eCurrOper;
1059 : }
1060 : aVarName = aStr;
1061 : eCurrOper = CALC_NAME;
1062 : }
1063 : else
1064 : {
1065 : eError = CALC_SYNTAX;
1066 : eCurrOper = CALC_PRINT;
1067 : }
1068 : break;
1069 : }
1070 : }
1071 : #endif
1072 30 : return eCurrOper;
1073 : }
1074 :
1075 19 : SwSbxValue SwCalc::Term()
1076 : {
1077 19 : SwSbxValue left( Prim() );
1078 19 : nLastLeft = left;
1079 : for(;;)
1080 : {
1081 26 : sal_uInt16 nSbxOper = USHRT_MAX;
1082 :
1083 26 : switch( eCurrOper )
1084 : {
1085 : case CALC_AND:
1086 : {
1087 0 : GetToken();
1088 0 : sal_Bool bB = Prim().GetBool();
1089 0 : left.PutBool( left.GetBool() && bB );
1090 : }
1091 0 : break;
1092 : case CALC_OR:
1093 : {
1094 0 : GetToken();
1095 0 : sal_Bool bB = Prim().GetBool();
1096 0 : left.PutBool( left.GetBool() || bB );
1097 : }
1098 0 : break;
1099 : case CALC_XOR:
1100 : {
1101 0 : GetToken();
1102 0 : sal_Bool bR = Prim().GetBool();
1103 0 : sal_Bool bL = left.GetBool();
1104 0 : left.PutBool( (bL && !bR) || (!bL && bR) );
1105 : }
1106 0 : break;
1107 :
1108 5 : case CALC_EQ: nSbxOper = SbxEQ; break;
1109 2 : case CALC_NEQ: nSbxOper = SbxNE; break;
1110 0 : case CALC_LEQ: nSbxOper = SbxLE; break;
1111 0 : case CALC_GEQ: nSbxOper = SbxGE; break;
1112 0 : case CALC_GRE: nSbxOper = SbxGT; break;
1113 0 : case CALC_LES: nSbxOper = SbxLT; break;
1114 :
1115 0 : case CALC_MUL: nSbxOper = SbxMUL; break;
1116 0 : case CALC_DIV: nSbxOper = SbxDIV; break;
1117 :
1118 : case CALC_MIN_IN:
1119 : {
1120 0 : GetToken();
1121 0 : SwSbxValue e = Prim();
1122 0 : left = left.GetDouble() < e.GetDouble() ? left : e;
1123 : }
1124 0 : break;
1125 : case CALC_MAX_IN:
1126 : {
1127 0 : GetToken();
1128 0 : SwSbxValue e = Prim();
1129 0 : left = left.GetDouble() > e.GetDouble() ? left : e;
1130 : }
1131 0 : break;
1132 : case CALC_MONTH:
1133 : {
1134 0 : GetToken();
1135 0 : SwSbxValue e = Prim();
1136 0 : sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
1137 0 : nYear = nYear & 0x0000FFFF;
1138 0 : sal_Int32 nMonth = (sal_Int32) floor( e.GetDouble() );
1139 0 : nMonth = ( nMonth & 0x000000FF ) << 16;
1140 0 : left.PutLong( nMonth + nYear );
1141 0 : eCurrOper = CALC_DAY;
1142 : }
1143 0 : break;
1144 : case CALC_DAY:
1145 : {
1146 0 : GetToken();
1147 0 : SwSbxValue e = Prim();
1148 0 : sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
1149 0 : nYearMonth = nYearMonth & 0x00FFFFFF;
1150 0 : sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
1151 0 : nDay = ( nDay & 0x000000FF ) << 24;
1152 0 : left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
1153 : }
1154 0 : break;
1155 : case CALC_ROUND:
1156 : {
1157 0 : GetToken();
1158 0 : SwSbxValue e = Prim();
1159 :
1160 0 : double fVal = 0;
1161 0 : double fFac = 1;
1162 0 : sal_Int32 nDec = (sal_Int32) floor( e.GetDouble() );
1163 0 : if( nDec < -20 || nDec > 20 )
1164 : {
1165 0 : eError = CALC_OVERFLOW;
1166 0 : left.Clear();
1167 0 : return left;
1168 : }
1169 0 : fVal = left.GetDouble();
1170 : sal_uInt16 i;
1171 0 : if( nDec >= 0)
1172 : {
1173 0 : for (i = 0; i < (sal_uInt16) nDec; ++i )
1174 0 : fFac *= 10.0;
1175 : }
1176 : else
1177 : {
1178 0 : for (i = 0; i < (sal_uInt16) -nDec; ++i )
1179 0 : fFac /= 10.0;
1180 : }
1181 :
1182 0 : fVal *= fFac;
1183 : bool bSign;
1184 0 : if (fVal < 0.0)
1185 : {
1186 0 : fVal *= -1.0;
1187 0 : bSign = true;
1188 : }
1189 : else
1190 : {
1191 0 : bSign = false;
1192 : }
1193 :
1194 : // rounding
1195 0 : double fNum = fVal; // find the exponent
1196 0 : int nExp = 0;
1197 0 : if( fNum > 0 )
1198 : {
1199 0 : while( fNum < 1.0 )
1200 0 : fNum *= 10.0, --nExp;
1201 0 : while( fNum >= 10.0 )
1202 0 : fNum /= 10.0, ++nExp;
1203 : }
1204 0 : nExp = 15 - nExp;
1205 0 : if( nExp > 15 )
1206 0 : nExp = 15;
1207 0 : else if( nExp <= 1 )
1208 0 : nExp = 0;
1209 0 : fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1210 :
1211 0 : if (bSign)
1212 0 : fVal *= -1.0;
1213 :
1214 0 : fVal /= fFac;
1215 :
1216 0 : left.PutDouble( fVal );
1217 : }
1218 0 : break;
1219 :
1220 : //#77448# (=2*3^2 != 18)
1221 :
1222 : default:
1223 19 : return left;
1224 : }
1225 :
1226 7 : if( USHRT_MAX != nSbxOper )
1227 : {
1228 : // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1229 7 : SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1230 :
1231 7 : GetToken();
1232 7 : if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1233 : {
1234 7 : left.PutBool( left.Compare( eSbxOper, Prim() ));
1235 : }
1236 : else
1237 : {
1238 0 : SwSbxValue aRight( Prim() );
1239 0 : aRight.MakeDouble();
1240 0 : left.MakeDouble();
1241 :
1242 0 : if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1243 0 : eError = CALC_ZERODIV;
1244 : else
1245 0 : left.Compute( eSbxOper, aRight );
1246 : }
1247 : }
1248 7 : }
1249 : }
1250 :
1251 : extern "C" typedef double (*pfCalc)( double );
1252 :
1253 26 : SwSbxValue SwCalc::Prim()
1254 : {
1255 26 : SwSbxValue nErg;
1256 :
1257 26 : pfCalc pFnc = 0;
1258 :
1259 26 : bool bChkTrig = false, bChkPow = false;
1260 :
1261 26 : switch( eCurrOper )
1262 : {
1263 0 : case CALC_SIN: pFnc = &sin; break;
1264 0 : case CALC_COS: pFnc = &cos; break;
1265 0 : case CALC_TAN: pFnc = &tan; break;
1266 0 : case CALC_ATAN: pFnc = &atan; break;
1267 0 : case CALC_ASIN: pFnc = &asin; bChkTrig = true; break;
1268 0 : case CALC_ACOS: pFnc = &acos; bChkTrig = true; break;
1269 :
1270 : case CALC_NOT:
1271 : {
1272 0 : GetToken();
1273 0 : nErg = Prim();
1274 0 : if( SbxSTRING == nErg.GetType() )
1275 : {
1276 0 : nErg.PutBool( nErg.GetOUString().isEmpty() );
1277 : }
1278 0 : else if(SbxBOOL == nErg.GetType() )
1279 : {
1280 0 : nErg.PutBool(!nErg.GetBool());
1281 : }
1282 : // Evaluate arguments manually so that the binary NOT below does not
1283 : // get called. We want a BOOLEAN NOT.
1284 0 : else if (nErg.IsNumeric())
1285 : {
1286 0 : nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1287 : }
1288 : else
1289 : {
1290 : OSL_FAIL( "unexpected case. computing binary NOT" );
1291 : //!! computes a binary NOT
1292 0 : nErg.Compute( SbxNOT, nErg );
1293 : }
1294 : }
1295 0 : break;
1296 :
1297 : case CALC_NUMBER:
1298 9 : if( GetToken() == CALC_PHD )
1299 : {
1300 0 : double aTmp = nNumberValue.GetDouble();
1301 0 : aTmp *= 0.01;
1302 0 : nErg.PutDouble( aTmp );
1303 0 : GetToken();
1304 : }
1305 9 : else if( eCurrOper == CALC_NAME )
1306 : {
1307 0 : eError = CALC_SYNTAX;
1308 : }
1309 : else
1310 : {
1311 9 : nErg = nNumberValue;
1312 9 : bChkPow = true;
1313 : }
1314 9 : break;
1315 :
1316 : case CALC_NAME:
1317 17 : if( GetToken() == CALC_ASSIGN )
1318 : {
1319 2 : SwCalcExp* n = VarInsert( aVarName );
1320 2 : GetToken();
1321 2 : nErg = n->nValue = Expr();
1322 : }
1323 : else
1324 : {
1325 15 : nErg = VarLook( aVarName )->nValue;
1326 15 : bChkPow = true;
1327 : }
1328 17 : break;
1329 :
1330 : case CALC_MINUS:
1331 0 : GetToken();
1332 0 : nErg.PutDouble( -(Prim().GetDouble()) );
1333 0 : break;
1334 :
1335 : case CALC_LP:
1336 : {
1337 0 : GetToken();
1338 0 : nErg = Expr();
1339 0 : if( eCurrOper != CALC_RP )
1340 : {
1341 0 : eError = CALC_BRACK;
1342 : }
1343 : else
1344 : {
1345 0 : GetToken();
1346 0 : bChkPow = true; // in order for =(7)^2 to work
1347 : }
1348 : }
1349 0 : break;
1350 :
1351 : case CALC_MEAN:
1352 : {
1353 0 : nListPor = 1;
1354 0 : GetToken();
1355 0 : nErg = Expr();
1356 0 : double aTmp = nErg.GetDouble();
1357 0 : aTmp /= nListPor;
1358 0 : nErg.PutDouble( aTmp );
1359 : }
1360 0 : break;
1361 :
1362 : case CALC_SQRT:
1363 : {
1364 0 : GetToken();
1365 0 : nErg = Prim();
1366 0 : if( nErg.GetDouble() < 0 )
1367 0 : eError = CALC_OVERFLOW;
1368 : else
1369 0 : nErg.PutDouble( sqrt( nErg.GetDouble() ));
1370 : }
1371 0 : break;
1372 :
1373 : case CALC_SUM:
1374 : case CALC_DATE:
1375 : case CALC_MIN:
1376 : case CALC_MAX:
1377 0 : GetToken();
1378 0 : nErg = Expr();
1379 0 : break;
1380 :
1381 : case CALC_ENDCALC:
1382 0 : nErg.Clear();
1383 0 : break;
1384 :
1385 : default:
1386 0 : eError = CALC_SYNTAX;
1387 0 : break;
1388 : }
1389 :
1390 26 : if( pFnc )
1391 : {
1392 0 : GetToken();
1393 0 : double nVal = Prim().GetDouble();
1394 0 : if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1395 0 : nErg.PutDouble( (*pFnc)( nVal ) );
1396 : else
1397 0 : eError = CALC_OVERFLOW;
1398 : }
1399 :
1400 26 : if( bChkPow && eCurrOper == CALC_POW )
1401 : {
1402 0 : double dleft = nErg.GetDouble();
1403 0 : GetToken();
1404 0 : double right = Prim().GetDouble();
1405 :
1406 : double fraction, integer;
1407 0 : fraction = modf( right, &integer );
1408 0 : if( ( dleft < 0.0 && 0.0 != fraction ) ||
1409 0 : ( 0.0 == dleft && right < 0.0 ) )
1410 : {
1411 0 : eError = CALC_OVERFLOW;
1412 0 : nErg.Clear();
1413 : }
1414 : else
1415 : {
1416 0 : dleft = pow(dleft, right );
1417 0 : if( dleft == HUGE_VAL )
1418 : {
1419 0 : eError = CALC_POWERR;
1420 0 : nErg.Clear();
1421 : }
1422 : else
1423 : {
1424 0 : nErg.PutDouble( dleft );
1425 : }
1426 : }
1427 : }
1428 :
1429 26 : return nErg;
1430 : }
1431 :
1432 19 : SwSbxValue SwCalc::Expr()
1433 : {
1434 38 : SwSbxValue left = Term(), right;
1435 19 : nLastLeft = left;
1436 : for(;;)
1437 : {
1438 19 : switch(eCurrOper)
1439 : {
1440 : case CALC_PLUS:
1441 0 : GetToken();
1442 0 : left.MakeDouble();
1443 0 : ( right = Term() ).MakeDouble();
1444 0 : left.Compute( SbxPLUS, right );
1445 0 : nListPor++;
1446 0 : break;
1447 :
1448 : case CALC_MINUS:
1449 0 : GetToken();
1450 0 : left.MakeDouble();
1451 0 : ( right = Term() ).MakeDouble();
1452 0 : left.Compute( SbxMINUS, right );
1453 0 : break;
1454 :
1455 : default:
1456 38 : return left;
1457 : }
1458 : }
1459 : }
1460 :
1461 0 : OUString SwCalc::GetColumnName(const OUString& rName)
1462 : {
1463 0 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1464 0 : if( -1 != nPos )
1465 : {
1466 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1467 :
1468 0 : if( -1 != nPos )
1469 0 : return rName.copy(nPos + 1);
1470 : }
1471 0 : return rName;
1472 : }
1473 :
1474 8 : OUString SwCalc::GetDBName(const OUString& rName)
1475 : {
1476 8 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1477 8 : if( -1 != nPos )
1478 : {
1479 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1480 :
1481 0 : if( -1 != nPos )
1482 0 : return rName.copy( 0, nPos );
1483 : }
1484 8 : SwDBData aData = rDoc.GetDBData();
1485 16 : OUString sRet = aData.sDataSource;
1486 8 : sRet += OUString(DB_DELIM);
1487 8 : sRet += aData.sCommand;
1488 16 : return sRet;
1489 : }
1490 :
1491 : namespace
1492 : {
1493 204 : static bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1494 : double& rVal,
1495 : const LocaleDataWrapper* const pLclData )
1496 : {
1497 : OSL_ASSERT(pLclData);
1498 204 : const sal_Unicode nCurrCmdPos = rCommandPos;
1499 : rtl_math_ConversionStatus eStatus;
1500 : const sal_Unicode* pEnd;
1501 204 : rVal = rtl_math_uStringToDouble( rCommand.getStr() + rCommandPos,
1502 204 : rCommand.getStr() + rCommand.getLength(),
1503 204 : pLclData->getNumDecimalSep()[0],
1504 204 : pLclData->getNumThousandSep()[0],
1505 : &eStatus,
1506 816 : &pEnd );
1507 204 : rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1508 :
1509 408 : return rtl_math_ConversionStatus_Ok == eStatus &&
1510 408 : nCurrCmdPos != rCommandPos;
1511 : }
1512 : }
1513 :
1514 0 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1515 : double& rVal, const LocaleDataWrapper* const pLclData )
1516 : {
1517 0 : const SvtSysLocale aSysLocale;
1518 : return lcl_Str2Double( rCommand, rCommandPos, rVal,
1519 0 : pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
1520 : }
1521 :
1522 204 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1523 : double& rVal, SwDoc* const pDoc )
1524 : {
1525 204 : const SvtSysLocale aSysLocale;
1526 408 : boost::scoped_ptr<const LocaleDataWrapper> pLclD;
1527 204 : if( pDoc )
1528 : {
1529 204 : LanguageType eLang = GetDocAppScriptLang( *pDoc );
1530 204 : if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1531 : {
1532 112 : pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1533 : }
1534 : }
1535 :
1536 : bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
1537 204 : (pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
1538 :
1539 408 : return bRet;
1540 : }
1541 :
1542 0 : sal_Bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1543 : {
1544 0 : sal_Bool bRet = sal_False;
1545 : using namespace ::com::sun::star::i18n;
1546 : {
1547 : // Parse any token.
1548 0 : ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1549 : coStartFlags, OUString(),
1550 0 : coContFlags, OUString() );
1551 :
1552 0 : if( aRes.TokenType & KParseType::IDENTNAME )
1553 : {
1554 0 : bRet = aRes.EndPos == rStr.getLength();
1555 0 : if( pValidName )
1556 : {
1557 0 : *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1558 0 : aRes.EndPos - aRes.LeadingWhiteSpace );
1559 : }
1560 : }
1561 0 : else if( pValidName )
1562 0 : *pValidName = OUString();
1563 : }
1564 0 : return bRet;
1565 : }
1566 :
1567 450 : SwHash::SwHash(const OUString& rStr)
1568 : : aStr(rStr)
1569 450 : , pNext(0)
1570 : {
1571 450 : }
1572 :
1573 900 : SwHash::~SwHash()
1574 : {
1575 450 : delete pNext;
1576 450 : }
1577 :
1578 6 : void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
1579 : {
1580 216 : for ( sal_uInt16 i = 0; i < nCount; ++i )
1581 210 : delete *(ppHashTable+i);
1582 6 : delete [] ppHashTable;
1583 6 : }
1584 :
1585 412 : SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1586 : const SwFieldType* pType)
1587 : : SwHash(rStr)
1588 : , nValue(rVal)
1589 412 : , pFldType(pType)
1590 : {
1591 412 : }
1592 :
1593 1086 : SwSbxValue::~SwSbxValue()
1594 : {
1595 1086 : }
1596 :
1597 13 : sal_Bool SwSbxValue::GetBool() const
1598 : {
1599 26 : return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1600 39 : : SbxValue::GetBool();
1601 : }
1602 :
1603 2 : double SwSbxValue::GetDouble() const
1604 : {
1605 : double nRet;
1606 2 : if( SbxSTRING == GetType() )
1607 : {
1608 0 : sal_Int32 nStt = 0;
1609 0 : SwCalc::Str2Double( GetOUString(), nStt, nRet );
1610 : }
1611 2 : else if (IsBool())
1612 : {
1613 0 : nRet = 0 != GetBool() ? 1.0 : 0.0;
1614 : }
1615 : else
1616 : {
1617 2 : nRet = SbxValue::GetDouble();
1618 : }
1619 2 : return nRet;
1620 : }
1621 :
1622 0 : SwSbxValue& SwSbxValue::MakeDouble()
1623 : {
1624 0 : if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1625 0 : PutDouble( GetDouble() );
1626 0 : return *this;
1627 : }
1628 :
1629 : #ifdef STANDALONE_HASHCALC
1630 :
1631 : // this is example code how to create hash values in the CTOR:
1632 :
1633 : #include <stdio.h>
1634 : void main()
1635 : {
1636 : static sal_Char
1637 : sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1638 : sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1639 : sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1640 : sNType9[] = "word", sNType10[]= "char",
1641 : sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1642 : sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1643 : sNType15[] = "user_street" , sNType16[] = "user_country" ,
1644 : sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1645 : sNType19[] = "user_title" , sNType20[] = "user_position" ,
1646 : sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1647 : sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1648 : sNType25[] = "user_state", sNType26[] = "graph"
1649 : ;
1650 :
1651 : static const sal_Char* sNTypeTab[ 27 ] =
1652 : {
1653 : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1654 : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1655 : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1656 : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1657 : sNType24, sNType25, sNType26
1658 : };
1659 :
1660 : const unsigned short nTblSize = 47;
1661 : int aArr[ nTblSize ] = { 0 };
1662 : sal_Char ch;
1663 :
1664 : for( int n = 0; n < 27; ++n )
1665 : {
1666 : unsigned long ii = 0;
1667 : const sal_Char* pp = sNTypeTab[ n ];
1668 :
1669 : while( *pp )
1670 : {
1671 : ii = ii << 1 ^ *pp++;
1672 : }
1673 : ii %= nTblSize;
1674 :
1675 : ch = aArr[ ii ] ? 'X' : ' ';
1676 : aArr[ ii ] = 1;
1677 : printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1678 : }
1679 : }
1680 :
1681 : #endif
1682 :
1683 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|