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>
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/numformat.hxx>
44 #include <svl/languageoptions.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 const char sCalc_Int[] = "int";
92 
93 // ATTENTION: sorted list of all operators
94 struct CalcOp
95 {
96  union{
97  const char* pName;
98  const OUString* pUName;
99  };
101 };
102 
103 CalcOp const aOpTable[] = {
104 /* ABS */ {{sCalc_Abs}, CALC_ABS}, // Abs (since LibreOffice 7.1)
105 /* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arc cosine
106 /* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
107 /* AND */ {{sCalc_And}, CALC_AND}, // log. AND
108 /* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arc sine
109 /* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arc tangent
110 /* AVERAGE */ {{sCalc_Average}, CALC_AVERAGE}, // Average (since LibreOffice 7.1)
111 /* COS */ {{sCalc_Cos}, CALC_COS}, // Cosine
112 /* COUNT */ {{sCalc_Count}, CALC_COUNT}, // Count (since LibreOffice 7.1)
113 /* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
114 /* DIV */ {{sCalc_Div}, CALC_DIV}, // Division
115 /* EQ */ {{sCalc_Eq}, CALC_EQ}, // Equality
116 /* G */ {{sCalc_G}, CALC_GRE}, // Greater than
117 /* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // Greater or equal
118 /* INT */ {{sCalc_Int}, CALC_INT}, // Int (since LibreOffice 7.4)
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 {
202  return rDoc.GetDefault(nWhich).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( M_PI );
327  m_aVarTable[ aHashValue[ 3 ] ]->nValue.PutDouble( M_E );
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  std::u16string_view aName( m_sCommand.subView( nRealStt,
717  aRes.EndPos - nRealStt ));
718  if( 1 == aName.size() )
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  std::u16string_view aName( m_sCommand.subView( nRealStt,
823  aRes.EndPos - nRealStt ));
824  if( !aName.empty() )
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.size() && '=' == aName[1] )
837  m_eCurrOper = eTmp2;
838  else if( 1 != aName.size() )
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_INT:
1090  {
1091  SAL_INFO("sw.calc", "int");
1092  SwSbxValue nErg;
1093  GetToken();
1094  sal_Int32 nVal = static_cast<sal_Int32>( Prim().GetDouble() );
1095  nErg.PutDouble( nVal );
1096  return nErg;
1097  }
1098  case CALC_NOT:
1099  {
1100  SAL_INFO("sw.calc", "not");
1101  GetToken();
1102  SwSbxValue nErg = Prim();
1103  if( SbxSTRING == nErg.GetType() )
1104  {
1105  nErg.PutBool( nErg.GetOUString().isEmpty() );
1106  }
1107  else if(SbxBOOL == nErg.GetType() )
1108  {
1109  nErg.PutBool(!nErg.GetBool());
1110  }
1111  // Evaluate arguments manually so that the binary NOT below does not
1112  // get called. We want a BOOLEAN NOT.
1113  else if (nErg.IsNumeric())
1114  {
1115  nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1116  }
1117  else
1118  {
1119  OSL_FAIL( "unexpected case. computing binary NOT" );
1121  nErg.Compute( SbxNOT, nErg );
1122  }
1123  return nErg;
1124  }
1125  case CALC_NUMBER:
1126  {
1127  SAL_INFO("sw.calc", "number: " << m_nNumberValue.GetDouble());
1128  SwSbxValue nErg;
1129  m_bHasNumber = true;
1130  if( GetToken() == CALC_PHD )
1131  {
1132  double aTmp = m_nNumberValue.GetDouble();
1133  aTmp *= 0.01;
1134  nErg.PutDouble( aTmp );
1135  GetToken();
1136  }
1137  else if( m_eCurrOper == CALC_NAME )
1138  {
1140  }
1141  else
1142  {
1143  nErg = m_nNumberValue;
1144  rChkPow = true;
1145  }
1146  return nErg;
1147  }
1148  case CALC_NAME:
1149  {
1150  SAL_INFO("sw.calc", "name");
1151  SwSbxValue nErg;
1152  switch(SwCalcOper eOper = GetToken())
1153  {
1154  case CALC_ASSIGN:
1155  {
1156  SwCalcExp* n = VarInsert(m_aVarName.toString());
1157  GetToken();
1158  nErg = n->nValue = Expr();
1159  break;
1160  }
1161  default:
1162  nErg = VarLook(m_aVarName.toString())->nValue;
1163  // Explicitly disallow unknown function names (followed by "("),
1164  // allow unknown variable names (equal to zero)
1165  if (nErg.IsVoidValue() && (eOper == CALC_LP))
1167  else
1168  rChkPow = true;
1169  break;
1170  }
1171  return nErg;
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  }
1181  case CALC_LP:
1182  {
1183  SAL_INFO("sw.calc", "(");
1184  GetToken();
1185  SwSbxValue nErg = Expr();
1186  if( m_eCurrOper != CALC_RP )
1187  {
1189  }
1190  else
1191  {
1192  GetToken();
1193  rChkPow = true; // in order for =(7)^2 to work
1194  }
1195  return nErg;
1196  }
1197  case CALC_RP:
1198  // ignore, see tdf#121962
1199  SAL_INFO("sw.calc", ")");
1200  break;
1201  case CALC_MEAN:
1202  case CALC_AVERAGE:
1203  {
1204  SAL_INFO("sw.calc", "mean");
1205  m_nListPor = 1;
1207  GetToken();
1208  SwSbxValue nErg = Expr();
1209  double aTmp = nErg.GetDouble();
1210  aTmp /= m_nListPor;
1211  if ( !m_bHasNumber )
1213  else
1214  nErg.PutDouble( aTmp );
1215  return nErg;
1216  }
1217  case CALC_COUNT:
1218  {
1219  SAL_INFO("sw.calc", "count");
1220  m_nListPor = 1;
1221  m_bHasNumber = false;
1222  GetToken();
1223  SwSbxValue nErg = Expr();
1224  nErg.PutDouble( m_bHasNumber ? m_nListPor : 0 );
1225  return nErg;
1226  }
1227  case CALC_SQRT:
1228  {
1229  SAL_INFO("sw.calc", "sqrt");
1230  GetToken();
1231  SwSbxValue nErg = Prim();
1232  if( nErg.GetDouble() < 0 )
1234  else
1235  nErg.PutDouble( sqrt( nErg.GetDouble() ));
1236  return nErg;
1237  }
1238  case CALC_SUM:
1239  case CALC_PRODUCT:
1240  case CALC_DATE:
1241  case CALC_MIN:
1242  case CALC_MAX:
1243  {
1244  SAL_INFO("sw.calc", "sum/product/date/min/max");
1245  GetToken();
1246  SwSbxValue nErg = Expr();
1247  return nErg;
1248  }
1249  case CALC_ENDCALC:
1250  {
1251  SAL_INFO("sw.calc", "endcalc");
1252  SwSbxValue nErg;
1253  nErg.Clear();
1254  return nErg;
1255  }
1256  default:
1257  SAL_INFO("sw.calc", "syntax error");
1259  break;
1260  }
1261 
1262  return SwSbxValue();
1263 }
1264 
1266 {
1267  bool bChkPow;
1268  SwSbxValue nErg = PrimFunc(bChkPow);
1269 
1270  if (bChkPow && m_eCurrOper == CALC_POW)
1271  {
1272  double dleft = nErg.GetDouble();
1273  GetToken();
1274  double right = Prim().GetDouble();
1275 
1276  double fraction;
1277  fraction = modf( right, &o3tl::temporary(double()) );
1278  if( ( dleft < 0.0 && 0.0 != fraction ) ||
1279  ( 0.0 == dleft && right < 0.0 ) )
1280  {
1282  nErg.Clear();
1283  }
1284  else
1285  {
1286  dleft = pow(dleft, right );
1287  if( dleft == HUGE_VAL )
1288  {
1290  nErg.Clear();
1291  }
1292  else
1293  {
1294  nErg.PutDouble( dleft );
1295  }
1296  }
1297  }
1298 
1299  return nErg;
1300 }
1301 
1303 {
1304  SwSbxValue left = Term();
1305  m_nLastLeft = left;
1306  for(;;)
1307  {
1308  switch(m_eCurrOper)
1309  {
1310  case CALC_PLUS:
1311  {
1312  GetToken();
1313  left.MakeDouble();
1314  SwSbxValue right(Term());
1315  right.MakeDouble();
1316  left.Compute(SbxPLUS, right);
1317  m_nListPor++;
1318  break;
1319  }
1320  case CALC_MINUS:
1321  {
1322  GetToken();
1323  left.MakeDouble();
1324  SwSbxValue right(Term());
1325  right.MakeDouble();
1326  left.Compute(SbxMINUS, right);
1327  break;
1328  }
1329  default:
1330  {
1331  return left;
1332  }
1333  }
1334  }
1335 }
1336 
1337 OUString SwCalc::GetColumnName(const OUString& rName)
1338 {
1339  sal_Int32 nPos = rName.indexOf(DB_DELIM);
1340  if( -1 != nPos )
1341  {
1342  nPos = rName.indexOf(DB_DELIM, nPos + 1);
1343 
1344  if( -1 != nPos )
1345  return rName.copy(nPos + 1);
1346  }
1347  return rName;
1348 }
1349 
1350 OUString SwCalc::GetDBName(std::u16string_view rName)
1351 {
1352  size_t nPos = rName.find(DB_DELIM);
1353  if( std::u16string_view::npos != nPos )
1354  {
1355  nPos = rName.find(DB_DELIM, nPos + 1);
1356 
1357  if( std::u16string_view::npos != nPos )
1358  return OUString(rName.substr( 0, nPos ));
1359  }
1361  return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand;
1362 }
1363 
1364 namespace
1365 {
1366  bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1367  double& rVal,
1368  const LocaleDataWrapper* const pLclData )
1369  {
1370  assert(pLclData);
1371  const sal_Unicode nCurrCmdPos = rCommandPos;
1372  rtl_math_ConversionStatus eStatus;
1373  const sal_Unicode* pEnd;
1374  rVal = pLclData->stringToDouble( rCommand.getStr() + rCommandPos,
1375  rCommand.getStr() + rCommand.getLength(),
1376  true,
1377  &eStatus,
1378  &pEnd );
1379  rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1380 
1381  return rtl_math_ConversionStatus_Ok == eStatus &&
1382  nCurrCmdPos != rCommandPos;
1383  }
1384 }
1385 
1386 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1387  double& rVal )
1388 {
1389  const SvtSysLocale aSysLocale;
1390  return lcl_Str2Double( rCommand, rCommandPos, rVal, &aSysLocale.GetLocaleData() );
1391 }
1392 
1393 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1394  double& rVal, SwDoc const * const pDoc )
1395 {
1396  const SvtSysLocale aSysLocale;
1397  std::unique_ptr<const LocaleDataWrapper> pLclD;
1398  if( pDoc )
1399  {
1400  LanguageType eLang = GetDocAppScriptLang( *pDoc );
1401  if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1402  {
1403  pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1404  }
1405  }
1406 
1407  bool const bRet = lcl_Str2Double(rCommand, rCommandPos, rVal,
1408  pLclD ? pLclD.get() : &aSysLocale.GetLocaleData());
1409 
1410  return bRet;
1411 }
1412 
1413 bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1414 {
1415  bool bRet = false;
1416  using namespace ::com::sun::star::i18n;
1417  {
1418  // Parse any token.
1419  ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1420  coStartFlags, OUString(),
1421  coContFlags, OUString() );
1422 
1423  if( aRes.TokenType & KParseType::IDENTNAME )
1424  {
1425  bRet = aRes.EndPos == rStr.getLength();
1426  if( pValidName )
1427  {
1428  *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1429  aRes.EndPos - aRes.LeadingWhiteSpace );
1430  }
1431  }
1432  else if( pValidName )
1433  pValidName->clear();
1434  }
1435  return bRet;
1436 }
1437 
1438 SwHash::SwHash(const OUString& rStr)
1439  : aStr(rStr)
1440 {
1441 }
1442 
1444 {
1445 }
1446 
1447 SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1448  const SwFieldType* pType)
1449  : SwHash(rStr)
1450  , nValue(rVal)
1451  , pFieldType(pType)
1452 {
1453 }
1454 
1456 {
1457  return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1458  : SbxValue::GetBool();
1459 }
1460 
1462 {
1463  double nRet;
1464  if( SbxSTRING == GetType() )
1465  {
1466  sal_Int32 nStt = 0;
1467  SwCalc::Str2Double( GetOUString(), nStt, nRet );
1468  }
1469  else if (IsBool())
1470  {
1471  nRet = GetBool() ? 1.0 : 0.0;
1472  }
1473  else
1474  {
1475  nRet = SbxValue::GetDouble();
1476  }
1477  return nRet;
1478 }
1479 
1481 {
1482  if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1483  PutDouble( GetDouble() );
1484  return *this;
1485 }
1486 
1487 #ifdef STANDALONE_HASHCALC
1488 
1489 // this is example code how to create hash values in the CTOR:
1490 
1491 #include <stdio.h>
1492 void main()
1493 {
1494  static char
1495  sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1496  sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1497  sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1498  sNType9[] = "word", sNType10[]= "char",
1499  sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1500  sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1501  sNType15[] = "user_street" , sNType16[] = "user_country" ,
1502  sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1503  sNType19[] = "user_title" , sNType20[] = "user_position" ,
1504  sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1505  sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1506  sNType25[] = "user_state", sNType26[] = "graph"
1507  ;
1508 
1509  static const char* sNTypeTab[ 27 ] =
1510  {
1511  sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1512  sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1513  sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1514  sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1515  sNType24, sNType25, sNType26
1516  };
1517 
1518  const unsigned short nTableSize = 47;
1519  int aArr[ nTableSize ] = { 0 };
1520  char ch;
1521 
1522  for( int n = 0; n < 27; ++n )
1523  {
1524  unsigned int ii = 0;
1525  const char* pp = sNTypeTab[ n ];
1526 
1527  while( *pp )
1528  {
1529  ii = ii << 1 ^ *pp++;
1530  }
1531  ii %= nTableSize;
1532 
1533  ch = aArr[ ii ] ? 'X' : ' ';
1534  aArr[ ii ] = 1;
1535  printf( "%-20s -> %3u [%c]\n", sNTypeTab[ n ], ii, ch );
1536  }
1537 }
1538 
1539 #endif
1540 
1541 /* 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:241
SwCalcExp(const OUString &rStr, const SwSbxValue &rVal, const SwFieldType *pFieldType)
Definition: calc.cxx:1447
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:134
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:201
SbxOperator
SbxLT
sal_uInt64 left
sal_uLong nPara
paragraphs for document statistic: non-empty and non-hidden ones
Definition: docstat.hxx:32
const char sCalc_Acos[]
Definition: calc.cxx:82
static ShellResource * GetShellRes()
Definition: viewsh.cxx:2662
OUString aCalc_Default
Definition: shellres.hxx:40
#define TBLSZ
Definition: calc.hxx:39
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1410
SbxNE
const char sCalc_Tan[]
Definition: calc.cxx:80
bool m_bHasNumber
Definition: calc.hxx:211
SbxMINUS
OUString GetOUString() const
sal_uInt16 GetType() const
Definition: usrfld.hxx:87
const char sCalc_Product[]
Definition: calc.cxx:86
LanguageType getLanguageType(bool bResolveSystem=true) const
Definition: calc.hxx:48
OUString m_sCommand
Definition: calc.hxx:199
CalcOp * FindOperator(const OUString &rSrch)
Definition: calc.cxx:184
const char sCalc_Count[]
Definition: calc.cxx:88
const char sCalc_Cos[]
Definition: calc.cxx:79
std::unique_ptr< LocaleDataWrapper > m_xLocaleDataWrapper
Definition: calc.hxx:207
bool OpenDataSource(const OUString &rDataSource, const OUString &rTableOrQuery)
open the source while fields are updated - for the calculator only!
Definition: dbmgr.cxx:2284
sal_uIntPtr sal_uLong
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
OUString sDataSource
Definition: swdbdata.hxx:30
SwCalc(const SwCalc &)=delete
sal_Int64 n
Definition: doc.hxx:187
const LanguageTag & getLanguageTag() const
const SwFieldType * pFieldType
Definition: calc.hxx:145
sal_uLong nChar
Definition: docstat.hxx:37
sal_uInt16 nTable
Definition: docstat.hxx:27
std::unique_ptr< SwHash > pNext
Definition: calc.hxx:139
const char * pName
Definition: calc.cxx:97
const char sCalc_Date[]
Definition: calc.cxx:85
bool IsInMerge() const
Definition: dbmgr.hxx:342
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
static const OUString & GetTypeStr(SwFieldTypesEnum nTypeId)
Definition: fldbas.cxx:122
SwSbxValue Term()
Definition: calc.cxx:860
const sal_Int32 coStartFlags
Definition: calc.cxx:148
static LanguageType nLang
Definition: srtdlg.cxx:51
const char sCalc_Not[]
Definition: calc.cxx:67
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:1201
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:71
void SetCharClass(const LanguageTag &rLanguageTag)
Definition: calc.cxx:630
static bool Str2Double(const OUString &rStr, sal_Int32 &rPos, double &rVal)
Definition: calc.cxx:1386
SwCalcError
Definition: calc.hxx:102
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:664
Definition: calc.hxx:51
SbxBOOL
OUString aCalc_Overflow
Definition: shellres.hxx:39
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:204
SwCalcOper m_eCurrListOper
Definition: calc.hxx:213
OUString GetDBName(std::u16string_view rName)
Definition: calc.cxx:1350
SwSbxValue StdFunc(pfCalc pFnc, bool bChkTrig)
Definition: calc.cxx:1041
sal_uInt16 nOLE
Definition: docstat.hxx:29
SwSbxValue & MakeDouble()
Definition: calc.cxx:1480
Definition: calc.cxx:94
double(* pfCalc)(double)
Definition: calc.hxx:192
OString right
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:144
double const nRoundVal[]
Definition: calc.cxx:141
double GetDouble() const
Definition: calc.cxx:1461
sal_uInt16 char * pName
SwSbxValue Prim()
Definition: calc.cxx:1265
SwDoc & m_rDoc
Definition: calc.hxx:206
bool IsNumeric() const
#define SW_MOD()
Definition: swmodule.hxx:255
const char sCalc_Pow[]
Definition: calc.cxx:63
Definition: calc.hxx:48
SwDBData const & GetDBData()
Definition: docfld.cxx:384
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:635
bool IsBool() const
static double lcl_ConvertToDateValue(SwDoc &rDoc, sal_Int32 nDate)
Definition: calc.cxx:205
SwSbxValue m_nNumberValue
Definition: calc.hxx:202
bool GetColumnCnt(const OUString &rSourceName, const OUString &rTableName, const OUString &rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:2020
const char sCalc_Sign[]
Definition: calc.cxx:89
SwCalcExp m_aErrExpr
Definition: calc.hxx:203
const SvxPageUsage aArr[]
const char sCalc_Atan[]
Definition: calc.cxx:83
const sal_Int32 coContFlags
Definition: calc.cxx:154
virtual ~SwHash()
Definition: calc.cxx:1443
static OUString GetColumnName(const OUString &rName)
Definition: calc.cxx:1337
bool IsVoidValue() const
Definition: calc.hxx:126
SwCalcOper
Definition: calc.hxx:43
const char sCalc_Sqrt[]
Definition: calc.cxx:62
sal_uInt16 GetWhichOfScript(sal_uInt16 nWhich, sal_uInt16 nScript)
Definition: hints.cxx:193
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:162
const char sCalc_Max[]
Definition: calc.cxx:77
SwHash(const OUString &rStr)
Definition: calc.cxx:1438
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:70
#define DB_DELIM
Definition: swtypes.hxx:130
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:1413
OUStringBuffer m_aVarName
Definition: calc.hxx:197
SbxLE
SwCalcError m_eError
Definition: calc.hxx:214
bool IsDBvalue() const
Definition: calc.hxx:129
OUString GetFirstName() const
const char sCalc_Sub[]
Definition: calc.cxx:58
bool GetBool() const
SwSbxValue Expr()
Definition: calc.cxx:1302
SwSbxValue Calculate(const OUString &rStr)
Definition: calc.cxx:356
sal_uInt16 m_nListPor
Definition: calc.hxx:210
bool IsValid() const
Definition: usrfld.hxx:78
SwHashTable< SwCalcFieldType > const & GetFieldTypeTable() const
Definition: docfld.hxx:187
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:73
SwHashTable< SwCalcExp > m_aVarTable
Definition: calc.hxx:196
SbxEQ
OUString GetLastName() const
SbxSTRING
sal_uInt32 GetSelectedRecordId(const OUString &rDataSource, const OUString &rTableOrQuery, sal_Int32 nCommandType=-1)
Definition: dbmgr.cxx:2352
UserOptToken
const char sCalc_Neq[]
Definition: calc.cxx:69
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:57
LanguageType GetAppLanguage()
Definition: init.cxx:725
OString strip(const OString &rIn, char c)
const char sCalc_Int[]
Definition: calc.cxx:91
bool PutDouble(double)
virtual SwDocUpdateField & GetUpdateFields() const =0
CalcOp const aOpTable[]
Definition: calc.cxx:103
bool GetBool() const
Definition: calc.cxx:1455
const char sCalc_Phd[]
Definition: calc.cxx:61
const char sCalc_Div[]
Definition: calc.cxx:60
Reference< XComponentContext > getProcessComponentContext()
SwCalcOper eOp
Definition: calc.cxx:100
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:208
const char sCalc_Xor[]
Definition: calc.cxx:65
SwCalcExp * VarLook(const OUString &rStr, bool bIns=false)
Definition: calc.cxx:422
double stringToDouble(std::u16string_view aString, bool bUseGroupSep, rtl_math_ConversionStatus *pStatus, sal_Int32 *pParseEnd) const
SwSbxValue PrimFunc(bool &rChkPow)
Definition: calc.cxx:1053
SwCalcOper m_eCurrOper
Definition: calc.hxx:212
const LanguageTag & GetLanguageTag() const
const CharClass * GetCharClass() const
Definition: calc.cxx:625
SbxMUL
const OUString * pUName
Definition: calc.cxx:98
const SwGetSetExpType GSE_STRING
String.
Definition: fldbas.hxx:203
SwCalcExp * VarInsert(const OUString &r)
Definition: calc.cxx:416
const char sCalc_Eq[]
Definition: calc.cxx:68
OUString m_sCurrSym
Definition: calc.hxx:198
const char sCalc_Sin[]
Definition: calc.cxx:78
const sal_Unicode cListDelim
Definition: calc.hxx:41
sal_uLong nWord
Definition: docstat.hxx:35
SbxGT
const Date & GetNullDate() const
bool Push(const SwUserFieldType *pUserFieldType)
Definition: calc.cxx:609
bool Compute(SbxOperator, const SbxValue &)
CharClass & GetAppCharClass()
Definition: init.cxx:705
SwFieldIds Which() const
Definition: fldbas.hxx:273
OUString sCommand
Definition: swdbdata.hxx:31
aStr
SwDBManager * GetDBManager() const
Definition: doc.hxx:669
sal_uInt16 nPos
OUString aStr
Definition: calc.hxx:138
Definition: calc.hxx:50
const char sCalc_Mean[]
Definition: calc.cxx:75
sal_Int16 nValue
std::vector< const SwUserFieldType * > m_aRekurStack
Definition: calc.hxx:200
void SetVoidValue(bool bSet)
Definition: calc.hxx:127
SbxDIV
bool m_bDetectedRangeSegmentation false