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