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