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 180 : static int SAL_CALL OperatorCompare( const void *pFirst, const void *pSecond)
151 : {
152 180 : int nRet = 0;
153 180 : if( CALC_NAME == static_cast<const _CalcOp*>(pFirst)->eOp )
154 : {
155 180 : if( CALC_NAME == static_cast<const _CalcOp*>(pSecond)->eOp )
156 : nRet = static_cast<const _CalcOp*>(pFirst)->pUName->compareTo(
157 0 : *static_cast<const _CalcOp*>(pSecond)->pUName );
158 : else
159 : nRet = static_cast<const _CalcOp*>(pFirst)->pUName->compareToAscii(
160 180 : static_cast<const _CalcOp*>(pSecond)->pName );
161 : }
162 : else
163 : {
164 0 : if( CALC_NAME == static_cast<const _CalcOp*>(pSecond)->eOp )
165 : nRet = -1 * static_cast<const _CalcOp*>(pSecond)->pUName->compareToAscii(
166 0 : static_cast<const _CalcOp*>(pFirst)->pName );
167 : else
168 : nRet = strcmp( static_cast<const _CalcOp*>(pFirst)->pName,
169 0 : static_cast<const _CalcOp*>(pSecond)->pName );
170 : }
171 180 : return nRet;
172 : }
173 : }// extern "C"
174 :
175 36 : _CalcOp* FindOperator( const OUString& rSrch )
176 : {
177 : _CalcOp aSrch;
178 36 : aSrch.pUName = &rSrch;
179 36 : aSrch.eOp = CALC_NAME;
180 :
181 : return static_cast<_CalcOp*>(bsearch( static_cast<void*>(&aSrch),
182 : static_cast<void const *>(aOpTable),
183 : sizeof( aOpTable ) / sizeof( _CalcOp ),
184 : sizeof( _CalcOp ),
185 36 : OperatorCompare ));
186 : }
187 :
188 847 : SwHash* Find( const OUString& rStr, SwHash* const * ppTable,
189 : sal_uInt16 nTableSize, sal_uInt16* pPos )
190 : {
191 847 : sal_uLong ii = 0;
192 13106 : for( sal_Int32 n = 0; n < rStr.getLength(); ++n )
193 : {
194 12259 : ii = ii << 1 ^ rStr[n];
195 : }
196 847 : ii %= nTableSize;
197 :
198 847 : if( pPos )
199 846 : *pPos = static_cast<sal_uInt16>(ii);
200 :
201 1425 : for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
202 : {
203 621 : if( rStr == pEntry->aStr )
204 : {
205 43 : return pEntry;
206 : }
207 : }
208 804 : return 0;
209 : }
210 :
211 334 : inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
212 : {
213 : return static_cast<const SvxLanguageItem&>(rDoc.GetDefault(
214 : GetWhichOfScript( RES_CHRATR_LANGUAGE,
215 334 : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ))
216 334 : )).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 78 : SwCalc::SwCalc( SwDoc& rD )
233 : : aErrExpr( OUString(), SwSbxValue(), 0 )
234 : , nCommandPos(0)
235 : , rDoc( rD )
236 78 : , pLclData( m_aSysLocale.GetLocaleDataPtr() )
237 78 : , pCharClass( &GetAppCharClass() )
238 : , nListPor( 0 )
239 : , eCurrOper( CALC_NAME )
240 : , eCurrListOper( CALC_NAME )
241 234 : , eError( CALC_NOERR )
242 : {
243 78 : aErrExpr.aStr = "~C_ERR~";
244 78 : memset( VarTable, 0, sizeof(VarTable) );
245 78 : LanguageType eLang = GetDocAppScriptLang( rDoc );
246 :
247 83 : if( eLang != pLclData->getLanguageTag().getLanguageType() ||
248 5 : eLang != pCharClass->getLanguageTag().getLanguageType() )
249 : {
250 73 : LanguageTag aLanguageTag( eLang );
251 73 : pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), aLanguageTag );
252 73 : pLclData = new LocaleDataWrapper( aLanguageTag );
253 : }
254 :
255 78 : sCurrSym = comphelper::string::strip(pLclData->getCurrSymbol(), ' ');
256 78 : 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 UserOptToken const aAdrToken[ 12 ] =
307 : {
308 : UserOptToken::Company, UserOptToken::Street, UserOptToken::Country, UserOptToken::Zip,
309 : UserOptToken::City, UserOptToken::Title, UserOptToken::Position, UserOptToken::TelephoneWork,
310 : UserOptToken::TelephoneHome, UserOptToken::Fax, UserOptToken::Email, UserOptToken::State
311 : };
312 :
313 : static sal_uInt16 SwDocStat::* const aDocStat1[ 3 ] =
314 : {
315 : &SwDocStat::nTable, &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 78 : const SwDocStat& rDocStat = rDoc.getIDocumentStatistics().GetDocStat();
328 :
329 78 : SwSbxValue nVal;
330 156 : OUString sTmpStr;
331 : sal_uInt16 n;
332 :
333 2028 : for( n = 0; n < 25; ++n )
334 : {
335 1950 : sTmpStr = OUString::createFromAscii(sNTypeTab[n]);
336 1950 : VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
337 : }
338 :
339 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( false );
340 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( true );
341 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
342 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
343 :
344 312 : for( n = 0; n < 3; ++n )
345 234 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
346 390 : for( n = 0; n < 4; ++n )
347 312 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
348 :
349 78 : SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
350 :
351 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 11 ] ])->nValue.PutString( rUserOptions.GetFirstName() );
352 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 12 ] ])->nValue.PutString( rUserOptions.GetLastName() );
353 78 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ 13 ] ])->nValue.PutString( rUserOptions.GetID() );
354 :
355 936 : for( n = 0; n < 11; ++n )
356 1716 : static_cast<SwCalcExp*>(VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
357 2574 : rUserOptions.GetToken( aAdrToken[ n ] ));
358 :
359 78 : nVal.PutString( rUserOptions.GetToken( aAdrToken[ 11 ] ));
360 78 : sTmpStr = OUString::createFromAscii(sNTypeTab[25]);
361 156 : VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
362 :
363 78 : } // SwCalc::SwCalc
364 :
365 156 : SwCalc::~SwCalc()
366 : {
367 3744 : for( sal_uInt16 n = 0; n < TBLSZ; ++n )
368 3666 : delete VarTable[n];
369 :
370 78 : if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
371 73 : delete pLclData;
372 78 : if( pCharClass != &GetAppCharClass() )
373 73 : delete pCharClass;
374 78 : }
375 :
376 22 : SwSbxValue SwCalc::Calculate( const OUString& rStr )
377 : {
378 22 : eError = CALC_NOERR;
379 22 : SwSbxValue nResult;
380 :
381 22 : if( rStr.isEmpty() )
382 0 : return nResult;
383 :
384 22 : nListPor = 0;
385 22 : eCurrListOper = CALC_PLUS; // default: sum
386 :
387 22 : sCommand = rStr;
388 22 : nCommandPos = 0;
389 :
390 66 : while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
391 22 : nResult = Expr();
392 :
393 22 : if( eError )
394 0 : nResult.PutDouble( DBL_MAX );
395 :
396 22 : 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 <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 : const sal_Int32 nDecPlaces = 15;
434 : OUString aRetStr( ::rtl::math::doubleToUString(
435 : nValue,
436 : rtl_math_StringFormat_Automatic,
437 : nDecPlaces,
438 0 : pLclData->getNumDecimalSep()[0],
439 0 : true ));
440 0 : return aRetStr;
441 : }
442 :
443 12 : SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
444 : {
445 12 : OUString aStr = pCharClass->lowercase( rStr );
446 12 : return VarLook( aStr, true );
447 : }
448 :
449 31 : SwCalcExp* SwCalc::VarLook( const OUString& rStr, bool bIns )
450 : {
451 31 : aErrExpr.nValue.SetVoidValue(false);
452 :
453 31 : sal_uInt16 ii = 0;
454 31 : OUString aStr = pCharClass->lowercase( rStr );
455 :
456 31 : SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
457 :
458 31 : if( !pFnd )
459 : {
460 : // then check doc
461 11 : SwHash* const * ppDocTable = rDoc.getIDocumentFieldsAccess().GetUpdateFields().GetFieldTypeTable();
462 11 : for( SwHash* pEntry = *(ppDocTable+ii); pEntry; pEntry = pEntry->pNext )
463 : {
464 9 : if( aStr == pEntry->aStr )
465 : {
466 : // then insert here
467 : pFnd = new SwCalcExp( aStr, SwSbxValue(),
468 9 : static_cast<SwCalcFieldType*>(pEntry)->pFieldType );
469 9 : pFnd->pNext = *(VarTable+ii);
470 9 : *(VarTable+ii) = pFnd;
471 9 : break;
472 : }
473 : }
474 : }
475 :
476 31 : if( pFnd )
477 : {
478 29 : SwCalcExp* pFndExp = static_cast<SwCalcExp*>(pFnd);
479 :
480 29 : if( pFndExp->pFieldType && pFndExp->pFieldType->Which() == RES_USERFLD )
481 : {
482 2 : SwUserFieldType* pUField = const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFndExp->pFieldType));
483 2 : if( nsSwGetSetExpType::GSE_STRING & pUField->GetType() )
484 : {
485 2 : pFndExp->nValue.PutString( pUField->GetContent() );
486 : }
487 0 : else if( !pUField->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( pUField->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( pUField->GetValue() );
510 : }
511 : }
512 29 : return pFndExp;
513 : }
514 :
515 : // At this point the "real" case variable has to be used
516 4 : OUString const sTmpName( ::ReplacePoint(rStr) );
517 :
518 2 : if( !bIns )
519 : {
520 : #if HAVE_FEATURE_DBCONNECTIVITY
521 0 : SwDBManager *pMgr = rDoc.GetDBManager();
522 :
523 0 : OUString sDBName(GetDBName( sTmpName ));
524 0 : OUString sSourceName(sDBName.getToken(0, DB_DELIM));
525 0 : OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
526 0 : 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 = static_cast<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 0 : aErrExpr.nValue.SetVoidValue(true);
570 : }
571 : // NEVER save!
572 0 : return &aErrExpr;
573 : }
574 :
575 2 : SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
576 2 : pNewExp->pNext = VarTable[ ii ];
577 2 : VarTable[ ii ] = pNewExp;
578 :
579 4 : OUString sColumnName( GetColumnName( sTmpName ));
580 : OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
581 4 : if( sColumnName.equalsIgnoreAsciiCase(
582 4 : 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 33 : return pNewExp;
603 : }
604 :
605 75 : void SwCalc::VarChange( const OUString& rStr, double nValue )
606 : {
607 75 : SwSbxValue aVal( nValue );
608 75 : VarChange( rStr, aVal );
609 75 : }
610 :
611 637 : void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
612 : {
613 637 : OUString aStr = pCharClass->lowercase( rStr );
614 :
615 637 : sal_uInt16 nPos = 0;
616 637 : SwCalcExp* pFnd = static_cast<SwCalcExp*>(Find( aStr, VarTable, TBLSZ, &nPos ));
617 :
618 637 : if( !pFnd )
619 : {
620 617 : pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
621 617 : pFnd->pNext = VarTable[ nPos ];
622 617 : VarTable[ nPos ] = pFnd;
623 : }
624 : else
625 : {
626 20 : pFnd->nValue = rValue;
627 637 : }
628 637 : }
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 128 : 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 128 : if( nCommandPos >= sCommand.getLength() )
657 44 : 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 84 : coContFlags, OUString());
665 :
666 84 : bool bSetError = true;
667 84 : sal_Int32 nRealStt = nCommandPos + aRes.LeadingWhiteSpace;
668 84 : if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
669 : {
670 18 : nNumberValue.PutDouble( aRes.Value );
671 18 : eCurrOper = CALC_NUMBER;
672 18 : bSetError = false;
673 : }
674 66 : else if( aRes.TokenType & KParseType::IDENTNAME )
675 : {
676 : OUString aName( sCommand.copy( nRealStt,
677 36 : 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 67 : OUString sLowerCaseName = pCharClass->lowercase( aName );
682 : // catch currency symbol
683 36 : if( sLowerCaseName == sCurrSym )
684 : {
685 0 : nCommandPos = aRes.EndPos;
686 0 : return GetToken(); // call again
687 : }
688 :
689 : // catch operators
690 36 : _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
691 36 : if( pFnd )
692 : {
693 5 : switch( ( eCurrOper = static_cast<_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 5 : break;
710 : }
711 5 : nCommandPos = aRes.EndPos;
712 5 : return eCurrOper;
713 : }
714 31 : aVarName = aName;
715 31 : eCurrOper = CALC_NAME;
716 62 : bSetError = false;
717 : }
718 30 : else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
719 : {
720 4 : nNumberValue.PutString( aRes.DequotedNameOrString );
721 4 : eCurrOper = CALC_NUMBER;
722 4 : bSetError = false;
723 : }
724 26 : else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
725 : {
726 : OUString aName( sCommand.copy( nRealStt,
727 26 : aRes.EndPos - nRealStt ));
728 26 : if( 1 == aName.getLength() )
729 : {
730 26 : bSetError = false;
731 26 : sal_Unicode ch = aName[0];
732 26 : 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 9 : eCurrOper = SwCalcOper(ch);
754 9 : break;
755 :
756 : case '=':
757 : case '!':
758 : {
759 : SwCalcOper eTmp2;
760 17 : if( '=' == ch )
761 17 : eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
762 : else
763 0 : eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
764 :
765 34 : if( aRes.EndPos < sCommand.getLength() &&
766 17 : '=' == sCommand[aRes.EndPos] )
767 : {
768 5 : eCurrOper = eTmp2;
769 5 : ++aRes.EndPos;
770 : }
771 : }
772 17 : 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.clear();
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 26 : }
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 79 : if( bSetError )
854 : {
855 0 : eError = CALC_SYNTAX;
856 0 : eCurrOper = CALC_PRINT;
857 : }
858 79 : 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 = static_cast<_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 79 : return eCurrOper;
1077 : }
1078 :
1079 43 : SwSbxValue SwCalc::Term()
1080 : {
1081 43 : SwSbxValue left( Prim() );
1082 43 : nLastLeft = left;
1083 : for(;;)
1084 : {
1085 53 : sal_uInt16 nSbxOper = USHRT_MAX;
1086 :
1087 53 : 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 8 : case CALC_EQ: nSbxOper = SbxEQ; break;
1113 2 : 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 0 : if( nDec >= 0)
1175 : {
1176 0 : for (sal_Int32 i = 0; i < nDec; ++i )
1177 0 : fFac *= 10.0;
1178 : }
1179 : else
1180 : {
1181 0 : for (sal_Int32 i = 0; i < -nDec; ++i )
1182 0 : fFac /= 10.0;
1183 : }
1184 :
1185 0 : fVal *= fFac;
1186 : bool bSign;
1187 0 : if (fVal < 0.0)
1188 : {
1189 0 : fVal *= -1.0;
1190 0 : bSign = true;
1191 : }
1192 : else
1193 : {
1194 0 : bSign = false;
1195 : }
1196 :
1197 : // rounding
1198 0 : double fNum = fVal; // find the exponent
1199 0 : int nExp = 0;
1200 0 : if( fNum > 0 )
1201 : {
1202 0 : while( fNum < 1.0 )
1203 0 : fNum *= 10.0, --nExp;
1204 0 : while( fNum >= 10.0 )
1205 0 : fNum /= 10.0, ++nExp;
1206 : }
1207 0 : nExp = 15 - nExp;
1208 0 : if( nExp > 15 )
1209 0 : nExp = 15;
1210 0 : else if( nExp <= 1 )
1211 0 : nExp = 0;
1212 0 : fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1213 :
1214 0 : if (bSign)
1215 0 : fVal *= -1.0;
1216 :
1217 0 : fVal /= fFac;
1218 :
1219 0 : left.PutDouble( fVal );
1220 : }
1221 0 : break;
1222 :
1223 : //#77448# (=2*3^2 != 18)
1224 :
1225 : default:
1226 43 : return left;
1227 : }
1228 :
1229 10 : if( USHRT_MAX != nSbxOper )
1230 : {
1231 : // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1232 10 : SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1233 :
1234 10 : GetToken();
1235 10 : if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1236 : {
1237 10 : left.PutBool( left.Compare( eSbxOper, Prim() ));
1238 : }
1239 : else
1240 : {
1241 0 : SwSbxValue aRight( Prim() );
1242 0 : aRight.MakeDouble();
1243 0 : left.MakeDouble();
1244 :
1245 0 : if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1246 0 : eError = CALC_ZERODIV;
1247 : else
1248 0 : left.Compute( eSbxOper, aRight );
1249 : }
1250 : }
1251 10 : }
1252 : }
1253 :
1254 : extern "C" typedef double (*pfCalc)( double );
1255 :
1256 53 : SwSbxValue SwCalc::Prim()
1257 : {
1258 53 : SwSbxValue nErg;
1259 :
1260 53 : pfCalc pFnc = 0;
1261 :
1262 53 : bool bChkTrig = false, bChkPow = false;
1263 :
1264 53 : switch( eCurrOper )
1265 : {
1266 0 : case CALC_SIN: pFnc = &sin; break;
1267 0 : case CALC_COS: pFnc = &cos; break;
1268 0 : case CALC_TAN: pFnc = &tan; break;
1269 0 : case CALC_ATAN: pFnc = &atan; break;
1270 0 : case CALC_ASIN: pFnc = &asin; bChkTrig = true; break;
1271 0 : case CALC_ACOS: pFnc = &acos; bChkTrig = true; break;
1272 :
1273 : case CALC_NOT:
1274 : {
1275 0 : GetToken();
1276 0 : nErg = Prim();
1277 0 : if( SbxSTRING == nErg.GetType() )
1278 : {
1279 0 : nErg.PutBool( nErg.GetOUString().isEmpty() );
1280 : }
1281 0 : else if(SbxBOOL == nErg.GetType() )
1282 : {
1283 0 : nErg.PutBool(!nErg.GetBool());
1284 : }
1285 : // Evaluate arguments manually so that the binary NOT below does not
1286 : // get called. We want a BOOLEAN NOT.
1287 0 : else if (nErg.IsNumeric())
1288 : {
1289 0 : nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1290 : }
1291 : else
1292 : {
1293 : OSL_FAIL( "unexpected case. computing binary NOT" );
1294 : //!! computes a binary NOT
1295 0 : nErg.Compute( SbxNOT, nErg );
1296 : }
1297 : }
1298 0 : break;
1299 :
1300 : case CALC_NUMBER:
1301 22 : if( GetToken() == CALC_PHD )
1302 : {
1303 0 : double aTmp = nNumberValue.GetDouble();
1304 0 : aTmp *= 0.01;
1305 0 : nErg.PutDouble( aTmp );
1306 0 : GetToken();
1307 : }
1308 22 : else if( eCurrOper == CALC_NAME )
1309 : {
1310 0 : eError = CALC_SYNTAX;
1311 : }
1312 : else
1313 : {
1314 22 : nErg = nNumberValue;
1315 22 : bChkPow = true;
1316 : }
1317 22 : break;
1318 :
1319 : case CALC_NAME:
1320 31 : if( GetToken() == CALC_ASSIGN )
1321 : {
1322 12 : SwCalcExp* n = VarInsert( aVarName );
1323 12 : GetToken();
1324 12 : nErg = n->nValue = Expr();
1325 : }
1326 : else
1327 : {
1328 19 : nErg = VarLook( aVarName )->nValue;
1329 19 : bChkPow = true;
1330 : }
1331 31 : break;
1332 :
1333 : case CALC_MINUS:
1334 0 : GetToken();
1335 0 : nErg.PutDouble( -(Prim().GetDouble()) );
1336 0 : break;
1337 :
1338 : case CALC_LP:
1339 : {
1340 0 : GetToken();
1341 0 : nErg = Expr();
1342 0 : if( eCurrOper != CALC_RP )
1343 : {
1344 0 : eError = CALC_BRACK;
1345 : }
1346 : else
1347 : {
1348 0 : GetToken();
1349 0 : bChkPow = true; // in order for =(7)^2 to work
1350 : }
1351 : }
1352 0 : break;
1353 :
1354 : case CALC_MEAN:
1355 : {
1356 0 : nListPor = 1;
1357 0 : GetToken();
1358 0 : nErg = Expr();
1359 0 : double aTmp = nErg.GetDouble();
1360 0 : aTmp /= nListPor;
1361 0 : nErg.PutDouble( aTmp );
1362 : }
1363 0 : break;
1364 :
1365 : case CALC_SQRT:
1366 : {
1367 0 : GetToken();
1368 0 : nErg = Prim();
1369 0 : if( nErg.GetDouble() < 0 )
1370 0 : eError = CALC_OVERFLOW;
1371 : else
1372 0 : nErg.PutDouble( sqrt( nErg.GetDouble() ));
1373 : }
1374 0 : break;
1375 :
1376 : case CALC_SUM:
1377 : case CALC_DATE:
1378 : case CALC_MIN:
1379 : case CALC_MAX:
1380 0 : GetToken();
1381 0 : nErg = Expr();
1382 0 : break;
1383 :
1384 : case CALC_ENDCALC:
1385 0 : nErg.Clear();
1386 0 : break;
1387 :
1388 : default:
1389 0 : eError = CALC_SYNTAX;
1390 0 : break;
1391 : }
1392 :
1393 53 : if( pFnc )
1394 : {
1395 0 : GetToken();
1396 0 : double nVal = Prim().GetDouble();
1397 0 : if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1398 0 : nErg.PutDouble( (*pFnc)( nVal ) );
1399 : else
1400 0 : eError = CALC_OVERFLOW;
1401 : }
1402 :
1403 53 : if( bChkPow && eCurrOper == CALC_POW )
1404 : {
1405 0 : double dleft = nErg.GetDouble();
1406 0 : GetToken();
1407 0 : double right = Prim().GetDouble();
1408 :
1409 : double fraction, integer;
1410 0 : fraction = modf( right, &integer );
1411 0 : if( ( dleft < 0.0 && 0.0 != fraction ) ||
1412 0 : ( 0.0 == dleft && right < 0.0 ) )
1413 : {
1414 0 : eError = CALC_OVERFLOW;
1415 0 : nErg.Clear();
1416 : }
1417 : else
1418 : {
1419 0 : dleft = pow(dleft, right );
1420 0 : if( dleft == HUGE_VAL )
1421 : {
1422 0 : eError = CALC_POWERR;
1423 0 : nErg.Clear();
1424 : }
1425 : else
1426 : {
1427 0 : nErg.PutDouble( dleft );
1428 : }
1429 : }
1430 : }
1431 :
1432 53 : return nErg;
1433 : }
1434 :
1435 34 : SwSbxValue SwCalc::Expr()
1436 : {
1437 68 : SwSbxValue left = Term(), right;
1438 34 : nLastLeft = left;
1439 : for(;;)
1440 : {
1441 43 : switch(eCurrOper)
1442 : {
1443 : case CALC_PLUS:
1444 9 : GetToken();
1445 9 : left.MakeDouble();
1446 9 : ( right = Term() ).MakeDouble();
1447 9 : left.Compute( SbxPLUS, right );
1448 9 : nListPor++;
1449 9 : break;
1450 :
1451 : case CALC_MINUS:
1452 0 : GetToken();
1453 0 : left.MakeDouble();
1454 0 : ( right = Term() ).MakeDouble();
1455 0 : left.Compute( SbxMINUS, right );
1456 0 : break;
1457 :
1458 : default:
1459 68 : return left;
1460 : }
1461 : }
1462 : }
1463 :
1464 2 : OUString SwCalc::GetColumnName(const OUString& rName)
1465 : {
1466 2 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1467 2 : if( -1 != nPos )
1468 : {
1469 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1470 :
1471 0 : if( -1 != nPos )
1472 0 : return rName.copy(nPos + 1);
1473 : }
1474 2 : return rName;
1475 : }
1476 :
1477 0 : OUString SwCalc::GetDBName(const OUString& rName)
1478 : {
1479 0 : sal_Int32 nPos = rName.indexOf(DB_DELIM);
1480 0 : if( -1 != nPos )
1481 : {
1482 0 : nPos = rName.indexOf(DB_DELIM, nPos + 1);
1483 :
1484 0 : if( -1 != nPos )
1485 0 : return rName.copy( 0, nPos );
1486 : }
1487 0 : SwDBData aData = rDoc.GetDBData();
1488 0 : OUString sRet = aData.sDataSource;
1489 0 : sRet += OUString(DB_DELIM);
1490 0 : sRet += aData.sCommand;
1491 0 : return sRet;
1492 : }
1493 :
1494 : namespace
1495 : {
1496 256 : static bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1497 : double& rVal,
1498 : const LocaleDataWrapper* const pLclData )
1499 : {
1500 : OSL_ASSERT(pLclData);
1501 256 : const sal_Unicode nCurrCmdPos = rCommandPos;
1502 : rtl_math_ConversionStatus eStatus;
1503 : const sal_Unicode* pEnd;
1504 256 : rVal = rtl_math_uStringToDouble( rCommand.getStr() + rCommandPos,
1505 256 : rCommand.getStr() + rCommand.getLength(),
1506 256 : pLclData->getNumDecimalSep()[0],
1507 256 : pLclData->getNumThousandSep()[0],
1508 : &eStatus,
1509 1024 : &pEnd );
1510 256 : rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1511 :
1512 512 : return rtl_math_ConversionStatus_Ok == eStatus &&
1513 512 : nCurrCmdPos != rCommandPos;
1514 : }
1515 : }
1516 :
1517 0 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1518 : double& rVal, const LocaleDataWrapper* const pLclData )
1519 : {
1520 0 : const SvtSysLocale aSysLocale;
1521 : return lcl_Str2Double( rCommand, rCommandPos, rVal,
1522 0 : pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
1523 : }
1524 :
1525 256 : bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1526 : double& rVal, SwDoc* const pDoc )
1527 : {
1528 256 : const SvtSysLocale aSysLocale;
1529 512 : boost::scoped_ptr<const LocaleDataWrapper> pLclD;
1530 256 : if( pDoc )
1531 : {
1532 256 : LanguageType eLang = GetDocAppScriptLang( *pDoc );
1533 256 : if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1534 : {
1535 112 : pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1536 : }
1537 : }
1538 :
1539 : bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
1540 256 : (pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
1541 :
1542 512 : return bRet;
1543 : }
1544 :
1545 0 : bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1546 : {
1547 0 : bool bRet = false;
1548 : using namespace ::com::sun::star::i18n;
1549 : {
1550 : // Parse any token.
1551 0 : ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1552 : coStartFlags, OUString(),
1553 0 : coContFlags, OUString() );
1554 :
1555 0 : if( aRes.TokenType & KParseType::IDENTNAME )
1556 : {
1557 0 : bRet = aRes.EndPos == rStr.getLength();
1558 0 : if( pValidName )
1559 : {
1560 0 : *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1561 0 : aRes.EndPos - aRes.LeadingWhiteSpace );
1562 : }
1563 : }
1564 0 : else if( pValidName )
1565 0 : pValidName->clear();
1566 : }
1567 0 : return bRet;
1568 : }
1569 :
1570 2909 : SwHash::SwHash(const OUString& rStr)
1571 : : aStr(rStr)
1572 2909 : , pNext(0)
1573 : {
1574 2909 : }
1575 :
1576 5818 : SwHash::~SwHash()
1577 : {
1578 2909 : delete pNext;
1579 2909 : }
1580 :
1581 73 : void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
1582 : {
1583 2656 : for ( sal_uInt16 i = 0; i < nCount; ++i )
1584 2583 : delete *(ppHashTable+i);
1585 73 : delete [] ppHashTable;
1586 73 : }
1587 :
1588 2734 : SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1589 : const SwFieldType* pType)
1590 : : SwHash(rStr)
1591 : , nValue(rVal)
1592 2734 : , pFieldType(pType)
1593 : {
1594 2734 : }
1595 :
1596 10080 : SwSbxValue::~SwSbxValue()
1597 : {
1598 10080 : }
1599 :
1600 10 : bool SwSbxValue::GetBool() const
1601 : {
1602 20 : return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1603 30 : : SbxValue::GetBool();
1604 : }
1605 :
1606 12 : double SwSbxValue::GetDouble() const
1607 : {
1608 : double nRet;
1609 12 : if( SbxSTRING == GetType() )
1610 : {
1611 0 : sal_Int32 nStt = 0;
1612 0 : SwCalc::Str2Double( GetOUString(), nStt, nRet );
1613 : }
1614 12 : else if (IsBool())
1615 : {
1616 0 : nRet = GetBool() ? 1.0 : 0.0;
1617 : }
1618 : else
1619 : {
1620 12 : nRet = SbxValue::GetDouble();
1621 : }
1622 12 : return nRet;
1623 : }
1624 :
1625 18 : SwSbxValue& SwSbxValue::MakeDouble()
1626 : {
1627 18 : if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1628 0 : PutDouble( GetDouble() );
1629 18 : return *this;
1630 177 : }
1631 :
1632 : #ifdef STANDALONE_HASHCALC
1633 :
1634 : // this is example code how to create hash values in the CTOR:
1635 :
1636 : #include <stdio.h>
1637 : void main()
1638 : {
1639 : static sal_Char
1640 : sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1641 : sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1642 : sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1643 : sNType9[] = "word", sNType10[]= "char",
1644 : sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1645 : sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1646 : sNType15[] = "user_street" , sNType16[] = "user_country" ,
1647 : sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1648 : sNType19[] = "user_title" , sNType20[] = "user_position" ,
1649 : sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1650 : sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1651 : sNType25[] = "user_state", sNType26[] = "graph"
1652 : ;
1653 :
1654 : static const sal_Char* sNTypeTab[ 27 ] =
1655 : {
1656 : sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1657 : sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1658 : sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1659 : sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1660 : sNType24, sNType25, sNType26
1661 : };
1662 :
1663 : const unsigned short nTableSize = 47;
1664 : int aArr[ nTableSize ] = { 0 };
1665 : sal_Char ch;
1666 :
1667 : for( int n = 0; n < 27; ++n )
1668 : {
1669 : unsigned long ii = 0;
1670 : const sal_Char* pp = sNTypeTab[ n ];
1671 :
1672 : while( *pp )
1673 : {
1674 : ii = ii << 1 ^ *pp++;
1675 : }
1676 : ii %= nTableSize;
1677 :
1678 : ch = aArr[ ii ] ? 'X' : ' ';
1679 : aArr[ ii ] = 1;
1680 : printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1681 : }
1682 : }
1683 :
1684 : #endif
1685 :
1686 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|