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