LibreOffice Module sw (master)  1
calc.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <config_features.h>
21 
22 #include <calc.hxx>
23 #include <cfloat>
24 #include <climits>
25 #include <memory>
26 #include <string_view>
28 #include <comphelper/string.hxx>
29 #include <cstdlib>
30 #include <dbmgr.hxx>
31 #include <docfld.hxx>
32 #include <docstat.hxx>
33 #include <doc.hxx>
35 #include <IDocumentStatistics.hxx>
36 #include <editeng/langitem.hxx>
37 #include <expfld.hxx>
38 #include <hintids.hxx>
39 #include <o3tl/temporary.hxx>
40 #include <osl/diagnose.h>
41 #include <rtl/math.hxx>
42 #include <shellres.hxx>
43 #include <svl/languageoptions.hxx>
44 #include <svl/zforlist.hxx>
45 #include <swmodule.hxx>
46 #include <swtypes.hxx>
47 #include <unotools/charclass.hxx>
49 #include <unotools/useroptions.hxx>
50 #include <usrfld.hxx>
51 #include <viewsh.hxx>
52 #include <com/sun/star/i18n/KParseTokens.hpp>
53 #include <com/sun/star/i18n/KParseType.hpp>
54 
55 using namespace ::com::sun::star;
56 
57 const char sCalc_Add[] = "add";
58 const char sCalc_Sub[] = "sub";
59 const char sCalc_Mul[] = "mul";
60 const char sCalc_Div[] = "div";
61 const char sCalc_Phd[] = "phd";
62 const char sCalc_Sqrt[] = "sqrt";
63 const char sCalc_Pow[] = "pow";
64 const char sCalc_Or[] = "or";
65 const char sCalc_Xor[] = "xor";
66 const char sCalc_And[] = "and";
67 const char sCalc_Not[] = "not";
68 const char sCalc_Eq[] = "eq";
69 const char sCalc_Neq[] = "neq";
70 const char sCalc_Leq[] = "leq";
71 const char sCalc_Geq[] = "geq";
72 const char sCalc_L[] = "l";
73 const char sCalc_G[] = "g";
74 const char sCalc_Sum[] = "sum";
75 const char sCalc_Mean[] = "mean";
76 const char sCalc_Min[] = "min";
77 const char sCalc_Max[] = "max";
78 const char sCalc_Sin[] = "sin";
79 const char sCalc_Cos[] = "cos";
80 const char sCalc_Tan[] = "tan";
81 const char sCalc_Asin[] = "asin";
82 const char sCalc_Acos[] = "acos";
83 const char sCalc_Atan[] = "atan";
84 const char sCalc_Round[]= "round";
85 const char sCalc_Date[] = "date";
86 
87 // ATTENTION: sorted list of all operators
88 struct CalcOp
89 {
90  union{
91  const 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 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 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 
361  for (;;)
362  {
363  m_eCurrOper = GetToken();
365  break;
366  nResult = Expr();
367  }
368 
370  nResult.PutDouble( DBL_MAX );
371 
372  return nResult;
373 }
374 
375 OUString SwCalc::GetStrResult( const SwSbxValue& rVal )
376 {
377  if( !rVal.IsDouble() )
378  {
379  return rVal.GetOUString();
380  }
381  return GetStrResult( rVal.GetDouble() );
382 }
383 
384 OUString SwCalc::GetStrResult( double nValue )
385 {
386  if( nValue >= DBL_MAX )
387  switch( m_eError )
388  {
394  default : return SwViewShell::GetShellRes()->aCalc_Default;
395  }
396 
397  const sal_Int32 nDecPlaces = 15;
398  OUString aRetStr( ::rtl::math::doubleToUString(
399  nValue,
400  rtl_math_StringFormat_Automatic,
401  nDecPlaces,
403  true ));
404  return aRetStr;
405 }
406 
407 SwCalcExp* SwCalc::VarInsert( const OUString &rStr )
408 {
409  OUString aStr = m_pCharClass->lowercase( rStr );
410  return VarLook( aStr, true );
411 }
412 
413 SwCalcExp* SwCalc::VarLook( const OUString& rStr, bool bIns )
414 {
416 
417  sal_uInt16 ii = 0;
418  OUString aStr = m_pCharClass->lowercase( rStr );
419 
420  SwCalcExp* pFnd = m_aVarTable.Find(aStr, &ii);
421 
422  if( !pFnd )
423  {
424  // then check doc
426  for( SwHash* pEntry = rDocTable[ii].get(); pEntry; pEntry = pEntry->pNext.get() )
427  {
428  if( aStr == pEntry->aStr )
429  {
430  // then insert here
431  pFnd = new SwCalcExp( aStr, SwSbxValue(),
432  static_cast<SwCalcFieldType*>(pEntry)->pFieldType );
433  pFnd->pNext = std::move( m_aVarTable[ii] );
434  m_aVarTable[ii].reset(pFnd);
435  break;
436  }
437  }
438  }
439 
440  if( pFnd )
441  {
442  if( pFnd->pFieldType && pFnd->pFieldType->Which() == SwFieldIds::User )
443  {
444  SwUserFieldType* pUField = const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFnd->pFieldType));
445  if( nsSwGetSetExpType::GSE_STRING & pUField->GetType() )
446  {
447  pFnd->nValue.PutString( pUField->GetContent() );
448  }
449  else if( !pUField->IsValid() )
450  {
451  // Save the current values...
452  sal_uInt16 nListPor = m_nListPor;
453  SwSbxValue nLastLeft = m_nLastLeft;
454  SwSbxValue nNumberValue = m_nNumberValue;
455  sal_Int32 nCommandPos = m_nCommandPos;
456  SwCalcOper eCurrOper = m_eCurrOper;
457  SwCalcOper eCurrListOper = m_eCurrListOper;
458  OUString sCurrCommand = m_sCommand;
459 
460  pFnd->nValue.PutDouble( pUField->GetValue( *this ) );
461 
462  // ...and write them back.
463  m_nListPor = nListPor;
464  m_nLastLeft = nLastLeft;
465  m_nNumberValue = nNumberValue;
466  m_nCommandPos = nCommandPos;
467  m_eCurrOper = eCurrOper;
468  m_eCurrListOper = eCurrListOper;
469  m_sCommand = sCurrCommand;
470  }
471  else
472  {
473  pFnd->nValue.PutDouble( pUField->GetValue() );
474  }
475  }
476  else if ( !pFnd->pFieldType && pFnd->nValue.IsDBvalue() )
477  {
478  if ( pFnd->nValue.IsString() )
480  else if ( pFnd->nValue.IsDouble() )
482  pFnd = &m_aErrExpr;
483  }
484  return pFnd;
485  }
486 
487  // At this point the "real" case variable has to be used
488  OUString const sTmpName( ::ReplacePoint(rStr) );
489 
490  if( !bIns )
491  {
492 #if HAVE_FEATURE_DBCONNECTIVITY
493  SwDBManager *pMgr = m_rDoc.GetDBManager();
494 
495  OUString sDBName(GetDBName( sTmpName ));
496  OUString sSourceName(sDBName.getToken(0, DB_DELIM));
497  OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
498  if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
499  pMgr->OpenDataSource(sSourceName, sTableName))
500  {
501  OUString sColumnName( GetColumnName( sTmpName ));
502  OSL_ENSURE(!sColumnName.isEmpty(), "Missing DB column name");
503 
505  sDBNum = m_pCharClass->lowercase(sDBNum);
506 
507  // Initialize again because this doesn't happen in docfld anymore for
508  // elements != SwFieldIds::Database. E.g. if there is an expression field before
509  // a DB_Field in a document.
510  const sal_uInt32 nTmpRec = pMgr->GetSelectedRecordId(sSourceName, sTableName);
511  VarChange(sDBNum, nTmpRec);
512 
513  if( sDBNum.equalsIgnoreAsciiCase(sColumnName) )
514  {
515  m_aErrExpr.nValue.PutULong(nTmpRec);
516  return &m_aErrExpr;
517  }
518 
519  OUString sResult;
520  double nNumber = DBL_MAX;
521 
523  if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
524  nTmpRec, nLang, sResult, &nNumber ))
525  {
526  if (nNumber != DBL_MAX)
527  m_aErrExpr.nValue.PutDouble( nNumber );
528  else
529  m_aErrExpr.nValue.PutString( sResult );
530 
531  return &m_aErrExpr;
532  }
533  }
534  else
535 #endif
536  {
537  //data source was not available - set return to "NoValue"
539  }
540  // NEVER save!
541  return &m_aErrExpr;
542  }
543 
544  SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), nullptr );
545  pNewExp->pNext = std::move( m_aVarTable[ ii ] );
546  m_aVarTable[ ii ].reset( pNewExp );
547 
548  OUString sColumnName( GetColumnName( sTmpName ));
549  OSL_ENSURE( !sColumnName.isEmpty(), "Missing DB column name" );
550  if( sColumnName.equalsIgnoreAsciiCase(
552  {
553 #if HAVE_FEATURE_DBCONNECTIVITY
554  SwDBManager *pMgr = m_rDoc.GetDBManager();
555  OUString sDBName(GetDBName( sTmpName ));
556  OUString sSourceName(sDBName.getToken(0, DB_DELIM));
557  OUString sTableName(sDBName.getToken(0, ';').getToken(1, DB_DELIM));
558  if( pMgr && !sSourceName.isEmpty() && !sTableName.isEmpty() &&
559  pMgr->OpenDataSource(sSourceName, sTableName) &&
560  !pMgr->IsInMerge())
561  {
562  pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
563  }
564  else
565 #endif
566  {
567  pNewExp->nValue.SetVoidValue(true);
568  }
569  }
570 
571  return pNewExp;
572 }
573 
574 void SwCalc::VarChange( const OUString& rStr, double nValue )
575 {
576  SwSbxValue aVal( nValue );
577  VarChange( rStr, aVal );
578 }
579 
580 void SwCalc::VarChange( const OUString& rStr, const SwSbxValue& rValue )
581 {
582  OUString aStr = m_pCharClass->lowercase( rStr );
583 
584  sal_uInt16 nPos = 0;
585  SwCalcExp* pFnd = m_aVarTable.Find( aStr, &nPos );
586 
587  if( !pFnd )
588  {
589  pFnd = new SwCalcExp( aStr, rValue, nullptr );
590  pFnd->pNext = std::move( m_aVarTable[ nPos ] );
591  m_aVarTable[ nPos ].reset( pFnd );
592  }
593  else
594  {
595  pFnd->nValue = rValue;
596  }
597 }
598 
599 bool SwCalc::Push( const SwUserFieldType* pUserFieldType )
600 {
601  if( m_aRekurStack.end() != std::find(m_aRekurStack.begin(), m_aRekurStack.end(), pUserFieldType ) )
602  return false;
603 
604  m_aRekurStack.push_back( pUserFieldType );
605  return true;
606 }
607 
609 {
610  OSL_ENSURE( m_aRekurStack.size(), "SwCalc: Pop on an invalid pointer" );
611 
612  m_aRekurStack.pop_back();
613 }
614 
616 {
617  return m_pCharClass;
618 }
619 
621 {
622  if( m_nCommandPos >= m_sCommand.getLength() )
623  {
625  return m_eCurrOper;
626  }
627 
628  using namespace ::com::sun::star::i18n;
629  {
630  // Parse any token.
631  ParseResult aRes = m_pCharClass->parseAnyToken( m_sCommand, m_nCommandPos,
632  coStartFlags, OUString(),
633  coContFlags, OUString());
634 
635  bool bSetError = true;
636  sal_Int32 nRealStt = m_nCommandPos + aRes.LeadingWhiteSpace;
637  if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
638  {
639  m_nNumberValue.PutDouble( aRes.Value );
641  bSetError = false;
642  }
643  else if( aRes.TokenType & KParseType::IDENTNAME )
644  {
645  OUString aName( m_sCommand.copy( nRealStt,
646  aRes.EndPos - nRealStt ) );
647  //#101436#: The variable may contain a database name. It must not be
648  // converted to lower case! Instead all further comparisons must be
649  // done case-insensitive
650  OUString sLowerCaseName = m_pCharClass->lowercase( aName );
651  // catch currency symbol
652  if( sLowerCaseName == m_sCurrSym )
653  {
654  m_nCommandPos = aRes.EndPos;
655  return GetToken(); // call again
656  }
657 
658  // catch operators
659  CalcOp* pFnd = ::FindOperator( sLowerCaseName );
660  if( pFnd )
661  {
662  m_eCurrOper = pFnd->eOp;
663  switch( m_eCurrOper )
664  {
665  case CALC_SUM:
666  case CALC_MEAN:
668  break;
669  case CALC_MIN:
671  break;
672  case CALC_MAX:
674  break;
675  case CALC_DATE:
677  break;
678  default:
679  break;
680  }
681  m_nCommandPos = aRes.EndPos;
682  return m_eCurrOper;
683  }
684  m_aVarName = aName;
686  bSetError = false;
687  }
688  else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
689  {
690  m_nNumberValue.PutString( aRes.DequotedNameOrString );
692  bSetError = false;
693  }
694  else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
695  {
696  OUString aName( m_sCommand.copy( nRealStt,
697  aRes.EndPos - nRealStt ));
698  if( 1 == aName.getLength() )
699  {
700  bSetError = false;
701  sal_Unicode ch = aName[0];
702  switch( ch )
703  {
704  case ';':
706  {
708  break;
709  }
710  [[fallthrough]];
711  case '\n':
713  break;
714 
715  case '%':
716  case '^':
717  case '*':
718  case '/':
719  case '+':
720  case '-':
721  case '(':
722  case ')':
723  m_eCurrOper = SwCalcOper(ch);
724  break;
725 
726  case '=':
727  case '!':
728  {
729  SwCalcOper eTmp2;
730  if( '=' == ch )
731  {
732  m_eCurrOper = SwCalcOper('=');
733  eTmp2 = CALC_EQ;
734  }
735  else
736  {
738  eTmp2 = CALC_NEQ;
739  }
740 
741  if( aRes.EndPos < m_sCommand.getLength() &&
742  '=' == m_sCommand[aRes.EndPos] )
743  {
744  m_eCurrOper = eTmp2;
745  ++aRes.EndPos;
746  }
747  }
748  break;
749 
750  case cListDelim:
752  break;
753 
754  case '[':
755  if( aRes.EndPos < m_sCommand.getLength() )
756  {
757  m_aVarName.setLength(0);
758  sal_Int32 nFndPos = aRes.EndPos,
759  nSttPos = nFndPos;
760 
761  do {
762  if( -1 != ( nFndPos =
763  m_sCommand.indexOf( ']', nFndPos )) )
764  {
765  // ignore the ]
766  if ('\\' == m_sCommand[nFndPos-1])
767  {
768  m_aVarName.append(std::u16string_view(m_sCommand).substr(nSttPos,
769  nFndPos - nSttPos - 1) );
770  nSttPos = ++nFndPos;
771  }
772  else
773  break;
774  }
775  } while( nFndPos != -1 );
776 
777  if( nFndPos != -1 )
778  {
779  if( nSttPos != nFndPos )
780  m_aVarName.append(std::u16string_view(m_sCommand).substr(nSttPos,
781  nFndPos - nSttPos) );
782  aRes.EndPos = nFndPos + 1;
784  }
785  else
786  bSetError = true;
787  }
788  else
789  {
790  bSetError = true;
791  }
792  break;
793 
794  default:
795  bSetError = true;
796  break;
797  }
798  }
799  }
800  else if( aRes.TokenType & KParseType::BOOLEAN )
801  {
802  OUString aName( m_sCommand.copy( nRealStt,
803  aRes.EndPos - nRealStt ));
804  if( !aName.isEmpty() )
805  {
806  sal_Unicode ch = aName[0];
807 
808  bSetError = true;
809  if ('<' == ch || '>' == ch)
810  {
811  bSetError = false;
812 
813  SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
814  m_eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
815 
816  if( 2 == aName.getLength() && '=' == aName[1] )
817  m_eCurrOper = eTmp2;
818  else if( 1 != aName.getLength() )
819  bSetError = true;
820  }
821  }
822  }
823  else if( nRealStt == m_sCommand.getLength() )
824  {
826  bSetError = false;
827  }
828 
829  if( bSetError )
830  {
833  }
834  m_nCommandPos = aRes.EndPos;
835  };
836 
837  return m_eCurrOper;
838 }
839 
841 {
842  SwSbxValue left( Prim() );
843  m_nLastLeft = left;
844  for(;;)
845  {
846  sal_uInt16 nSbxOper = USHRT_MAX;
847 
848  switch( m_eCurrOper )
849  {
850  case CALC_AND:
851  {
852  GetToken();
853  bool bB = Prim().GetBool();
854  left.PutBool( left.GetBool() && bB );
855  }
856  break;
857  case CALC_OR:
858  {
859  GetToken();
860  bool bB = Prim().GetBool();
861  left.PutBool( left.GetBool() || bB );
862  }
863  break;
864  case CALC_XOR:
865  {
866  GetToken();
867  bool bR = Prim().GetBool();
868  bool bL = left.GetBool();
869  left.PutBool(bL != bR);
870  }
871  break;
872 
873  case CALC_EQ: nSbxOper = SbxEQ; break;
874  case CALC_NEQ: nSbxOper = SbxNE; break;
875  case CALC_LEQ: nSbxOper = SbxLE; break;
876  case CALC_GEQ: nSbxOper = SbxGE; break;
877  case CALC_GRE: nSbxOper = SbxGT; break;
878  case CALC_LES: nSbxOper = SbxLT; break;
879 
880  case CALC_MUL: nSbxOper = SbxMUL; break;
881  case CALC_DIV: nSbxOper = SbxDIV; break;
882 
883  case CALC_MIN_IN:
884  {
885  GetToken();
886  SwSbxValue e = Prim();
887  left = left.GetDouble() < e.GetDouble() ? left : e;
888  }
889  break;
890  case CALC_MAX_IN:
891  {
892  GetToken();
893  SwSbxValue e = Prim();
894  left = left.GetDouble() > e.GetDouble() ? left : e;
895  }
896  break;
897  case CALC_MONTH:
898  {
899  GetToken();
900  SwSbxValue e = Prim();
901  sal_Int32 nYear = static_cast<sal_Int32>(floor( left.GetDouble() ));
902  nYear = nYear & 0x0000FFFF;
903  sal_Int32 nMonth = static_cast<sal_Int32>(floor( e.GetDouble() ));
904  nMonth = ( nMonth & 0x000000FF ) << 16;
905  left.PutLong( nMonth + nYear );
907  }
908  break;
909  case CALC_DAY:
910  {
911  GetToken();
912  SwSbxValue e = Prim();
913  sal_Int32 nYearMonth = static_cast<sal_Int32>(floor( left.GetDouble() ));
914  nYearMonth = nYearMonth & 0x00FFFFFF;
915  sal_Int32 nDay = static_cast<sal_Int32>(floor( e.GetDouble() ));
916  nDay = ( nDay & 0x000000FF ) << 24;
917  left = lcl_ConvertToDateValue( m_rDoc, nDay + nYearMonth );
918  }
919  break;
920  case CALC_ROUND:
921  {
922  GetToken();
923  SwSbxValue e = Prim();
924 
925  double fVal = 0;
926  double fFac = 1;
927  sal_Int32 nDec = static_cast<sal_Int32>(floor( e.GetDouble() ));
928  if( nDec < -20 || nDec > 20 )
929  {
931  left.Clear();
932  return left;
933  }
934  fVal = left.GetDouble();
935  if( nDec >= 0)
936  {
937  for (sal_Int32 i = 0; i < nDec; ++i )
938  fFac *= 10.0;
939  }
940  else
941  {
942  for (sal_Int32 i = 0; i < -nDec; ++i )
943  fFac /= 10.0;
944  }
945 
946  fVal *= fFac;
947  bool bSign;
948  if (fVal < 0.0)
949  {
950  fVal *= -1.0;
951  bSign = true;
952  }
953  else
954  {
955  bSign = false;
956  }
957 
958  // rounding
959  double fNum = fVal; // find the exponent
960  int nExp = 0;
961  if( fNum > 0 )
962  {
963  while( fNum < 1.0 )
964  {
965  fNum *= 10.0;
966  --nExp;
967  }
968  while( fNum >= 10.0 )
969  {
970  fNum /= 10.0;
971  ++nExp;
972  }
973  }
974  nExp = 15 - nExp;
975  if( nExp > 15 )
976  nExp = 15;
977  else if( nExp <= 1 )
978  nExp = 0;
979  fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
980 
981  if (bSign)
982  fVal *= -1.0;
983 
984  fVal /= fFac;
985 
986  left.PutDouble( fVal );
987  }
988  break;
989 
990 //#77448# (=2*3^2 != 18)
991 
992  default:
993  return left;
994  }
995 
996  if( USHRT_MAX != nSbxOper )
997  {
998  // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
999  SbxOperator eSbxOper = static_cast<SbxOperator>(nSbxOper);
1000 
1001  GetToken();
1002  if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1003  {
1004  left.PutBool( left.Compare( eSbxOper, Prim() ));
1005  }
1006  else
1007  {
1008  SwSbxValue aRight( Prim() );
1009  aRight.MakeDouble();
1010  left.MakeDouble();
1011 
1012  if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1014  else
1015  left.Compute( eSbxOper, aRight );
1016  }
1017  }
1018  }
1019 }
1020 
1021 SwSbxValue SwCalc::StdFunc(pfCalc pFnc, bool bChkTrig)
1022 {
1023  SwSbxValue nErg;
1024  GetToken();
1025  double nVal = Prim().GetDouble();
1026  if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1027  nErg.PutDouble( (*pFnc)( nVal ) );
1028  else
1030  return nErg;
1031 }
1032 
1034 {
1035  rChkPow = false;
1036 
1037  switch (m_eCurrOper)
1038  {
1039  case CALC_SIN:
1040  SAL_INFO("sw.calc", "sin");
1041  return StdFunc(&sin, false);
1042  break;
1043  case CALC_COS:
1044  SAL_INFO("sw.calc", "cos");
1045  return StdFunc(&cos, false);
1046  break;
1047  case CALC_TAN:
1048  SAL_INFO("sw.calc", "tan");
1049  return StdFunc(&tan, false);
1050  break;
1051  case CALC_ATAN:
1052  SAL_INFO("sw.calc", "atan");
1053  return StdFunc(&atan, false);
1054  break;
1055  case CALC_ASIN:
1056  SAL_INFO("sw.calc", "asin");
1057  return StdFunc(&asin, true);
1058  break;
1059  case CALC_ACOS:
1060  SAL_INFO("sw.calc", "acos");
1061  return StdFunc(&acos, true);
1062  break;
1063  case CALC_NOT:
1064  {
1065  SAL_INFO("sw.calc", "not");
1066  GetToken();
1067  SwSbxValue nErg = Prim();
1068  if( SbxSTRING == nErg.GetType() )
1069  {
1070  nErg.PutBool( nErg.GetOUString().isEmpty() );
1071  }
1072  else if(SbxBOOL == nErg.GetType() )
1073  {
1074  nErg.PutBool(!nErg.GetBool());
1075  }
1076  // Evaluate arguments manually so that the binary NOT below does not
1077  // get called. We want a BOOLEAN NOT.
1078  else if (nErg.IsNumeric())
1079  {
1080  nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1081  }
1082  else
1083  {
1084  OSL_FAIL( "unexpected case. computing binary NOT" );
1086  nErg.Compute( SbxNOT, nErg );
1087  }
1088  return nErg;
1089  break;
1090  }
1091  case CALC_NUMBER:
1092  {
1093  SAL_INFO("sw.calc", "number: " << m_nNumberValue.GetDouble());
1094  SwSbxValue nErg;
1095  if( GetToken() == CALC_PHD )
1096  {
1097  double aTmp = m_nNumberValue.GetDouble();
1098  aTmp *= 0.01;
1099  nErg.PutDouble( aTmp );
1100  GetToken();
1101  }
1102  else if( m_eCurrOper == CALC_NAME )
1103  {
1105  }
1106  else
1107  {
1108  nErg = m_nNumberValue;
1109  rChkPow = true;
1110  }
1111  return nErg;
1112  break;
1113  }
1114  case CALC_NAME:
1115  {
1116  SAL_INFO("sw.calc", "name");
1117  SwSbxValue nErg;
1118  switch(SwCalcOper eOper = GetToken())
1119  {
1120  case CALC_ASSIGN:
1121  {
1122  SwCalcExp* n = VarInsert(m_aVarName.toString());
1123  GetToken();
1124  nErg = n->nValue = Expr();
1125  break;
1126  }
1127  default:
1128  nErg = VarLook(m_aVarName.toString())->nValue;
1129  // Explicitly disallow unknown function names (followed by "("),
1130  // allow unknown variable names (equal to zero)
1131  if (nErg.IsVoidValue() && (eOper == CALC_LP))
1133  else
1134  rChkPow = true;
1135  break;
1136  }
1137  return nErg;
1138  break;
1139  }
1140  case CALC_MINUS:
1141  {
1142  SAL_INFO("sw.calc", "-");
1143  SwSbxValue nErg;
1144  GetToken();
1145  nErg.PutDouble( -(Prim().GetDouble()) );
1146  return nErg;
1147  break;
1148  }
1149  case CALC_LP:
1150  {
1151  SAL_INFO("sw.calc", "(");
1152  GetToken();
1153  SwSbxValue nErg = Expr();
1154  if( m_eCurrOper != CALC_RP )
1155  {
1157  }
1158  else
1159  {
1160  GetToken();
1161  rChkPow = true; // in order for =(7)^2 to work
1162  }
1163  return nErg;
1164  break;
1165  }
1166  case CALC_RP:
1167  // ignore, see tdf#121962
1168  SAL_INFO("sw.calc", ")");
1169  break;
1170  case CALC_MEAN:
1171  {
1172  SAL_INFO("sw.calc", "mean");
1173  m_nListPor = 1;
1174  GetToken();
1175  SwSbxValue nErg = Expr();
1176  double aTmp = nErg.GetDouble();
1177  aTmp /= m_nListPor;
1178  nErg.PutDouble( aTmp );
1179  return nErg;
1180  break;
1181  }
1182  case CALC_SQRT:
1183  {
1184  SAL_INFO("sw.calc", "sqrt");
1185  GetToken();
1186  SwSbxValue nErg = Prim();
1187  if( nErg.GetDouble() < 0 )
1189  else
1190  nErg.PutDouble( sqrt( nErg.GetDouble() ));
1191  return nErg;
1192  break;
1193  }
1194  case CALC_SUM:
1195  case CALC_DATE:
1196  case CALC_MIN:
1197  case CALC_MAX:
1198  {
1199  SAL_INFO("sw.calc", "sum/date/min/max");
1200  GetToken();
1201  SwSbxValue nErg = Expr();
1202  return nErg;
1203  break;
1204  }
1205  case CALC_ENDCALC:
1206  {
1207  SAL_INFO("sw.calc", "endcalc");
1208  SwSbxValue nErg;
1209  nErg.Clear();
1210  return nErg;
1211  break;
1212  }
1213  default:
1214  SAL_INFO("sw.calc", "syntax error");
1216  break;
1217  }
1218 
1219  return SwSbxValue();
1220 }
1221 
1223 {
1224  bool bChkPow;
1225  SwSbxValue nErg = PrimFunc(bChkPow);
1226 
1227  if (bChkPow && m_eCurrOper == CALC_POW)
1228  {
1229  double dleft = nErg.GetDouble();
1230  GetToken();
1231  double right = Prim().GetDouble();
1232 
1233  double fraction;
1234  fraction = modf( right, &o3tl::temporary(double()) );
1235  if( ( dleft < 0.0 && 0.0 != fraction ) ||
1236  ( 0.0 == dleft && right < 0.0 ) )
1237  {
1239  nErg.Clear();
1240  }
1241  else
1242  {
1243  dleft = pow(dleft, right );
1244  if( dleft == HUGE_VAL )
1245  {
1247  nErg.Clear();
1248  }
1249  else
1250  {
1251  nErg.PutDouble( dleft );
1252  }
1253  }
1254  }
1255 
1256  return nErg;
1257 }
1258 
1260 {
1261  SwSbxValue left = Term();
1262  m_nLastLeft = left;
1263  for(;;)
1264  {
1265  switch(m_eCurrOper)
1266  {
1267  case CALC_PLUS:
1268  {
1269  GetToken();
1270  left.MakeDouble();
1271  SwSbxValue right(Term());
1272  right.MakeDouble();
1273  left.Compute(SbxPLUS, right);
1274  m_nListPor++;
1275  break;
1276  }
1277  case CALC_MINUS:
1278  {
1279  GetToken();
1280  left.MakeDouble();
1281  SwSbxValue right(Term());
1282  right.MakeDouble();
1283  left.Compute(SbxMINUS, right);
1284  break;
1285  }
1286  default:
1287  {
1288  return left;
1289  }
1290  }
1291  }
1292 }
1293 
1294 OUString SwCalc::GetColumnName(const OUString& rName)
1295 {
1296  sal_Int32 nPos = rName.indexOf(DB_DELIM);
1297  if( -1 != nPos )
1298  {
1299  nPos = rName.indexOf(DB_DELIM, nPos + 1);
1300 
1301  if( -1 != nPos )
1302  return rName.copy(nPos + 1);
1303  }
1304  return rName;
1305 }
1306 
1307 OUString SwCalc::GetDBName(const OUString& rName)
1308 {
1309  sal_Int32 nPos = rName.indexOf(DB_DELIM);
1310  if( -1 != nPos )
1311  {
1312  nPos = rName.indexOf(DB_DELIM, nPos + 1);
1313 
1314  if( -1 != nPos )
1315  return rName.copy( 0, nPos );
1316  }
1318  return aData.sDataSource + OUStringChar(DB_DELIM) + aData.sCommand;
1319 }
1320 
1321 namespace
1322 {
1323  bool lcl_Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1324  double& rVal,
1325  const LocaleDataWrapper* const pLclData )
1326  {
1327  assert(pLclData);
1328  const sal_Unicode nCurrCmdPos = rCommandPos;
1329  rtl_math_ConversionStatus eStatus;
1330  const sal_Unicode* pEnd;
1331  rVal = pLclData->stringToDouble( rCommand.getStr() + rCommandPos,
1332  rCommand.getStr() + rCommand.getLength(),
1333  true,
1334  &eStatus,
1335  &pEnd );
1336  rCommandPos = static_cast<sal_Int32>(pEnd - rCommand.getStr());
1337 
1338  return rtl_math_ConversionStatus_Ok == eStatus &&
1339  nCurrCmdPos != rCommandPos;
1340  }
1341 }
1342 
1343 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1344  double& rVal )
1345 {
1346  const SvtSysLocale aSysLocale;
1347  return lcl_Str2Double( rCommand, rCommandPos, rVal, aSysLocale.GetLocaleDataPtr() );
1348 }
1349 
1350 bool SwCalc::Str2Double( const OUString& rCommand, sal_Int32& rCommandPos,
1351  double& rVal, SwDoc const * const pDoc )
1352 {
1353  const SvtSysLocale aSysLocale;
1354  std::unique_ptr<const LocaleDataWrapper> pLclD;
1355  if( pDoc )
1356  {
1357  LanguageType eLang = GetDocAppScriptLang( *pDoc );
1358  if (eLang != aSysLocale.GetLanguageTag().getLanguageType())
1359  {
1360  pLclD.reset( new LocaleDataWrapper( LanguageTag( eLang )) );
1361  }
1362  }
1363 
1364  bool const bRet = lcl_Str2Double(rCommand, rCommandPos, rVal,
1365  pLclD ? pLclD.get() : aSysLocale.GetLocaleDataPtr());
1366 
1367  return bRet;
1368 }
1369 
1370 bool SwCalc::IsValidVarName( const OUString& rStr, OUString* pValidName )
1371 {
1372  bool bRet = false;
1373  using namespace ::com::sun::star::i18n;
1374  {
1375  // Parse any token.
1376  ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1377  coStartFlags, OUString(),
1378  coContFlags, OUString() );
1379 
1380  if( aRes.TokenType & KParseType::IDENTNAME )
1381  {
1382  bRet = aRes.EndPos == rStr.getLength();
1383  if( pValidName )
1384  {
1385  *pValidName = rStr.copy( aRes.LeadingWhiteSpace,
1386  aRes.EndPos - aRes.LeadingWhiteSpace );
1387  }
1388  }
1389  else if( pValidName )
1390  pValidName->clear();
1391  }
1392  return bRet;
1393 }
1394 
1395 SwHash::SwHash(const OUString& rStr)
1396  : aStr(rStr)
1397 {
1398 }
1399 
1401 {
1402 }
1403 
1404 SwCalcExp::SwCalcExp(const OUString& rStr, const SwSbxValue& rVal,
1405  const SwFieldType* pType)
1406  : SwHash(rStr)
1407  , nValue(rVal)
1408  , pFieldType(pType)
1409 {
1410 }
1411 
1413 {
1414  return SbxSTRING == GetType() ? !GetOUString().isEmpty()
1415  : SbxValue::GetBool();
1416 }
1417 
1419 {
1420  double nRet;
1421  if( SbxSTRING == GetType() )
1422  {
1423  sal_Int32 nStt = 0;
1424  SwCalc::Str2Double( GetOUString(), nStt, nRet );
1425  }
1426  else if (IsBool())
1427  {
1428  nRet = GetBool() ? 1.0 : 0.0;
1429  }
1430  else
1431  {
1432  nRet = SbxValue::GetDouble();
1433  }
1434  return nRet;
1435 }
1436 
1438 {
1439  if( GetType() == SbxSTRING || GetType() == SbxBOOL )
1440  PutDouble( GetDouble() );
1441  return *this;
1442 }
1443 
1444 #ifdef STANDALONE_HASHCALC
1445 
1446 // this is example code how to create hash values in the CTOR:
1447 
1448 #include <stdio.h>
1449 void main()
1450 {
1451  static char
1452  sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1453  sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1454  sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1455  sNType9[] = "word", sNType10[]= "char",
1456  sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1457  sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1458  sNType15[] = "user_street" , sNType16[] = "user_country" ,
1459  sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1460  sNType19[] = "user_title" , sNType20[] = "user_position" ,
1461  sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1462  sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1463  sNType25[] = "user_state", sNType26[] = "graph"
1464  ;
1465 
1466  static const char* sNTypeTab[ 27 ] =
1467  {
1468  sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1469  sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1470  sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1471  sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1472  sNType24, sNType25, sNType26
1473  };
1474 
1475  const unsigned short nTableSize = 47;
1476  int aArr[ nTableSize ] = { 0 };
1477  char ch;
1478 
1479  for( int n = 0; n < 27; ++n )
1480  {
1481  unsigned int ii = 0;
1482  const char* pp = sNTypeTab[ n ];
1483 
1484  while( *pp )
1485  {
1486  ii = ii << 1 ^ *pp++;
1487  }
1488  ii %= nTableSize;
1489 
1490  ch = aArr[ ii ] ? 'X' : ' ';
1491  aArr[ ii ] = 1;
1492  printf( "%-20s -> %3u [%c]\n", sNTypeTab[ n ], ii, ch );
1493  }
1494 }
1495 
1496 #endif
1497 
1498 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Instances of SwFields and those derived from it occur 0 to n times.
Definition: fldbas.hxx:240
SwCalcExp(const OUString &rStr, const SwSbxValue &rVal, const SwFieldType *pFieldType)
Definition: calc.cxx:1404
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
Definition: calc.hxx:124
IDocumentStatistics const & getIDocumentStatistics() const
Definition: doc.cxx:372
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
sal_uInt64 left
sal_uLong nPara
paragraphs for document statistic: non-empty and non-hidden ones
Definition: docstat.hxx:32
const char sCalc_Acos[]
Definition: calc.cxx:82
const char aData[]
Definition: ww8scan.hxx:47
static ShellResource * GetShellRes()
Definition: viewsh.cxx:2487
OUString aCalc_Default
Definition: shellres.hxx:39
#define TBLSZ
Definition: calc.hxx:37
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1409
SbxNE
const char sCalc_Tan[]
Definition: calc.cxx:80
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
const char sCalc_Cos[]
Definition: calc.cxx:79
bool OpenDataSource(const OUString &rDataSource, const OUString &rTableOrQuery)
open the source while fields are updated - for the calculator only!
Definition: dbmgr.cxx:2322
sal_uIntPtr sal_uLong
constexpr TypedWhichId< SvxLanguageItem > RES_CHRATR_LANGUAGE(10)
OUString sDataSource
Definition: swdbdata.hxx:30
LanguageType GetLanguage(SfxItemSet const &aSet, sal_uInt16 nLangWhichId)
Definition: langhelper.cxx:399
SwCalc(const SwCalc &)=delete
sal_Int64 n
Definition: doc.hxx:186
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:615
std::unique_ptr< SwHash > pNext
Definition: calc.hxx:129
const char * pName
Definition: calc.cxx:91
const char sCalc_Date[]
Definition: calc.cxx:85
bool IsInMerge() const
Definition: dbmgr.hxx:336
SwSbxValue Term()
Definition: calc.cxx:840
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:51
const char sCalc_Not[]
Definition: calc.cxx:67
OUString aCalc_Pow
Definition: shellres.hxx:37
OUString aCalc_Syntax
Definition: shellres.hxx:34
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:356
sal_uInt16 sal_Unicode
void Pop()
Definition: calc.cxx:608
OUString ReplacePoint(const OUString &rTmpName, bool bWithCommandType)
Definition: expfld.cxx:104
const char sCalc_Geq[]
Definition: calc.cxx:71
static bool Str2Double(const OUString &rStr, sal_Int32 &rPos, double &rVal)
Definition: calc.cxx:1343
SwCalcError
Definition: calc.hxx:93
void VarChange(const OUString &rStr, const SwSbxValue &rValue)
Definition: calc.cxx:580
const SfxPoolItem & GetDefault(sal_uInt16 nFormatHint) const
Get the default attribute in this document.
Definition: docfmt.cxx:653
Definition: calc.hxx:49
SbxBOOL
OUString aCalc_Overflow
Definition: shellres.hxx:38
const char sCalc_Mul[]
Definition: calc.cxx:59
const char sCalc_Or[]
Definition: calc.cxx:64
const char sCalc_L[]
Definition: calc.cxx:72
bool PutBool(bool)
virtual SbxDataType GetType() const override
sal_Int32 m_nCommandPos
Definition: calc.hxx:194
SwCalcOper m_eCurrListOper
Definition: calc.hxx:203
SwSbxValue StdFunc(pfCalc pFnc, bool bChkTrig)
Definition: calc.cxx:1021
sal_uInt16 nOLE
Definition: docstat.hxx:29
SwSbxValue & MakeDouble()
Definition: calc.cxx:1437
Definition: calc.cxx:88
double(* pfCalc)(double)
Definition: calc.hxx:182
OUString aCalc_ZeroDiv
Definition: shellres.hxx:35
#define SAL_N_ELEMENTS(arr)
SbxNOT
SwSbxValue nValue
Definition: calc.hxx:134
double const nRoundVal[]
Definition: calc.cxx:129
double GetDouble() const
Definition: calc.cxx:1418
const OUString & getNumDecimalSep() const
sal_uInt16 char * pName
static OUString GetTypeStr(SwFieldTypesEnum nTypeId)
Definition: fldbas.cxx:120
SwSbxValue Prim()
Definition: calc.cxx:1222
def right
SwDoc & m_rDoc
Definition: calc.hxx:196
#define F_PI
bool IsNumeric() const
#define SW_MOD()
Definition: swmodule.hxx:256
const char sCalc_Pow[]
Definition: calc.cxx:63
Definition: calc.hxx:46
SwDBData const & GetDBData()
Definition: docfld.cxx:342
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:620
bool IsBool() const
static double lcl_ConvertToDateValue(SwDoc &rDoc, sal_Int32 nDate)
Definition: calc.cxx:193
SwSbxValue m_nNumberValue
Definition: calc.hxx:192
bool GetColumnCnt(const OUString &rSourceName, const OUString &rTableName, const OUString &rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage, OUString &rResult, double *pNumber)
Definition: dbmgr.cxx:2058
SwCalcExp m_aErrExpr
Definition: calc.hxx:193
const SvxPageUsage aArr[]
const char sCalc_Atan[]
Definition: calc.cxx:83
const sal_Int32 coContFlags
Definition: calc.cxx:142
virtual ~SwHash()
Definition: calc.cxx:1400
static OUString GetColumnName(const OUString &rName)
Definition: calc.cxx:1294
bool IsVoidValue() const
Definition: calc.hxx:116
SwCalcOper
Definition: calc.hxx:41
static sal_Int16 GetI18NScriptTypeOfLanguage(LanguageType nLang)
const char sCalc_Sqrt[]
Definition: calc.cxx:62
sal_uInt16 GetWhichOfScript(sal_uInt16 nWhich, sal_uInt16 nScript)
Definition: hints.cxx:195
SbxGE
virtual void Clear() override
double GetValue(SwCalc &rCalc)
Definition: usrfld.cxx:231
T * Find(const OUString &rStr, sal_uInt16 *pPos=nullptr) const
Definition: calc.hxx:152
const char sCalc_Max[]
Definition: calc.cxx:77
SwHash(const OUString &rStr)
Definition: calc.cxx:1395
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
PDFDocument & m_rDoc
const char sCalc_Leq[]
Definition: calc.cxx:70
#define DB_DELIM
Definition: swtypes.hxx:141
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:1370
OUStringBuffer m_aVarName
Definition: calc.hxx:187
SbxLE
SwCalcError m_eError
Definition: calc.hxx:204
bool IsDBvalue() const
Definition: calc.hxx:119
const OUString & getCurrSymbol() const
OUString GetFirstName() const
const char sCalc_Sub[]
Definition: calc.cxx:58
bool GetBool() const
SwSbxValue Expr()
Definition: calc.cxx:1259
SwSbxValue Calculate(const OUString &rStr)
Definition: calc.cxx:347
sal_uInt16 m_nListPor
Definition: calc.hxx:201
bool IsValid() const
Definition: usrfld.hxx:77
SwHashTable< SwCalcFieldType > const & GetFieldTypeTable() const
Definition: docfld.hxx:174
double GetDouble() const
sal_uInt16 nGrf
Definition: docstat.hxx:28
~SwCalc() COVERITY_NOEXCEPT_FALSE
Definition: calc.cxx:339
const LanguageTag & getLanguageTag() const
const char sCalc_G[]
Definition: calc.cxx:73
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:2390
UserOptToken
const char sCalc_Neq[]
Definition: calc.cxx:69
OUString aCalc_Brack
Definition: shellres.hxx:36
css::i18n::ParseResult parseAnyToken(const OUString &rStr, sal_Int32 nPos, sal_Int32 nStartCharFlags, const OUString &userDefinedCharactersStart, sal_Int32 nContCharFlags, const OUString &userDefinedCharactersCont) const
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:253
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:729
OString strip(const OString &rIn, char c)
bool PutDouble(double)
virtual SwDocUpdateField & GetUpdateFields() const =0
CalcOp const aOpTable[]
Definition: calc.cxx:97
bool GetBool() const
Definition: calc.cxx:1412
const char sCalc_Phd[]
Definition: calc.cxx:61
const char sCalc_Div[]
Definition: calc.cxx:60
Reference< XComponentContext > getProcessComponentContext()
SwCalcOper eOp
Definition: calc.cxx:94
OUString GetStrResult(const SwSbxValue &rValue)
Definition: calc.cxx:375
static LanguageType GetDocAppScriptLang(SwDoc const &rDoc)
Definition: calc.cxx:185
OUString GetContent(sal_uInt32 nFormat=0)
Definition: usrfld.cxx:266
CharClass * m_pCharClass
Definition: calc.hxx:199
const char sCalc_Xor[]
Definition: calc.cxx:65
SwCalcExp * VarLook(const OUString &rStr, bool bIns=false)
Definition: calc.cxx:413
SwSbxValue PrimFunc(bool &rChkPow)
Definition: calc.cxx:1033
SwCalcOper m_eCurrOper
Definition: calc.hxx:202
const LocaleDataWrapper * m_pLocaleDataWrapper
Definition: calc.hxx:198
const LanguageTag & GetLanguageTag() const
SbxMUL
const OUString * pUName
Definition: calc.cxx:92
const SwGetSetExpType GSE_STRING
String.
Definition: fldbas.hxx:202
SwCalcExp * VarInsert(const OUString &r)
Definition: calc.cxx:407
const char sCalc_Eq[]
Definition: calc.cxx:68
SvtSysLocale m_aSysLocale
Definition: calc.hxx:197
OUString m_sCurrSym
Definition: calc.hxx:188
const char sCalc_Sin[]
Definition: calc.cxx:78
const sal_Unicode cListDelim
Definition: calc.hxx:39
sal_uLong nWord
Definition: docstat.hxx:35
OUString GetDBName(const OUString &rName)
Definition: calc.cxx:1307
SbxGT
const Date & GetNullDate() const
bool Push(const SwUserFieldType *pUserFieldType)
Definition: calc.cxx:599
bool Compute(SbxOperator, const SbxValue &)
CharClass & GetAppCharClass()
Definition: init.cxx:709
SwFieldIds Which() const
Definition: fldbas.hxx:272
OUString sCommand
Definition: swdbdata.hxx:31
aStr
SwDBManager * GetDBManager() const
Definition: doc.hxx:666
sal_uInt16 nPos
OUString aStr
Definition: calc.hxx:128
Definition: calc.hxx:48
const char sCalc_Mean[]
Definition: calc.cxx:75
sal_Int16 nValue
std::vector< const SwUserFieldType * > m_aRekurStack
Definition: calc.hxx:190
void SetVoidValue(bool bSet)
Definition: calc.hxx:117
SbxDIV