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