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_pLocaleDataWrapper( m_aSysLocale.GetLocaleDataPtr() )
222  , m_pCharClass( &GetAppCharClass() )
223  , m_nListPor( 0 )
224  , m_bHasNumber( false )
225  , m_eCurrOper( CALC_NAME )
226  , m_eCurrListOper( CALC_NAME )
227  , m_eError( SwCalcError::NONE )
228 {
229  m_aErrExpr.aStr = "~C_ERR~";
231 
234  {
235  LanguageTag aLanguageTag( eLang );
237  m_pLocaleDataWrapper = new LocaleDataWrapper( aLanguageTag );
238  }
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 {
353  delete m_pLocaleDataWrapper;
354  if( m_pCharClass != &GetAppCharClass() )
355  delete m_pCharClass;
356 }
357 
358 SwSbxValue SwCalc::Calculate( const OUString& rStr )
359 {
361  SwSbxValue nResult;
362 
363  if( rStr.isEmpty() )
364  return nResult;
365 
366  m_nListPor = 0;
367  m_eCurrListOper = CALC_PLUS; // default: sum
368 
369  m_sCommand = rStr;
370  m_nCommandPos = 0;
371 
372  for (;;)
373  {
374  m_eCurrOper = GetToken();
376  break;
377  nResult = Expr();
378  }
379 
381  nResult.PutDouble( DBL_MAX );
382 
383  return nResult;
384 }
385 
386 OUString SwCalc::GetStrResult( const SwSbxValue& rVal )
387 {
388  if( !rVal.IsDouble() )
389  {
390  return rVal.GetOUString();
391  }
392  return GetStrResult( rVal.GetDouble() );
393 }
394 
395 OUString SwCalc::GetStrResult( double nValue )
396 {
397  if( nValue >= DBL_MAX )
398  switch( m_eError )
399  {
405  default : return SwViewShell::GetShellRes()->aCalc_Default;
406  }
407 
408  const sal_Int32 nDecPlaces = 15;
409  OUString aRetStr( ::rtl::math::doubleToUString(
410  nValue,
411  rtl_math_StringFormat_Automatic,
412  nDecPlaces,
414  true ));
415  return aRetStr;
416 }
417 
418 SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
419 {
420  OUString aStr = m_pCharClass->lowercase( rStr );
421  return VarLook( aStr, true );
422 }
423 
424 SwCalcExp* SwCalc::VarLook( const OUString& rStr, bool bIns )
425 {
427 
428  sal_uInt16 ii = 0;
429  OUString aStr = m_pCharClass->lowercase( rStr );
430 
431  SwCalcExp* pFnd = m_aVarTable.Find(aStr, &ii);
432 
433  if( !pFnd )
434  {
435  // then check doc
437  for( SwHash* pEntry = rDocTable[ii].get(); pEntry; pEntry = pEntry->pNext.get() )
438  {
439  if( aStr == pEntry->aStr )
440  {
441  // then insert here
442  pFnd = new SwCalcExp( aStr, SwSbxValue(),
443  static_cast<SwCalcFieldType*>(pEntry)->pFieldType );
444  pFnd->pNext = std::move( m_aVarTable[ii] );
445  m_aVarTable[ii].reset(pFnd);
446  break;
447  }
448  }
449  }
450 
451  if( pFnd )
452  {
453  if( pFnd->pFieldType && pFnd->pFieldType->Which() == SwFieldIds::User )
454  {
455  SwUserFieldType* pUField = const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFnd->pFieldType));
456  if( nsSwGetSetExpType::GSE_STRING & pUField->GetType() )
457  {
458  pFnd->nValue.PutString( pUField->GetContent() );
459  }
460  else if( !pUField->IsValid() )
461  {
462  // Save the current values...
463  sal_uInt16 nListPor = m_nListPor;
464  bool bHasNumber = m_bHasNumber;
465  SwSbxValue nLastLeft = m_nLastLeft;
466  SwSbxValue nNumberValue = m_nNumberValue;
467  sal_Int32 nCommandPos = m_nCommandPos;
468  SwCalcOper eCurrOper = m_eCurrOper;
469  SwCalcOper eCurrListOper = m_eCurrListOper;
470  OUString sCurrCommand = m_sCommand;
471 
472  pFnd->nValue.PutDouble( pUField->GetValue( *this ) );
473 
474  // ...and write them back.
475  m_nListPor = nListPor;
476  m_bHasNumber = bHasNumber;
477  m_nLastLeft = nLastLeft;
478  m_nNumberValue = nNumberValue;
479  m_nCommandPos = nCommandPos;
480  m_eCurrOper = eCurrOper;
481  m_eCurrListOper = eCurrListOper;
482  m_sCommand = sCurrCommand;
483  }
484  else
485  {
486  pFnd->nValue.PutDouble( pUField->GetValue() );
487  }
488  }
489  else if ( !pFnd->pFieldType && pFnd->nValue.IsDBvalue() )
490  {
491  if ( pFnd->nValue.IsString() )
493  else if ( pFnd->nValue.IsDouble() )
495  pFnd = &m_aErrExpr;
496  }
497  return pFnd;
498  }
499 
500  // At this point the "real" case variable has to be used
501  OUString const sTmpName( ::ReplacePoint(rStr) );
502 
503  if( !bIns )
504  {
505 #if HAVE_FEATURE_DBCONNECTIVITY
506  SwDBManager *pMgr = m_rDoc.GetDBManager();
507 
508  OUString sDBName(GetDBName( sTmpName ));
509  OUString sSourceName(sDBName.getToken(0, DB_DELIM));
510  OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
511  if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
512  pMgr->OpenDataSource(sSourceName, sTableName))
513  {
514  OUString sColumnName( GetColumnName( sTmpName ));
515  OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name");
516 
518  sDBNum = m_pCharClass->lowercase(sDBNum);
519 
520  // Initialize again because this doesn't happen in docfld anymore for
521  // elements != SwFieldIds::Database. E.g. if there is an expression field before
522  // a DB_Field in a document.
523  const sal_uInt32 nTmpRec = pMgr->GetSelectedRecordId(sSourceName, sTableName);
524  VarChange(sDBNum, nTmpRec);
525 
526  if( sDBNum.equalsIgnoreAsciiCase(sColumnName) )
527  {
528  m_aErrExpr.nValue.PutULong(nTmpRec);
529  return &m_aErrExpr;
530  }
531 
532  OUString sResult;
533  double nNumber = DBL_MAX;
534 
536  if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
537  nTmpRec, nLang, sResult, &nNumber ))
538  {
539  if (nNumber != DBL_MAX)
540  m_aErrExpr.nValue.PutDouble( nNumber );
541  else
542  m_aErrExpr.nValue.PutString( sResult );
543 
544  return &m_aErrExpr;
545  }
546  }
547  else
548 #endif
549  {
550  //data source was not available - set return to "NoValue"
552  }
553  // NEVER save!
554  return &m_aErrExpr;
555  }
556 
557  SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), nullptr );
558  pNewExp->pNext = std::move( m_aVarTable[ ii ] );
559  m_aVarTable[ ii ].reset( pNewExp );
560 
561  OUString sColumnName( GetColumnName( sTmpName ));
562  OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
563  if( sColumnName.equalsIgnoreAsciiCase(
565  {
566 #if HAVE_FEATURE_DBCONNECTIVITY
567  SwDBManager *pMgr = m_rDoc.GetDBManager();
568  OUString sDBName(GetDBName( sTmpName ));
569  OUString sSourceName(sDBName.getToken(0, DB_DELIM));
570  OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
571  if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
572  pMgr->OpenDataSource(sSourceName, sTableName) &&
573  !pMgr->IsInMerge())
574  {
575  pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
576  }
577  else
578 #endif
579  {
580  pNewExp->nValue.SetVoidValue(true);
581  }
582  }
583 
584  return pNewExp;
585 }
586 
587 void SwCalc::VarChange( const OUString& rStr, double nValue )
588 {
589  SwSbxValue aVal( nValue );
590  VarChange( rStr, aVal );
591 }
592 
593 void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
594 {
595  OUString aStr = m_pCharClass->lowercase( rStr );
596 
597  sal_uInt16 nPos = 0;
598  SwCalcExp* pFnd = m_aVarTable.Find( aStr, &nPos );
599 
600  if( !pFnd )
601  {
602  pFnd = new SwCalcExp( aStr, rValue, nullptr );
603  pFnd->pNext = std::move( m_aVarTable[ nPos ] );
604  m_aVarTable[ nPos ].reset( pFnd );
605  }
606  else
607  {
608  pFnd->nValue = rValue;
609  }
610 }
611 
612 bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
613 {
614  if( m_aRekurStack.end() != std::find(m_aRekurStack.begin(), m_aRekurStack.end(), pUserFieldType ) )
615  return false;
616 
617  m_aRekurStack.push_back( pUserFieldType );
618  return true;
619 }
620 
622 {
623  OSL_ENSURE( m_aRekurStack.size(), "SwCalc: Pop on an invalid pointer" );
624 
625  m_aRekurStack.pop_back();
626 }
627 
629 {
630  return m_pCharClass;
631 }
632 
634 {
635  if( m_nCommandPos >= m_sCommand.getLength() )
636  {
638  return m_eCurrOper;
639  }
640 
641  using namespace ::com::sun::star::i18n;
642  {
643  // Parse any token.
644  ParseResult aRes = m_pCharClass->parseAnyToken( m_sCommand, m_nCommandPos,
645  coStartFlags, OUString(),
646  coContFlags, OUString());
647 
648  bool bSetError = true;
649  sal_Int32 nRealStt = m_nCommandPos + aRes.LeadingWhiteSpace;
650  if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
651  {
652  m_nNumberValue.PutDouble( aRes.Value );
654  bSetError = false;
655  }
656  else if( aRes.TokenType & KParseType::IDENTNAME )
657  {
658  OUString aName( m_sCommand.copy( nRealStt,
659  aRes.EndPos - nRealStt ) );
660  //#101436#: The variable may contain a database name. It must not be
661  // converted to lower case! Instead all further comparisons must be
662  // done case-insensitive
663  OUString sLowerCaseName = m_pCharClass->lowercase( aName );
664  // catch currency symbol
665  if( sLowerCaseName == m_sCurrSym )
666  {
667  m_nCommandPos = aRes.EndPos;
668  return GetToken(); // call again
669  }
670 
671  // catch operators
672  CalcOp* pFnd = ::FindOperator( sLowerCaseName );
673  if( pFnd )
674  {
675  m_eCurrOper = pFnd->eOp;
676  switch( m_eCurrOper )
677  {
678  case CALC_SUM:
679  case CALC_MEAN:
680  case CALC_AVERAGE:
681  case CALC_COUNT:
683  break;
684  case CALC_MIN:
686  break;
687  case CALC_MAX:
689  break;
690  case CALC_DATE:
692  break;
693  case CALC_PRODUCT:
695  break;
696  default:
697  break;
698  }
699  m_nCommandPos = aRes.EndPos;
700  return m_eCurrOper;
701  }
702  m_aVarName = aName;
704  bSetError = false;
705  }
706  else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
707  {
708  m_nNumberValue.PutString( aRes.DequotedNameOrString );
710  bSetError = false;
711  }
712  else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
713  {
714  OUString aName( m_sCommand.copy( nRealStt,
715  aRes.EndPos - nRealStt ));
716  if( 1 == aName.getLength() )
717  {
718  bSetError = false;
719  sal_Unicode ch = aName[0];
720  switch( ch )
721  {
722  case ';':
724  {
726  break;
727  }
728  [[fallthrough]];
729  case '\n':
731  break;
732 
733  case '%':
734  case '^':
735  case '*':
736  case '/':
737  case '+':
738  case '-':
739  case '(':
740  case ')':
741  m_eCurrOper = SwCalcOper(ch);
742  break;
743 
744  case '=':
745  case '!':
746  {
747  SwCalcOper eTmp2;
748  if( '=' == ch )
749  {
750  m_eCurrOper = SwCalcOper('=');
751  eTmp2 = CALC_EQ;
752  }
753  else
754  {
756  eTmp2 = CALC_NEQ;
757  }
758 
759  if( aRes.EndPos < m_sCommand.getLength() &&
760  '=' == m_sCommand[aRes.EndPos] )
761  {
762  m_eCurrOper = eTmp2;
763  ++aRes.EndPos;
764  }
765  }
766  break;
767 
768  case cListDelim:
770  break;
771 
772  case '[':
773  if( aRes.EndPos < m_sCommand.getLength() )
774  {
775  m_aVarName.setLength(0);
776  sal_Int32 nFndPos = aRes.EndPos,
777  nSttPos = nFndPos;
778 
779  do {
780  nFndPos = m_sCommand.indexOf( ']', nFndPos );
781  if( -1 != nFndPos )
782  {
783  // ignore the ]
784  if ('\\' == m_sCommand[nFndPos-1])
785  {
786  m_aVarName.append(std::u16string_view(m_sCommand).substr(nSttPos,
787  nFndPos - nSttPos - 1) );
788  nSttPos = ++nFndPos;
789  }
790  else
791  break;
792  }
793  } while( nFndPos != -1 );
794 
795  if( nFndPos != -1 )
796  {
797  if( nSttPos != nFndPos )
798  m_aVarName.append(std::u16string_view(m_sCommand).substr(nSttPos,
799  nFndPos - nSttPos) );
800  aRes.EndPos = nFndPos + 1;
802  }
803  else
804  bSetError = true;
805  }
806  else
807  {
808  bSetError = true;
809  }
810  break;
811 
812  default:
813  bSetError = true;
814  break;
815  }
816  }
817  }
818  else if( aRes.TokenType & KParseType::BOOLEAN )
819  {
820  OUString aName( m_sCommand.copy( nRealStt,
821  aRes.EndPos - nRealStt ));
822  if( !aName.isEmpty() )
823  {
824  sal_Unicode ch = aName[0];
825 
826  bSetError = true;
827  if ('<' == ch || '>' == ch)
828  {
829  bSetError = false;
830 
831  SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
832  m_eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
833 
834  if( 2 == aName.getLength() && '=' == aName[1] )
835  m_eCurrOper = eTmp2;
836  else if( 1 != aName.getLength() )
837  bSetError = true;
838  }
839  }
840  }
841  else if( nRealStt == m_sCommand.getLength() )
842  {
844  bSetError = false;
845  }
846 
847  if( bSetError )
848  {
851  }
852  m_nCommandPos = aRes.EndPos;
853  };
854 
855  return m_eCurrOper;
856 }
857 
859 {
860  SwSbxValue left( Prim() );
861  m_nLastLeft = left;
862  for(;;)
863  {
864  sal_uInt16 nSbxOper = USHRT_MAX;
865 
866  switch( m_eCurrOper )
867  {
868  case CALC_AND:
869  {
870  GetToken();
871  bool bB = Prim().GetBool();
872  left.PutBool( left.GetBool() && bB );
873  }
874  break;
875  case CALC_OR:
876  {
877  GetToken();
878  bool bB = Prim().GetBool();
879  left.PutBool( left.GetBool() || bB );
880  }
881  break;
882  case CALC_XOR:
883  {
884  GetToken();
885  bool bR = Prim().GetBool();
886  bool bL = left.GetBool();
887  left.PutBool(bL != bR);
888  }
889  break;
890 
891  case CALC_EQ: nSbxOper = SbxEQ; break;
892  case CALC_NEQ: nSbxOper = SbxNE; break;
893  case CALC_LEQ: nSbxOper = SbxLE; break;
894  case CALC_GEQ: nSbxOper = SbxGE; break;
895  case CALC_GRE: nSbxOper = SbxGT; break;
896  case CALC_LES: nSbxOper = SbxLT; break;
897 
898  case CALC_MUL: nSbxOper = SbxMUL; break;
899  case CALC_DIV: nSbxOper = SbxDIV; break;
900 
901  case CALC_MIN_IN:
902  {
903  GetToken();
904  SwSbxValue e = Prim();
905  left = left.GetDouble() < e.GetDouble() ? left : e;
906  }
907  break;
908  case CALC_MAX_IN:
909  {
910  GetToken();
911  SwSbxValue e = Prim();
912  left = left.GetDouble() > e.GetDouble() ? left : e;
913  }
914  break;
915  case CALC_MONTH:
916  {
917  GetToken();
918  SwSbxValue e = Prim();
919  sal_Int32 nYear = static_cast<sal_Int32>(floor( left.GetDouble() ));
920  nYear = nYear & 0x0000FFFF;
921  sal_Int32 nMonth = static_cast<sal_Int32>(floor( e.GetDouble() ));
922  nMonth = ( nMonth & 0x000000FF ) << 16;
923  left.PutLong( nMonth + nYear );
925  }
926  break;
927  case CALC_DAY:
928  {
929  GetToken();
930  SwSbxValue e = Prim();
931  sal_Int32 nYearMonth = static_cast<sal_Int32>(floor( left.GetDouble() ));
932  nYearMonth = nYearMonth & 0x00FFFFFF;
933  sal_Int32 nDay = static_cast<sal_Int32>(floor( e.GetDouble() ));
934  nDay = ( nDay & 0x000000FF ) << 24;
935  left = lcl_ConvertToDateValue( m_rDoc, nDay + nYearMonth );
936  }
937  break;
938  case CALC_ROUND:
939  {
940  GetToken();
941  SwSbxValue e = Prim();
942 
943  double fVal = 0;
944  double fFac = 1;
945  sal_Int32 nDec = static_cast<sal_Int32>(floor( e.GetDouble() ));
946  if( nDec < -20 || nDec > 20 )
947  {
949  left.Clear();
950  return left;
951  }
952  fVal = left.GetDouble();
953  if( nDec >= 0)
954  {
955  for (sal_Int32 i = 0; i < nDec; ++i )
956  fFac *= 10.0;
957  }
958  else
959  {
960  for (sal_Int32 i = 0; i < -nDec; ++i )
961  fFac /= 10.0;
962  }
963 
964  fVal *= fFac;
965  bool bSign;
966  if (fVal < 0.0)
967  {
968  fVal *= -1.0;
969  bSign = true;
970  }
971  else
972  {
973  bSign = false;
974  }
975 
976  // rounding
977  double fNum = fVal; // find the exponent
978  int nExp = 0;
979  if( fNum > 0 )
980  {
981  while( fNum < 1.0 )
982  {
983  fNum *= 10.0;
984  --nExp;
985  }
986  while( fNum >= 10.0 )
987  {
988  fNum /= 10.0;
989  ++nExp;
990  }
991  }
992  nExp = 15 - nExp;
993  if( nExp > 15 )
994  nExp = 15;
995  else if( nExp <= 1 )
996  nExp = 0;
997  fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
998 
999  if (bSign)
1000  fVal *= -1.0;
1001 
1002  fVal /= fFac;
1003 
1004  left.PutDouble( fVal );
1005  }
1006  break;
1007 
1008 //#77448# (=2*3^2 != 18)
1009 
1010  default:
1011  return left;
1012  }
1013 
1014  if( USHRT_MAX != nSbxOper )
1015  {
1016  // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1017  SbxOperator eSbxOper = static_cast<SbxOperator>(nSbxOper);
1018 
1019  GetToken();
1020  if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1021  {
1022  left.PutBool( left.Compare( eSbxOper, Prim() ));
1023  }
1024  else
1025  {
1026  SwSbxValue aRight( Prim() );
1027  aRight.MakeDouble();
1028  left.MakeDouble();
1029 
1030  if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1032  else
1033  left.Compute( eSbxOper, aRight );
1034  }
1035  }
1036  }
1037 }
1038 
1039 SwSbxValue SwCalc::StdFunc(pfCalc pFnc, bool bChkTrig)
1040 {
1041  SwSbxValue nErg;
1042  GetToken();
1043  double nVal = Prim().GetDouble();
1044  if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1045  nErg.PutDouble( (*pFnc)( nVal ) );
1046  else
1048  return nErg;
1049 }
1050 
1052 {
1053  rChkPow = false;
1054 
1055  switch (m_eCurrOper)
1056  {
1057  case CALC_SIN:
1058  SAL_INFO("sw.calc", "sin");
1059  return StdFunc(&sin, false);
1060  break;
1061  case CALC_COS:
1062  SAL_INFO("sw.calc", "cos");
1063  return StdFunc(&cos, false);
1064  break;
1065  case CALC_TAN:
1066  SAL_INFO("sw.calc", "tan");
1067  return StdFunc(&tan, false);
1068  break;
1069  case CALC_ATAN:
1070  SAL_INFO("sw.calc", "atan");
1071  return StdFunc(&atan, false);
1072  break;
1073  case CALC_ASIN:
1074  SAL_INFO("sw.calc", "asin");
1075  return StdFunc(&asin, true);
1076  break;
1077  case CALC_ACOS:
1078  SAL_INFO("sw.calc", "acos");
1079  return StdFunc(&acos, true);
1080  break;
1081  case CALC_ABS:
1082  SAL_INFO("sw.calc", "abs");
1083  return StdFunc(&abs, false);
1084  break;
1085  case CALC_SIGN:
1086  {
1087  SAL_INFO("sw.calc", "sign");
1088  SwSbxValue nErg;
1089  GetToken();
1090  double nVal = Prim().GetDouble();
1091  nErg.PutDouble( int(0 < nVal) - int(nVal < 0) );
1092  return nErg;
1093  break;
1094  }
1095  case CALC_NOT:
1096  {
1097  SAL_INFO("sw.calc", "not");
1098  GetToken();
1099  SwSbxValue nErg = Prim();
1100  if( SbxSTRING == nErg.GetType() )
1101  {
1102  nErg.PutBool( nErg.GetOUString().isEmpty() );
1103  }
1104  else if(SbxBOOL == nErg.GetType() )
1105  {
1106  nErg.PutBool(!nErg.GetBool());
1107  }
1108  // Evaluate arguments manually so that the binary NOT below does not
1109  // get called. We want a BOOLEAN NOT.
1110  else if (nErg.IsNumeric())
1111  {
1112  nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1113  }
1114  else
1115  {
1116  OSL_FAIL( "unexpected case. computing binary NOT" );
1118  nErg.Compute( SbxNOT, nErg );
1119  }
1120  return nErg;
1121  break;
1122  }
1123  case CALC_NUMBER:
1124  {
1125  SAL_INFO("sw.calc", "number: " << m_nNumberValue.GetDouble());
1126  SwSbxValue nErg;
1127  m_bHasNumber = true;
1128  if( GetToken() == CALC_PHD )
1129  {
1130  double aTmp = m_nNumberValue.GetDouble();
1131  aTmp *= 0.01;
1132  nErg.PutDouble( aTmp );
1133  GetToken();
1134  }
1135  else if( m_eCurrOper == CALC_NAME )
1136  {
1138  }
1139  else
1140  {
1141  nErg = m_nNumberValue;
1142  rChkPow = true;
1143  }
1144  return nErg;
1145  break;
1146  }
1147  case CALC_NAME:
1148  {
1149  SAL_INFO("sw.calc", "name");
1150  SwSbxValue nErg;
1151  switch(SwCalcOper eOper = GetToken())
1152  {
1153  case CALC_ASSIGN:
1154  {
1155  SwCalcExp* n = VarInsert(m_aVarName.toString());
1156  GetToken();
1157  nErg = n->nValue = Expr();
1158  break;
1159  }
1160  default:
1161  nErg = VarLook(m_aVarName.toString())->nValue;
1162  // Explicitly disallow unknown function names (followed by "("),
1163  // allow unknown variable names (equal to zero)
1164  if (nErg.IsVoidValue() && (eOper == CALC_LP))
1166  else
1167  rChkPow = true;
1168  break;
1169  }
1170  return nErg;
1171  break;
1172  }
1173  case CALC_MINUS:
1174  {
1175  SAL_INFO("sw.calc", "-");
1176  SwSbxValue nErg;
1177  GetToken();
1178  nErg.PutDouble( -(Prim().GetDouble()) );
1179  return nErg;
1180  break;
1181  }
1182  case CALC_LP:
1183  {
1184  SAL_INFO("sw.calc", "(");
1185  GetToken();
1186  SwSbxValue nErg = Expr();
1187  if( m_eCurrOper != CALC_RP )
1188  {
1190  }
1191  else
1192  {
1193  GetToken();
1194  rChkPow = true; // in order for =(7)^2 to work
1195  }
1196  return nErg;
1197  break;
1198  }
1199  case CALC_RP:
1200  // ignore, see tdf#121962
1201  SAL_INFO("sw.calc", ")");
1202  break;
1203  case CALC_MEAN:
1204  case CALC_AVERAGE:
1205  {
1206  SAL_INFO("sw.calc", "mean");
1207  m_nListPor = 1;
1209  GetToken();
1210  SwSbxValue nErg = Expr();
1211  double aTmp = nErg.GetDouble();
1212  aTmp /= m_nListPor;
1213  if ( !m_bHasNumber )
1215  else
1216  nErg.PutDouble( aTmp );
1217  return nErg;
1218  break;
1219  }
1220  case CALC_COUNT:
1221  {
1222  SAL_INFO("sw.calc", "count");
1223  m_nListPor = 1;
1224  m_bHasNumber = false;
1225  GetToken();
1226  SwSbxValue nErg = Expr();
1227  nErg.PutDouble( m_bHasNumber ? m_nListPor : 0 );
1228  return nErg;
1229  break;
1230  }
1231  case CALC_SQRT:
1232  {
1233  SAL_INFO("sw.calc", "sqrt");
1234  GetToken();
1235  SwSbxValue nErg = Prim();
1236  if( nErg.GetDouble() < 0 )
1238  else
1239  nErg.PutDouble( sqrt( nErg.GetDouble() ));
1240  return nErg;
1241  break;
1242  }
1243  case CALC_SUM:
1244  case CALC_PRODUCT:
1245  case CALC_DATE:
1246  case CALC_MIN:
1247  case CALC_MAX:
1248  {
1249  SAL_INFO("sw.calc", "sum/product/date/min/max");
1250  GetToken();
1251  SwSbxValue nErg = Expr();
1252  return nErg;
1253  break;
1254  }
1255  case CALC_ENDCALC:
1256  {
1257  SAL_INFO("sw.calc", "endcalc");
1258  SwSbxValue nErg;
1259  nErg.Clear();
1260  return nErg;
1261  break;
1262  }
1263  default:
1264  SAL_INFO("sw.calc", "syntax error");
1266  break;
1267  }
1268 
1269  return SwSbxValue();
1270 }
1271 
1273 {
1274  bool bChkPow;
1275  SwSbxValue nErg = PrimFunc(bChkPow);
1276 
1277  if (bChkPow && m_eCurrOper == CALC_POW)
1278  {
1279  double dleft = nErg.GetDouble();
1280  GetToken();
1281  double right = Prim().GetDouble();
1282 
1283  double fraction;
1284  fraction = modf( right, &o3tl::temporary(double()) );
1285  if( ( dleft < 0.0 && 0.0 != fraction ) ||
1286  ( 0.0 == dleft && right < 0.0 ) )
1287  {
1289  nErg.Clear();
1290  }
1291  else
1292  {
1293  dleft = pow(dleft, right );
1294  if( dleft == HUGE_VAL )
1295  {
1297  nErg.Clear();
1298  }
1299  else
1300  {
1301  nErg.PutDouble( dleft );
1302  }
1303  }
1304  }
1305 
1306  return nErg;
1307 }
1308 
1310 {
1311  SwSbxValue left = Term();
1312  m_nLastLeft = left;
1313  for(;;)
1314  {
1315  switch(m_eCurrOper)
1316  {
1317  case CALC_PLUS:
1318  {
1319  GetToken();
1320  left.MakeDouble();
1321  SwSbxValue right(Term());
1322  right.MakeDouble();
1323  left.Compute(SbxPLUS, right);
1324  m_nListPor++;
1325  break;
1326  }
1327  case CALC_MINUS:
1328  {
1329  GetToken();
1330  left.MakeDouble();
1331  SwSbxValue right(Term());
1332  right.MakeDouble();
1333  left.Compute(SbxMINUS, right);
1334  break;
1335  }
1336  default:
1337  {
1338  return left;
1339  }
1340  }
1341  }
1342 }
1343 
1344 OUString SwCalc::GetColumnName(const OUString& rName)
1345 {
1346  sal_Int32 nPos = rName.indexOf(DB_DELIM);
1347  if( -1 != nPos )
1348  {
1349  nPos = rName.indexOf(DB_DELIM, nPos + 1);
1350 
1351  if( -1 != nPos )
1352  return rName.copy(nPos + 1);
1353  }
1354  return rName;
1355 }
1356 
1357 OUString SwCalc::GetDBName(const OUString& rName)
1358 {
1359  sal_Int32 nPos = rName.indexOf(DB_DELIM);
1360  if( -1 != nPos )
1361  {
1362  nPos = rName.indexOf(DB_DELIM, nPos + 1);
1363 
1364  if( -1 != nPos )
1365  return rName.copy( 0, nPos );
1366  }
1368  return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand;
1369 }
1370 
1371 namespace
1372 {
1373  bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1374  double& rVal,
1375  const LocaleDataWrapper* const pLclData )
1376  {
1377  assert(pLclData);
1378  const sal_Unicode nCurrCmdPos = rCommandPos;
1379  rtl_math_ConversionStatus eStatus;
1380  const sal_Unicode* pEnd;
1381  rVal = pLclData->stringToDouble( rCommand.getStr() + rCommandPos,
1382  rCommand.getStr() + rCommand.getLength(),
1383  true,
1384  &eStatus,
1385  &pEnd );
1386  rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1387 
1388  return rtl_math_ConversionStatus_Ok == eStatus &&
1389  nCurrCmdPos != rCommandPos;
1390  }
1391 }
1392 
1393 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1394  double& rVal )
1395 {
1396  const SvtSysLocale aSysLocale;
1397  return lcl_Str2Double( rCommand, rCommandPos, rVal, aSysLocale.GetLocaleDataPtr() );
1398 }
1399 
1400 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1401  double& rVal, SwDoc const * const pDoc )
1402 {
1403  const SvtSysLocale aSysLocale;
1404  std::unique_ptr<const LocaleDataWrapper> pLclD;
1405  if( pDoc )
1406  {
1407  LanguageType eLang = GetDocAppScriptLang( *pDoc );
1408  if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1409  {
1410  pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1411  }
1412  }
1413 
1414  bool const bRet = lcl_Str2Double(rCommand, rCommandPos, rVal,
1415  pLclD ? pLclD.get() : aSysLocale.GetLocaleDataPtr());
1416 
1417  return bRet;
1418 }
1419 
1420 bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1421 {
1422  bool bRet = false;
1423  using namespace ::com::sun::star::i18n;
1424  {
1425  // Parse any token.
1426  ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1427  coStartFlags, OUString(),
1428  coContFlags, OUString() );
1429 
1430  if( aRes.TokenType & KParseType::IDENTNAME )
1431  {
1432  bRet = aRes.EndPos == rStr.getLength();
1433  if( pValidName )
1434  {
1435  *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1436  aRes.EndPos - aRes.LeadingWhiteSpace );
1437  }
1438  }
1439  else if( pValidName )
1440  pValidName->clear();
1441  }
1442  return bRet;
1443 }
1444 
1445 SwHash::SwHash(const OUString& rStr)
1446  : aStr(rStr)
1447 {
1448 }
1449 
1451 {
1452 }
1453 
1454 SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1455  const SwFieldType* pType)
1456  : SwHash(rStr)
1457  , nValue(rVal)
1458  , pFieldType(pType)
1459 {
1460 }
1461 
1463 {
1464  return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1465  : SbxValue::GetBool();
1466 }
1467 
1469 {
1470  double nRet;
1471  if( SbxSTRING == GetType() )
1472  {
1473  sal_Int32 nStt = 0;
1474  SwCalc::Str2Double( GetOUString(), nStt, nRet );
1475  }
1476  else if (IsBool())
1477  {
1478  nRet = GetBool() ? 1.0 : 0.0;
1479  }
1480  else
1481  {
1482  nRet = SbxValue::GetDouble();
1483  }
1484  return nRet;
1485 }
1486 
1488 {
1489  if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1490  PutDouble( GetDouble() );
1491  return *this;
1492 }
1493 
1494 #ifdef STANDALONE_HASHCALC
1495 
1496 // this is example code how to create hash values in the CTOR:
1497 
1498 #include <stdio.h>
1499 void main()
1500 {
1501  static char
1502  sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1503  sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1504  sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1505  sNType9[] = "word", sNType10[]= "char",
1506  sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1507  sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1508  sNType15[] = "user_street" , sNType16[] = "user_country" ,
1509  sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1510  sNType19[] = "user_title" , sNType20[] = "user_position" ,
1511  sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1512  sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1513  sNType25[] = "user_state", sNType26[] = "graph"
1514  ;
1515 
1516  static const char* sNTypeTab[ 27 ] =
1517  {
1518  sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1519  sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1520  sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1521  sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1522  sNType24, sNType25, sNType26
1523  };
1524 
1525  const unsigned short nTableSize = 47;
1526  int aArr[ nTableSize ] = { 0 };
1527  char ch;
1528 
1529  for( int n = 0; n < 27; ++n )
1530  {
1531  unsigned int ii = 0;
1532  const char* pp = sNTypeTab[ n ];
1533 
1534  while( *pp )
1535  {
1536  ii = ii << 1 ^ *pp++;
1537  }
1538  ii %= nTableSize;
1539 
1540  ch = aArr[ ii ] ? 'X' : ' ';
1541  aArr[ ii ] = 1;
1542  printf( "%-20s -> %3u [%c]\n", sNTypeTab[ n ], ii, ch );
1543  }
1544 }
1545 
1546 #endif
1547 
1548 /* 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:1454
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:130
IDocumentStatistics const & getIDocumentStatistics() const
Definition: doc.cxx:373
SbxPLUS
bool IsString() const
The shared part of a user field.
Definition: usrfld.hxx:35
OUString GetToken(UserOptToken nToken) const
bool IsDouble() const
SwSbxValue m_nLastLeft
Definition: calc.hxx:197
SbxOperator
const LocaleDataWrapper * GetLocaleDataPtr() const
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
const char aData[]
Definition: ww8scan.hxx:47
static ShellResource * GetShellRes()
Definition: viewsh.cxx:2486
OUString aCalc_Default
Definition: shellres.hxx:39
#define TBLSZ
Definition: calc.hxx:37
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1407
SbxNE
const char sCalc_Tan[]
Definition: calc.cxx:80
bool m_bHasNumber
Definition: calc.hxx:208
SbxMINUS
OUString GetOUString() const
sal_uInt16 GetType() const
Definition: usrfld.hxx:86
const char sCalc_Product[]
Definition: calc.cxx:86
LanguageType getLanguageType(bool bResolveSystem=true) const
Definition: calc.hxx:46
OUString m_sCommand
Definition: calc.hxx:195
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
bool OpenDataSource(const OUString &rDataSource, const OUString &rTableOrQuery)
open the source while fields are updated - for the calculator only!
Definition: dbmgr.cxx:2287
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:399
SwCalc(const SwCalc &)=delete
sal_Int64 n
Definition: doc.hxx:184
const LanguageTag & getLanguageTag() const
const SwFieldType * pFieldType
Definition: calc.hxx:141
sal_uLong nChar
Definition: docstat.hxx:37
sal_uInt16 nTable
Definition: docstat.hxx:27
CharClass * GetCharClass()
Definition: calc.cxx:628
std::unique_ptr< SwHash > pNext
Definition: calc.hxx:135
const char * pName
Definition: calc.cxx:96
const char sCalc_Date[]
Definition: calc.cxx:85
bool IsInMerge() const
Definition: dbmgr.hxx:340
SwSbxValue Term()
Definition: calc.cxx:858
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
sal_uInt16 sal_Unicode
void Pop()
Definition: calc.cxx:621
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:1393
SwCalcError
Definition: calc.hxx:98
void VarChange(const OUString &rStr, const SwSbxValue &rValue)
Definition: calc.cxx:593
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:49
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:200
SwCalcOper m_eCurrListOper
Definition: calc.hxx:210
SwSbxValue StdFunc(pfCalc pFnc, bool bChkTrig)
Definition: calc.cxx:1039
sal_uInt16 nOLE
Definition: docstat.hxx:29
SwSbxValue & MakeDouble()
Definition: calc.cxx:1487
Definition: calc.cxx:93
double(* pfCalc)(double)
Definition: calc.hxx:188
OUString aCalc_ZeroDiv
Definition: shellres.hxx:35
#define SAL_N_ELEMENTS(arr)
SbxNOT
SwSbxValue nValue
Definition: calc.hxx:140
double const nRoundVal[]
Definition: calc.cxx:139
double GetDouble() const
Definition: calc.cxx:1468
const OUString & getNumDecimalSep() const
sal_uInt16 char * pName
static OUString GetTypeStr(SwFieldTypesEnum nTypeId)
Definition: fldbas.cxx:120
SwSbxValue Prim()
Definition: calc.cxx:1272
def right
SwDoc & m_rDoc
Definition: calc.hxx:202
#define F_PI
bool IsNumeric() const
#define SW_MOD()
Definition: swmodule.hxx:255
const char sCalc_Pow[]
Definition: calc.cxx:63
Definition: calc.hxx:46
SwDBData const & GetDBData()
Definition: docfld.cxx:343
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:633
bool IsBool() const
static double lcl_ConvertToDateValue(SwDoc &rDoc, sal_Int32 nDate)
Definition: calc.cxx:203
SwSbxValue m_nNumberValue
Definition: calc.hxx:198
bool GetColumnCnt(const OUString &rSourceName, const OUString &rTableName, const OUString &rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:2023
const char sCalc_Sign[]
Definition: calc.cxx:89
SwCalcExp m_aErrExpr
Definition: calc.hxx:199
const SvxPageUsage aArr[]
const char sCalc_Atan[]
Definition: calc.cxx:83
const sal_Int32 coContFlags
Definition: calc.cxx:152
virtual ~SwHash()
Definition: calc.cxx:1450
static OUString GetColumnName(const OUString &rName)
Definition: calc.cxx:1344
bool IsVoidValue() const
Definition: calc.hxx:122
SwCalcOper
Definition: calc.hxx:41
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:195
SbxGE
virtual void Clear() override
double GetValue(SwCalc &rCalc)
Definition: usrfld.cxx:231
T * Find(const OUString &rStr, sal_uInt16 *pPos=nullptr) const
Definition: calc.hxx:158
const char sCalc_Max[]
Definition: calc.cxx:77
SwHash(const OUString &rStr)
Definition: calc.cxx:1445
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
PDFDocument & m_rDoc
const char sCalc_Leq[]
Definition: calc.cxx:70
#define DB_DELIM
Definition: swtypes.hxx:133
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:1420
OUStringBuffer m_aVarName
Definition: calc.hxx:193
SbxLE
SwCalcError m_eError
Definition: calc.hxx:211
bool IsDBvalue() const
Definition: calc.hxx:125
const OUString & getCurrSymbol() const
OUString GetFirstName() const
const char sCalc_Sub[]
Definition: calc.cxx:58
bool GetBool() const
SwSbxValue Expr()
Definition: calc.cxx:1309
SwSbxValue Calculate(const OUString &rStr)
Definition: calc.cxx:358
sal_uInt16 m_nListPor
Definition: calc.hxx:207
bool IsValid() const
Definition: usrfld.hxx:77
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:350
const LanguageTag & getLanguageTag() const
const char sCalc_G[]
Definition: calc.cxx:73
SwHashTable< SwCalcExp > m_aVarTable
Definition: calc.hxx:192
SbxEQ
OUString GetLastName() const
SbxSTRING
sal_uInt32 GetSelectedRecordId(const OUString &rDataSource, const OUString &rTableOrQuery, sal_Int32 nCommandType=-1)
Definition: dbmgr.cxx:2355
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:728
OString strip(const OString &rIn, char c)
bool PutDouble(double)
virtual SwDocUpdateField & GetUpdateFields() const =0
CalcOp const aOpTable[]
Definition: calc.cxx:102
bool GetBool() const
Definition: calc.cxx:1462
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:386
static LanguageType GetDocAppScriptLang(SwDoc const &rDoc)
Definition: calc.cxx:195
OUString GetContent(sal_uInt32 nFormat=0)
Definition: usrfld.cxx:266
CharClass * m_pCharClass
Definition: calc.hxx:205
const char sCalc_Xor[]
Definition: calc.cxx:65
SwCalcExp * VarLook(const OUString &rStr, bool bIns=false)
Definition: calc.cxx:424
SwSbxValue PrimFunc(bool &rChkPow)
Definition: calc.cxx:1051
SwCalcOper m_eCurrOper
Definition: calc.hxx:209
const LocaleDataWrapper * m_pLocaleDataWrapper
Definition: calc.hxx:204
const LanguageTag & GetLanguageTag() const
SbxMUL
const OUString * pUName
Definition: calc.cxx:97
const SwGetSetExpType GSE_STRING
String.
Definition: fldbas.hxx:202
SwCalcExp * VarInsert(const OUString &r)
Definition: calc.cxx:418
const char sCalc_Eq[]
Definition: calc.cxx:68
SvtSysLocale m_aSysLocale
Definition: calc.hxx:203
OUString m_sCurrSym
Definition: calc.hxx:194
const char sCalc_Sin[]
Definition: calc.cxx:78
const sal_Unicode cListDelim
Definition: calc.hxx:39
sal_uLong nWord
Definition: docstat.hxx:35
OUString GetDBName(const OUString &rName)
Definition: calc.cxx:1357
SbxGT
const Date & GetNullDate() const
bool Push(const SwUserFieldType *pUserFieldType)
Definition: calc.cxx:612
bool Compute(SbxOperator, const SbxValue &)
CharClass & GetAppCharClass()
Definition: init.cxx:708
SwFieldIds Which() const
Definition: fldbas.hxx:272
OUString sCommand
Definition: swdbdata.hxx:31
aStr
SwDBManager * GetDBManager() const
Definition: doc.hxx:664
sal_uInt16 nPos
OUString aStr
Definition: calc.hxx:134
Definition: calc.hxx:48
const char sCalc_Mean[]
Definition: calc.cxx:75
sal_Int16 nValue
std::vector< const SwUserFieldType * > m_aRekurStack
Definition: calc.hxx:196
void SetVoidValue(bool bSet)
Definition: calc.hxx:123
SbxDIV