LibreOffice Module sc (master)  1
interpr2.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 <memory>
21 #include <interpre.hxx>
22 
23 #include <comphelper/string.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <sfx2/linkmgr.hxx>
27 #include <sfx2/objsh.hxx>
28 #include <svl/zforlist.hxx>
29 #include <sal/macros.h>
30 #include <osl/diagnose.h>
31 
32 #include <sc.hrc>
33 #include <ddelink.hxx>
34 #include <scmatrix.hxx>
35 #include <formulacell.hxx>
36 #include <document.hxx>
37 #include <dociter.hxx>
38 #include <unitconv.hxx>
39 #include <hints.hxx>
40 #include <dpobject.hxx>
41 #include <tokenarray.hxx>
42 #include <globalnames.hxx>
43 #include <stlsheet.hxx>
44 #include <dpcache.hxx>
45 
46 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
47 
48 #include <string.h>
49 
50 using ::std::vector;
51 using namespace com::sun::star;
52 using namespace formula;
53 
54 #define SCdEpsilon 1.0E-7
55 
56 // Date and Time
57 
58 double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
59  bool bStrict )
60 {
61  if ( nYear < 100 && !bStrict )
62  nYear = pFormatter->ExpandTwoDigitYear( nYear );
63  // Do not use a default Date ctor here because it asks system time with a
64  // performance penalty.
65  sal_Int16 nY, nM, nD;
66  if (bStrict)
67  {
68  nY = nYear;
69  nM = nMonth;
70  nD = nDay;
71  }
72  else
73  {
74  if (nMonth > 0)
75  {
76  nY = nYear + (nMonth-1) / 12;
77  nM = ((nMonth-1) % 12) + 1;
78  }
79  else
80  {
81  nY = nYear + (nMonth-12) / 12;
82  nM = 12 - (-nMonth) % 12;
83  }
84  nD = 1;
85  }
86  Date aDate( nD, nM, nY);
87  if (!bStrict)
88  aDate.AddDays( nDay - 1 );
89  if (aDate.IsValidAndGregorian())
90  return static_cast<double>(aDate - pFormatter->GetNullDate());
91  else
92  {
93  SetError(FormulaError::NoValue);
94  return 0;
95  }
96 }
97 
99 {
100  nFuncFmtType = SvNumFormatType::DATE;
101  Date aActDate( Date::SYSTEM );
102  tools::Long nDiff = aActDate - pFormatter->GetNullDate();
103  PushDouble(static_cast<double>(nDiff));
104 }
105 
107 {
108  nFuncFmtType = SvNumFormatType::DATETIME;
109  DateTime aActTime( DateTime::SYSTEM );
110  tools::Long nDiff = aActTime - pFormatter->GetNullDate();
111  double fTime = aActTime.GetHour() / static_cast<double>(::tools::Time::hourPerDay) +
112  aActTime.GetMin() / static_cast<double>(::tools::Time::minutePerDay) +
113  aActTime.GetSec() / static_cast<double>(::tools::Time::secondPerDay) +
114  aActTime.GetNanoSec() / static_cast<double>(::tools::Time::nanoSecPerDay);
115  PushDouble( static_cast<double>(nDiff) + fTime );
116 }
117 
119 {
120  Date aDate = pFormatter->GetNullDate();
121  aDate.AddDays( GetInt32());
122  PushDouble( static_cast<double>(aDate.GetYear()) );
123 }
124 
126 {
127  Date aDate = pFormatter->GetNullDate();
128  aDate.AddDays( GetInt32());
129  PushDouble( static_cast<double>(aDate.GetMonth()) );
130 }
131 
133 {
134  Date aDate = pFormatter->GetNullDate();
135  aDate.AddDays( GetInt32());
136  PushDouble(static_cast<double>(aDate.GetDay()));
137 }
138 
140 {
141  sal_uInt16 nHour, nMinute, nSecond;
142  double fFractionOfSecond;
143  tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
144  PushDouble( nMinute);
145 }
146 
148 {
149  sal_uInt16 nHour, nMinute, nSecond;
150  double fFractionOfSecond;
151  tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
152  if ( fFractionOfSecond >= 0.5 )
153  nSecond = ( nSecond + 1 ) % 60;
154  PushDouble( nSecond );
155 
156 }
157 
159 {
160  sal_uInt16 nHour, nMinute, nSecond;
161  double fFractionOfSecond;
162  tools::Time::GetClock( GetDouble(), nHour, nMinute, nSecond, fFractionOfSecond, 0);
163  PushDouble( nHour);
164 }
165 
167 {
168  OUString aInputString = GetString().getString();
169  sal_uInt32 nFIndex = 0; // for a default country/language
170  double fVal;
171  if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
172  {
173  SvNumFormatType eType = pFormatter->GetType(nFIndex);
174  if (eType == SvNumFormatType::DATE || eType == SvNumFormatType::DATETIME)
175  {
176  nFuncFmtType = SvNumFormatType::DATE;
177  PushDouble(::rtl::math::approxFloor(fVal));
178  }
179  else
180  PushIllegalArgument();
181  }
182  else
183  PushIllegalArgument();
184 }
185 
187 {
188  sal_uInt8 nParamCount = GetByte();
189  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
190  return;
191 
192  sal_Int16 nFlag;
193  if (nParamCount == 2)
194  nFlag = GetInt16();
195  else
196  nFlag = 1;
197 
198  Date aDate = pFormatter->GetNullDate();
199  aDate.AddDays( GetInt32());
200  int nVal = static_cast<int>(aDate.GetDayOfWeek()); // MONDAY = 0
201  switch (nFlag)
202  {
203  case 1: // Sunday = 1
204  if (nVal == 6)
205  nVal = 1;
206  else
207  nVal += 2;
208  break;
209  case 2: // Monday = 1
210  nVal += 1;
211  break;
212  case 3: // Monday = 0
213  ; // nothing
214  break;
215  case 11: // Monday = 1
216  case 12: // Tuesday = 1
217  case 13: // Wednesday = 1
218  case 14: // Thursday = 1
219  case 15: // Friday = 1
220  case 16: // Saturday = 1
221  case 17: // Sunday = 1
222  if (nVal < nFlag - 11) // x = nFlag - 11 = 0,1,2,3,4,5,6
223  nVal += 19 - nFlag; // nVal += (8 - (nFlag - 11) = 8 - x = 8,7,6,5,4,3,2)
224  else
225  nVal -= nFlag - 12; // nVal -= ((nFlag - 11) - 1 = x - 1 = -1,0,1,2,3,4,5)
226  break;
227  default:
228  SetError( FormulaError::IllegalArgument);
229  }
230  PushInt( nVal );
231 }
232 
234 {
235  if ( MustHaveParamCount( GetByte(), 2 ) )
236  {
237  sal_Int16 nFlag = GetInt16();
238 
239  Date aDate = pFormatter->GetNullDate();
240  aDate.AddDays( GetInt32());
241  PushInt( static_cast<int>(aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY )));
242  }
243 }
244 
246 {
247  sal_uInt8 nParamCount = GetByte();
248  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
249  return;
250 
251  sal_Int16 nFlag;
252  if (nParamCount == 1)
253  nFlag = 1;
254  else
255  nFlag = GetInt16();
256 
257  Date aDate = pFormatter->GetNullDate();
258  aDate.AddDays( GetInt32());
259 
260  sal_Int32 nMinimumNumberOfDaysInWeek;
261  DayOfWeek eFirstDayOfWeek;
262  switch ( nFlag )
263  {
264  case 1 :
265  eFirstDayOfWeek = SUNDAY;
266  nMinimumNumberOfDaysInWeek = 1;
267  break;
268  case 2 :
269  eFirstDayOfWeek = MONDAY;
270  nMinimumNumberOfDaysInWeek = 1;
271  break;
272  case 11 :
273  case 12 :
274  case 13 :
275  case 14 :
276  case 15 :
277  case 16 :
278  case 17 :
279  eFirstDayOfWeek = static_cast<DayOfWeek>( nFlag - 11 ); // MONDAY := 0
280  nMinimumNumberOfDaysInWeek = 1; //the week containing January 1 is week 1
281  break;
282  case 21 :
283  case 150 :
284  // ISO 8601
285  eFirstDayOfWeek = MONDAY;
286  nMinimumNumberOfDaysInWeek = 4;
287  break;
288  default :
289  PushIllegalArgument();
290  return;
291  }
292  PushInt( static_cast<int>(aDate.GetWeekOfYear( eFirstDayOfWeek, nMinimumNumberOfDaysInWeek )) );
293 }
294 
296 {
297  if ( MustHaveParamCount( GetByte(), 1 ) )
298  {
299  Date aDate = pFormatter->GetNullDate();
300  aDate.AddDays( GetInt32());
301  PushInt( static_cast<int>(aDate.GetWeekOfYear()) );
302  }
303 }
304 
306 {
307  nFuncFmtType = SvNumFormatType::DATE;
308  if ( !MustHaveParamCount( GetByte(), 1 ) )
309  return;
310 
311  sal_Int16 nDay, nMonth, nYear;
312  nYear = GetInt16();
313  if (nGlobalError != FormulaError::NONE)
314  {
315  PushError( nGlobalError);
316  return;
317  }
318  if ( nYear < 100 )
319  nYear = pFormatter->ExpandTwoDigitYear( nYear );
320  if (nYear < 1583 || nYear > 9956)
321  {
322  // Valid Gregorian and maximum year constraints not met.
323  PushIllegalArgument();
324  return;
325  }
326  // don't worry, be happy :)
327  int B,C,D,E,F,G,H,I,K,L,M,N,O;
328  N = nYear % 19;
329  B = int(nYear / 100);
330  C = nYear % 100;
331  D = int(B / 4);
332  E = B % 4;
333  F = int((B + 8) / 25);
334  G = int((B - F + 1) / 3);
335  H = (19 * N + B - D - G + 15) % 30;
336  I = int(C / 4);
337  K = C % 4;
338  L = (32 + 2 * E + 2 * I - H - K) % 7;
339  M = int((N + 11 * H + 22 * L) / 451);
340  O = H + L - 7 * M + 114;
341  nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
342  nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
343  PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) );
344 }
345 
347  const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, vector< double >& rSortArray,
348  bool bWeekendMask[ 7 ] )
349 {
350  if ( nParamCount == 4 )
351  {
352  vector< double > nWeekendDays;
353  GetNumberSequenceArray( 1, nWeekendDays, false );
354  if ( nGlobalError != FormulaError::NONE )
355  return nGlobalError;
356  else
357  {
358  if ( nWeekendDays.size() != 7 )
359  return FormulaError::IllegalArgument;
360 
361  // Weekend days defined by string, Sunday...Saturday
362  for ( int i = 0; i < 7; i++ )
363  bWeekendMask[ i ] = static_cast<bool>(nWeekendDays[ ( i == 6 ? 0 : i + 1 ) ]);
364  }
365  }
366  else
367  {
368  for ( int i = 0; i < 7; i++ )
369  bWeekendMask[ i] = false;
370 
371  bWeekendMask[ SATURDAY ] = true;
372  bWeekendMask[ SUNDAY ] = true;
373  }
374 
375  if ( nParamCount >= 3 )
376  {
377  GetSortArray( 1, rSortArray, nullptr, true, true );
378  size_t nMax = rSortArray.size();
379  for ( size_t i = 0; i < nMax; i++ )
380  rSortArray.at( i ) = ::rtl::math::approxFloor( rSortArray.at( i ) ) + nNullDate;
381  }
382 
383  return nGlobalError;
384 }
385 
387  const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, vector< double >& rSortArray,
388  bool bWeekendMask[ 7 ], bool bWorkdayFunction )
389 {
390  FormulaError nErr = FormulaError::NONE;
391  OUString aWeekendDays;
392  if ( nParamCount == 4 )
393  {
394  GetSortArray( 1, rSortArray, nullptr, true, true );
395  size_t nMax = rSortArray.size();
396  for ( size_t i = 0; i < nMax; i++ )
397  rSortArray.at( i ) = ::rtl::math::approxFloor( rSortArray.at( i ) ) + nNullDate;
398  }
399 
400  if ( nParamCount >= 3 )
401  {
402  if ( IsMissing() )
403  Pop();
404  else
405  {
406  switch ( GetStackType() )
407  {
408  case svDoubleRef :
409  case svExternalDoubleRef :
410  return FormulaError::NoValue;
411 
412  default :
413  {
414  double fDouble;
415  svl::SharedString aSharedString;
416  bool bDouble = GetDoubleOrString( fDouble, aSharedString);
417  if ( bDouble )
418  {
419  if ( fDouble >= 1.0 && fDouble <= 17 )
420  aWeekendDays = OUString::number( fDouble );
421  else
422  return FormulaError::NoValue;
423  }
424  else
425  {
426  if ( aSharedString.isEmpty() || aSharedString.getLength() != 7 ||
427  ( bWorkdayFunction && aSharedString.getString() == "1111111" ) )
428  return FormulaError::NoValue;
429  else
430  aWeekendDays = aSharedString.getString();
431  }
432  }
433  break;
434  }
435  }
436  }
437 
438  for ( int i = 0; i < 7; i++ )
439  bWeekendMask[ i] = false;
440 
441  if ( aWeekendDays.isEmpty() )
442  {
443  bWeekendMask[ SATURDAY ] = true;
444  bWeekendMask[ SUNDAY ] = true;
445  }
446  else
447  {
448  switch ( aWeekendDays.getLength() )
449  {
450  case 1 :
451  // Weekend days defined by code
452  switch ( aWeekendDays[ 0 ] )
453  {
454  case '1' : bWeekendMask[ SATURDAY ] = true; bWeekendMask[ SUNDAY ] = true; break;
455  case '2' : bWeekendMask[ SUNDAY ] = true; bWeekendMask[ MONDAY ] = true; break;
456  case '3' : bWeekendMask[ MONDAY ] = true; bWeekendMask[ TUESDAY ] = true; break;
457  case '4' : bWeekendMask[ TUESDAY ] = true; bWeekendMask[ WEDNESDAY ] = true; break;
458  case '5' : bWeekendMask[ WEDNESDAY ] = true; bWeekendMask[ THURSDAY ] = true; break;
459  case '6' : bWeekendMask[ THURSDAY ] = true; bWeekendMask[ FRIDAY ] = true; break;
460  case '7' : bWeekendMask[ FRIDAY ] = true; bWeekendMask[ SATURDAY ] = true; break;
461  default : nErr = FormulaError::IllegalArgument; break;
462  }
463  break;
464  case 2 :
465  // Weekend day defined by code
466  if ( aWeekendDays[ 0 ] == '1' )
467  {
468  switch ( aWeekendDays[ 1 ] )
469  {
470  case '1' : bWeekendMask[ SUNDAY ] = true; break;
471  case '2' : bWeekendMask[ MONDAY ] = true; break;
472  case '3' : bWeekendMask[ TUESDAY ] = true; break;
473  case '4' : bWeekendMask[ WEDNESDAY ] = true; break;
474  case '5' : bWeekendMask[ THURSDAY ] = true; break;
475  case '6' : bWeekendMask[ FRIDAY ] = true; break;
476  case '7' : bWeekendMask[ SATURDAY ] = true; break;
477  default : nErr = FormulaError::IllegalArgument; break;
478  }
479  }
480  else
481  nErr = FormulaError::IllegalArgument;
482  break;
483  case 7 :
484  // Weekend days defined by string
485  for ( int i = 0; i < 7 && nErr == FormulaError::NONE; i++ )
486  {
487  switch ( aWeekendDays[ i ] )
488  {
489  case '0' : bWeekendMask[ i ] = false; break;
490  case '1' : bWeekendMask[ i ] = true; break;
491  default : nErr = FormulaError::IllegalArgument; break;
492  }
493  }
494  break;
495  default :
496  nErr = FormulaError::IllegalArgument;
497  break;
498  }
499  }
500  return nErr;
501 }
502 
503 void ScInterpreter::ScNetWorkdays( bool bOOXML_Version )
504 {
505  sal_uInt8 nParamCount = GetByte();
506  if ( !MustHaveParamCount( nParamCount, 2, 4 ) )
507  return;
508 
509  vector<double> nSortArray;
510  bool bWeekendMask[ 7 ];
511  const Date& rNullDate = pFormatter->GetNullDate();
512  sal_uInt32 nNullDate = Date::DateToDays( rNullDate.GetDay(), rNullDate.GetMonth(), rNullDate.GetYear() );
513  FormulaError nErr;
514  if ( bOOXML_Version )
515  {
516  nErr = GetWeekendAndHolidayMasks_MS( nParamCount, nNullDate,
517  nSortArray, bWeekendMask, false );
518  }
519  else
520  {
521  nErr = GetWeekendAndHolidayMasks( nParamCount, nNullDate,
522  nSortArray, bWeekendMask );
523  }
524  if ( nErr != FormulaError::NONE )
525  PushError( nErr );
526  else
527  {
528  sal_uInt32 nDate2 = GetUInt32();
529  sal_uInt32 nDate1 = GetUInt32();
530  if (nGlobalError != FormulaError::NONE || (nDate1 > SAL_MAX_UINT32 - nNullDate) || nDate2 > (SAL_MAX_UINT32 - nNullDate))
531  {
532  PushIllegalArgument();
533  return;
534  }
535  nDate2 += nNullDate;
536  nDate1 += nNullDate;
537 
538  sal_Int32 nCnt = 0;
539  size_t nRef = 0;
540  bool bReverse = ( nDate1 > nDate2 );
541  if ( bReverse )
542  {
543  sal_uInt32 nTemp = nDate1;
544  nDate1 = nDate2;
545  nDate2 = nTemp;
546  }
547  size_t nMax = nSortArray.size();
548  while ( nDate1 <= nDate2 )
549  {
550  if ( !bWeekendMask[ GetDayOfWeek( nDate1 ) ] )
551  {
552  while ( nRef < nMax && nSortArray.at( nRef ) < nDate1 )
553  nRef++;
554  if ( nRef >= nMax || nSortArray.at( nRef ) != nDate1 )
555  nCnt++;
556  }
557  ++nDate1;
558  }
559  PushDouble( static_cast<double>( bReverse ? -nCnt : nCnt ) );
560  }
561 }
562 
564 {
565  sal_uInt8 nParamCount = GetByte();
566  if ( !MustHaveParamCount( nParamCount, 2, 4 ) )
567  return;
568 
569  nFuncFmtType = SvNumFormatType::DATE;
570  vector<double> nSortArray;
571  bool bWeekendMask[ 7 ];
572  const Date& rNullDate = pFormatter->GetNullDate();
573  sal_uInt32 nNullDate = Date::DateToDays( rNullDate.GetDay(), rNullDate.GetMonth(), rNullDate.GetYear() );
574  FormulaError nErr = GetWeekendAndHolidayMasks_MS( nParamCount, nNullDate,
575  nSortArray, bWeekendMask, true );
576  if ( nErr != FormulaError::NONE )
577  PushError( nErr );
578  else
579  {
580  sal_Int32 nDays = GetInt32();
581  sal_uInt32 nDate = GetUInt32();
582  if (nGlobalError != FormulaError::NONE || (nDate > SAL_MAX_UINT32 - nNullDate))
583  {
584  PushIllegalArgument();
585  return;
586  }
587  nDate += nNullDate;
588 
589  if ( !nDays )
590  PushDouble( static_cast<double>( nDate - nNullDate ) );
591  else
592  {
593  size_t nMax = nSortArray.size();
594  if ( nDays > 0 )
595  {
596  size_t nRef = 0;
597  while ( nDays )
598  {
599  do
600  {
601  ++nDate;
602  }
603  while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
604 
605  while ( nRef < nMax && nSortArray.at( nRef ) < nDate )
606  nRef++;
607 
608  if ( nRef >= nMax || nSortArray.at( nRef ) != nDate || nRef >= nMax )
609  nDays--;
610  }
611  }
612  else
613  {
614  sal_Int16 nRef = nMax - 1;
615  while ( nDays )
616  {
617  do
618  {
619  --nDate;
620  }
621  while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
622 
623  while ( nRef >= 0 && nSortArray.at( nRef ) > nDate )
624  nRef--;
625 
626  if (nRef < 0 || nSortArray.at(nRef) != nDate)
627  nDays++;
628  }
629  }
630  PushDouble( static_cast<double>( nDate - nNullDate ) );
631  }
632  }
633 }
634 
636 {
637  nFuncFmtType = SvNumFormatType::DATE;
638  if ( !MustHaveParamCount( GetByte(), 3 ) )
639  return;
640 
641  sal_Int16 nDay = GetInt16();
642  sal_Int16 nMonth = GetInt16();
643  if (IsMissing())
644  SetError( FormulaError::ParameterExpected); // Year must be given.
645  sal_Int16 nYear = GetInt16();
646  if (nGlobalError != FormulaError::NONE || nYear < 0)
647  PushIllegalArgument();
648  else
649  {
650  PushDouble(GetDateSerial(nYear, nMonth, nDay, false));
651  }
652 }
653 
655 {
656  nFuncFmtType = SvNumFormatType::TIME;
657  if ( MustHaveParamCount( GetByte(), 3 ) )
658  {
659  double fSec = GetDouble();
660  double fMin = GetDouble();
661  double fHour = GetDouble();
662  double fTime = fmod( (fHour * ::tools::Time::secondPerHour) + (fMin * ::tools::Time::secondPerMinute) + fSec, DATE_TIME_FACTOR) / DATE_TIME_FACTOR;
663  if (fTime < 0)
664  PushIllegalArgument();
665  else
666  PushDouble( fTime);
667  }
668 }
669 
671 {
672  if ( MustHaveParamCount( GetByte(), 2 ) )
673  {
674  double fDate2 = GetDouble();
675  double fDate1 = GetDouble();
676  PushDouble(fDate1 - fDate2);
677  }
678 }
679 
681 {
682  /* Implementation follows
683  * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
684  * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
685  * 30-days count. That document also claims that Excel implements the "PSA
686  * 30" or "NASD 30" method (funny enough they also state that Excel is the
687  * only tool that does so).
688  *
689  * Note that the definition given in
690  * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
691  * is _not_ the way how it is actually calculated by Excel (that would not
692  * even match any of the 7 methods mentioned above) and would result in the
693  * following test cases producing wrong results according to that appendix B:
694  *
695  * 28-Feb-95 31-Aug-95 181 instead of 180
696  * 29-Feb-96 31-Aug-96 181 instead of 180
697  * 30-Jan-96 31-Mar-96 61 instead of 60
698  * 31-Jan-96 31-Mar-96 61 instead of 60
699  *
700  * Still, there is a difference between OOoCalc and Excel:
701  * In Excel:
702  * 02-Feb-99 31-Mar-00 results in 419
703  * 31-Mar-00 02-Feb-99 results in -418
704  * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
705  */
706 
707  sal_uInt8 nParamCount = GetByte();
708  if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
709  return;
710 
711  bool bFlag;
712  if (nParamCount == 3)
713  bFlag = GetBool();
714  else
715  bFlag = false;
716  sal_Int32 nDate2 = GetInt32();
717  sal_Int32 nDate1 = GetInt32();
718  if (nGlobalError != FormulaError::NONE)
719  PushError( nGlobalError);
720  else
721  {
722  sal_Int32 nSign;
723  // #i84934# only for non-US European algorithm swap dates. Else
724  // follow Excel's meaningless extrapolation for "interoperability".
725  if (bFlag && (nDate2 < nDate1))
726  {
727  nSign = nDate1;
728  nDate1 = nDate2;
729  nDate2 = nSign;
730  nSign = -1;
731  }
732  else
733  nSign = 1;
734  Date aDate1 = pFormatter->GetNullDate();
735  aDate1.AddDays( nDate1);
736  Date aDate2 = pFormatter->GetNullDate();
737  aDate2.AddDays( nDate2);
738  if (aDate1.GetDay() == 31)
739  aDate1.AddDays( -1);
740  else if (!bFlag)
741  {
742  if (aDate1.GetMonth() == 2)
743  {
744  switch ( aDate1.GetDay() )
745  {
746  case 28 :
747  if ( !aDate1.IsLeapYear() )
748  aDate1.SetDay(30);
749  break;
750  case 29 :
751  aDate1.SetDay(30);
752  break;
753  }
754  }
755  }
756  if (aDate2.GetDay() == 31)
757  {
758  if (!bFlag )
759  {
760  if (aDate1.GetDay() == 30)
761  aDate2.AddDays( -1);
762  }
763  else
764  aDate2.SetDay(30);
765  }
766  PushDouble( static_cast<double>(nSign) *
767  ( static_cast<double>(aDate2.GetDay()) + static_cast<double>(aDate2.GetMonth()) * 30.0 +
768  static_cast<double>(aDate2.GetYear()) * 360.0
769  - static_cast<double>(aDate1.GetDay()) - static_cast<double>(aDate1.GetMonth()) * 30.0
770  - static_cast<double>(aDate1.GetYear()) * 360.0) );
771  }
772 }
773 
774 // fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
776 {
777  if ( !MustHaveParamCount( GetByte(), 3 ) )
778  return;
779 
780  OUString aInterval = GetString().getString();
781  sal_Int32 nDate2 = GetInt32();
782  sal_Int32 nDate1 = GetInt32();
783 
784  if (nGlobalError != FormulaError::NONE)
785  {
786  PushError( nGlobalError);
787  return;
788  }
789 
790  // Excel doesn't swap dates or return negative numbers, so don't we.
791  if (nDate1 > nDate2)
792  {
793  PushIllegalArgument();
794  return;
795  }
796 
797  double dd = nDate2 - nDate1;
798  // Zero difference or number of days can be returned immediately.
799  if (dd == 0.0 || aInterval.equalsIgnoreAsciiCase( "d" ))
800  {
801  PushDouble( dd );
802  return;
803  }
804 
805  // split dates in day, month, year for use with formats other than "d"
806  sal_uInt16 d1, m1, d2, m2;
807  sal_Int16 y1, y2;
808  Date aDate1( pFormatter->GetNullDate());
809  aDate1.AddDays( nDate1);
810  y1 = aDate1.GetYear();
811  m1 = aDate1.GetMonth();
812  d1 = aDate1.GetDay();
813  Date aDate2( pFormatter->GetNullDate());
814  aDate2.AddDays( nDate2);
815  y2 = aDate2.GetYear();
816  m2 = aDate2.GetMonth();
817  d2 = aDate2.GetDay();
818 
819  // Close the year 0 gap to calculate year difference.
820  if (y1 < 0 && y2 > 0)
821  ++y1;
822  else if (y1 > 0 && y2 < 0)
823  ++y2;
824 
825  if ( aInterval.equalsIgnoreAsciiCase( "m" ) )
826  {
827  // Return number of months.
828  int md = m2 - m1 + 12 * (y2 - y1);
829  if (d1 > d2)
830  --md;
831  PushInt( md );
832  }
833  else if ( aInterval.equalsIgnoreAsciiCase( "y" ) )
834  {
835  // Return number of years.
836  int yd;
837  if ( y2 > y1 )
838  {
839  if (m2 > m1 || (m2 == m1 && d2 >= d1))
840  yd = y2 - y1; // complete years between dates
841  else
842  yd = y2 - y1 - 1; // one incomplete year
843  }
844  else
845  {
846  // Year is equal as we don't allow reversed arguments, no
847  // complete year between dates.
848  yd = 0;
849  }
850  PushInt( yd );
851  }
852  else if ( aInterval.equalsIgnoreAsciiCase( "md" ) )
853  {
854  // Return number of days, excluding months and years.
855  // This is actually the remainder of days when subtracting years
856  // and months from the difference of dates. Birthday-like 23 years
857  // and 10 months and 19 days.
858 
859  // Algorithm's roll-over behavior extracted from Excel by try and
860  // error...
861  // If day1 <= day2 then simply day2 - day1.
862  // If day1 > day2 then set month1 to month2-1 and year1 to
863  // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
864  // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
865  // year).
866  // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
867  // to 2011-03-01 so the result is 0. Same for day 31 in months with
868  // only 30 days.
869 
870  tools::Long nd;
871  if (d1 <= d2)
872  nd = d2 - d1;
873  else
874  {
875  if (m2 == 1)
876  {
877  aDate1.SetYear( y2 == 1 ? -1 : y2 - 1 );
878  aDate1.SetMonth( 12 );
879  }
880  else
881  {
882  aDate1.SetYear( y2 );
883  aDate1.SetMonth( m2 - 1 );
884  }
885  aDate1.Normalize();
886  nd = aDate2 - aDate1;
887  }
888  PushDouble( nd );
889  }
890  else if ( aInterval.equalsIgnoreAsciiCase( "ym" ) )
891  {
892  // Return number of months, excluding years.
893  int md = m2 - m1 + 12 * (y2 - y1);
894  if (d1 > d2)
895  --md;
896  md %= 12;
897  PushInt( md );
898  }
899  else if ( aInterval.equalsIgnoreAsciiCase( "yd" ) )
900  {
901  // Return number of days, excluding years.
902 
903  // Condition corresponds with "y".
904  if (m2 > m1 || (m2 == m1 && d2 >= d1))
905  aDate1.SetYear( y2 );
906  else
907  aDate1.SetYear( y2 - 1 );
908  // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
909  // 323, whereas the result here is 324. Don't they use the leap
910  // year of 2012?
911  // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
912  // Years" is not correct and Excel 2010 correctly returns 0 in
913  // both cases mentioned there. Also using year1 as mentioned
914  // produces incorrect results in other cases and different from
915  // Excel 2010. Apparently they fixed some calculations.
916  aDate1.Normalize();
917  double fd = aDate2 - aDate1;
918  PushDouble( fd );
919  }
920  else
921  PushIllegalArgument(); // unsupported format
922 }
923 
925 {
926  OUString aInputString = GetString().getString();
927  sal_uInt32 nFIndex = 0; // damit default Land/Spr.
928  double fVal;
929  if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal, SvNumInputOptions::LAX_TIME))
930  {
931  SvNumFormatType eType = pFormatter->GetType(nFIndex);
932  if (eType == SvNumFormatType::TIME || eType == SvNumFormatType::DATETIME)
933  {
934  nFuncFmtType = SvNumFormatType::TIME;
935  double fDateVal = rtl::math::approxFloor(fVal);
936  double fTimeVal = fVal - fDateVal;
937  PushDouble(fTimeVal);
938  }
939  else
940  PushIllegalArgument();
941  }
942  else
943  PushIllegalArgument();
944 }
945 
947 {
948  double fVal = GetDouble();
949  short n = 0;
950  if (fVal < 0.0)
951  n = -1;
952  else if (fVal > 0.0)
953  n = 1;
954  PushInt( n );
955 }
956 
958 {
959  PushDouble(fabs(GetDouble()));
960 }
961 
963 {
964  PushDouble(::rtl::math::approxFloor(GetDouble()));
965 }
966 
967 void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
968 {
969  sal_uInt8 nParamCount = GetByte();
970  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
971  return;
972 
973  double fVal = 0.0;
974  if (nParamCount == 1)
975  fVal = ::rtl::math::round( GetDouble(), 0, eMode );
976  else
977  {
978  sal_Int16 nDec = GetInt16();
979  double fX = GetDouble();
980  if ( nGlobalError != FormulaError::NONE || nDec < -20 || nDec > 20 )
981  PushIllegalArgument();
982  else
983  {
984  if ( ( eMode == rtl_math_RoundingMode_Down ||
985  eMode == rtl_math_RoundingMode_Up ) &&
986  nDec < 12 && fmod( fX, 1.0 ) != 0.0 )
987  {
988  // tdf124286 : round to 12 significant digits before rounding
989  // down or up to avoid unexpected rounding errors
990  // caused by decimal -> binary -> decimal conversion
991  double fRes;
992  RoundSignificant( fX, 12, fRes );
993  fVal = ::rtl::math::round( fRes, nDec, eMode );
994  }
995  else
996  fVal = ::rtl::math::round( fX, nDec, eMode );
997  }
998  }
999  PushDouble(fVal);
1000 }
1001 
1003 {
1004  RoundNumber( rtl_math_RoundingMode_Corrected );
1005 }
1006 
1008 {
1009  RoundNumber( rtl_math_RoundingMode_Down );
1010 }
1011 
1013 {
1014  RoundNumber( rtl_math_RoundingMode_Up );
1015 }
1016 
1017 void ScInterpreter::RoundSignificant( double fX, double fDigits, double &fRes )
1018 {
1019  bool bNegVal = ( fX < 0 );
1020  if ( bNegVal )
1021  fX *= -1.0;
1022  double fTemp = ::rtl::math::approxFloor( log10( fX ) ) + 1.0 - fDigits;
1023  fRes = ::rtl::math::round( pow(10.0, -fTemp ) * fX ) * pow( 10.0, fTemp );
1024  if ( bNegVal )
1025  fRes *= -1.0;
1026 }
1027 
1028 // tdf#106931
1030 {
1031  if ( !MustHaveParamCount( GetByte(), 2 ) )
1032  return;
1033 
1034  double fDigits = ::rtl::math::approxFloor( GetDouble() );
1035  double fX = GetDouble();
1036  if ( nGlobalError != FormulaError::NONE || fDigits < 1.0 )
1037  {
1038  PushIllegalArgument();
1039  return;
1040  }
1041 
1042  if ( fX == 0.0 )
1043  PushDouble( 0.0 );
1044  else
1045  {
1046  double fRes;
1047  RoundSignificant( fX, fDigits, fRes );
1048  PushDouble( fRes );
1049  }
1050 }
1051 
1059 void ScInterpreter::ScCeil( bool bODFF )
1060 {
1061  sal_uInt8 nParamCount = GetByte();
1062  if ( !MustHaveParamCount( nParamCount, 1, 3 ) )
1063  return;
1064 
1065  bool bAbs = nParamCount == 3 && GetBool();
1066  double fDec, fVal;
1067  if ( nParamCount == 1 )
1068  {
1069  fVal = GetDouble();
1070  fDec = ( fVal < 0 ? -1 : 1 );
1071  }
1072  else
1073  {
1074  bool bArgumentMissing = IsMissing();
1075  fDec = GetDouble();
1076  fVal = GetDouble();
1077  if ( bArgumentMissing )
1078  fDec = ( fVal < 0 ? -1 : 1 );
1079  }
1080  if ( fVal == 0 || fDec == 0.0 )
1081  PushInt( 0 );
1082  else
1083  {
1084  if ( bODFF && fVal * fDec < 0 )
1085  PushIllegalArgument();
1086  else
1087  {
1088  if ( fVal * fDec < 0.0 )
1089  fDec = -fDec;
1090 
1091  if ( !bAbs && fVal < 0.0 )
1092  PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1093  else
1094  PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1095  }
1096  }
1097 }
1098 
1100 {
1101  sal_uInt8 nParamCount = GetByte();
1102  if ( !MustHaveParamCount( nParamCount, 2 ) )
1103  return;
1104 
1105  double fDec = GetDouble();
1106  double fVal = GetDouble();
1107  if ( fVal == 0 || fDec == 0.0 )
1108  PushInt(0);
1109  else if ( fVal * fDec > 0 )
1110  PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1111  else if ( fVal < 0.0 )
1112  PushDouble(::rtl::math::approxFloor( fVal / -fDec ) * -fDec );
1113  else
1114  PushIllegalArgument();
1115 }
1116 
1118 {
1119  sal_uInt8 nParamCount = GetByte();
1120  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1121  return;
1122 
1123  double fDec, fVal;
1124  if ( nParamCount == 1 )
1125  {
1126  fVal = GetDouble();
1127  fDec = 1.0;
1128  }
1129  else
1130  {
1131  fDec = fabs( GetDoubleWithDefault( 1.0 ));
1132  fVal = GetDouble();
1133  }
1134  if ( fDec == 0.0 || fVal == 0.0 )
1135  PushInt( 0 );
1136  else
1137  PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1138 }
1139 
1147 void ScInterpreter::ScFloor( bool bODFF )
1148 {
1149  sal_uInt8 nParamCount = GetByte();
1150  if ( !MustHaveParamCount( nParamCount, 1, 3 ) )
1151  return;
1152 
1153  bool bAbs = ( nParamCount == 3 && GetBool() );
1154  double fDec, fVal;
1155  if ( nParamCount == 1 )
1156  {
1157  fVal = GetDouble();
1158  fDec = ( fVal < 0 ? -1 : 1 );
1159  }
1160  else
1161  {
1162  bool bArgumentMissing = IsMissing();
1163  fDec = GetDouble();
1164  fVal = GetDouble();
1165  if ( bArgumentMissing )
1166  fDec = ( fVal < 0 ? -1 : 1 );
1167  }
1168  if ( fDec == 0.0 || fVal == 0.0 )
1169  PushInt( 0 );
1170  else
1171  {
1172  if ( bODFF && ( fVal * fDec < 0.0 ) )
1173  PushIllegalArgument();
1174  else
1175  {
1176  if ( fVal * fDec < 0.0 )
1177  fDec = -fDec;
1178 
1179  if ( !bAbs && fVal < 0.0 )
1180  PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
1181  else
1182  PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1183  }
1184  }
1185 }
1186 
1188 {
1189  sal_uInt8 nParamCount = GetByte();
1190  if ( !MustHaveParamCount( nParamCount, 2 ) )
1191  return;
1192 
1193  double fDec = GetDouble();
1194  double fVal = GetDouble();
1195 
1196  if ( fVal == 0 )
1197  PushInt( 0 );
1198  else if ( fVal * fDec > 0 )
1199  PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1200  else if ( fDec == 0 )
1201  PushIllegalArgument();
1202  else if ( fVal < 0.0 )
1203  PushDouble(::rtl::math::approxCeil( fVal / -fDec ) * -fDec );
1204  else
1205  PushIllegalArgument();
1206 }
1207 
1209 {
1210  sal_uInt8 nParamCount = GetByte();
1211  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1212  return;
1213 
1214  double fDec, fVal;
1215  if ( nParamCount == 1 )
1216  {
1217  fVal = GetDouble();
1218  fDec = 1.0;
1219  }
1220  else
1221  {
1222  fDec = fabs( GetDoubleWithDefault( 1.0 ) );
1223  fVal = GetDouble();
1224  }
1225  if ( fDec == 0.0 || fVal == 0.0 )
1226  PushInt( 0 );
1227  else
1228  PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
1229 }
1230 
1232 {
1233  double fVal = GetDouble();
1234  if (fVal < 0.0)
1235  PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
1236  else
1237  PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
1238 }
1239 
1241 {
1242  double fVal = GetDouble();
1243  if (fVal >= 0.0)
1244  {
1245  fVal = ::rtl::math::approxCeil(fVal);
1246  if (fmod(fVal, 2.0) == 0.0)
1247  fVal += 1.0;
1248  }
1249  else
1250  {
1251  fVal = ::rtl::math::approxFloor(fVal);
1252  if (fmod(fVal, 2.0) == 0.0)
1253  fVal -= 1.0;
1254  }
1255  PushDouble(fVal);
1256 }
1257 
1259 {
1260  if ( MustHaveParamCount( GetByte(), 2 ) )
1261  {
1262  double fVal2 = GetDouble();
1263  double fVal1 = GetDouble();
1264  PushDouble(atan2(fVal2, fVal1));
1265  }
1266 }
1267 
1269 {
1270  sal_uInt8 nParamCount = GetByte();
1271  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1272  return;
1273 
1274  double fBase;
1275  if (nParamCount == 2)
1276  fBase = GetDouble();
1277  else
1278  fBase = 10.0;
1279  double fVal = GetDouble();
1280  if (fVal > 0.0 && fBase > 0.0 && fBase != 1.0)
1281  PushDouble(log(fVal) / log(fBase));
1282  else
1283  PushIllegalArgument();
1284 }
1285 
1287 {
1288  double fVal = GetDouble();
1289  if (fVal > 0.0)
1290  PushDouble(log(fVal));
1291  else
1292  PushIllegalArgument();
1293 }
1294 
1296 {
1297  double fVal = GetDouble();
1298  if (fVal > 0.0)
1299  PushDouble(log10(fVal));
1300  else
1301  PushIllegalArgument();
1302 }
1303 
1305 {
1306  nFuncFmtType = SvNumFormatType::CURRENCY;
1307  short nParamCount = GetByte();
1308  if ( !MustHaveParamCountMin( nParamCount, 2) )
1309  return;
1310 
1311  double fVal = 0.0;
1312  // We turn the stack upside down!
1313  ReverseStack( nParamCount);
1314  if (nGlobalError == FormulaError::NONE)
1315  {
1316  double fCount = 1.0;
1317  double fRate = GetDouble();
1318  --nParamCount;
1319  size_t nRefInList = 0;
1320  ScRange aRange;
1321  while (nParamCount-- > 0)
1322  {
1323  switch (GetStackType())
1324  {
1325  case svDouble :
1326  {
1327  fVal += (GetDouble() / pow(1.0 + fRate, fCount));
1328  fCount++;
1329  }
1330  break;
1331  case svSingleRef :
1332  {
1333  ScAddress aAdr;
1334  PopSingleRef( aAdr );
1335  ScRefCellValue aCell(mrDoc, aAdr);
1336  if (!aCell.hasEmptyValue() && aCell.hasNumeric())
1337  {
1338  double fCellVal = GetCellValue(aAdr, aCell);
1339  fVal += (fCellVal / pow(1.0 + fRate, fCount));
1340  fCount++;
1341  }
1342  }
1343  break;
1344  case svDoubleRef :
1345  case svRefList :
1346  {
1347  FormulaError nErr = FormulaError::NONE;
1348  double fCellVal;
1349  PopDoubleRef( aRange, nParamCount, nRefInList);
1350  ScHorizontalValueIterator aValIter( mrDoc, aRange );
1351  while ((nErr == FormulaError::NONE) && aValIter.GetNext(fCellVal, nErr))
1352  {
1353  fVal += (fCellVal / pow(1.0 + fRate, fCount));
1354  fCount++;
1355  }
1356  if ( nErr != FormulaError::NONE )
1357  SetError(nErr);
1358  }
1359  break;
1360  case svMatrix :
1361  case svExternalSingleRef:
1362  case svExternalDoubleRef:
1363  {
1364  ScMatrixRef pMat = GetMatrix();
1365  if (pMat)
1366  {
1367  SCSIZE nC, nR;
1368  pMat->GetDimensions(nC, nR);
1369  if (nC == 0 || nR == 0)
1370  {
1371  PushIllegalArgument();
1372  return;
1373  }
1374  else
1375  {
1376  double fx;
1377  for ( SCSIZE j = 0; j < nC; j++ )
1378  {
1379  for (SCSIZE k = 0; k < nR; ++k)
1380  {
1381  if (!pMat->IsValue(j,k))
1382  {
1383  PushIllegalArgument();
1384  return;
1385  }
1386  fx = pMat->GetDouble(j,k);
1387  fVal += (fx / pow(1.0 + fRate, fCount));
1388  fCount++;
1389  }
1390  }
1391  }
1392  }
1393  }
1394  break;
1395  default : SetError(FormulaError::IllegalParameter); break;
1396  }
1397  }
1398  }
1399  PushDouble(fVal);
1400 }
1401 
1403 {
1404  double fEstimated;
1405  nFuncFmtType = SvNumFormatType::PERCENT;
1406  sal_uInt8 nParamCount = GetByte();
1407  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1408  return;
1409  if (nParamCount == 2)
1410  fEstimated = GetDouble();
1411  else
1412  fEstimated = 0.1;
1413  sal_uInt16 sPos = sp; // memorize the position of the stack
1414  double fEps = 1.0;
1415  double x, fValue;
1416  if (fEstimated == -1.0)
1417  x = 0.1; // default result for division by zero
1418  else
1419  x = fEstimated; // startvalue
1420  switch (GetStackType())
1421  {
1422  case svDoubleRef :
1423  break;
1424  default:
1425  {
1426  PushIllegalParameter();
1427  return;
1428  }
1429  }
1430  const sal_uInt16 nIterationsMax = 20;
1431  sal_uInt16 nItCount = 0;
1432  ScRange aRange;
1433  while (fEps > SCdEpsilon && nItCount < nIterationsMax)
1434  { // Newtons method:
1435  sp = sPos; // reset stack
1436  double fNom = 0.0;
1437  double fDenom = 0.0;
1438  FormulaError nErr = FormulaError::NONE;
1439  PopDoubleRef( aRange );
1440  ScValueIterator aValIter(mrDoc, aRange, mnSubTotalFlags);
1441  if (aValIter.GetFirst(fValue, nErr))
1442  {
1443  double fCount = 0.0;
1444  fNom += fValue / pow(1.0+x,fCount);
1445  fDenom += -fCount * fValue / pow(1.0+x,fCount+1.0);
1446  fCount++;
1447  while ((nErr == FormulaError::NONE) && aValIter.GetNext(fValue, nErr))
1448  {
1449  fNom += fValue / pow(1.0+x,fCount);
1450  fDenom += -fCount * fValue / pow(1.0+x,fCount+1.0);
1451  fCount++;
1452  }
1453  SetError(nErr);
1454  }
1455  double xNew = x - fNom / fDenom; // x(i+1) = x(i)-f(x(i))/f'(x(i))
1456  nItCount++;
1457  fEps = fabs(xNew - x);
1458  x = xNew;
1459  }
1460  if (fEstimated == 0.0 && fabs(x) < SCdEpsilon)
1461  x = 0.0; // adjust to zero
1462  if (fEps < SCdEpsilon)
1463  PushDouble(x);
1464  else
1465  PushError( FormulaError::NoConvergence);
1466 }
1467 
1469 { // range_of_values ; rate_invest ; rate_reinvest
1470  nFuncFmtType = SvNumFormatType::PERCENT;
1471  if ( !MustHaveParamCount( GetByte(), 3 ) )
1472  return;
1473 
1474  double fRate1_reinvest = GetDouble() + 1;
1475  double fRate1_invest = GetDouble() + 1;
1476 
1477  ScRange aRange;
1478  ScMatrixRef pMat;
1479  SCSIZE nC = 0;
1480  SCSIZE nR = 0;
1481  bool bIsMatrix = false;
1482  switch ( GetStackType() )
1483  {
1484  case svDoubleRef :
1485  PopDoubleRef( aRange );
1486  break;
1487  case svMatrix :
1488  case svExternalSingleRef:
1489  case svExternalDoubleRef:
1490  {
1491  pMat = GetMatrix();
1492  if ( pMat )
1493  {
1494  pMat->GetDimensions( nC, nR );
1495  if ( nC == 0 || nR == 0 )
1496  SetError( FormulaError::IllegalArgument );
1497  bIsMatrix = true;
1498  }
1499  else
1500  SetError( FormulaError::IllegalArgument );
1501  }
1502  break;
1503  default :
1504  SetError( FormulaError::IllegalParameter );
1505  break;
1506  }
1507 
1508  if ( nGlobalError != FormulaError::NONE )
1509  PushError( nGlobalError );
1510  else
1511  {
1512  double fNPV_reinvest = 0.0;
1513  double fPow_reinvest = 1.0;
1514  double fNPV_invest = 0.0;
1515  double fPow_invest = 1.0;
1516  sal_uLong nCount = 0;
1517  bool bHasPosValue = false;
1518  bool bHasNegValue = false;
1519 
1520  if ( bIsMatrix )
1521  {
1522  double fX;
1523  for ( SCSIZE j = 0; j < nC; j++ )
1524  {
1525  for ( SCSIZE k = 0; k < nR; ++k )
1526  {
1527  if ( !pMat->IsValue( j, k ) )
1528  continue;
1529  fX = pMat->GetDouble( j, k );
1530  if ( nGlobalError != FormulaError::NONE )
1531  break;
1532 
1533  if ( fX > 0.0 )
1534  { // reinvestments
1535  bHasPosValue = true;
1536  fNPV_reinvest += fX * fPow_reinvest;
1537  }
1538  else if ( fX < 0.0 )
1539  { // investments
1540  bHasNegValue = true;
1541  fNPV_invest += fX * fPow_invest;
1542  }
1543  fPow_reinvest /= fRate1_reinvest;
1544  fPow_invest /= fRate1_invest;
1545  nCount++;
1546  }
1547  }
1548  }
1549  else
1550  {
1551  ScValueIterator aValIter( mrDoc, aRange, mnSubTotalFlags );
1552  double fCellValue;
1553  FormulaError nIterError = FormulaError::NONE;
1554 
1555  bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
1556  while( bLoop )
1557  {
1558  if( fCellValue > 0.0 ) // reinvestments
1559  { // reinvestments
1560  bHasPosValue = true;
1561  fNPV_reinvest += fCellValue * fPow_reinvest;
1562  }
1563  else if( fCellValue < 0.0 ) // investments
1564  { // investments
1565  bHasNegValue = true;
1566  fNPV_invest += fCellValue * fPow_invest;
1567  }
1568  fPow_reinvest /= fRate1_reinvest;
1569  fPow_invest /= fRate1_invest;
1570  nCount++;
1571 
1572  bLoop = aValIter.GetNext( fCellValue, nIterError );
1573  }
1574 
1575  if ( nIterError != FormulaError::NONE )
1576  SetError( nIterError );
1577  }
1578  if ( !( bHasPosValue && bHasNegValue ) )
1579  SetError( FormulaError::IllegalArgument );
1580 
1581  if ( nGlobalError != FormulaError::NONE )
1582  PushError( nGlobalError );
1583  else
1584  {
1585  double fResult = -fNPV_reinvest / fNPV_invest;
1586  fResult *= pow( fRate1_reinvest, static_cast<double>( nCount - 1 ) );
1587  fResult = pow( fResult, div( 1.0, (nCount - 1)) );
1588  PushDouble( fResult - 1.0 );
1589  }
1590  }
1591 }
1592 
1594 { // rate ; period ; total_periods ; invest
1595  if( MustHaveParamCount( GetByte(), 4 ) )
1596  {
1597  double fInvest = GetDouble();
1598  double fTotal = GetDouble();
1599  double fPeriod = GetDouble();
1600  double fRate = GetDouble();
1601 
1602  if( nGlobalError != FormulaError::NONE )
1603  PushError( nGlobalError);
1604  else
1605  PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
1606  }
1607 }
1608 
1609 // financial functions
1610 double ScInterpreter::ScGetPV(double fRate, double fNper, double fPmt,
1611  double fFv, bool bPayInAdvance)
1612 {
1613  double fPv;
1614  if (fRate == 0.0)
1615  fPv = fFv + fPmt * fNper;
1616  else
1617  {
1618  if (bPayInAdvance)
1619  fPv = (fFv * pow(1.0 + fRate, -fNper))
1620  + (fPmt * (1.0 - pow(1.0 + fRate, -fNper + 1.0)) / fRate)
1621  + fPmt;
1622  else
1623  fPv = (fFv * pow(1.0 + fRate, -fNper))
1624  + (fPmt * (1.0 - pow(1.0 + fRate, -fNper)) / fRate);
1625  }
1626  return -fPv;
1627 }
1628 
1630 {
1631  nFuncFmtType = SvNumFormatType::CURRENCY;
1632  double fPmt, fNper, fRate, fFv = 0;
1633  bool bPayInAdvance = false;
1634  sal_uInt8 nParamCount = GetByte();
1635  if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1636  return;
1637  if (nParamCount == 5)
1638  bPayInAdvance = GetBool();
1639  if (nParamCount >= 4)
1640  fFv = GetDouble();
1641  fPmt = GetDouble();
1642  fNper = GetDouble();
1643  fRate = GetDouble();
1644  PushDouble(ScGetPV(fRate, fNper, fPmt, fFv, bPayInAdvance));
1645 }
1646 
1648 {
1649  nFuncFmtType = SvNumFormatType::CURRENCY;
1650  if ( MustHaveParamCount( GetByte(), 4 ) )
1651  {
1652  double fPer = GetDouble();
1653  double fLife = GetDouble();
1654  double fSalvage = GetDouble();
1655  double fCost = GetDouble();
1656  double fSyd = ((fCost - fSalvage) * (fLife - fPer + 1.0)) /
1657  ((fLife * (fLife + 1.0)) / 2.0);
1658  PushDouble(fSyd);
1659  }
1660 }
1661 
1662 double ScInterpreter::ScGetDDB(double fCost, double fSalvage, double fLife,
1663  double fPeriod, double fFactor)
1664 {
1665  double fDdb, fRate, fOldValue, fNewValue;
1666  fRate = fFactor / fLife;
1667  if (fRate >= 1.0)
1668  {
1669  fRate = 1.0;
1670  if (fPeriod == 1.0)
1671  fOldValue = fCost;
1672  else
1673  fOldValue = 0.0;
1674  }
1675  else
1676  fOldValue = fCost * pow(1.0 - fRate, fPeriod - 1.0);
1677  fNewValue = fCost * pow(1.0 - fRate, fPeriod);
1678 
1679  if (fNewValue < fSalvage)
1680  fDdb = fOldValue - fSalvage;
1681  else
1682  fDdb = fOldValue - fNewValue;
1683  if (fDdb < 0.0)
1684  fDdb = 0.0;
1685  return fDdb;
1686 }
1687 
1689 {
1690  nFuncFmtType = SvNumFormatType::CURRENCY;
1691  sal_uInt8 nParamCount = GetByte();
1692  if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1693  return;
1694 
1695  double fFactor;
1696  if (nParamCount == 5)
1697  fFactor = GetDouble();
1698  else
1699  fFactor = 2.0;
1700  double fPeriod = GetDouble();
1701  double fLife = GetDouble();
1702  double fSalvage = GetDouble();
1703  double fCost = GetDouble();
1704  if (fCost < 0.0 || fSalvage < 0.0 || fFactor <= 0.0 || fSalvage > fCost
1705  || fPeriod < 1.0 || fPeriod > fLife)
1706  PushIllegalArgument();
1707  else
1708  PushDouble(ScGetDDB(fCost, fSalvage, fLife, fPeriod, fFactor));
1709 }
1710 
1712 {
1713  nFuncFmtType = SvNumFormatType::CURRENCY;
1714  sal_uInt8 nParamCount = GetByte();
1715  if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1716  return ;
1717  double fMonths;
1718  if (nParamCount == 4)
1719  fMonths = 12.0;
1720  else
1721  fMonths = ::rtl::math::approxFloor(GetDouble());
1722  double fPeriod = GetDouble();
1723  double fLife = GetDouble();
1724  double fSalvage = GetDouble();
1725  double fCost = GetDouble();
1726  if (fMonths < 1.0 || fMonths > 12.0 || fLife > 1200.0 || fSalvage < 0.0 ||
1727  fPeriod > (fLife + 1.0) || fSalvage > fCost || fCost <= 0.0 ||
1728  fLife <= 0 || fPeriod <= 0 )
1729  {
1730  PushIllegalArgument();
1731  return;
1732  }
1733  double fOffRate = 1.0 - pow(fSalvage / fCost, 1.0 / fLife);
1734  fOffRate = ::rtl::math::approxFloor((fOffRate * 1000.0) + 0.5) / 1000.0;
1735  double fFirstOffRate = fCost * fOffRate * fMonths / 12.0;
1736  double fDb = 0.0;
1737  if (::rtl::math::approxFloor(fPeriod) == 1)
1738  fDb = fFirstOffRate;
1739  else
1740  {
1741  double fSumOffRate = fFirstOffRate;
1742  double fMin = fLife;
1743  if (fMin > fPeriod) fMin = fPeriod;
1744  sal_uInt16 iMax = static_cast<sal_uInt16>(::rtl::math::approxFloor(fMin));
1745  for (sal_uInt16 i = 2; i <= iMax; i++)
1746  {
1747  fDb = (fCost - fSumOffRate) * fOffRate;
1748  fSumOffRate += fDb;
1749  }
1750  if (fPeriod > fLife)
1751  fDb = ((fCost - fSumOffRate) * fOffRate * (12.0 - fMonths)) / 12.0;
1752  }
1753  PushDouble(fDb);
1754 }
1755 
1756 double ScInterpreter::ScInterVDB(double fCost, double fSalvage, double fLife,
1757  double fLife1, double fPeriod, double fFactor)
1758 {
1759  double fVdb=0;
1760  double fIntEnd = ::rtl::math::approxCeil(fPeriod);
1761  sal_uLong nLoopEnd = static_cast<sal_uLong>(fIntEnd);
1762 
1763  double fTerm, fSln; // SLN: Straight-Line Depreciation
1764  double fSalvageValue = fCost - fSalvage;
1765  bool bNowSln = false;
1766 
1767  double fDdb;
1768  sal_uLong i;
1769  fSln=0;
1770  for ( i = 1; i <= nLoopEnd; i++)
1771  {
1772  if(!bNowSln)
1773  {
1774  fDdb = ScGetDDB(fCost, fSalvage, fLife, static_cast<double>(i), fFactor);
1775  fSln = fSalvageValue/ (fLife1 - static_cast<double>(i-1));
1776 
1777  if (fSln > fDdb)
1778  {
1779  fTerm = fSln;
1780  bNowSln = true;
1781  }
1782  else
1783  {
1784  fTerm = fDdb;
1785  fSalvageValue -= fDdb;
1786  }
1787  }
1788  else
1789  {
1790  fTerm = fSln;
1791  }
1792 
1793  if ( i == nLoopEnd)
1794  fTerm *= ( fPeriod + 1.0 - fIntEnd );
1795 
1796  fVdb += fTerm;
1797  }
1798  return fVdb;
1799 }
1800 
1802 {
1803  nFuncFmtType = SvNumFormatType::CURRENCY;
1804  sal_uInt8 nParamCount = GetByte();
1805  if ( !MustHaveParamCount( nParamCount, 5, 7 ) )
1806  return;
1807 
1808  double fCost, fSalvage, fLife, fStart, fEnd, fFactor, fVdb = 0.0;
1809  bool bNoSwitch;
1810  if (nParamCount == 7)
1811  bNoSwitch = GetBool();
1812  else
1813  bNoSwitch = false;
1814  if (nParamCount >= 6)
1815  fFactor = GetDouble();
1816  else
1817  fFactor = 2.0;
1818  fEnd = GetDouble();
1819  fStart = GetDouble();
1820  fLife = GetDouble();
1821  fSalvage = GetDouble();
1822  fCost = GetDouble();
1823  if (fStart < 0.0 || fEnd < fStart || fEnd > fLife || fCost < 0.0
1824  || fSalvage > fCost || fFactor <= 0.0)
1825  PushIllegalArgument();
1826  else
1827  {
1828  double fIntStart = ::rtl::math::approxFloor(fStart);
1829  double fIntEnd = ::rtl::math::approxCeil(fEnd);
1830  sal_uLong nLoopStart = static_cast<sal_uLong>(fIntStart);
1831  sal_uLong nLoopEnd = static_cast<sal_uLong>(fIntEnd);
1832 
1833  fVdb = 0.0;
1834  if (bNoSwitch)
1835  {
1836  for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
1837  {
1838  double fTerm = ScGetDDB(fCost, fSalvage, fLife, static_cast<double>(i), fFactor);
1839 
1840  //respect partial period in the Beginning/ End:
1841  if ( i == nLoopStart+1 )
1842  fTerm *= ( std::min( fEnd, fIntStart + 1.0 ) - fStart );
1843  else if ( i == nLoopEnd )
1844  fTerm *= ( fEnd + 1.0 - fIntEnd );
1845 
1846  fVdb += fTerm;
1847  }
1848  }
1849  else
1850  {
1851  double fPart = 0.0;
1852  // respect partial period in the Beginning / End:
1853  if ( !::rtl::math::approxEqual( fStart, fIntStart ) ||
1854  !::rtl::math::approxEqual( fEnd, fIntEnd ) )
1855  {
1856  if ( !::rtl::math::approxEqual( fStart, fIntStart ) )
1857  {
1858  // part to be subtracted at the beginning
1859  double fTempIntEnd = fIntStart + 1.0;
1860  double fTempValue = fCost -
1861  ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );
1862  fPart += ( fStart - fIntStart ) *
1863  ScInterVDB( fTempValue, fSalvage, fLife, fLife - fIntStart,
1864  fTempIntEnd - fIntStart, fFactor);
1865  }
1866  if ( !::rtl::math::approxEqual( fEnd, fIntEnd ) )
1867  {
1868  // part to be subtracted at the end
1869  double fTempIntStart = fIntEnd - 1.0;
1870  double fTempValue = fCost -
1871  ScInterVDB( fCost, fSalvage, fLife, fLife, fTempIntStart, fFactor );
1872  fPart += ( fIntEnd - fEnd ) *
1873  ScInterVDB( fTempValue, fSalvage, fLife, fLife - fTempIntStart,
1874  fIntEnd - fTempIntStart, fFactor);
1875  }
1876  }
1877  // calculate depreciation for whole periods
1878  fCost -= ScInterVDB( fCost, fSalvage, fLife, fLife, fIntStart, fFactor );
1879  fVdb = ScInterVDB( fCost, fSalvage, fLife, fLife - fIntStart,
1880  fIntEnd - fIntStart, fFactor);
1881  fVdb -= fPart;
1882  }
1883  }
1884  PushDouble(fVdb);
1885 }
1886 
1888 {
1889  if ( MustHaveParamCount( GetByte(), 3 ) )
1890  {
1891  double fFuture = GetDouble();
1892  double fPresent = GetDouble();
1893  double fRate = GetDouble();
1894  if ( fFuture <= 0.0 || fPresent <= 0.0 || fRate <= 0.0 )
1895  PushIllegalArgument();
1896  else
1897  PushDouble( log( fFuture / fPresent ) / rtl::math::log1p( fRate ) );
1898  }
1899 }
1900 
1902 {
1903  nFuncFmtType = SvNumFormatType::CURRENCY;
1904  if ( MustHaveParamCount( GetByte(), 3 ) )
1905  {
1906  double fLife = GetDouble();
1907  double fSalvage = GetDouble();
1908  double fCost = GetDouble();
1909  PushDouble( div( fCost - fSalvage, fLife ) );
1910  }
1911 }
1912 
1913 double ScInterpreter::ScGetPMT(double fRate, double fNper, double fPv,
1914  double fFv, bool bPayInAdvance)
1915 {
1916  double fPayment;
1917  if (fRate == 0.0)
1918  fPayment = (fPv + fFv) / fNper;
1919  else
1920  {
1921  if (bPayInAdvance) // payment in advance
1922  fPayment = (fFv + fPv * exp( fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1923  (::rtl::math::expm1( (fNper + 1) * ::rtl::math::log1p(fRate) ) - fRate);
1924  else // payment in arrear
1925  fPayment = (fFv + fPv * exp(fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1926  ::rtl::math::expm1( fNper * ::rtl::math::log1p(fRate) );
1927  }
1928  return -fPayment;
1929 }
1930 
1932 {
1933  double fRate, fNper, fPv, fFv = 0;
1934  bool bPayInAdvance = false;
1935  nFuncFmtType = SvNumFormatType::CURRENCY;
1936  sal_uInt8 nParamCount = GetByte();
1937  if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1938  return;
1939  if (nParamCount == 5)
1940  bPayInAdvance = GetBool();
1941  if (nParamCount >= 4)
1942  fFv = GetDouble();
1943  fPv = GetDouble();
1944  fNper = GetDouble();
1945  fRate = GetDouble();
1946  PushDouble(ScGetPMT(fRate, fNper, fPv, fFv, bPayInAdvance));
1947 }
1948 
1950 {
1951  nFuncFmtType = SvNumFormatType::PERCENT;
1952  if ( MustHaveParamCount( GetByte(), 3 ) )
1953  {
1954  double fFutureValue = GetDouble();
1955  double fPresentValue = GetDouble();
1956  double fNrOfPeriods = GetDouble();
1957  if ( fNrOfPeriods <= 0.0 || fPresentValue == 0.0 )
1958  PushIllegalArgument();
1959  else
1960  PushDouble(pow(fFutureValue / fPresentValue, 1.0 / fNrOfPeriods) - 1.0);
1961  }
1962 }
1963 
1964 double ScInterpreter::ScGetFV(double fRate, double fNper, double fPmt,
1965  double fPv, bool bPayInAdvance)
1966 {
1967  double fFv;
1968  if (fRate == 0.0)
1969  fFv = fPv + fPmt * fNper;
1970  else
1971  {
1972  double fTerm = pow(1.0 + fRate, fNper);
1973  if (bPayInAdvance)
1974  fFv = fPv * fTerm + fPmt*(1.0 + fRate)*(fTerm - 1.0)/fRate;
1975  else
1976  fFv = fPv * fTerm + fPmt*(fTerm - 1.0)/fRate;
1977  }
1978  return -fFv;
1979 }
1980 
1982 {
1983  double fRate, fNper, fPmt, fPv = 0;
1984  bool bPayInAdvance = false;
1985  nFuncFmtType = SvNumFormatType::CURRENCY;
1986  sal_uInt8 nParamCount = GetByte();
1987  if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1988  return;
1989  if (nParamCount == 5)
1990  bPayInAdvance = GetBool();
1991  if (nParamCount >= 4)
1992  fPv = GetDouble();
1993  fPmt = GetDouble();
1994  fNper = GetDouble();
1995  fRate = GetDouble();
1996  PushDouble(ScGetFV(fRate, fNper, fPmt, fPv, bPayInAdvance));
1997 }
1998 
2000 {
2001  double fRate, fPmt, fPV, fFV = 0;
2002  bool bPayInAdvance = false;
2003  sal_uInt8 nParamCount = GetByte();
2004  if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
2005  return;
2006  if (nParamCount == 5)
2007  bPayInAdvance = GetBool();
2008  if (nParamCount >= 4)
2009  fFV = GetDouble(); // Future Value
2010  fPV = GetDouble(); // Present Value
2011  fPmt = GetDouble(); // Payment
2012  fRate = GetDouble();
2013  // Note that due to the function specification in ODFF1.2 (and Excel) the
2014  // amount to be paid to get from fPV to fFV is fFV_+_fPV.
2015  if ( fPV + fFV == 0.0 )
2016  PushDouble( 0.0 );
2017  else if (fRate == 0.0)
2018  PushDouble(-(fPV + fFV)/fPmt);
2019  else if (bPayInAdvance)
2020  PushDouble(log(-(fRate*fFV-fPmt*(1.0+fRate))/(fRate*fPV+fPmt*(1.0+fRate)))
2021  / rtl::math::log1p(fRate));
2022  else
2023  PushDouble(log(-(fRate*fFV-fPmt)/(fRate*fPV+fPmt)) / rtl::math::log1p(fRate));
2024 }
2025 
2026 bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
2027  double fFv, bool bPayType, double & fGuess )
2028 {
2029  // See also #i15090#
2030  // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
2031  // This solution handles integer and non-integer values of Nper different.
2032  // If ODFF will constraint Nper to integer, the distinction of cases can be
2033  // removed; only the integer-part is needed then.
2034  bool bValid = true, bFound = false;
2035  double fX, fXnew, fTerm, fTermDerivation;
2036  double fGeoSeries, fGeoSeriesDerivation;
2037  const sal_uInt16 nIterationsMax = 150;
2038  sal_uInt16 nCount = 0;
2039  const double fEpsilonSmall = 1.0E-14;
2040  if ( bPayType )
2041  {
2042  // payment at beginning of each period
2043  fFv = fFv - fPayment;
2044  fPv = fPv + fPayment;
2045  }
2046  if (fNper == ::rtl::math::round( fNper ))
2047  { // Nper is an integer value
2048  fX = fGuess;
2049  while (!bFound && nCount < nIterationsMax)
2050  {
2051  double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
2052  fPowNminus1 = pow( 1.0+fX, fNper-1.0);
2053  fPowN = fPowNminus1 * (1.0+fX);
2054  if (fX == 0.0)
2055  {
2056  fGeoSeries = fNper;
2057  fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
2058  }
2059  else
2060  {
2061  fGeoSeries = (fPowN-1.0)/fX;
2062  fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
2063  }
2064  fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
2065  fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
2066  if (fabs(fTerm) < fEpsilonSmall)
2067  bFound = true; // will catch root which is at an extreme
2068  else
2069  {
2070  if (fTermDerivation == 0.0)
2071  fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
2072  else
2073  fXnew = fX - fTerm / fTermDerivation;
2074  nCount++;
2075  // more accuracy not possible in oscillating cases
2076  bFound = (fabs(fXnew - fX) < SCdEpsilon);
2077  fX = fXnew;
2078  }
2079  }
2080  // Gnumeric returns roots < -1, Excel gives an error in that cases,
2081  // ODFF says nothing about it. Enable the statement, if you want Excel's
2082  // behavior.
2083  //bValid =(fX >=-1.0);
2084  // Update 2013-06-17: Gnumeric (v1.12.2) doesn't return roots <= -1
2085  // anymore.
2086  bValid = (fX > -1.0);
2087  }
2088  else
2089  { // Nper is not an integer value.
2090  fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
2091  while (bValid && !bFound && nCount < nIterationsMax)
2092  {
2093  if (fX == 0.0)
2094  {
2095  fGeoSeries = fNper;
2096  fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
2097  }
2098  else
2099  {
2100  fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
2101  fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
2102  }
2103  fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
2104  fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
2105  if (fabs(fTerm) < fEpsilonSmall)
2106  bFound = true; // will catch root which is at an extreme
2107  else
2108  {
2109  if (fTermDerivation == 0.0)
2110  fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
2111  else
2112  fXnew = fX - fTerm / fTermDerivation;
2113  nCount++;
2114  // more accuracy not possible in oscillating cases
2115  bFound = (fabs(fXnew - fX) < SCdEpsilon);
2116  fX = fXnew;
2117  bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
2118  }
2119  }
2120  }
2121  fGuess = fX; // return approximate root
2122  return bValid && bFound;
2123 }
2124 
2125 // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
2127 {
2128  double fPv, fPayment, fNper;
2129  // defaults for missing arguments, see ODFF spec
2130  double fFv = 0, fGuess = 0.1, fOrigGuess = 0.1;
2131  bool bPayType = false, bValid = true;
2132  bool bDefaultGuess = true;
2133  nFuncFmtType = SvNumFormatType::PERCENT;
2134  sal_uInt8 nParamCount = GetByte();
2135  if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
2136  return;
2137  if (nParamCount == 6)
2138  {
2139  fOrigGuess = fGuess = GetDouble();
2140  bDefaultGuess = false;
2141  }
2142  if (nParamCount >= 5)
2143  bPayType = GetBool();
2144  if (nParamCount >= 4)
2145  fFv = GetDouble();
2146  fPv = GetDouble();
2147  fPayment = GetDouble();
2148  fNper = GetDouble();
2149  if (fNper <= 0.0) // constraint from ODFF spec
2150  {
2151  PushIllegalArgument();
2152  return;
2153  }
2154  bValid = RateIteration(fNper, fPayment, fPv, fFv, bPayType, fGuess);
2155  if (!bValid)
2156  {
2157  /* TODO: try also for specified guess values, not only default? As is,
2158  * a specified 0.1 guess may be error result but a default 0.1 guess
2159  * may succeed. On the other hand, using a different guess value than
2160  * the specified one may not be desired, even if that didn't match. */
2161  if (bDefaultGuess)
2162  {
2163  /* TODO: this is rather ugly, instead of looping over different
2164  * guess values and doing a Newton goal seek for each we could
2165  * first insert the values into the RATE equation to obtain a set
2166  * of y values and then do a bisecting goal seek, possibly using
2167  * different algorithms. */
2168  double fX = fOrigGuess;
2169  for (int nStep = 2; nStep <= 10 && !bValid; ++nStep)
2170  {
2171  fGuess = fX * nStep;
2172  bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, fGuess);
2173  if (!bValid)
2174  {
2175  fGuess = fX / nStep;
2176  bValid = RateIteration( fNper, fPayment, fPv, fFv, bPayType, fGuess);
2177  }
2178  }
2179  }
2180  if (!bValid)
2181  SetError(FormulaError::NoConvergence);
2182  }
2183  PushDouble(fGuess);
2184 }
2185 
2186 double ScInterpreter::ScGetIpmt(double fRate, double fPer, double fNper, double fPv,
2187  double fFv, bool bPayInAdvance, double& fPmt)
2188 {
2189  fPmt = ScGetPMT(fRate, fNper, fPv, fFv, bPayInAdvance); // for PPMT also if fPer == 1
2190  double fIpmt;
2191  nFuncFmtType = SvNumFormatType::CURRENCY;
2192  if (fPer == 1.0)
2193  {
2194  if (bPayInAdvance)
2195  fIpmt = 0.0;
2196  else
2197  fIpmt = -fPv;
2198  }
2199  else
2200  {
2201  if (bPayInAdvance)
2202  fIpmt = ScGetFV(fRate, fPer-2.0, fPmt, fPv, true) - fPmt;
2203  else
2204  fIpmt = ScGetFV(fRate, fPer-1.0, fPmt, fPv, false);
2205  }
2206  return fIpmt * fRate;
2207 }
2208 
2210 {
2211  double fRate, fPer, fNper, fPv, fFv = 0;
2212  bool bPayInAdvance = false;
2213  nFuncFmtType = SvNumFormatType::CURRENCY;
2214  sal_uInt8 nParamCount = GetByte();
2215  if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
2216  return;
2217  if (nParamCount == 6)
2218  bPayInAdvance = GetBool();
2219  if (nParamCount >= 5)
2220  fFv = GetDouble();
2221  fPv = GetDouble();
2222  fNper = GetDouble();
2223  fPer = GetDouble();
2224  fRate = GetDouble();
2225  if (fPer < 1.0 || fPer > fNper)
2226  PushIllegalArgument();
2227  else
2228  {
2229  double fPmt;
2230  PushDouble(ScGetIpmt(fRate, fPer, fNper, fPv, fFv, bPayInAdvance, fPmt));
2231  }
2232 }
2233 
2235 {
2236  double fRate, fPer, fNper, fPv, fFv = 0;
2237  bool bPayInAdvance = false;
2238  nFuncFmtType = SvNumFormatType::CURRENCY;
2239  sal_uInt8 nParamCount = GetByte();
2240  if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
2241  return;
2242  if (nParamCount == 6)
2243  bPayInAdvance = GetBool();
2244  if (nParamCount >= 5)
2245  fFv = GetDouble();
2246  fPv = GetDouble();
2247  fNper = GetDouble();
2248  fPer = GetDouble();
2249  fRate = GetDouble();
2250  if (fPer < 1.0 || fPer > fNper)
2251  PushIllegalArgument();
2252  else
2253  {
2254  double fPmt;
2255  double fInterestPer = ScGetIpmt(fRate, fPer, fNper, fPv, fFv, bPayInAdvance, fPmt);
2256  PushDouble(fPmt - fInterestPer);
2257  }
2258 }
2259 
2261 {
2262  nFuncFmtType = SvNumFormatType::CURRENCY;
2263  if ( !MustHaveParamCount( GetByte(), 6 ) )
2264  return;
2265 
2266  double fRate, fNper, fPv, fStart, fEnd;
2267  double fFlag = GetDoubleWithDefault( -1.0 );
2268  fEnd = ::rtl::math::approxFloor(GetDouble());
2269  fStart = ::rtl::math::approxFloor(GetDouble());
2270  fPv = GetDouble();
2271  fNper = GetDouble();
2272  fRate = GetDouble();
2273  if (fStart < 1.0 || fEnd < fStart || fRate <= 0.0 ||
2274  fEnd > fNper || fNper <= 0.0 || fPv <= 0.0 ||
2275  ( fFlag != 0.0 && fFlag != 1.0 ))
2276  PushIllegalArgument();
2277  else
2278  {
2279  bool bPayInAdvance = static_cast<bool>(fFlag);
2280  sal_uLong nStart = static_cast<sal_uLong>(fStart);
2281  sal_uLong nEnd = static_cast<sal_uLong>(fEnd) ;
2282  double fPmt = ScGetPMT(fRate, fNper, fPv, 0.0, bPayInAdvance);
2283  double fIpmt = 0.0;
2284  if (nStart == 1)
2285  {
2286  if (!bPayInAdvance)
2287  fIpmt = -fPv;
2288  nStart++;
2289  }
2290  for (sal_uLong i = nStart; i <= nEnd; i++)
2291  {
2292  if (bPayInAdvance)
2293  fIpmt += ScGetFV(fRate, static_cast<double>(i-2), fPmt, fPv, true) - fPmt;
2294  else
2295  fIpmt += ScGetFV(fRate, static_cast<double>(i-1), fPmt, fPv, false);
2296  }
2297  fIpmt *= fRate;
2298  PushDouble(fIpmt);
2299  }
2300 }
2301 
2303 {
2304  nFuncFmtType = SvNumFormatType::CURRENCY;
2305  if ( !MustHaveParamCount( GetByte(), 6 ) )
2306  return;
2307 
2308  double fRate, fNper, fPv, fStart, fEnd;
2309  double fFlag = GetDoubleWithDefault( -1.0 );
2310  fEnd = ::rtl::math::approxFloor(GetDouble());
2311  fStart = ::rtl::math::approxFloor(GetDouble());
2312  fPv = GetDouble();
2313  fNper = GetDouble();
2314  fRate = GetDouble();
2315  if (fStart < 1.0 || fEnd < fStart || fRate <= 0.0 ||
2316  fEnd > fNper || fNper <= 0.0 || fPv <= 0.0 ||
2317  ( fFlag != 0.0 && fFlag != 1.0 ))
2318  PushIllegalArgument();
2319  else
2320  {
2321  bool bPayInAdvance = static_cast<bool>(fFlag);
2322  double fPmt = ScGetPMT(fRate, fNper, fPv, 0.0, bPayInAdvance);
2323  double fPpmt = 0.0;
2324  sal_uLong nStart = static_cast<sal_uLong>(fStart);
2325  sal_uLong nEnd = static_cast<sal_uLong>(fEnd);
2326  if (nStart == 1)
2327  {
2328  if (bPayInAdvance)
2329  fPpmt = fPmt;
2330  else
2331  fPpmt = fPmt + fPv * fRate;
2332  nStart++;
2333  }
2334  for (sal_uLong i = nStart; i <= nEnd; i++)
2335  {
2336  if (bPayInAdvance)
2337  fPpmt += fPmt - (ScGetFV(fRate, static_cast<double>(i-2), fPmt, fPv, true) - fPmt) * fRate;
2338  else
2339  fPpmt += fPmt - ScGetFV(fRate, static_cast<double>(i-1), fPmt, fPv, false) * fRate;
2340  }
2341  PushDouble(fPpmt);
2342  }
2343 }
2344 
2346 {
2347  nFuncFmtType = SvNumFormatType::PERCENT;
2348  if ( !MustHaveParamCount( GetByte(), 2 ) )
2349  return;
2350 
2351  double fPeriods = GetDouble();
2352  double fNominal = GetDouble();
2353  if (fPeriods < 1.0 || fNominal < 0.0)
2354  PushIllegalArgument();
2355  else if ( fNominal == 0.0 )
2356  PushDouble( 0.0 );
2357  else
2358  {
2359  fPeriods = ::rtl::math::approxFloor(fPeriods);
2360  PushDouble(pow(1.0 + fNominal/fPeriods, fPeriods) - 1.0);
2361  }
2362 }
2363 
2365 {
2366  nFuncFmtType = SvNumFormatType::PERCENT;
2367  if ( MustHaveParamCount( GetByte(), 2 ) )
2368  {
2369  double fPeriods = GetDouble();
2370  double fEffective = GetDouble();
2371  if (fPeriods < 1.0 || fEffective <= 0.0)
2372  PushIllegalArgument();
2373  else
2374  {
2375  fPeriods = ::rtl::math::approxFloor(fPeriods);
2376  PushDouble( (pow(fEffective + 1.0, 1.0 / fPeriods) - 1.0) * fPeriods );
2377  }
2378  }
2379 }
2380 
2382 {
2383  if ( !MustHaveParamCount( GetByte(), 2 ) )
2384  return;
2385 
2386  double fDenom = GetDouble(); // Denominator
2387  if ( fDenom == 0.0 )
2388  {
2389  PushError(FormulaError::DivisionByZero);
2390  return;
2391  }
2392  double fNum = GetDouble(); // Numerator
2393  double fRes = ::rtl::math::approxSub( fNum,
2394  ::rtl::math::approxFloor( fNum / fDenom ) * fDenom );
2395  if ( ( fDenom > 0 && fRes >= 0 && fRes < fDenom ) ||
2396  ( fDenom < 0 && fRes <= 0 && fRes > fDenom ) )
2397  PushDouble( fRes );
2398  else
2399  PushError( FormulaError::NoValue );
2400 }
2401 
2403 {
2404  formula::FormulaConstTokenRef p2nd = PopToken();
2405  formula::FormulaConstTokenRef p1st = PopToken();
2406 
2407  if (nGlobalError != FormulaError::NONE || !p2nd || !p1st)
2408  {
2409  PushIllegalArgument();
2410  return;
2411  }
2412 
2413  StackVar sv1 = p1st->GetType();
2414  StackVar sv2 = p2nd->GetType();
2415  if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
2416  (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2417  {
2418  PushIllegalArgument();
2419  return;
2420  }
2421 
2422  const formula::FormulaToken* x1 = p1st.get();
2423  const formula::FormulaToken* x2 = p2nd.get();
2424  if (sv1 == svRefList || sv2 == svRefList)
2425  {
2426  // Now this is a bit nasty but it simplifies things, and having
2427  // intersections with lists isn't too common, if at all...
2428  // Convert a reference to list.
2429  const formula::FormulaToken* xt[2] = { x1, x2 };
2430  StackVar sv[2] = { sv1, sv2 };
2431  // There may only be one reference; the other is necessarily a list
2432  // Ensure converted list proper destruction
2433  std::unique_ptr<formula::FormulaToken> p;
2434  for (size_t i=0; i<2; ++i)
2435  {
2436  if (sv[i] == svSingleRef)
2437  {
2438  ScComplexRefData aRef;
2439  aRef.Ref1 = aRef.Ref2 = *xt[i]->GetSingleRef();
2440  p.reset(new ScRefListToken);
2441  p->GetRefList()->push_back( aRef);
2442  xt[i] = p.get();
2443  }
2444  else if (sv[i] == svDoubleRef)
2445  {
2446  ScComplexRefData aRef = *xt[i]->GetDoubleRef();
2447  p.reset(new ScRefListToken);
2448  p->GetRefList()->push_back( aRef);
2449  xt[i] = p.get();
2450  }
2451  }
2452  x1 = xt[0];
2453  x2 = xt[1];
2454 
2455  ScTokenRef xRes = new ScRefListToken;
2456  ScRefList* pRefList = xRes->GetRefList();
2457  for (const auto& rRef1 : *x1->GetRefList())
2458  {
2459  const ScAddress& r11 = rRef1.Ref1.toAbs(mrDoc, aPos);
2460  const ScAddress& r12 = rRef1.Ref2.toAbs(mrDoc, aPos);
2461  for (const auto& rRef2 : *x2->GetRefList())
2462  {
2463  const ScAddress& r21 = rRef2.Ref1.toAbs(mrDoc, aPos);
2464  const ScAddress& r22 = rRef2.Ref2.toAbs(mrDoc, aPos);
2465  SCCOL nCol1 = ::std::max( r11.Col(), r21.Col());
2466  SCROW nRow1 = ::std::max( r11.Row(), r21.Row());
2467  SCTAB nTab1 = ::std::max( r11.Tab(), r21.Tab());
2468  SCCOL nCol2 = ::std::min( r12.Col(), r22.Col());
2469  SCROW nRow2 = ::std::min( r12.Row(), r22.Row());
2470  SCTAB nTab2 = ::std::min( r12.Tab(), r22.Tab());
2471  if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
2472  ; // nothing
2473  else
2474  {
2475  ScComplexRefData aRef;
2476  aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2477  pRefList->push_back( aRef);
2478  }
2479  }
2480  }
2481  size_t n = pRefList->size();
2482  if (!n)
2483  PushError( FormulaError::NoRef);
2484  else if (n == 1)
2485  {
2486  const ScComplexRefData& rRef = (*pRefList)[0];
2487  if (rRef.Ref1 == rRef.Ref2)
2488  PushTempToken( new ScSingleRefToken(mrDoc.GetSheetLimits(), rRef.Ref1));
2489  else
2490  PushTempToken( new ScDoubleRefToken(mrDoc.GetSheetLimits(), rRef));
2491  }
2492  else
2493  PushTokenRef( xRes);
2494  }
2495  else
2496  {
2497  const formula::FormulaToken* pt[2] = { x1, x2 };
2498  StackVar sv[2] = { sv1, sv2 };
2499  SCCOL nC1[2], nC2[2];
2500  SCROW nR1[2], nR2[2];
2501  SCTAB nT1[2], nT2[2];
2502  for (size_t i=0; i<2; ++i)
2503  {
2504  switch (sv[i])
2505  {
2506  case svSingleRef:
2507  case svDoubleRef:
2508  {
2509  {
2510  const ScAddress& r = pt[i]->GetSingleRef()->toAbs(mrDoc, aPos);
2511  nC1[i] = r.Col();
2512  nR1[i] = r.Row();
2513  nT1[i] = r.Tab();
2514  }
2515  if (sv[i] == svDoubleRef)
2516  {
2517  const ScAddress& r = pt[i]->GetSingleRef2()->toAbs(mrDoc, aPos);
2518  nC2[i] = r.Col();
2519  nR2[i] = r.Row();
2520  nT2[i] = r.Tab();
2521  }
2522  else
2523  {
2524  nC2[i] = nC1[i];
2525  nR2[i] = nR1[i];
2526  nT2[i] = nT1[i];
2527  }
2528  }
2529  break;
2530  default:
2531  ; // nothing, prevent compiler warning
2532  }
2533  }
2534  SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
2535  SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
2536  SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
2537  SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
2538  SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
2539  SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
2540  if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
2541  PushError( FormulaError::NoRef);
2542  else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
2543  PushSingleRef( nCol1, nRow1, nTab1);
2544  else
2545  PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2546  }
2547 }
2548 
2550 {
2551  formula::FormulaConstTokenRef x2 = PopToken();
2552  formula::FormulaConstTokenRef x1 = PopToken();
2553 
2554  if (nGlobalError != FormulaError::NONE || !x2 || !x1)
2555  {
2556  PushIllegalArgument();
2557  return;
2558  }
2559  // We explicitly tell extendRangeReference() to not reuse the token,
2560  // casting const away spares two clones.
2562  mrDoc.GetSheetLimits(), const_cast<FormulaToken&>(*x1), const_cast<FormulaToken&>(*x2), aPos, false);
2563  if (!xRes)
2564  PushIllegalArgument();
2565  else
2566  PushTokenRef( xRes);
2567 }
2568 
2570 {
2571  formula::FormulaConstTokenRef p2nd = PopToken();
2572  formula::FormulaConstTokenRef p1st = PopToken();
2573 
2574  if (nGlobalError != FormulaError::NONE || !p2nd || !p1st)
2575  {
2576  PushIllegalArgument();
2577  return;
2578  }
2579 
2580  StackVar sv1 = p1st->GetType();
2581  StackVar sv2 = p2nd->GetType();
2582  if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
2583  (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2584  {
2585  PushIllegalArgument();
2586  return;
2587  }
2588 
2589  const formula::FormulaToken* x1 = p1st.get();
2590  const formula::FormulaToken* x2 = p2nd.get();
2591 
2592  ScTokenRef xRes;
2593  // Append to an existing RefList if there is one.
2594  if (sv1 == svRefList)
2595  {
2596  xRes = x1->Clone();
2597  sv1 = svUnknown; // mark as handled
2598  }
2599  else if (sv2 == svRefList)
2600  {
2601  xRes = x2->Clone();
2602  sv2 = svUnknown; // mark as handled
2603  }
2604  else
2605  xRes = new ScRefListToken;
2606  ScRefList* pRes = xRes->GetRefList();
2607  const formula::FormulaToken* pt[2] = { x1, x2 };
2608  StackVar sv[2] = { sv1, sv2 };
2609  for (size_t i=0; i<2; ++i)
2610  {
2611  if (pt[i] == xRes)
2612  continue;
2613  switch (sv[i])
2614  {
2615  case svSingleRef:
2616  {
2617  ScComplexRefData aRef;
2618  aRef.Ref1 = aRef.Ref2 = *pt[i]->GetSingleRef();
2619  pRes->push_back( aRef);
2620  }
2621  break;
2622  case svDoubleRef:
2623  pRes->push_back( *pt[i]->GetDoubleRef());
2624  break;
2625  case svRefList:
2626  {
2627  const ScRefList* p = pt[i]->GetRefList();
2628  for (const auto& rRef : *p)
2629  {
2630  pRes->push_back( rRef);
2631  }
2632  }
2633  break;
2634  default:
2635  ; // nothing, prevent compiler warning
2636  }
2637  }
2638  ValidateRef( *pRes); // set #REF! if needed
2639  PushTokenRef( xRes);
2640 }
2641 
2643 {
2644  FormulaConstTokenRef xTok( PopToken());
2645  if (xTok)
2646  {
2647  PushTokenRef( xTok);
2648  PushTokenRef( xTok);
2649  }
2650  else
2651  PushError( FormulaError::UnknownStackVariable);
2652 }
2653 
2655 {
2656  sal_uInt8 nParamCount = GetByte();
2657  if (nParamCount >= 1 && nParamCount <= 3)
2658  {
2659  OUString aStyle2; // Template after timer
2660  if (nParamCount >= 3)
2661  aStyle2 = GetString().getString();
2662  tools::Long nTimeOut = 0; // timeout
2663  if (nParamCount >= 2)
2664  nTimeOut = static_cast<tools::Long>(GetDouble()*1000.0);
2665  OUString aStyle1 = GetString().getString(); // Template for immediate
2666 
2667  if (nTimeOut < 0)
2668  nTimeOut = 0;
2669 
2670  // Execute request to apply template
2671  if ( !mrDoc.IsClipOrUndo() )
2672  {
2673  SfxObjectShell* pShell = mrDoc.GetDocumentShell();
2674  if (pShell)
2675  {
2676  // notify object shell directly!
2677  bool bNotify = true;
2678  if (aStyle2.isEmpty())
2679  {
2680  const ScStyleSheet* pStyle = mrDoc.GetStyle(aPos.Col(), aPos.Row(), aPos.Tab());
2681 
2682  if (pStyle && pStyle->GetName() == aStyle1)
2683  bNotify = false;
2684  }
2685 
2686  if (bNotify)
2687  {
2688  ScRange aRange(aPos);
2689  ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
2690  pShell->Broadcast( aHint );
2691  }
2692  }
2693  }
2694 
2695  PushDouble(0.0);
2696  }
2697  else
2698  PushIllegalParameter();
2699 }
2700 
2701 static ScDdeLink* lcl_GetDdeLink( const sfx2::LinkManager* pLinkMgr,
2702  std::u16string_view rA, std::u16string_view rT, std::u16string_view rI, sal_uInt8 nM )
2703 {
2704  size_t nCount = pLinkMgr->GetLinks().size();
2705  for (size_t i=0; i<nCount; i++ )
2706  {
2707  ::sfx2::SvBaseLink* pBase = pLinkMgr->GetLinks()[i].get();
2708  if (ScDdeLink* pLink = dynamic_cast<ScDdeLink*>(pBase))
2709  {
2710  if ( pLink->GetAppl() == rA &&
2711  pLink->GetTopic() == rT &&
2712  pLink->GetItem() == rI &&
2713  pLink->GetMode() == nM )
2714  return pLink;
2715  }
2716  }
2717 
2718  return nullptr;
2719 }
2720 
2722 {
2723  // application, file, scope
2724  // application, Topic, Item
2725 
2726  sal_uInt8 nParamCount = GetByte();
2727  if ( !MustHaveParamCount( nParamCount, 3, 4 ) )
2728  return;
2729 
2730  sal_uInt8 nMode = SC_DDE_DEFAULT;
2731  if (nParamCount == 4)
2732  {
2733  sal_uInt32 nTmp = GetUInt32();
2734  if (nGlobalError != FormulaError::NONE || nTmp > SAL_MAX_UINT8)
2735  {
2736  PushIllegalArgument();
2737  return;
2738  }
2739  nMode = static_cast<sal_uInt8>(nTmp);
2740  }
2741  OUString aItem = GetString().getString();
2742  OUString aTopic = GetString().getString();
2743  OUString aAppl = GetString().getString();
2744 
2745  if (nMode > SC_DDE_TEXT)
2746  nMode = SC_DDE_DEFAULT;
2747 
2748  // temporary documents (ScFunctionAccess) have no DocShell
2749  // and no LinkManager -> abort
2750 
2751  //sfx2::LinkManager* pLinkMgr = mrDoc.GetLinkManager();
2752  if (!mpLinkManager)
2753  {
2754  PushNoValue();
2755  return;
2756  }
2757 
2758  // Need to reinterpret after loading (build links)
2759  pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
2760 
2761  // while the link is not evaluated, idle must be disabled (to avoid circular references)
2762 
2763  bool bOldEnabled = mrDoc.IsIdleEnabled();
2764  mrDoc.EnableIdle(false);
2765 
2766  // Get/ Create link object
2767 
2768  ScDdeLink* pLink = lcl_GetDdeLink( mpLinkManager, aAppl, aTopic, aItem, nMode );
2769 
2770  //TODO: Save Dde-links (in addition) more efficient at document !!!!!
2771  // ScDdeLink* pLink = mrDoc.GetDdeLink( aAppl, aTopic, aItem );
2772 
2773  bool bWasError = ( pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE );
2774 
2775  if (!pLink)
2776  {
2777  pLink = new ScDdeLink( mrDoc, aAppl, aTopic, aItem, nMode );
2778  mpLinkManager->InsertDDELink( pLink, aAppl, aTopic, aItem );
2779  if ( mpLinkManager->GetLinks().size() == 1 ) // the first one?
2780  {
2781  SfxBindings* pBindings = mrDoc.GetViewBindings();
2782  if (pBindings)
2783  pBindings->Invalidate( SID_LINKS ); // Link-Manager enabled
2784  }
2785 
2786  //if the document was just loaded, but the ScDdeLink entry was missing, then
2787  //don't update this link until the links are updated in response to the users
2788  //decision
2789  if (!mrDoc.HasLinkFormulaNeedingCheck())
2790  {
2791  //TODO: evaluate asynchron ???
2792  pLink->TryUpdate(); // TryUpdate doesn't call Update multiple times
2793  }
2794 
2795  if (pMyFormulaCell)
2796  {
2797  // StartListening after the Update to avoid circular references
2798  pMyFormulaCell->StartListening( *pLink );
2799  }
2800  }
2801  else
2802  {
2803  if (pMyFormulaCell)
2804  pMyFormulaCell->StartListening( *pLink );
2805  }
2806 
2807  // If a new Error from Reschedule appears when the link is executed then reset the errorflag
2808 
2809 
2810  if ( pMyFormulaCell && pMyFormulaCell->GetRawError() != FormulaError::NONE && !bWasError )
2811  pMyFormulaCell->SetErrCode(FormulaError::NONE);
2812 
2813  // check the value
2814 
2815  const ScMatrix* pLinkMat = pLink->GetResult();
2816  if (pLinkMat)
2817  {
2818  SCSIZE nC, nR;
2819  pLinkMat->GetDimensions(nC, nR);
2820  ScMatrixRef pNewMat = GetNewMat( nC, nR);
2821  if (pNewMat)
2822  {
2823  pLinkMat->MatCopy(*pNewMat); // copy
2824  PushMatrix( pNewMat );
2825  }
2826  else
2827  PushIllegalArgument();
2828  }
2829  else
2830  PushNA();
2831 
2832  mrDoc.EnableIdle(bOldEnabled);
2833  mpLinkManager->CloseCachedComps();
2834 }
2835 
2837 { // Value, Base [, MinLen]
2838  sal_uInt8 nParamCount = GetByte();
2839  if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
2840  return;
2841 
2842  static const sal_Unicode pDigits[] = {
2843  '0','1','2','3','4','5','6','7','8','9',
2844  'A','B','C','D','E','F','G','H','I','J','K','L','M',
2845  'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2846  0
2847  };
2848  static const int nDigits = SAL_N_ELEMENTS(pDigits) - 1;
2849  sal_Int32 nMinLen;
2850  if ( nParamCount == 3 )
2851  {
2852  double fLen = ::rtl::math::approxFloor( GetDouble() );
2853  if ( 1.0 <= fLen && fLen < SAL_MAX_UINT16 )
2854  nMinLen = static_cast<sal_Int32>(fLen);
2855  else if ( fLen == 0.0 )
2856  nMinLen = 1;
2857  else
2858  nMinLen = 0; // Error
2859  }
2860  else
2861  nMinLen = 1;
2862  double fBase = ::rtl::math::approxFloor( GetDouble() );
2863  double fVal = ::rtl::math::approxFloor( GetDouble() );
2864  double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2865  (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2866  2.0);
2867  if ( fChars >= SAL_MAX_UINT16 )
2868  nMinLen = 0; // Error
2869 
2870  if ( nGlobalError == FormulaError::NONE && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
2871  {
2872  const sal_Int32 nConstBuf = 128;
2873  sal_Unicode aBuf[nConstBuf];
2874  sal_Int32 nBuf = std::max<sal_Int32>( fChars, nMinLen + 1 );
2875  sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2876  for ( sal_Int32 j = 0; j < nBuf; ++j )
2877  {
2878  pBuf[j] = '0';
2879  }
2880  sal_Unicode* p = pBuf + nBuf - 1;
2881  *p = 0;
2882  if ( o3tl::convertsToAtMost(fVal, sal_uLong(~0)) )
2883  {
2884  sal_uLong nVal = static_cast<sal_uLong>(fVal);
2885  sal_uLong nBase = static_cast<sal_uLong>(fBase);
2886  while ( nVal && p > pBuf )
2887  {
2888  *--p = pDigits[ nVal % nBase ];
2889  nVal /= nBase;
2890  }
2891  fVal = static_cast<double>(nVal);
2892  }
2893  else
2894  {
2895  bool bDirt = false;
2896  while ( fVal && p > pBuf )
2897  {
2898 //TODO: roundoff error starting with numbers greater than 2**48
2899 // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2900 // a little bit better:
2901  double fInt = ::rtl::math::approxFloor( fVal / fBase );
2902  double fMult = fInt * fBase;
2903 #if 0
2904  // =BASIS(1e308;36) => GPF with
2905  // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2906  // in spite off previous test if fVal >= fMult
2907  double fDebug1 = fVal - fMult;
2908  // fVal := 7,5975311883090e+290
2909  // fMult := 7,5975311883090e+290
2910  // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2911  // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2912  double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2913  // and ::rtl::math::approxSub( fVal, fMult ) == 0
2914  double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2915 
2916  // Actual after strange fDebug1 and fVal < fMult is fDebug2 == fBase, but
2917  // anyway it can't be compared, then bDirt is executed an everything is good...
2918 
2919  // prevent compiler warnings
2920  (void)fDebug1; (void)fDebug2; (void)fDebug3;
2921 #endif
2922  size_t nDig;
2923  if ( fVal < fMult )
2924  { // something is wrong there
2925  bDirt = true;
2926  nDig = 0;
2927  }
2928  else
2929  {
2930  double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2931  if ( bDirt )
2932  {
2933  bDirt = false;
2934  --fDig;
2935  }
2936  if ( fDig <= 0.0 )
2937  nDig = 0;
2938  else if ( fDig >= fBase )
2939  nDig = static_cast<size_t>(fBase) - 1;
2940  else
2941  nDig = static_cast<size_t>(fDig);
2942  }
2943  *--p = pDigits[ nDig ];
2944  fVal = fInt;
2945  }
2946  }
2947  if ( fVal )
2948  PushError( FormulaError::StringOverflow );
2949  else
2950  {
2951  if ( nBuf - (p - pBuf) <= nMinLen )
2952  p = pBuf + nBuf - 1 - nMinLen;
2953  PushStringBuffer( p );
2954  }
2955  if ( pBuf != aBuf )
2956  delete [] pBuf;
2957  }
2958  else
2959  PushIllegalArgument();
2960 }
2961 
2963 { // Text, Base
2964  if ( !MustHaveParamCount( GetByte(), 2 ) )
2965  return;
2966 
2967  double fBase = ::rtl::math::approxFloor( GetDouble() );
2968  OUString aStr = GetString().getString();
2969  if ( nGlobalError == FormulaError::NONE && 2 <= fBase && fBase <= 36 )
2970  {
2971  double fVal = 0.0;
2972  int nBase = static_cast<int>(fBase);
2973  const sal_Unicode* p = aStr.getStr();
2974  while ( *p == ' ' || *p == '\t' )
2975  p++; // strip leading white space
2976  if ( nBase == 16 )
2977  { // evtl. hex-prefix stripped
2978  if ( *p == 'x' || *p == 'X' )
2979  p++;
2980  else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
2981  p += 2;
2982  }
2983  while ( *p )
2984  {
2985  int n;
2986  if ( '0' <= *p && *p <= '9' )
2987  n = *p - '0';
2988  else if ( 'A' <= *p && *p <= 'Z' )
2989  n = 10 + (*p - 'A');
2990  else if ( 'a' <= *p && *p <= 'z' )
2991  n = 10 + (*p - 'a');
2992  else
2993  n = nBase;
2994  if ( nBase <= n )
2995  {
2996  if ( *(p+1) == 0 &&
2997  ( (nBase == 2 && (*p == 'b' || *p == 'B'))
2998  ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2999  )
3000  ; // 101b and F00Dh are ok
3001  else
3002  {
3003  PushIllegalArgument();
3004  return ;
3005  }
3006  }
3007  else
3008  fVal = fVal * fBase + n;
3009  p++;
3010 
3011  }
3012  PushDouble( fVal );
3013  }
3014  else
3015  PushIllegalArgument();
3016 }
3017 
3019 { // Value, FromUnit, ToUnit
3020  if ( !MustHaveParamCount( GetByte(), 3 ) )
3021  return;
3022 
3023  OUString aToUnit = GetString().getString();
3024  OUString aFromUnit = GetString().getString();
3025  double fVal = GetDouble();
3026  if ( nGlobalError != FormulaError::NONE )
3027  PushError( nGlobalError);
3028  else
3029  {
3030  // first of all search for the given order; if it can't be found then search for the inverse
3031  double fConv;
3032  if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
3033  PushDouble( fVal * fConv );
3034  else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
3035  PushDouble( fVal / fConv );
3036  else
3037  PushNA();
3038  }
3039 }
3040 
3042 { // Value [Mode]
3043  sal_uInt8 nParamCount = GetByte();
3044  if( !MustHaveParamCount( nParamCount, 1, 2 ) )
3045  return;
3046 
3047  double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
3048  double fVal = ::rtl::math::approxFloor( GetDouble() );
3049  if( nGlobalError != FormulaError::NONE )
3050  PushError( nGlobalError);
3051  else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
3052  {
3053  static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
3054  static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
3055  static const sal_uInt16 nMaxIndex = sal_uInt16(SAL_N_ELEMENTS(pValues) - 1);
3056 
3057  OUStringBuffer aRoman;
3058  sal_uInt16 nVal = static_cast<sal_uInt16>(fVal);
3059  sal_uInt16 nMode = static_cast<sal_uInt16>(fMode);
3060 
3061  for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
3062  {
3063  sal_uInt16 nIndex = 2 * i;
3064  sal_uInt16 nDigit = nVal / pValues[ nIndex ];
3065 
3066  if( (nDigit % 5) == 4 )
3067  {
3068  // assert can't happen with nVal<4000 precondition
3069  assert( ((nDigit == 4) ? (nIndex >= 1) : (nIndex >= 2)));
3070 
3071  sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
3072  sal_uInt16 nSteps = 0;
3073  while( (nSteps < nMode) && (nIndex < nMaxIndex) )
3074  {
3075  nSteps++;
3076  if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
3077  nIndex++;
3078  else
3079  nSteps = nMode;
3080  }
3081  aRoman.append( pChars[ nIndex ] ).append( pChars[ nIndex2 ] );
3082  nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
3083  nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
3084  }
3085  else
3086  {
3087  if( nDigit > 4 )
3088  {
3089  // assert can't happen with nVal<4000 precondition
3090  assert( nIndex >= 1 );
3091  aRoman.append( pChars[ nIndex - 1 ] );
3092  }
3093  sal_Int32 nPad = nDigit % 5;
3094  if (nPad)
3095  {
3096  OUStringBuffer aBuf(aRoman);
3097  comphelper::string::padToLength(aBuf, aBuf.getLength() + nPad,
3098  pChars[nIndex]);
3099  aRoman = aBuf.makeStringAndClear();
3100  }
3101  nVal %= pValues[ nIndex ];
3102  }
3103  }
3104 
3105  PushString( aRoman.makeStringAndClear() );
3106  }
3107  else
3108  PushIllegalArgument();
3109 }
3110 
3111 static bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, bool& rbIsDec )
3112 {
3113  switch( cChar )
3114  {
3115  case 'M': rnValue = 1000; rbIsDec = true; break;
3116  case 'D': rnValue = 500; rbIsDec = false; break;
3117  case 'C': rnValue = 100; rbIsDec = true; break;
3118  case 'L': rnValue = 50; rbIsDec = false; break;
3119  case 'X': rnValue = 10; rbIsDec = true; break;
3120  case 'V': rnValue = 5; rbIsDec = false; break;
3121  case 'I': rnValue = 1; rbIsDec = true; break;
3122  default: return false;
3123  }
3124  return true;
3125 }
3126 
3128 {
3129  OUString aRoman = GetString().getString();
3130  if( nGlobalError != FormulaError::NONE )
3131  PushError( nGlobalError);
3132  else
3133  {
3134  aRoman = aRoman.toAsciiUpperCase();
3135 
3136  sal_uInt16 nValue = 0;
3137  sal_uInt16 nValidRest = 3999;
3138  sal_Int32 nCharIndex = 0;
3139  sal_Int32 nCharCount = aRoman.getLength();
3140  bool bValid = true;
3141 
3142  while( bValid && (nCharIndex < nCharCount) )
3143  {
3144  sal_uInt16 nDigit1 = 0;
3145  sal_uInt16 nDigit2 = 0;
3146  bool bIsDec1 = false;
3147  bValid = lcl_GetArabicValue( aRoman[nCharIndex], nDigit1, bIsDec1 );
3148  if( bValid && (nCharIndex + 1 < nCharCount) )
3149  {
3150  bool bIsDec2 = false;
3151  bValid = lcl_GetArabicValue( aRoman[nCharIndex + 1], nDigit2, bIsDec2 );
3152  }
3153  if( bValid )
3154  {
3155  if( nDigit1 >= nDigit2 )
3156  {
3157  nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
3158  nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
3159  bValid = (nValidRest >= nDigit1);
3160  if( bValid )
3161  nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
3162  nCharIndex++;
3163  }
3164  else if( nDigit1 * 2 != nDigit2 )
3165  {
3166  sal_uInt16 nDiff = nDigit2 - nDigit1;
3167  nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
3168  bValid = (nValidRest >= nDiff);
3169  if( bValid )
3170  nValidRest = nDigit1 - 1;
3171  nCharIndex += 2;
3172  }
3173  else
3174  bValid = false;
3175  }
3176  }
3177  if( bValid )
3178  PushInt( nValue );
3179  else
3180  PushIllegalArgument();
3181  }
3182 }
3183 
3185 {
3186  sal_uInt8 nParamCount = GetByte();
3187  if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
3188  return;
3189 
3190  double fVal = 0.0;
3192  ScMatValType nResultType = ScMatValType::String;
3193 
3194  if ( nParamCount == 2 )
3195  {
3196  switch ( GetStackType() )
3197  {
3198  case svDouble:
3199  fVal = GetDouble();
3200  nResultType = ScMatValType::Value;
3201  break;
3202  case svString:
3203  aStr = GetString();
3204  break;
3205  case svSingleRef:
3206  case svDoubleRef:
3207  {
3208  ScAddress aAdr;
3209  if ( !PopDoubleRefOrSingleRef( aAdr ) )
3210  break;
3211 
3212  ScRefCellValue aCell(mrDoc, aAdr);
3213  if (aCell.hasEmptyValue())
3214  nResultType = ScMatValType::Empty;
3215  else
3216  {
3217  FormulaError nErr = GetCellErrCode(aCell);
3218  if (nErr != FormulaError::NONE)
3219  SetError( nErr);
3220  else if (aCell.hasNumeric())
3221  {
3222  fVal = GetCellValue(aAdr, aCell);
3223  nResultType = ScMatValType::Value;
3224  }
3225  else
3226  GetCellString(aStr, aCell);
3227  }
3228  }
3229  break;
3230  case svMatrix:
3231  nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
3232  break;
3233  case svMissing:
3234  case svEmptyCell:
3235  Pop();
3236  // mimic xcl
3237  fVal = 0.0;
3238  nResultType = ScMatValType::Value;
3239  break;
3240  default:
3241  PopError();
3242  SetError( FormulaError::IllegalArgument);
3243  }
3244  }
3245  svl::SharedString aUrl = GetString();
3246  ScMatrixRef pResMat = GetNewMat( 1, 2);
3247  if (nGlobalError != FormulaError::NONE)
3248  {
3249  fVal = CreateDoubleError( nGlobalError);
3250  nResultType = ScMatValType::Value;
3251  }
3252  if (nParamCount == 2 || nGlobalError != FormulaError::NONE)
3253  {
3254  if (ScMatrix::IsValueType( nResultType))
3255  pResMat->PutDouble( fVal, 0);
3256  else if (ScMatrix::IsRealStringType( nResultType))
3257  pResMat->PutString(aStr, 0);
3258  else // EmptyType, EmptyPathType, mimic xcl
3259  pResMat->PutDouble( 0.0, 0 );
3260  }
3261  else
3262  pResMat->PutString(aUrl, 0);
3263  pResMat->PutString(aUrl, 1);
3264  bMatrixFormula = true;
3265  PushMatrix(pResMat);
3266 }
3267 
3272 static bool lclConvertMoney( const OUString& aSearchUnit, double& rfRate, int& rnDec )
3273 {
3274  struct ConvertInfo
3275  {
3276  const char* pCurrText;
3277  double fRate;
3278  int nDec;
3279  };
3280  static const ConvertInfo aConvertTable[] = {
3281  { "EUR", 1.0, 2 },
3282  { "ATS", 13.7603, 2 },
3283  { "BEF", 40.3399, 0 },
3284  { "DEM", 1.95583, 2 },
3285  { "ESP", 166.386, 0 },
3286  { "FIM", 5.94573, 2 },
3287  { "FRF", 6.55957, 2 },
3288  { "IEP", 0.787564, 2 },
3289  { "ITL", 1936.27, 0 },
3290  { "LUF", 40.3399, 0 },
3291  { "NLG", 2.20371, 2 },
3292  { "PTE", 200.482, 2 },
3293  { "GRD", 340.750, 2 },
3294  { "SIT", 239.640, 2 },
3295  { "MTL", 0.429300, 2 },
3296  { "CYP", 0.585274, 2 },
3297  { "SKK", 30.1260, 2 },
3298  { "EEK", 15.6466, 2 },
3299  { "LVL", 0.702804, 2 },
3300  { "LTL", 3.45280, 2 }
3301  };
3302 
3303  for (const auto & i : aConvertTable)
3304  if ( aSearchUnit.equalsIgnoreAsciiCaseAscii( i.pCurrText ) )
3305  {
3306  rfRate = i.fRate;
3307  rnDec = i.nDec;
3308  return true;
3309  }
3310  return false;
3311 }
3312 
3314 { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
3315  sal_uInt8 nParamCount = GetByte();
3316  if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
3317  return;
3318 
3319  double fPrecision = 0.0;
3320  if ( nParamCount == 5 )
3321  {
3322  fPrecision = ::rtl::math::approxFloor(GetDouble());
3323  if ( fPrecision < 3 )
3324  {
3325  PushIllegalArgument();
3326  return;
3327  }
3328  }
3329  bool bFullPrecision = false;
3330  if ( nParamCount >= 4 )
3331  bFullPrecision = GetBool();
3332  OUString aToUnit = GetString().getString();
3333  OUString aFromUnit = GetString().getString();
3334  double fVal = GetDouble();
3335  if ( nGlobalError != FormulaError::NONE )
3336  PushError( nGlobalError);
3337  else
3338  {
3339  double fFromRate;
3340  double fToRate;
3341  int nFromDec;
3342  int nToDec;
3343  if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
3344  && lclConvertMoney( aToUnit, fToRate, nToDec ) )
3345  {
3346  double fRes;
3347  if ( aFromUnit.equalsIgnoreAsciiCase( aToUnit ) )
3348  fRes = fVal;
3349  else
3350  {
3351  if ( aFromUnit.equalsIgnoreAsciiCase( "EUR" ) )
3352  fRes = fVal * fToRate;
3353  else
3354  {
3355  double fIntermediate = fVal / fFromRate;
3356  if ( fPrecision )
3357  fIntermediate = ::rtl::math::round( fIntermediate,
3358  static_cast<int>(fPrecision) );
3359  fRes = fIntermediate * fToRate;
3360  }
3361  if ( !bFullPrecision )
3362  fRes = ::rtl::math::round( fRes, nToDec );
3363  }
3364  PushDouble( fRes );
3365  }
3366  else
3367  PushIllegalArgument();
3368  }
3369 }
3370 
3371 // BAHTTEXT
3372 #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
3373 #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
3374 #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
3375 #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
3376 #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
3377 #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
3378 #define UTF8_TH_6 "\340\270\253\340\270\201"
3379 #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
3380 #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
3381 #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
3382 #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
3383 #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
3384 #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
3385 #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
3386 #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
3387 #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
3388 #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
3389 #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
3390 #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
3391 #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
3392 #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
3393 #define UTF8_TH_MINUS "\340\270\245\340\270\232"
3394 
3395 // local functions
3396 namespace {
3397 
3398 void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
3399 {
3400  rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
3401 }
3402 
3404 void lclAppendDigit( OStringBuffer& rText, sal_Int32 nDigit )
3405 {
3406  switch( nDigit )
3407  {
3408  case 0: rText.append( UTF8_TH_0 ); break;
3409  case 1: rText.append( UTF8_TH_1 ); break;
3410  case 2: rText.append( UTF8_TH_2 ); break;
3411  case 3: rText.append( UTF8_TH_3 ); break;
3412  case 4: rText.append( UTF8_TH_4 ); break;
3413  case 5: rText.append( UTF8_TH_5 ); break;
3414  case 6: rText.append( UTF8_TH_6 ); break;
3415  case 7: rText.append( UTF8_TH_7 ); break;
3416  case 8: rText.append( UTF8_TH_8 ); break;
3417  case 9: rText.append( UTF8_TH_9 ); break;
3418  default: OSL_FAIL( "lclAppendDigit - illegal digit" );
3419  }
3420 }
3421 
3426 void lclAppendPow10( OStringBuffer& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
3427 {
3428  OSL_ENSURE( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
3429  lclAppendDigit( rText, nDigit );
3430  switch( nPow10 )
3431  {
3432  case 2: rText.append( UTF8_TH_1E2 ); break;
3433  case 3: rText.append( UTF8_TH_1E3 ); break;
3434  case 4: rText.append( UTF8_TH_1E4 ); break;
3435  case 5: rText.append( UTF8_TH_1E5 ); break;
3436  default: OSL_FAIL( "lclAppendPow10 - illegal power" );
3437  }
3438 }
3439 
3441 void lclAppendBlock( OStringBuffer& rText, sal_Int32 nValue )
3442 {
3443  OSL_ENSURE( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
3444  if( nValue >= 100000 )
3445  {
3446  lclAppendPow10( rText, nValue / 100000, 5 );
3447  nValue %= 100000;
3448  }
3449  if( nValue >= 10000 )
3450  {
3451  lclAppendPow10( rText, nValue / 10000, 4 );
3452  nValue %= 10000;
3453  }
3454  if( nValue >= 1000 )
3455  {
3456  lclAppendPow10( rText, nValue / 1000, 3 );
3457  nValue %= 1000;
3458  }
3459  if( nValue >= 100 )
3460  {
3461  lclAppendPow10( rText, nValue / 100, 2 );
3462  nValue %= 100;
3463  }
3464  if( nValue <= 0 )
3465  return;
3466 
3467  sal_Int32 nTen = nValue / 10;
3468  sal_Int32 nOne = nValue % 10;
3469  if( nTen >= 1 )
3470  {
3471  if( nTen >= 3 )
3472  lclAppendDigit( rText, nTen );
3473  else if( nTen == 2 )
3474  rText.append( UTF8_TH_20 );
3475  rText.append( UTF8_TH_10 );
3476  }
3477  if( (nTen > 0) && (nOne == 1) )
3478  rText.append( UTF8_TH_11 );
3479  else if( nOne > 0 )
3480  lclAppendDigit( rText, nOne );
3481 }
3482 
3483 } // namespace
3484 
3486 {
3487  sal_uInt8 nParamCount = GetByte();
3488  if ( !MustHaveParamCount( nParamCount, 1 ) )
3489  return;
3490 
3491  double fValue = GetDouble();
3492  if( nGlobalError != FormulaError::NONE )
3493  {
3494  PushError( nGlobalError);
3495  return;
3496  }
3497 
3498  // sign
3499  bool bMinus = fValue < 0.0;
3500  fValue = fabs( fValue );
3501 
3502  // round to 2 digits after decimal point, fValue contains Satang as integer
3503  fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
3504 
3505  // split Baht and Satang
3506  double fBaht = 0.0;
3507  sal_Int32 nSatang = 0;
3508  lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
3509 
3510  OStringBuffer aText;
3511 
3512  // generate text for Baht value
3513  if( fBaht == 0.0 )
3514  {
3515  if( nSatang == 0 )
3516  aText.append( UTF8_TH_0 );
3517  }
3518  else while( fBaht > 0.0 )
3519  {
3520  OStringBuffer aBlock;
3521  sal_Int32 nBlock = 0;
3522  lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
3523  if( nBlock > 0 )
3524  lclAppendBlock( aBlock, nBlock );
3525  // add leading "million", if there will come more blocks
3526  if( fBaht > 0.0 )
3527  aBlock.insert( 0, UTF8_TH_1E6 );
3528 
3529  aText.insert(0, aBlock.makeStringAndClear());
3530  }
3531  if (!aText.isEmpty())
3532  aText.append( UTF8_TH_BAHT );
3533 
3534  // generate text for Satang value
3535  if( nSatang == 0 )
3536  {
3537  aText.append( UTF8_TH_DOT0 );
3538  }
3539  else
3540  {
3541  lclAppendBlock( aText, nSatang );
3542  aText.append( UTF8_TH_SATANG );
3543  }
3544 
3545  // add the minus sign
3546  if( bMinus )
3547  aText.insert( 0, UTF8_TH_MINUS );
3548 
3549  PushString( OStringToOUString(aText.makeStringAndClear(), RTL_TEXTENCODING_UTF8) );
3550 }
3551 
3553 {
3554  sal_uInt8 nParamCount = GetByte();
3555 
3556  if (!MustHaveParamCountMin(nParamCount, 2) || (nParamCount % 2) == 1)
3557  {
3558  PushError(FormulaError::NoRef);
3559  return;
3560  }
3561 
3562  bool bOldSyntax = false;
3563  if (nParamCount == 2)
3564  {
3565  // if the first parameter is a ref, assume old syntax
3566  StackVar eFirstType = GetStackType(2);
3567  if (eFirstType == svSingleRef || eFirstType == svDoubleRef)
3568  bOldSyntax = true;
3569  }
3570 
3571  std::vector<sheet::DataPilotFieldFilter> aFilters;
3572  OUString aDataFieldName;
3573  ScRange aBlock;
3574 
3575  if (bOldSyntax)
3576  {
3577  aDataFieldName = GetString().getString();
3578 
3579  switch (GetStackType())
3580  {
3581  case svDoubleRef :
3582  PopDoubleRef(aBlock);
3583  break;
3584  case svSingleRef :
3585  {
3586  ScAddress aAddr;
3587  PopSingleRef(aAddr);
3588  aBlock = aAddr;
3589  }
3590  break;
3591  default:
3592  PushError(FormulaError::NoRef);
3593  return;
3594  }
3595  }
3596  else
3597  {
3598  // Standard syntax: separate name/value pairs
3599 
3600  sal_uInt16 nFilterCount = nParamCount / 2 - 1;
3601  aFilters.resize(nFilterCount);
3602 
3603  sal_uInt16 i = nFilterCount;
3604  while (i-- > 0)
3605  {
3606  /* TODO: also, in case of numeric the entire filter match should
3607  * not be on a (even if locale independent) formatted string down
3608  * below in pDPObj->GetPivotData(). */
3609 
3610  bool bEvaluateFormatIndex;
3611  switch (GetRawStackType())
3612  {
3613  case svSingleRef:
3614  case svDoubleRef:
3615  bEvaluateFormatIndex = true;
3616  break;
3617  default:
3618  bEvaluateFormatIndex = false;
3619  }
3620 
3621  double fDouble;
3622  svl::SharedString aSharedString;
3623  bool bDouble = GetDoubleOrString( fDouble, aSharedString);
3624  if (nGlobalError != FormulaError::NONE)
3625  {
3626  PushError( nGlobalError);
3627  return;
3628  }
3629 
3630  if (bDouble)
3631  {
3632  sal_uInt32 nNumFormat;
3633  if (bEvaluateFormatIndex && nCurFmtIndex)
3634  nNumFormat = nCurFmtIndex;
3635  else
3636  {
3637  if (nCurFmtType == SvNumFormatType::UNDEFINED)
3638  nNumFormat = 0;
3639  else
3640  nNumFormat = pFormatter->GetStandardFormat( nCurFmtType, ScGlobal::eLnge);
3641  }
3642  const Color* pColor;
3643  pFormatter->GetOutputString( fDouble, nNumFormat, aFilters[i].MatchValueName, &pColor);
3644  aFilters[i].MatchValue = ScDPCache::GetLocaleIndependentFormattedString(
3645  fDouble, *pFormatter, nNumFormat);
3646  }
3647  else
3648  {
3649  aFilters[i].MatchValueName = aSharedString.getString();
3650 
3651  // Parse possible number from MatchValueName and format
3652  // locale independent as MatchValue.
3653  sal_uInt32 nNumFormat = 0;
3654  double fValue;
3655  if (pFormatter->IsNumberFormat( aFilters[i].MatchValueName, nNumFormat, fValue))
3656  aFilters[i].MatchValue = ScDPCache::GetLocaleIndependentFormattedString(
3657  fValue, *pFormatter, nNumFormat);
3658  else
3659  aFilters[i].MatchValue = aFilters[i].MatchValueName;
3660  }
3661 
3662  aFilters[i].FieldName = GetString().getString();
3663  }
3664 
3665  switch (GetStackType())
3666  {
3667  case svDoubleRef :
3668  PopDoubleRef(aBlock);
3669  break;
3670  case svSingleRef :
3671  {
3672  ScAddress aAddr;
3673  PopSingleRef(aAddr);
3674  aBlock = aAddr;
3675  }
3676  break;
3677  default:
3678  PushError(FormulaError::NoRef);
3679  return;
3680  }
3681 
3682  aDataFieldName = GetString().getString(); // First parameter is data field name.
3683  }
3684 
3685  // Early bail-out, don't grind through data pilot cache and all.
3686  if (nGlobalError != FormulaError::NONE)
3687  {
3688  PushError( nGlobalError);
3689  return;
3690  }
3691 
3692  // NOTE : MS Excel docs claim to use the 'most recent' which is not
3693  // exactly the same as what we do in ScDocument::GetDPAtBlock
3694  // However we do need to use GetDPABlock
3695  ScDPObject* pDPObj = mrDoc.GetDPAtBlock(aBlock);
3696  if (!pDPObj)
3697  {
3698  PushError(FormulaError::NoRef);
3699  return;
3700  }
3701 
3702  if (bOldSyntax)
3703  {
3704  OUString aFilterStr = aDataFieldName;
3705  std::vector<sal_Int16> aFilterFuncs;
3706  if (!pDPObj->ParseFilters(aDataFieldName, aFilters, aFilterFuncs, aFilterStr))
3707  {
3708  PushError(FormulaError::NoRef);
3709  return;
3710  }
3711 
3712  // TODO : For now, we ignore filter functions since we couldn't find a
3713  // live example of how they are supposed to be used. We'll support
3714  // this again once we come across a real-world example.
3715  }
3716 
3717  double fVal = pDPObj->GetPivotData(aDataFieldName, aFilters);
3718  if (std::isnan(fVal))
3719  {
3720  PushError(FormulaError::NoRef);
3721  return;
3722  }
3723  PushDouble(fVal);
3724 }
3725 
3726 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:113
svString
void ScDecimal()
Definition: interpr2.cxx:2962
void ScRoundSignificant()
Definition: interpr2.cxx:1029
void ScGetDiffDate()
Definition: interpr2.cxx:670
::boost::intrusive_ptr< const FormulaToken > FormulaConstTokenRef
StackVar
static const sal_Int64 hourPerDay
svRefList
void ScArcTan2()
Definition: interpr2.cxx:1258
constexpr sal_Int64 md(Length i, Length j)
#define SCdEpsilon
Definition: interpr2.cxx:54
void ScEasterSunday()
Definition: interpr2.cxx:305
static void RoundSignificant(double fX, double fDigits, double &fRes)
Definition: interpr2.cxx:1017
sal_Int32 nIndex
OUString getString() const
void ScGetTimeValue()
Definition: interpr2.cxx:924
#define UTF8_TH_10
Definition: interpr2.cxx:3382
static const sal_Int64 secondPerMinute
DayOfWeek GetDayOfWeek() const
#define UTF8_TH_3
Definition: interpr2.cxx:3375
#define UTF8_TH_1E2
Definition: interpr2.cxx:3385
#define UTF8_TH_BAHT
Definition: interpr2.cxx:3391
SCROW Row() const
Definition: address.hxx:262
static OUString GetLocaleIndependentFormattedString(double fValue, SvNumberFormatter &rFormatter, sal_uInt32 nNumFormat)
Definition: dpcache.cxx:1194
void ScGetDay()
Definition: interpr2.cxx:132
#define DATE_TIME_FACTOR
Definition: globalnames.hxx:20
void ScFloor_Precise()
Definition: interpr2.cxx:1208
void ScRangeFunc()
Definition: interpr2.cxx:2549
std::string GetValue
int SetError()
void ScLog10()
Definition: interpr2.cxx:1295
void ScPDuration()
Definition: interpr2.cxx:1887
void ScIntersect()
Definition: interpr2.cxx:2402
void ScRound()
Definition: interpr2.cxx:1002
ScAddress toAbs(const ScSheetLimits &rLimits, const ScAddress &rPos) const
Definition: refdata.cxx:193
void ScEffect()
Definition: interpr2.cxx:2345
SATURDAY
void ScRoman()
Definition: interpr2.cxx:3041
#define UTF8_TH_9
Definition: interpr2.cxx:3381
sal_uIntPtr sal_uLong
long Long
const sal_uInt8 SC_DDE_DEFAULT
Definition: document.hxx:292
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
sal_Int64 n
FormulaError GetWeekendAndHolidayMasks_MS(const sal_uInt8 nParamCount, const sal_uInt32 nNullDate,::std::vector< double > &rSortArray, bool bWeekendMask[7], bool bWorkdayFunction)
Definition: interpr2.cxx:386
#define N
aBuf
void ScCeil_MS()
Definition: interpr2.cxx:1099
static const sal_Int64 minutePerDay
void ScCeil(bool bODFF)
tdf69552 ODFF1.2 function CEILING and Excel function CEILING.MATH In essence, the difference between ...
Definition: interpr2.cxx:1059
bool IsLeapYear() const
void ScGetActDate()
Definition: interpr2.cxx:98
void MatCopy(const ScMatrix &mRes) const
Definition: scmatrix.cxx:3144
static sal_Int32 DateToDays(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear)
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:104
FRIDAY
void ScGetDiffDate360()
Definition: interpr2.cxx:680
void Invalidate(sal_uInt16 nId)
sal_uInt16 GetWeekOfYear(DayOfWeek eStartDay=MONDAY, sal_Int16 nMinimumNumberOfDaysInWeek=4) const
const sal_uInt8 SC_DDE_TEXT
Definition: document.hxx:294
void ScGetMin()
Definition: interpr2.cxx:139
float x
void ScGetActTime()
Definition: interpr2.cxx:106
Row-wise value iterator.
Definition: dociter.hxx:479
sal_uInt16 GetHour() const
OUString GetString(int nId)
tuple log
#define SAL_MAX_UINT32
bool IsValidAndGregorian() const
WEDNESDAY
#define UTF8_TH_1E3
Definition: interpr2.cxx:3386
sal_uInt16 sal_Unicode
void ScCeil_Precise()
Definition: interpr2.cxx:1117
char sal_uInt16 & nParamCount
Definition: callform.cxx:53
void ScGetHour()
Definition: interpr2.cxx:158
void ScUnionFunc()
Definition: interpr2.cxx:2569
const OUString & GetName() const
FormulaTokenRef extendRangeReference(ScSheetLimits &rLimits, FormulaToken &rTok1, FormulaToken &rTok2, const ScAddress &rPos, bool bReuseDoubleRef)
If rTok1 and rTok2 both are SingleRef or DoubleRef tokens, extend/merge ranges as needed for ocRange...
Definition: token.cxx:495
sal_uInt32 GetNanoSec() const
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:45
#define SAL_MAX_UINT16
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
sal_uInt16 GetMonth() const
void ScGetDateValue()
Definition: interpr2.cxx:166
static double ScGetPMT(double fRate, double fNper, double fPv, double fFv, bool bPayInAdvance)
Definition: interpr2.cxx:1913
static double ScGetFV(double fRate, double fNper, double fPmt, double fPv, bool bPayInAdvance)
Definition: interpr2.cxx:1964
int nCount
virtual const ScSingleRefData * GetSingleRef() const
sal_uInt16 GetMin() const
THURSDAY
svDouble
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:26
SCTAB Tab() const
Definition: address.hxx:271
bool hasEmptyValue()
Definition: cellvalue.cxx:675
#define UTF8_TH_5
Definition: interpr2.cxx:3377
void ScConvertOOo()
Definition: interpr2.cxx:3018
void ScGetWeekOfYear()
Definition: interpr2.cxx:245
void ScNetWorkdays(bool bOOXML_Version)
Definition: interpr2.cxx:503
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:2334
#define SAL_N_ELEMENTS(arr)
DocumentType eType
void ScInt()
Definition: interpr2.cxx:962
sal_Int16 GetYear() const
void ScEuroConvert()
Definition: interpr2.cxx:3313
static bool lcl_GetArabicValue(sal_Unicode cChar, sal_uInt16 &rnValue, bool &rbIsDec)
Definition: interpr2.cxx:3111
sal_uInt16 GetSec() const
#define UTF8_TH_6
Definition: interpr2.cxx:3378
void ScFloor_MS()
Definition: interpr2.cxx:1187
#define UTF8_TH_1
Definition: interpr2.cxx:3373
static ScDdeLink * lcl_GetDdeLink(const sfx2::LinkManager *pLinkMgr, std::u16string_view rA, std::u16string_view rT, std::u16string_view rI, sal_uInt8 nM)
Definition: interpr2.cxx:2701
sal_Int32 nRef
virtual const ScComplexRefData * GetDoubleRef() const
bool ParseFilters(OUString &rDataFieldName, std::vector< css::sheet::DataPilotFieldFilter > &rFilters, std::vector< sal_Int16 > &rFilterFuncs, const OUString &rFilterList)
Definition: dpobject.cxx:1713
const SvBaseLinks & GetLinks() const
int i
#define UTF8_TH_2
Definition: interpr2.cxx:3374
void SetDay(sal_uInt16 nNewDay)
bool isEmpty() const
void ScGetIsoWeekOfYear()
Definition: interpr2.cxx:295
sal_Int32 getLength() const
void ScGetDateDif()
Definition: interpr2.cxx:775
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2974
sal_Int16 SCCOL
Definition: types.hxx:22
double ScGetIpmt(double fRate, double fPer, double fNper, double fPv, double fFv, bool bPayInAdvance, double &fPmt)
Definition: interpr2.cxx:2186
void ScAbs()
Definition: interpr2.cxx:957
virtual const ScRefList * GetRefList() const override
Definition: token.cxx:647
ScSingleRefData Ref1
Definition: refdata.hxx:125
static bool IsValueType(ScMatValType nType)
Value or boolean.
Definition: scmatrix.hxx:161
TUESDAY
::boost::intrusive_ptr< FormulaToken > FormulaTokenRef
ScSingleRefData Ref2
Definition: refdata.hxx:126
svExternalDoubleRef
sal_uInt16 GetDay() const
SUNDAY
SvNumFormatType
std::enable_if_t< std::is_floating_point_v< F > &&std::is_integral_v< I >, bool > convertsToAtMost(F value, I max)
svExternalSingleRef
void AddDays(sal_Int32 nAddDays)
void ScGetYear()
Definition: interpr2.cxx:118
void ScGetTime()
Definition: interpr2.cxx:654
static ScUnitConverter * GetUnitConverter()
Definition: global.cxx:634
MONDAY
#define UTF8_TH_1E5
Definition: interpr2.cxx:3388
bool hasNumeric() const
Definition: cellvalue.cxx:622
static SC_DLLPUBLIC LanguageType eLnge
Definition: global.hxx:547
double GetDateSerial(sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict)
Obtain the date serial number for a given date.
Definition: interpr2.cxx:58
virtual FormulaToken * Clone() const
void ScRoundDown()
Definition: interpr2.cxx:1007
void ScCumPrinc()
Definition: interpr2.cxx:2302
void ScFloor(bool bODFF)
tdf69552 ODFF1.2 function FLOOR and Excel function FLOOR.MATH In essence, the difference between the ...
Definition: interpr2.cxx:1147
svSingleRef
FormulaError
SCCOL Col() const
Definition: address.hxx:267
void ScGetSec()
Definition: interpr2.cxx:147
FormulaError GetWeekendAndHolidayMasks(const sal_uInt8 nParamCount, const sal_uInt32 nNullDate,::std::vector< double > &rSortArray, bool bWeekendMask[7])
Definition: interpr2.cxx:346
svDoubleRef
static bool IsRealStringType(ScMatValType nType)
String, but not empty or empty path or any other type.
Definition: scmatrix.hxx:181
#define UTF8_TH_20
Definition: interpr2.cxx:3384
void ScGetDate()
Definition: interpr2.cxx:635
void ScWeeknumOOo()
Definition: interpr2.cxx:233
svUnknown
const PropertyValue * pValues
void ScCumIpmt()
Definition: interpr2.cxx:2260
sal_Int32 SCROW
Definition: types.hxx:18
double CreateDoubleError(FormulaError nErr)
void ScISPMT()
Definition: interpr2.cxx:1593
#define C
Definition: xlformula.cxx:66
static void GetClock(double fTimeInDays, sal_uInt16 &nHour, sal_uInt16 &nMinute, sal_uInt16 &nSecond, double &fFractionOfSecond, int nFractionDecimals)
static bool RateIteration(double fNper, double fPayment, double fPv, double fFv, bool bPayType, double &fGuess)
Definition: interpr2.cxx:2026
void ScStyle()
Definition: interpr2.cxx:2654
void ScPlusMinus()
Definition: interpr2.cxx:946
static double ScGetDDB(double fCost, double fSalvage, double fLife, double fPeriod, double fFactor)
Definition: interpr2.cxx:1662
virtual const ScSingleRefData * GetSingleRef2() const
#define UTF8_TH_7
Definition: interpr2.cxx:3379
SvBaseLink * pLink
void ScArabic()
Definition: interpr2.cxx:3127
unsigned char sal_uInt8
#define SAL_MAX_UINT8
DayOfWeek
static bool lclConvertMoney(const OUString &aSearchUnit, double &rfRate, int &rnDec)
Resources at the website of the European Commission: http://ec.europa.eu/economy_finance/euro/adoptio...
Definition: interpr2.cxx:3272
bool GetFirst(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:285
void ScCurrent()
Definition: interpr2.cxx:2642
static double ScInterVDB(double fCost, double fSalvage, double fLife, double fLife1, double fPeriod, double fFactor)
Definition: interpr2.cxx:1756
svMatrix
void InitRange(const ScRange &rRange)
Definition: refdata.hxx:131
::boost::intrusive_ptr< formula::FormulaToken > ScTokenRef
Definition: types.hxx:30
ScMatValType
Definition: types.hxx:32
void ScWorkday_MS()
Definition: interpr2.cxx:563
#define UTF8_TH_MINUS
Definition: interpr2.cxx:3393
void RoundNumber(rtl_math_RoundingMode eMode)
Definition: interpr2.cxx:967
void ScBahtText()
Definition: interpr2.cxx:3485
void * p
std::string ScGetDDB
std::string ScInterVDB
void ScNominal()
Definition: interpr2.cxx:2364
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:309
void ScGetPivotData()
Definition: interpr2.cxx:3552
Complex reference (a range) into the sheet.
Definition: refdata.hxx:123
#define UTF8_TH_4
Definition: interpr2.cxx:3376
void ScRoundUp()
Definition: interpr2.cxx:1012
#define UTF8_TH_0
Definition: interpr2.cxx:3372
static const sal_Int64 nanoSecPerDay
double GetPivotData(const OUString &rDataFieldName, std::vector< css::sheet::DataPilotFieldFilter > &rFilters)
Definition: dpobject.cxx:1356
void ScGetMonth()
Definition: interpr2.cxx:125
static const sal_Int64 secondPerHour
#define UTF8_TH_11
Definition: interpr2.cxx:3383
void ScGetDayOfWeek()
Definition: interpr2.cxx:186
virtual const std::vector< ScComplexRefData > * GetRefList() const
svEmptyCell
::std::vector< ScComplexRefData > ScRefList
Definition: token.hxx:38
#define UTF8_TH_SATANG
Definition: interpr2.cxx:3392
static double ScGetPV(double fRate, double fNper, double fPmt, double fFv, bool bPayInAdvance)
Definition: interpr2.cxx:1610
svMissing
#define UTF8_TH_DOT0
Definition: interpr2.cxx:3390
M
aStr
move ScAutoStyleHint to a different file?
Definition: hints.hxx:100
#define UTF8_TH_1E6
Definition: interpr2.cxx:3389
double div(const double &fNumerator, const double &fDenominator)
Return fNumerator/fDenominator if fDenominator!=0 else #DIV/0! error coded into double.
Definition: math.hxx:31
void ScHyperLink()
Definition: interpr2.cxx:3184
sal_Int16 SCTAB
Definition: types.hxx:23
#define UTF8_TH_8
Definition: interpr2.cxx:3380
sal_Int16 nValue
#define UTF8_TH_1E4
Definition: interpr2.cxx:3387
sal_Int16 GetDayOfWeek(sal_Int32 nDate)
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill= '\0')
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo
static const sal_Int64 secondPerDay