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