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