android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / bastyp / calc.cxx
blob62d300f60ba76a249177b5d2c7ef024826db7771
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
21 #include <config_fuzzers.h>
23 #include <calc.hxx>
24 #include <cfloat>
25 #include <climits>
26 #include <memory>
27 #include <comphelper/processfactory.hxx>
28 #include <comphelper/string.hxx>
29 #include <cstdlib>
30 #include <dbmgr.hxx>
31 #include <docfld.hxx>
32 #include <docstat.hxx>
33 #include <doc.hxx>
34 #include <IDocumentFieldsAccess.hxx>
35 #include <IDocumentStatistics.hxx>
36 #include <editeng/langitem.hxx>
37 #include <expfld.hxx>
38 #include <hintids.hxx>
39 #include <o3tl/temporary.hxx>
40 #include <osl/diagnose.h>
41 #include <rtl/math.hxx>
42 #include <shellres.hxx>
43 #include <svl/numformat.hxx>
44 #include <svl/languageoptions.hxx>
45 #include <swmodule.hxx>
46 #include <swtypes.hxx>
47 #include <unotools/charclass.hxx>
48 #include <unotools/localedatawrapper.hxx>
49 #include <unotools/useroptions.hxx>
50 #include <usrfld.hxx>
51 #include <utility>
52 #include <viewsh.hxx>
53 #include <com/sun/star/i18n/KParseTokens.hpp>
54 #include <com/sun/star/i18n/KParseType.hpp>
56 using namespace ::com::sun::star;
58 const char sCalc_Add[] = "add";
59 const char sCalc_Sub[] = "sub";
60 const char sCalc_Mul[] = "mul";
61 const char sCalc_Div[] = "div";
62 const char sCalc_Phd[] = "phd";
63 const char sCalc_Sqrt[] = "sqrt";
64 const char sCalc_Pow[] = "pow";
65 const char sCalc_Or[] = "or";
66 const char sCalc_Xor[] = "xor";
67 const char sCalc_And[] = "and";
68 const char sCalc_Not[] = "not";
69 const char sCalc_Eq[] = "eq";
70 const char sCalc_Neq[] = "neq";
71 const char sCalc_Leq[] = "leq";
72 const char sCalc_Geq[] = "geq";
73 const char sCalc_L[] = "l";
74 const char sCalc_G[] = "g";
75 const char sCalc_Sum[] = "sum";
76 const char sCalc_Mean[] = "mean";
77 const char sCalc_Min[] = "min";
78 const char sCalc_Max[] = "max";
79 const char sCalc_Sin[] = "sin";
80 const char sCalc_Cos[] = "cos";
81 const char sCalc_Tan[] = "tan";
82 const char sCalc_Asin[] = "asin";
83 const char sCalc_Acos[] = "acos";
84 const char sCalc_Atan[] = "atan";
85 const char sCalc_Round[]= "round";
86 const char sCalc_Date[] = "date";
87 const char sCalc_Product[] = "product";
88 const char sCalc_Average[] = "average";
89 const char sCalc_Count[]= "count";
90 const char sCalc_Sign[] = "sign";
91 const char sCalc_Abs[] = "abs";
92 const char sCalc_Int[] = "int";
94 // ATTENTION: sorted list of all operators
95 struct CalcOp
97 union{
98 const char* pName;
99 const OUString* pUName;
101 SwCalcOper eOp;
104 CalcOp const aOpTable[] = {
105 /* ABS */ {{sCalc_Abs}, CALC_ABS}, // Abs (since LibreOffice 7.1)
106 /* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arc cosine
107 /* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
108 /* AND */ {{sCalc_And}, CALC_AND}, // log. AND
109 /* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arc sine
110 /* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arc tangent
111 /* AVERAGE */ {{sCalc_Average}, CALC_AVERAGE}, // Average (since LibreOffice 7.1)
112 /* COS */ {{sCalc_Cos}, CALC_COS}, // Cosine
113 /* COUNT */ {{sCalc_Count}, CALC_COUNT}, // Count (since LibreOffice 7.1)
114 /* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
115 /* DIV */ {{sCalc_Div}, CALC_DIV}, // Division
116 /* EQ */ {{sCalc_Eq}, CALC_EQ}, // Equality
117 /* G */ {{sCalc_G}, CALC_GRE}, // Greater than
118 /* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // Greater or equal
119 /* INT */ {{sCalc_Int}, CALC_INT}, // Int (since LibreOffice 7.4)
120 /* L */ {{sCalc_L}, CALC_LES}, // Less than
121 /* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // Less or equal
122 /* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximum value
123 /* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mean
124 /* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimum value
125 /* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplication
126 /* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // Not equal
127 /* NOT */ {{sCalc_Not}, CALC_NOT}, // log. NOT
128 /* OR */ {{sCalc_Or}, CALC_OR}, // log. OR
129 /* PHD */ {{sCalc_Phd}, CALC_PHD}, // Percentage
130 /* POW */ {{sCalc_Pow}, CALC_POW}, // Exponentiation
131 /* PRODUCT */ {{sCalc_Product}, CALC_PRODUCT}, // Product (since LibreOffice 7.1)
132 /* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Rounding
133 /* SIGN */ {{sCalc_Sign}, CALC_SIGN}, // Sign (since LibreOffice 7.1)
134 /* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sine
135 /* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Square root
136 /* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraction
137 /* SUM */ {{sCalc_Sum}, CALC_SUM}, // Sum
138 /* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangent
139 /* XOR */ {{sCalc_Xor}, CALC_XOR} // log. XOR
142 double const nRoundVal[] = {
143 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
144 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
145 0.5e-15,0.5e-16
148 // First character may be any alphabetic or underscore.
149 const sal_Int32 coStartFlags =
150 i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
151 i18n::KParseTokens::ASC_UNDERSCORE |
152 i18n::KParseTokens::IGNORE_LEADING_WS;
154 // Continuing characters may be any alphanumeric, underscore, or dot.
155 const sal_Int32 coContFlags =
156 (coStartFlags | i18n::KParseTokens::ASC_DOT | i18n::KParseTokens::GROUP_SEPARATOR_IN_NUMBER)
157 & ~i18n::KParseTokens::IGNORE_LEADING_WS;
159 extern "C" {
160 static int OperatorCompare( const void *pFirst, const void *pSecond)
162 int nRet = 0;
163 if( CALC_NAME == static_cast<const CalcOp*>(pFirst)->eOp )
165 if( CALC_NAME == static_cast<const CalcOp*>(pSecond)->eOp )
166 nRet = static_cast<const CalcOp*>(pFirst)->pUName->compareTo(
167 *static_cast<const CalcOp*>(pSecond)->pUName );
168 else
169 nRet = static_cast<const CalcOp*>(pFirst)->pUName->compareToAscii(
170 static_cast<const CalcOp*>(pSecond)->pName );
172 else
174 if( CALC_NAME == static_cast<const CalcOp*>(pSecond)->eOp )
175 nRet = -1 * static_cast<const CalcOp*>(pSecond)->pUName->compareToAscii(
176 static_cast<const CalcOp*>(pFirst)->pName );
177 else
178 nRet = strcmp( static_cast<const CalcOp*>(pFirst)->pName,
179 static_cast<const CalcOp*>(pSecond)->pName );
181 return nRet;
183 }// extern "C"
185 CalcOp* FindOperator( const OUString& rSrch )
187 CalcOp aSrch;
188 aSrch.pUName = &rSrch;
189 aSrch.eOp = CALC_NAME;
191 return static_cast<CalcOp*>(bsearch( static_cast<void*>(&aSrch),
192 static_cast<void const *>(aOpTable),
193 SAL_N_ELEMENTS( aOpTable ),
194 sizeof( CalcOp ),
195 OperatorCompare ));
198 // static
199 LanguageType SwCalc::GetDocAppScriptLang( SwDoc const & rDoc )
201 TypedWhichId<SvxLanguageItem> nWhich =
202 GetWhichOfScript( RES_CHRATR_LANGUAGE,
203 SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetAppLanguage() ));
204 return rDoc.GetDefault(nWhich).GetLanguage();
207 static double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
209 double nRet = 0;
210 SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
211 if( pFormatter )
213 const Date& rNull = pFormatter->GetNullDate();
214 Date aDate( nDate >> 24, (nDate& 0x00FF0000) >> 16, nDate& 0x0000FFFF );
215 nRet = aDate - rNull;
217 return nRet;
220 SwCalc::SwCalc( SwDoc& rD )
221 : m_aVarTable(TBLSZ)
222 , m_aErrExpr( OUString(), SwSbxValue(), nullptr )
223 , m_nCommandPos(0)
224 , m_rDoc( rD )
225 , m_pCharClass( &GetAppCharClass() )
226 , m_nListPor( 0 )
227 , m_bHasNumber( false )
228 , m_eCurrOper( CALC_NAME )
229 , m_eCurrListOper( CALC_NAME )
230 , m_eError( SwCalcError::NONE )
232 m_aErrExpr.aStr = "~C_ERR~";
233 LanguageType eLang = GetDocAppScriptLang( m_rDoc );
234 LanguageTag aLanguageTag( eLang );
236 if( eLang != m_pCharClass->getLanguageTag().getLanguageType() )
238 m_pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), aLanguageTag );
240 m_xLocaleDataWrapper.reset(new LocaleDataWrapper( std::move(aLanguageTag) ));
242 m_sCurrSym = comphelper::string::strip(m_xLocaleDataWrapper->getCurrSymbol(), ' ');
243 m_sCurrSym = m_pCharClass->lowercase( m_sCurrSym );
245 static char const
246 sNType0[] = "false",
247 sNType1[] = "true",
248 sNType2[] = "pi",
249 sNType3[] = "e",
250 sNType4[] = "tables",
251 sNType5[] = "graf",
252 sNType6[] = "ole",
253 sNType7[] = "page",
254 sNType8[] = "para",
255 sNType9[] = "word",
256 sNType10[]= "char",
258 sNType11[] = "user_firstname" ,
259 sNType12[] = "user_lastname" ,
260 sNType13[] = "user_initials" ,
261 sNType14[] = "user_company" ,
262 sNType15[] = "user_street" ,
263 sNType16[] = "user_country" ,
264 sNType17[] = "user_zipcode" ,
265 sNType18[] = "user_city" ,
266 sNType19[] = "user_title" ,
267 sNType20[] = "user_position" ,
268 sNType21[] = "user_tel_work" ,
269 sNType22[] = "user_tel_home" ,
270 sNType23[] = "user_fax" ,
271 sNType24[] = "user_email" ,
272 sNType25[] = "user_state" ,
273 sNType26[] = "graph"
275 static const char* const sNTypeTab[ 27 ] =
277 sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
278 sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
279 sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
280 sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
281 sNType24,
283 // those have two HashIds
284 sNType25, sNType26
286 static sal_uInt16 const aHashValue[ 27 ] =
288 34, 38, 43, 7, 18, 32, 22, 29, 30, 33, 3,
289 28, 24, 40, 9, 11, 26, 45, 4, 23, 36, 44, 19, 5, 1,
290 // those have two HashIds
291 11, 38
293 static UserOptToken const aAdrToken[ 12 ] =
295 UserOptToken::Company, UserOptToken::Street, UserOptToken::Country, UserOptToken::Zip,
296 UserOptToken::City, UserOptToken::Title, UserOptToken::Position, UserOptToken::TelephoneWork,
297 UserOptToken::TelephoneHome, UserOptToken::Fax, UserOptToken::Email, UserOptToken::State
300 static sal_uInt16 SwDocStat::* const aDocStat1[ 3 ] =
302 &SwDocStat::nTable, &SwDocStat::nGrf, &SwDocStat::nOLE
304 static sal_uLong SwDocStat::* const aDocStat2[ 4 ] =
306 &SwDocStat::nPage, &SwDocStat::nPara,
307 &SwDocStat::nWord, &SwDocStat::nChar
310 #if TBLSZ != 47
311 #error Did you adjust all hash values?
312 #endif
314 const SwDocStat& rDocStat = m_rDoc.getIDocumentStatistics().GetDocStat();
316 SwSbxValue nVal;
317 OUString sTmpStr;
318 sal_uInt16 n;
320 for( n = 0; n < 25; ++n )
322 sTmpStr = OUString::createFromAscii(sNTypeTab[n]);
323 m_aVarTable[ aHashValue[ n ] ].reset( new SwCalcExp( sTmpStr, nVal, nullptr ) );
326 m_aVarTable[ aHashValue[ 0 ] ]->nValue.PutBool( false );
327 m_aVarTable[ aHashValue[ 1 ] ]->nValue.PutBool( true );
328 m_aVarTable[ aHashValue[ 2 ] ]->nValue.PutDouble( M_PI );
329 m_aVarTable[ aHashValue[ 3 ] ]->nValue.PutDouble( M_E );
331 for( n = 0; n < 3; ++n )
332 m_aVarTable[ aHashValue[ n + 4 ] ]->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
333 for( n = 0; n < 4; ++n )
334 m_aVarTable[ aHashValue[ n + 7 ] ]->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
336 SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
338 m_aVarTable[ aHashValue[ 11 ] ]->nValue.PutString( rUserOptions.GetFirstName() );
339 m_aVarTable[ aHashValue[ 12 ] ]->nValue.PutString( rUserOptions.GetLastName() );
340 m_aVarTable[ aHashValue[ 13 ] ]->nValue.PutString( rUserOptions.GetID() );
342 for( n = 0; n < 11; ++n )
343 m_aVarTable[ aHashValue[ n + 14 ] ]->nValue.PutString(
344 rUserOptions.GetToken( aAdrToken[ n ] ));
346 nVal.PutString( rUserOptions.GetToken( aAdrToken[ 11 ] ));
347 sTmpStr = OUString::createFromAscii(sNTypeTab[25]);
348 m_aVarTable[ aHashValue[ 25 ] ]->pNext.reset( new SwCalcExp( sTmpStr, nVal, nullptr ) );
350 } // SwCalc::SwCalc
352 void SwCalc::ImplDestroy()
354 if( m_pCharClass != &GetAppCharClass() )
355 delete m_pCharClass;
358 SwCalc::~SwCalc()
360 suppress_fun_call_w_exception(ImplDestroy());
363 SwSbxValue SwCalc::Calculate( const OUString& rStr )
365 m_eError = SwCalcError::NONE;
366 SwSbxValue nResult;
368 if( rStr.isEmpty() )
369 return nResult;
371 m_nListPor = 0;
372 m_eCurrListOper = CALC_PLUS; // default: sum
374 m_sCommand = rStr;
375 m_nCommandPos = 0;
377 for (;;)
379 m_eCurrOper = GetToken();
380 if (m_eCurrOper == CALC_ENDCALC || m_eError != SwCalcError::NONE )
381 break;
382 nResult = Expr();
385 if( m_eError != SwCalcError::NONE)
386 nResult.PutDouble( DBL_MAX );
388 return nResult;
391 OUString SwCalc::GetStrResult( const SwSbxValue& rVal )
393 if( !rVal.IsDouble() )
395 return rVal.GetOUString();
397 return GetStrResult( rVal.GetDouble() );
400 OUString SwCalc::GetStrResult( double nValue )
402 if( nValue >= DBL_MAX )
403 switch( m_eError )
405 case SwCalcError::Syntax : return SwViewShell::GetShellRes()->aCalc_Syntax;
406 case SwCalcError::DivByZero : return SwViewShell::GetShellRes()->aCalc_ZeroDiv;
407 case SwCalcError::FaultyBrackets : return SwViewShell::GetShellRes()->aCalc_Brack;
408 case SwCalcError::OverflowInPower : return SwViewShell::GetShellRes()->aCalc_Pow;
409 case SwCalcError::Overflow : return SwViewShell::GetShellRes()->aCalc_Overflow;
410 default : return SwViewShell::GetShellRes()->aCalc_Default;
413 const sal_Int32 nDecPlaces = 15;
414 OUString aRetStr( ::rtl::math::doubleToUString(
415 nValue,
416 rtl_math_StringFormat_Automatic,
417 nDecPlaces,
418 m_xLocaleDataWrapper->getNumDecimalSep()[0],
419 true ));
420 return aRetStr;
423 SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
425 OUString aStr = m_pCharClass->lowercase( rStr );
426 return VarLook( aStr, true );
429 SwCalcExp* SwCalc::VarLook( const OUString& rStr, bool bIns )
431 m_aErrExpr.nValue.SetVoidValue(false);
433 sal_uInt32 ii = 0;
434 OUString aStr = m_pCharClass->lowercase( rStr );
436 SwCalcExp* pFnd = m_aVarTable.Find(aStr, &ii);
438 if( !pFnd )
440 // then check doc
441 SwHashTable<SwCalcFieldType> const & rDocTable = m_rDoc.getIDocumentFieldsAccess().GetUpdateFields().GetFieldTypeTable();
442 for( SwHash* pEntry = rDocTable[ii].get(); pEntry; pEntry = pEntry->pNext.get() )
444 if( aStr == pEntry->aStr )
446 // then insert here
447 pFnd = new SwCalcExp( aStr, SwSbxValue(),
448 static_cast<SwCalcFieldType*>(pEntry)->pFieldType );
449 pFnd->pNext = std::move( m_aVarTable[ii] );
450 m_aVarTable[ii].reset(pFnd);
451 break;
456 if( pFnd )
458 if( pFnd->pFieldType && pFnd->pFieldType->Which() == SwFieldIds::User )
460 SwUserFieldType* pUField = const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFnd->pFieldType));
461 if( nsSwGetSetExpType::GSE_STRING & pUField->GetType() )
463 pFnd->nValue.PutString( pUField->GetContent() );
465 else if( !pUField->IsValid() )
467 // Save the current values...
468 sal_uInt16 nListPor = m_nListPor;
469 bool bHasNumber = m_bHasNumber;
470 SwSbxValue nLastLeft = m_nLastLeft;
471 SwSbxValue nNumberValue = m_nNumberValue;
472 sal_Int32 nCommandPos = m_nCommandPos;
473 SwCalcOper eCurrOper = m_eCurrOper;
474 SwCalcOper eCurrListOper = m_eCurrListOper;
475 OUString sCurrCommand = m_sCommand;
477 pFnd->nValue.PutDouble( pUField->GetValue( *this ) );
479 // ...and write them back.
480 m_nListPor = nListPor;
481 m_bHasNumber = bHasNumber;
482 m_nLastLeft = nLastLeft;
483 m_nNumberValue = nNumberValue;
484 m_nCommandPos = nCommandPos;
485 m_eCurrOper = eCurrOper;
486 m_eCurrListOper = eCurrListOper;
487 m_sCommand = sCurrCommand;
489 else
491 pFnd->nValue.PutDouble( pUField->GetValue() );
494 else if ( !pFnd->pFieldType && pFnd->nValue.IsDBvalue() )
496 if ( pFnd->nValue.IsString() )
497 m_aErrExpr.nValue.PutString( pFnd->nValue.GetOUString() );
498 else if ( pFnd->nValue.IsDouble() )
499 m_aErrExpr.nValue.PutDouble( pFnd->nValue.GetDouble() );
500 pFnd = &m_aErrExpr;
502 return pFnd;
505 // At this point the "real" case variable has to be used
506 OUString const sTmpName( ::ReplacePoint(rStr) );
508 if( !bIns )
510 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
511 SwDBManager *pMgr = m_rDoc.GetDBManager();
512 OUString sDBName(GetDBName( sTmpName ));
513 OUString sSourceName(sDBName.getToken(0, DB_DELIM));
514 OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
515 if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
516 pMgr->OpenDataSource(sSourceName, sTableName))
518 OUString sColumnName( GetColumnName( sTmpName ));
519 OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name");
521 OUString sDBNum( SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber) );
522 sDBNum = m_pCharClass->lowercase(sDBNum);
524 // Initialize again because this doesn't happen in docfld anymore for
525 // elements != SwFieldIds::Database. E.g. if there is an expression field before
526 // a DB_Field in a document.
527 const sal_uInt32 nTmpRec = pMgr->GetSelectedRecordId(sSourceName, sTableName);
528 VarChange(sDBNum, nTmpRec);
530 if( sDBNum.equalsIgnoreAsciiCase(sColumnName) )
532 m_aErrExpr.nValue.PutULong(nTmpRec);
533 return &m_aErrExpr;
536 OUString sResult;
537 double nNumber = DBL_MAX;
539 LanguageType nLang = m_xLocaleDataWrapper->getLanguageTag().getLanguageType();
540 if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
541 nTmpRec, nLang, sResult, &nNumber ))
543 if (nNumber != DBL_MAX)
544 m_aErrExpr.nValue.PutDouble( nNumber );
545 else
546 m_aErrExpr.nValue.PutString( sResult );
548 return &m_aErrExpr;
551 else
552 #endif
554 //data source was not available - set return to "NoValue"
555 m_aErrExpr.nValue.SetVoidValue(true);
557 // NEVER save!
558 return &m_aErrExpr;
561 SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), nullptr );
562 pNewExp->pNext = std::move( m_aVarTable[ ii ] );
563 m_aVarTable[ ii ].reset( pNewExp );
565 OUString sColumnName( GetColumnName( sTmpName ));
566 OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
567 if( sColumnName.equalsIgnoreAsciiCase(
568 SwFieldType::GetTypeStr( SwFieldTypesEnum::DatabaseSetNumber ) ))
570 #if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
571 SwDBManager *pMgr = m_rDoc.GetDBManager();
572 OUString sDBName(GetDBName( sTmpName ));
573 OUString sSourceName(sDBName.getToken(0, DB_DELIM));
574 OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
575 if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
576 pMgr->OpenDataSource(sSourceName, sTableName) &&
577 !pMgr->IsInMerge())
579 pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
581 else
582 #endif
584 pNewExp->nValue.SetVoidValue(true);
588 return pNewExp;
591 void SwCalc::VarChange( const OUString& rStr, double nValue )
593 SwSbxValue aVal( nValue );
594 VarChange( rStr, aVal );
597 void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
599 OUString aStr = m_pCharClass->lowercase( rStr );
601 sal_uInt32 nPos = 0;
602 SwCalcExp* pFnd = m_aVarTable.Find( aStr, &nPos );
604 if( !pFnd )
606 pFnd = new SwCalcExp( aStr, rValue, nullptr );
607 pFnd->pNext = std::move( m_aVarTable[ nPos ] );
608 m_aVarTable[ nPos ].reset( pFnd );
610 else
612 pFnd->nValue = rValue;
616 bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
618 if( m_aRekurStack.end() != std::find(m_aRekurStack.begin(), m_aRekurStack.end(), pUserFieldType ) )
619 return false;
621 m_aRekurStack.push_back( pUserFieldType );
622 return true;
625 void SwCalc::Pop()
627 OSL_ENSURE( m_aRekurStack.size(), "SwCalc: Pop on an invalid pointer" );
629 m_aRekurStack.pop_back();
632 const CharClass* SwCalc::GetCharClass() const
634 return m_pCharClass;
637 void SwCalc::SetCharClass(const LanguageTag& rLanguageTag)
639 m_pCharClass = new CharClass( ::comphelper::getProcessComponentContext(), rLanguageTag );
642 SwCalcOper SwCalc::GetToken()
644 if( m_nCommandPos >= m_sCommand.getLength() )
646 m_eCurrOper = CALC_ENDCALC;
647 return m_eCurrOper;
650 using namespace ::com::sun::star::i18n;
652 // Parse any token.
653 ParseResult aRes = m_pCharClass->parseAnyToken( m_sCommand, m_nCommandPos,
654 coStartFlags, OUString(),
655 coContFlags, OUString());
657 bool bSetError = true;
658 sal_Int32 nRealStt = m_nCommandPos + aRes.LeadingWhiteSpace;
659 if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
661 m_nNumberValue.PutDouble( aRes.Value );
662 m_eCurrOper = CALC_NUMBER;
663 bSetError = false;
665 else if( aRes.TokenType & KParseType::IDENTNAME )
667 OUString aName( m_sCommand.copy( nRealStt,
668 aRes.EndPos - nRealStt ) );
669 //#101436#: The variable may contain a database name. It must not be
670 // converted to lower case! Instead all further comparisons must be
671 // done case-insensitive
672 OUString sLowerCaseName = m_pCharClass->lowercase( aName );
673 // catch currency symbol
674 if( sLowerCaseName == m_sCurrSym )
676 m_nCommandPos = aRes.EndPos;
677 return GetToken(); // call again
680 // catch operators
681 CalcOp* pFnd = ::FindOperator( sLowerCaseName );
682 if( pFnd )
684 m_eCurrOper = pFnd->eOp;
685 switch( m_eCurrOper )
687 case CALC_SUM:
688 case CALC_MEAN:
689 case CALC_AVERAGE:
690 case CALC_COUNT:
691 m_eCurrListOper = CALC_PLUS;
692 break;
693 case CALC_MIN:
694 m_eCurrListOper = CALC_MIN_IN;
695 break;
696 case CALC_MAX:
697 m_eCurrListOper = CALC_MAX_IN;
698 break;
699 case CALC_DATE:
700 m_eCurrListOper = CALC_MONTH;
701 break;
702 case CALC_PRODUCT:
703 m_eCurrListOper = CALC_MUL;
704 break;
705 default:
706 break;
708 m_nCommandPos = aRes.EndPos;
709 return m_eCurrOper;
711 m_aVarName = aName;
712 m_eCurrOper = CALC_NAME;
713 bSetError = false;
715 else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
717 m_nNumberValue.PutString( aRes.DequotedNameOrString );
718 m_eCurrOper = CALC_NUMBER;
719 bSetError = false;
721 else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
723 std::u16string_view aName( m_sCommand.subView( nRealStt,
724 aRes.EndPos - nRealStt ));
725 if( 1 == aName.size() )
727 bSetError = false;
728 sal_Unicode ch = aName[0];
729 switch( ch )
731 case ';':
732 if( CALC_MONTH == m_eCurrListOper || CALC_DAY == m_eCurrListOper )
734 m_eCurrOper = m_eCurrListOper;
735 break;
737 [[fallthrough]];
738 case '\n':
739 m_eCurrOper = CALC_PRINT;
740 break;
742 case '%':
743 case '^':
744 case '*':
745 case '/':
746 case '+':
747 case '-':
748 case '(':
749 case ')':
750 m_eCurrOper = SwCalcOper(ch);
751 break;
753 case '=':
754 case '!':
756 SwCalcOper eTmp2;
757 if( '=' == ch )
759 m_eCurrOper = SwCalcOper('=');
760 eTmp2 = CALC_EQ;
762 else
764 m_eCurrOper = CALC_NOT;
765 eTmp2 = CALC_NEQ;
768 if( aRes.EndPos < m_sCommand.getLength() &&
769 '=' == m_sCommand[aRes.EndPos] )
771 m_eCurrOper = eTmp2;
772 ++aRes.EndPos;
775 break;
777 case cListDelim:
778 m_eCurrOper = m_eCurrListOper;
779 break;
781 case '[':
782 if( aRes.EndPos < m_sCommand.getLength() )
784 m_aVarName.setLength(0);
785 sal_Int32 nFndPos = aRes.EndPos,
786 nSttPos = nFndPos;
788 do {
789 nFndPos = m_sCommand.indexOf( ']', nFndPos );
790 if( -1 != nFndPos )
792 // ignore the ]
793 if ('\\' == m_sCommand[nFndPos-1])
795 m_aVarName.append(m_sCommand.subView(nSttPos,
796 nFndPos - nSttPos - 1) );
797 nSttPos = ++nFndPos;
799 else
800 break;
802 } while( nFndPos != -1 );
804 if( nFndPos != -1 )
806 if( nSttPos != nFndPos )
807 m_aVarName.append(m_sCommand.subView(nSttPos,
808 nFndPos - nSttPos) );
809 aRes.EndPos = nFndPos + 1;
810 m_eCurrOper = CALC_NAME;
812 else
813 bSetError = true;
815 else
817 bSetError = true;
819 break;
821 default:
822 bSetError = true;
823 break;
827 else if( aRes.TokenType & KParseType::BOOLEAN )
829 std::u16string_view aName( m_sCommand.subView( nRealStt,
830 aRes.EndPos - nRealStt ));
831 if( !aName.empty() )
833 sal_Unicode ch = aName[0];
835 bSetError = true;
836 if ('<' == ch || '>' == ch)
838 bSetError = false;
840 SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
841 m_eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
843 if( 2 == aName.size() && '=' == aName[1] )
844 m_eCurrOper = eTmp2;
845 else if( 1 != aName.size() )
846 bSetError = true;
850 else if( nRealStt == m_sCommand.getLength() )
852 m_eCurrOper = CALC_ENDCALC;
853 bSetError = false;
856 if( bSetError )
858 m_eError = SwCalcError::Syntax;
859 m_eCurrOper = CALC_PRINT;
861 m_nCommandPos = aRes.EndPos;
864 return m_eCurrOper;
867 SwSbxValue SwCalc::Term()
869 SwSbxValue left( Prim() );
870 m_nLastLeft = left;
871 for(;;)
873 sal_uInt16 nSbxOper = USHRT_MAX;
875 switch( m_eCurrOper )
877 case CALC_AND:
879 GetToken();
880 bool bB = Prim().GetBool();
881 left.PutBool( left.GetBool() && bB );
883 break;
884 case CALC_OR:
886 GetToken();
887 bool bB = Prim().GetBool();
888 left.PutBool( left.GetBool() || bB );
890 break;
891 case CALC_XOR:
893 GetToken();
894 bool bR = Prim().GetBool();
895 bool bL = left.GetBool();
896 left.PutBool(bL != bR);
898 break;
900 case CALC_EQ: nSbxOper = SbxEQ; break;
901 case CALC_NEQ: nSbxOper = SbxNE; break;
902 case CALC_LEQ: nSbxOper = SbxLE; break;
903 case CALC_GEQ: nSbxOper = SbxGE; break;
904 case CALC_GRE: nSbxOper = SbxGT; break;
905 case CALC_LES: nSbxOper = SbxLT; break;
907 case CALC_MUL: nSbxOper = SbxMUL; break;
908 case CALC_DIV: nSbxOper = SbxDIV; break;
910 case CALC_MIN_IN:
912 GetToken();
913 SwSbxValue e = Prim();
914 left = left.GetDouble() < e.GetDouble() ? left : e;
916 break;
917 case CALC_MAX_IN:
919 GetToken();
920 SwSbxValue e = Prim();
921 left = left.GetDouble() > e.GetDouble() ? left : e;
923 break;
924 case CALC_MONTH:
926 GetToken();
927 SwSbxValue e = Prim();
928 sal_Int32 nYear = static_cast<sal_Int32>(floor( left.GetDouble() ));
929 nYear = nYear & 0x0000FFFF;
930 sal_Int32 nMonth = static_cast<sal_Int32>(floor( e.GetDouble() ));
931 nMonth = ( nMonth & 0x000000FF ) << 16;
932 left.PutLong( nMonth + nYear );
933 m_eCurrOper = CALC_DAY;
935 break;
936 case CALC_DAY:
938 GetToken();
939 SwSbxValue e = Prim();
940 sal_Int32 nYearMonth = static_cast<sal_Int32>(floor( left.GetDouble() ));
941 nYearMonth = nYearMonth & 0x00FFFFFF;
942 sal_Int32 nDay = static_cast<sal_Int32>(floor( e.GetDouble() ));
943 nDay = ( nDay & 0x000000FF ) << 24;
944 left = lcl_ConvertToDateValue( m_rDoc, nDay + nYearMonth );
946 break;
947 case CALC_ROUND:
949 GetToken();
950 SwSbxValue e = Prim();
952 double fVal = 0;
953 double fFac = 1;
954 sal_Int32 nDec = static_cast<sal_Int32>(floor( e.GetDouble() ));
955 if( nDec < -20 || nDec > 20 )
957 m_eError = SwCalcError::Overflow;
958 left.Clear();
959 return left;
961 fVal = left.GetDouble();
962 if( nDec >= 0)
964 for (sal_Int32 i = 0; i < nDec; ++i )
965 fFac *= 10.0;
967 else
969 for (sal_Int32 i = 0; i < -nDec; ++i )
970 fFac /= 10.0;
973 fVal *= fFac;
974 bool bSign;
975 if (fVal < 0.0)
977 fVal *= -1.0;
978 bSign = true;
980 else
982 bSign = false;
985 // rounding
986 double fNum = fVal; // find the exponent
987 int nExp = 0;
988 if( fNum > 0 )
990 while( fNum < 1.0 )
992 fNum *= 10.0;
993 --nExp;
995 while( fNum >= 10.0 )
997 fNum /= 10.0;
998 ++nExp;
1001 nExp = 15 - nExp;
1002 if( nExp > 15 )
1003 nExp = 15;
1004 else if( nExp <= 1 )
1005 nExp = 0;
1006 fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1008 if (bSign)
1009 fVal *= -1.0;
1011 fVal /= fFac;
1013 left.PutDouble( fVal );
1015 break;
1017 //#77448# (=2*3^2 != 18)
1019 default:
1020 return left;
1023 if( USHRT_MAX != nSbxOper )
1025 // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1026 SbxOperator eSbxOper = static_cast<SbxOperator>(nSbxOper);
1028 GetToken();
1029 if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1031 left.PutBool( left.Compare( eSbxOper, Prim() ));
1033 else
1035 SwSbxValue aRight( Prim() );
1036 aRight.MakeDouble();
1037 left.MakeDouble();
1039 if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1040 m_eError = SwCalcError::DivByZero;
1041 else
1042 left.Compute( eSbxOper, aRight );
1048 SwSbxValue SwCalc::StdFunc(pfCalc pFnc, bool bChkTrig)
1050 SwSbxValue nErg;
1051 GetToken();
1052 double nVal = Prim().GetDouble();
1053 if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1054 nErg.PutDouble( (*pFnc)( nVal ) );
1055 else
1056 m_eError = SwCalcError::Overflow;
1057 return nErg;
1060 SwSbxValue SwCalc::PrimFunc(bool &rChkPow)
1062 rChkPow = false;
1064 switch (m_eCurrOper)
1066 case CALC_SIN:
1067 SAL_INFO("sw.calc", "sin");
1068 return StdFunc(&sin, false);
1069 case CALC_COS:
1070 SAL_INFO("sw.calc", "cos");
1071 return StdFunc(&cos, false);
1072 case CALC_TAN:
1073 SAL_INFO("sw.calc", "tan");
1074 return StdFunc(&tan, false);
1075 case CALC_ATAN:
1076 SAL_INFO("sw.calc", "atan");
1077 return StdFunc(&atan, false);
1078 case CALC_ASIN:
1079 SAL_INFO("sw.calc", "asin");
1080 return StdFunc(&asin, true);
1081 case CALC_ACOS:
1082 SAL_INFO("sw.calc", "acos");
1083 return StdFunc(&acos, true);
1084 case CALC_ABS:
1085 SAL_INFO("sw.calc", "abs");
1086 return StdFunc(&abs, false);
1087 case CALC_SIGN:
1089 SAL_INFO("sw.calc", "sign");
1090 SwSbxValue nErg;
1091 GetToken();
1092 double nVal = Prim().GetDouble();
1093 nErg.PutDouble( int(0 < nVal) - int(nVal < 0) );
1094 return nErg;
1096 case CALC_INT:
1098 SAL_INFO("sw.calc", "int");
1099 SwSbxValue nErg;
1100 GetToken();
1101 sal_Int32 nVal = static_cast<sal_Int32>( Prim().GetDouble() );
1102 nErg.PutDouble( nVal );
1103 return nErg;
1105 case CALC_NOT:
1107 SAL_INFO("sw.calc", "not");
1108 GetToken();
1109 SwSbxValue nErg = Prim();
1110 if( SbxSTRING == nErg.GetType() )
1112 nErg.PutBool( nErg.GetOUString().isEmpty() );
1114 else if(SbxBOOL == nErg.GetType() )
1116 nErg.PutBool(!nErg.GetBool());
1118 // Evaluate arguments manually so that the binary NOT below does not
1119 // get called. We want a BOOLEAN NOT.
1120 else if (nErg.IsNumeric())
1122 nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1124 else
1126 OSL_FAIL( "unexpected case. computing binary NOT" );
1127 //!! computes a binary NOT
1128 nErg.Compute( SbxNOT, nErg );
1130 return nErg;
1132 case CALC_NUMBER:
1134 SAL_INFO("sw.calc", "number: " << m_nNumberValue.GetDouble());
1135 SwSbxValue nErg;
1136 m_bHasNumber = true;
1137 if( GetToken() == CALC_PHD )
1139 double aTmp = m_nNumberValue.GetDouble();
1140 aTmp *= 0.01;
1141 nErg.PutDouble( aTmp );
1142 GetToken();
1144 else if( m_eCurrOper == CALC_NAME )
1146 m_eError = SwCalcError::Syntax;
1148 else
1150 nErg = m_nNumberValue;
1151 rChkPow = true;
1153 return nErg;
1155 case CALC_NAME:
1157 SAL_INFO("sw.calc", "name");
1158 SwSbxValue nErg;
1159 switch(SwCalcOper eOper = GetToken())
1161 case CALC_ASSIGN:
1163 SwCalcExp* n = VarInsert(m_aVarName.toString());
1164 GetToken();
1165 nErg = n->nValue = Expr();
1166 break;
1168 default:
1169 nErg = VarLook(m_aVarName.toString())->nValue;
1170 // Explicitly disallow unknown function names (followed by "("),
1171 // allow unknown variable names (equal to zero)
1172 if (nErg.IsVoidValue() && (eOper == CALC_LP))
1173 m_eError = SwCalcError::Syntax;
1174 else
1175 rChkPow = true;
1176 break;
1178 return nErg;
1180 case CALC_MINUS:
1182 SAL_INFO("sw.calc", "-");
1183 SwSbxValue nErg;
1184 GetToken();
1185 nErg.PutDouble( -(Prim().GetDouble()) );
1186 return nErg;
1188 case CALC_LP:
1190 SAL_INFO("sw.calc", "(");
1191 GetToken();
1192 SwSbxValue nErg = Expr();
1193 if( m_eCurrOper != CALC_RP )
1195 m_eError = SwCalcError::FaultyBrackets;
1197 else
1199 GetToken();
1200 rChkPow = true; // in order for =(7)^2 to work
1202 return nErg;
1204 case CALC_RP:
1205 // ignore, see tdf#121962
1206 SAL_INFO("sw.calc", ")");
1207 break;
1208 case CALC_MEAN:
1209 case CALC_AVERAGE:
1211 SAL_INFO("sw.calc", "mean");
1212 m_nListPor = 1;
1213 m_bHasNumber = CALC_MEAN == m_eCurrOper;
1214 GetToken();
1215 SwSbxValue nErg = Expr();
1216 double aTmp = nErg.GetDouble();
1217 aTmp /= m_nListPor;
1218 if ( !m_bHasNumber )
1219 m_eError = SwCalcError::DivByZero;
1220 else
1221 nErg.PutDouble( aTmp );
1222 return nErg;
1224 case CALC_COUNT:
1226 SAL_INFO("sw.calc", "count");
1227 m_nListPor = 1;
1228 m_bHasNumber = false;
1229 GetToken();
1230 SwSbxValue nErg = Expr();
1231 nErg.PutDouble( m_bHasNumber ? m_nListPor : 0 );
1232 return nErg;
1234 case CALC_SQRT:
1236 SAL_INFO("sw.calc", "sqrt");
1237 GetToken();
1238 SwSbxValue nErg = Prim();
1239 if( nErg.GetDouble() < 0 )
1240 m_eError = SwCalcError::Overflow;
1241 else
1242 nErg.PutDouble( sqrt( nErg.GetDouble() ));
1243 return nErg;
1245 case CALC_SUM:
1246 case CALC_PRODUCT:
1247 case CALC_DATE:
1248 case CALC_MIN:
1249 case CALC_MAX:
1251 SAL_INFO("sw.calc", "sum/product/date/min/max");
1252 GetToken();
1253 SwSbxValue nErg = Expr();
1254 return nErg;
1256 case CALC_ENDCALC:
1258 SAL_INFO("sw.calc", "endcalc");
1259 SwSbxValue nErg;
1260 nErg.Clear();
1261 return nErg;
1263 default:
1264 SAL_INFO("sw.calc", "syntax error");
1265 m_eError = SwCalcError::Syntax;
1266 break;
1269 return SwSbxValue();
1272 SwSbxValue SwCalc::Prim()
1274 bool bChkPow;
1275 SwSbxValue nErg = PrimFunc(bChkPow);
1277 if (bChkPow && m_eCurrOper == CALC_POW)
1279 double dleft = nErg.GetDouble();
1280 GetToken();
1281 double right = Prim().GetDouble();
1283 double fraction;
1284 fraction = modf( right, &o3tl::temporary(double()) );
1285 if( ( dleft < 0.0 && 0.0 != fraction ) ||
1286 ( 0.0 == dleft && right < 0.0 ) )
1288 m_eError = SwCalcError::Overflow;
1289 nErg.Clear();
1291 else
1293 dleft = pow(dleft, right );
1294 if( dleft == HUGE_VAL )
1296 m_eError = SwCalcError::OverflowInPower;
1297 nErg.Clear();
1299 else
1301 nErg.PutDouble( dleft );
1306 return nErg;
1309 SwSbxValue SwCalc::Expr()
1311 SwSbxValue left = Term();
1312 m_nLastLeft = left;
1313 for(;;)
1315 switch(m_eCurrOper)
1317 case CALC_PLUS:
1319 GetToken();
1320 left.MakeDouble();
1321 SwSbxValue right(Term());
1322 right.MakeDouble();
1323 left.Compute(SbxPLUS, right);
1324 m_nListPor++;
1325 break;
1327 case CALC_MINUS:
1329 GetToken();
1330 left.MakeDouble();
1331 SwSbxValue right(Term());
1332 right.MakeDouble();
1333 left.Compute(SbxMINUS, right);
1334 break;
1336 default:
1338 return left;
1344 OUString SwCalc::GetColumnName(const OUString& rName)
1346 sal_Int32 nPos = rName.indexOf(DB_DELIM);
1347 if( -1 != nPos )
1349 nPos = rName.indexOf(DB_DELIM, nPos + 1);
1351 if( -1 != nPos )
1352 return rName.copy(nPos + 1);
1354 return rName;
1357 OUString SwCalc::GetDBName(std::u16string_view rName)
1359 size_t nPos = rName.find(DB_DELIM);
1360 if( std::u16string_view::npos != nPos )
1362 nPos = rName.find(DB_DELIM, nPos + 1);
1364 if( std::u16string_view::npos != nPos )
1365 return OUString(rName.substr( 0, nPos ));
1367 SwDBData aData = m_rDoc.GetDBData();
1368 return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand;
1371 namespace
1373 bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1374 double& rVal,
1375 const LocaleDataWrapper* const pLclData )
1377 assert(pLclData);
1378 const sal_Unicode nCurrCmdPos = rCommandPos;
1379 rtl_math_ConversionStatus eStatus;
1380 const sal_Unicode* pEnd;
1381 rVal = pLclData->stringToDouble( rCommand.getStr() + rCommandPos,
1382 rCommand.getStr() + rCommand.getLength(),
1383 true,
1384 &eStatus,
1385 &pEnd );
1386 rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1388 return rtl_math_ConversionStatus_Ok == eStatus &&
1389 nCurrCmdPos != rCommandPos;
1393 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1394 double& rVal )
1396 const SvtSysLocale aSysLocale;
1397 return lcl_Str2Double( rCommand, rCommandPos, rVal, &aSysLocale.GetLocaleData() );
1400 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1401 double& rVal, SwDoc const * const pDoc )
1403 const SvtSysLocale aSysLocale;
1404 std::unique_ptr<const LocaleDataWrapper> pLclD;
1405 if( pDoc )
1407 LanguageType eLang = GetDocAppScriptLang( *pDoc );
1408 if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1410 pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1414 bool const bRet = lcl_Str2Double(rCommand, rCommandPos, rVal,
1415 pLclD ? pLclD.get() : &aSysLocale.GetLocaleData());
1417 return bRet;
1420 bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1422 bool bRet = false;
1423 using namespace ::com::sun::star::i18n;
1425 // Parse any token.
1426 ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1427 coStartFlags, OUString(),
1428 coContFlags, OUString() );
1430 if( aRes.TokenType & KParseType::IDENTNAME )
1432 bRet = aRes.EndPos == rStr.getLength();
1433 if( pValidName )
1435 *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1436 aRes.EndPos - aRes.LeadingWhiteSpace );
1439 else if( pValidName )
1440 pValidName->clear();
1442 return bRet;
1445 SwHash::SwHash(OUString _aStr)
1446 : aStr(std::move(_aStr))
1450 SwHash::~SwHash()
1454 SwCalcExp::SwCalcExp(const OUString& rStr, SwSbxValue aVal,
1455 const SwFieldType* pType)
1456 : SwHash(rStr)
1457 , nValue(std::move(aVal))
1458 , pFieldType(pType)
1462 bool SwSbxValue::GetBool() const
1464 return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1465 : SbxValue::GetBool();
1468 double SwSbxValue::GetDouble() const
1470 double nRet;
1471 if( SbxSTRING == GetType() )
1473 sal_Int32 nStt = 0;
1474 SwCalc::Str2Double( GetOUString(), nStt, nRet );
1476 else if (IsBool())
1478 nRet = GetBool() ? 1.0 : 0.0;
1480 else
1482 nRet = SbxValue::GetDouble();
1484 return nRet;
1487 SwSbxValue& SwSbxValue::MakeDouble()
1489 if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1490 PutDouble( GetDouble() );
1491 return *this;
1494 #ifdef STANDALONE_HASHCALC
1496 // this is example code how to create hash values in the CTOR:
1498 #include <stdio.h>
1499 void main()
1501 static char
1502 sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1503 sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1504 sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1505 sNType9[] = "word", sNType10[]= "char",
1506 sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1507 sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1508 sNType15[] = "user_street" , sNType16[] = "user_country" ,
1509 sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1510 sNType19[] = "user_title" , sNType20[] = "user_position" ,
1511 sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1512 sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1513 sNType25[] = "user_state", sNType26[] = "graph"
1516 static const char* sNTypeTab[ 27 ] =
1518 sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1519 sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1520 sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1521 sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1522 sNType24, sNType25, sNType26
1525 const unsigned short nTableSize = 47;
1526 int aArr[ nTableSize ] = { 0 };
1527 char ch;
1529 for( int n = 0; n < 27; ++n )
1531 unsigned int ii = 0;
1532 const char* pp = sNTypeTab[ n ];
1534 while( *pp )
1536 ii = ii << 1 ^ *pp++;
1538 ii %= nTableSize;
1540 ch = aArr[ ii ] ? 'X' : ' ';
1541 aArr[ ii ] = 1;
1542 printf( "%-20s -> %3u [%c]\n", sNTypeTab[ n ], ii, ch );
1546 #endif
1548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */