Line data Source code
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 "interpre.hxx"
21 :
22 : #include <comphelper/string.hxx>
23 : #include <sfx2/linkmgr.hxx>
24 : #include <sfx2/dispatch.hxx>
25 : #include <sfx2/objsh.hxx>
26 : #include <svl/stritem.hxx>
27 : #include <svl/zforlist.hxx>
28 : #include <svl/sharedstringpool.hxx>
29 : #include <sal/macros.h>
30 : #include <boost/math/special_functions/log1p.hpp>
31 :
32 : #include "attrib.hxx"
33 : #include "sc.hrc"
34 : #include "ddelink.hxx"
35 : #include "scmatrix.hxx"
36 : #include "compiler.hxx"
37 : #include "formulacell.hxx"
38 : #include "document.hxx"
39 : #include "dociter.hxx"
40 : #include "docoptio.hxx"
41 : #include "unitconv.hxx"
42 : #include "globstr.hrc"
43 : #include "hints.hxx"
44 : #include "dpobject.hxx"
45 : #include "postit.hxx"
46 : #include "tokenarray.hxx"
47 : #include "globalnames.hxx"
48 :
49 : #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
50 :
51 : #include <string.h>
52 : #include <math.h>
53 :
54 : using ::std::vector;
55 : using namespace com::sun::star;
56 : using namespace formula;
57 :
58 : #define SCdEpsilon 1.0E-7
59 :
60 : // Date and Time
61 :
62 116 : double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay,
63 : bool bStrict, bool bCheckGregorian )
64 : {
65 116 : if ( nYear < 100 && !bStrict )
66 0 : nYear = pFormatter->ExpandTwoDigitYear( nYear );
67 : // Do not use a default Date ctor here because it asks system time with a
68 : // performance penalty.
69 : sal_Int16 nY, nM, nD;
70 116 : if (bStrict)
71 2 : nY = nYear, nM = nMonth, nD = nDay;
72 : else
73 : {
74 114 : if (nMonth > 0)
75 : {
76 114 : nY = nYear + (nMonth-1) / 12;
77 114 : nM = ((nMonth-1) % 12) + 1;
78 : }
79 : else
80 : {
81 0 : nY = nYear + (nMonth-12) / 12;
82 0 : nM = 12 - (-nMonth) % 12;
83 : }
84 114 : nD = 1;
85 : }
86 116 : Date aDate( nD, nM, nY);
87 116 : if (!bStrict)
88 114 : aDate += nDay - 1;
89 116 : if ((!bCheckGregorian && aDate.IsValidDate()) || (bCheckGregorian && aDate.IsValidAndGregorian()))
90 116 : return (double) (aDate - *(pFormatter->GetNullDate()));
91 : else
92 : {
93 0 : SetError(errNoValue);
94 0 : return 0;
95 : }
96 : }
97 :
98 32 : void ScInterpreter::ScGetActDate()
99 : {
100 32 : nFuncFmtType = NUMBERFORMAT_DATE;
101 32 : Date aActDate( Date::SYSTEM );
102 32 : long nDiff = aActDate - *(pFormatter->GetNullDate());
103 32 : PushDouble((double) nDiff);
104 32 : }
105 :
106 6 : void ScInterpreter::ScGetActTime()
107 : {
108 6 : nFuncFmtType = NUMBERFORMAT_DATETIME;
109 6 : Date aActDate( Date::SYSTEM );
110 6 : long nDiff = aActDate - *(pFormatter->GetNullDate());
111 6 : tools::Time aActTime( tools::Time::SYSTEM );
112 12 : double nTime = aActTime.GetHour() / static_cast<double>(::tools::Time::hourPerDay) +
113 12 : aActTime.GetMin() / static_cast<double>(::tools::Time::minutePerDay) +
114 6 : aActTime.GetSec() / static_cast<double>(::tools::Time::secondPerDay) +
115 6 : aActTime.GetNanoSec() / static_cast<double>(::tools::Time::nanoSecPerDay);
116 6 : PushDouble( (double) nDiff + nTime );
117 6 : }
118 :
119 6 : void ScInterpreter::ScGetYear()
120 : {
121 6 : Date aDate = *(pFormatter->GetNullDate());
122 6 : aDate += (long) ::rtl::math::approxFloor(GetDouble());
123 6 : PushDouble( (double) aDate.GetYear() );
124 6 : }
125 :
126 2 : void ScInterpreter::ScGetMonth()
127 : {
128 2 : Date aDate = *(pFormatter->GetNullDate());
129 2 : aDate += (long) ::rtl::math::approxFloor(GetDouble());
130 2 : PushDouble( (double) aDate.GetMonth() );
131 2 : }
132 :
133 8 : void ScInterpreter::ScGetDay()
134 : {
135 8 : Date aDate = *(pFormatter->GetNullDate());
136 8 : aDate += (long)::rtl::math::approxFloor(GetDouble());
137 8 : PushDouble((double) aDate.GetDay());
138 8 : }
139 :
140 6 : void ScInterpreter::ScGetMin()
141 : {
142 6 : double fTime = GetDouble();
143 6 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
144 6 : long nVal = (long)::rtl::math::approxFloor(fTime*DATE_TIME_FACTOR+0.5) % ::tools::Time::secondPerHour;
145 6 : PushDouble( (double) (nVal / ::tools::Time::secondPerMinute) );
146 6 : }
147 :
148 2 : void ScInterpreter::ScGetSec()
149 : {
150 2 : double fTime = GetDouble();
151 2 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
152 2 : long nVal = (long)::rtl::math::approxFloor(fTime*DATE_TIME_FACTOR+0.5) % ::tools::Time::secondPerMinute;
153 2 : PushDouble( (double) nVal );
154 2 : }
155 :
156 2 : void ScInterpreter::ScGetHour()
157 : {
158 2 : double fTime = GetDouble();
159 2 : fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg
160 2 : long nVal = (long)::rtl::math::approxFloor(fTime*DATE_TIME_FACTOR+0.5) / ::tools::Time::secondPerHour;
161 2 : PushDouble((double) nVal);
162 2 : }
163 :
164 2 : void ScInterpreter::ScGetDateValue()
165 : {
166 2 : OUString aInputString = GetString().getString();
167 2 : sal_uInt32 nFIndex = 0; // damit default Land/Spr.
168 : double fVal;
169 2 : if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
170 : {
171 2 : short eType = pFormatter->GetType(nFIndex);
172 2 : if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME)
173 2 : PushDouble(::rtl::math::approxFloor(fVal));
174 : else
175 0 : PushIllegalArgument();
176 : }
177 : else
178 0 : PushIllegalArgument();
179 2 : }
180 :
181 6 : void ScInterpreter::ScGetDayOfWeek()
182 : {
183 6 : sal_uInt8 nParamCount = GetByte();
184 6 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
185 : {
186 : short nFlag;
187 6 : if (nParamCount == 2)
188 4 : nFlag = (short) ::rtl::math::approxFloor(GetDouble());
189 : else
190 2 : nFlag = 1;
191 :
192 6 : Date aDate = *(pFormatter->GetNullDate());
193 6 : aDate += (long)::rtl::math::approxFloor(GetDouble());
194 6 : int nVal = (int) aDate.GetDayOfWeek();
195 6 : if (nFlag == 1)
196 : {
197 4 : if (nVal == 6)
198 0 : nVal = 1;
199 : else
200 4 : nVal += 2;
201 : }
202 2 : else if (nFlag == 2)
203 2 : nVal += 1;
204 6 : PushInt( nVal );
205 : }
206 6 : }
207 :
208 4 : void ScInterpreter::ScGetWeekOfYear()
209 : {
210 4 : if ( MustHaveParamCount( GetByte(), 2 ) )
211 : {
212 4 : short nFlag = (short) ::rtl::math::approxFloor(GetDouble());
213 :
214 4 : Date aDate = *(pFormatter->GetNullDate());
215 4 : aDate += (long)::rtl::math::approxFloor(GetDouble());
216 4 : PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY ));
217 : }
218 4 : }
219 :
220 2 : void ScInterpreter::ScEasterSunday()
221 : {
222 2 : nFuncFmtType = NUMBERFORMAT_DATE;
223 2 : if ( MustHaveParamCount( GetByte(), 1 ) )
224 : {
225 : sal_Int16 nDay, nMonth, nYear;
226 2 : nYear = (sal_Int16) ::rtl::math::approxFloor( GetDouble() );
227 2 : if ( nYear < 100 )
228 0 : nYear = pFormatter->ExpandTwoDigitYear( nYear );
229 : // don't worry, be happy :)
230 : int B,C,D,E,F,G,H,I,K,L,M,N,O;
231 2 : N = nYear % 19;
232 2 : B = int(nYear / 100);
233 2 : C = nYear % 100;
234 2 : D = int(B / 4);
235 2 : E = B % 4;
236 2 : F = int((B + 8) / 25);
237 2 : G = int((B - F + 1) / 3);
238 2 : H = (19 * N + B - D - G + 15) % 30;
239 2 : I = int(C / 4);
240 2 : K = C % 4;
241 2 : L = (32 + 2 * E + 2 * I - H - K) % 7;
242 2 : M = int((N + 11 * H + 22 * L) / 451);
243 2 : O = H + L - 7 * M + 114;
244 2 : nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 );
245 2 : nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) );
246 2 : PushDouble( GetDateSerial( nYear, nMonth, nDay, true, true ) );
247 : }
248 2 : }
249 :
250 54 : sal_uInt16 ScInterpreter::GetWeekendAndHolidayMasks(
251 : const sal_uInt8 nParamCount, const sal_uInt32 nNullDate, vector< double >& rSortArray,
252 : OUString& rWeekendDays, bool bWeekendMask[ 7 ] )
253 : {
254 54 : sal_uInt16 nErr = 0;
255 54 : if ( nParamCount == 4 )
256 : {
257 36 : GetSortArray( 1, rSortArray );
258 36 : size_t nMax = rSortArray.size();
259 144 : for ( size_t i = 0; i < nMax; i++ )
260 108 : rSortArray.at( i ) = ::rtl::math::approxFloor( rSortArray.at( i ) ) + nNullDate;
261 : }
262 :
263 54 : if ( nParamCount >= 3 )
264 42 : rWeekendDays = GetString().getString();
265 :
266 432 : for ( int i = 0; i < 7; i++ )
267 378 : bWeekendMask[ i] = false;
268 :
269 54 : if ( rWeekendDays.isEmpty() )
270 : {
271 18 : bWeekendMask[ SATURDAY ] = true;
272 18 : bWeekendMask[ SUNDAY ] = true;
273 : }
274 : else
275 : {
276 36 : switch ( rWeekendDays.getLength() )
277 : {
278 : case 1 :
279 : // Weekend days defined by code
280 18 : switch ( rWeekendDays[ 0 ] )
281 : {
282 12 : case '1' : bWeekendMask[ SATURDAY ] = true; bWeekendMask[ SUNDAY ] = true; break;
283 6 : case '2' : bWeekendMask[ SUNDAY ] = true; bWeekendMask[ MONDAY ] = true; break;
284 0 : case '3' : bWeekendMask[ MONDAY ] = true; bWeekendMask[ TUESDAY ] = true; break;
285 0 : case '4' : bWeekendMask[ TUESDAY ] = true; bWeekendMask[ WEDNESDAY ] = true; break;
286 0 : case '5' : bWeekendMask[ WEDNESDAY ] = true; bWeekendMask[ THURSDAY ] = true; break;
287 0 : case '6' : bWeekendMask[ THURSDAY ] = true; bWeekendMask[ FRIDAY ] = true; break;
288 0 : case '7' : bWeekendMask[ FRIDAY ] = true; bWeekendMask[ SATURDAY ] = true; break;
289 0 : default : nErr = errIllegalArgument; break;
290 : }
291 18 : break;
292 : case 2 :
293 : // Weekend day defined by code
294 6 : if ( rWeekendDays[ 0 ] == '1' )
295 : {
296 6 : switch ( rWeekendDays[ 1 ] )
297 : {
298 0 : case '1' : bWeekendMask[ SUNDAY ] = true; break;
299 0 : case '2' : bWeekendMask[ MONDAY ] = true; break;
300 6 : case '3' : bWeekendMask[ TUESDAY ] = true; break;
301 0 : case '4' : bWeekendMask[ WEDNESDAY ] = true; break;
302 0 : case '5' : bWeekendMask[ THURSDAY ] = true; break;
303 0 : case '6' : bWeekendMask[ FRIDAY ] = true; break;
304 0 : case '7' : bWeekendMask[ SATURDAY ] = true; break;
305 0 : default : nErr = errIllegalArgument; break;
306 : }
307 : }
308 : else
309 0 : nErr = errIllegalArgument;
310 6 : break;
311 : case 7 :
312 : // Weekend days defined by string
313 96 : for ( int i = 0; i < 7 && !nErr; i++ )
314 : {
315 84 : switch ( rWeekendDays[ i ] )
316 : {
317 54 : case '0' : bWeekendMask[ i ] = false; break;
318 30 : case '1' : bWeekendMask[ i ] = true; break;
319 0 : default : nErr = errIllegalArgument; break;
320 : }
321 : }
322 12 : break;
323 : default :
324 0 : nErr = errIllegalArgument;
325 0 : break;
326 : }
327 : }
328 54 : return nErr;
329 : }
330 :
331 24 : void ScInterpreter::ScNetWorkdays_MS()
332 : {
333 24 : sal_uInt8 nParamCount = GetByte();
334 24 : if ( MustHaveParamCount( nParamCount, 2, 4 ) )
335 : {
336 24 : vector<double> nSortArray;
337 : bool bWeekendMask[ 7 ];
338 48 : OUString aWeekendDays;
339 24 : Date aNullDate = *( pFormatter->GetNullDate() );
340 24 : sal_uInt32 nNullDate = Date::DateToDays( aNullDate.GetDay(), aNullDate.GetMonth(), aNullDate.GetYear() );
341 : sal_uInt16 nErr = GetWeekendAndHolidayMasks( nParamCount, nNullDate,
342 24 : nSortArray , aWeekendDays, bWeekendMask );
343 24 : if ( nErr )
344 0 : PushError( nErr );
345 : else
346 : {
347 24 : sal_uInt32 nDate2 = ( sal_uInt32 )::rtl::math::approxFloor( GetDouble() ) + nNullDate;
348 24 : sal_uInt32 nDate1 = ( sal_uInt32 )::rtl::math::approxFloor( GetDouble() ) + nNullDate;
349 :
350 24 : sal_Int32 nCnt = 0;
351 24 : size_t nRef = 0;
352 24 : bool bReverse = ( nDate1 > nDate2 );
353 24 : if ( bReverse )
354 : {
355 0 : sal_uInt32 nTemp = nDate1;
356 0 : nDate1 = nDate2;
357 0 : nDate2 = nTemp;
358 : }
359 24 : size_t nMax = nSortArray.size();
360 2322 : while ( nDate1 <= nDate2 )
361 : {
362 2274 : if ( !bWeekendMask[ GetDayOfWeek( nDate1 ) ] )
363 : {
364 3304 : while ( nRef < nMax && nSortArray.at( nRef ) < nDate1 )
365 24 : nRef++;
366 1640 : if ( !( nRef < nMax && nSortArray.at( nRef ) == nDate1 ) )
367 1628 : nCnt++;
368 : }
369 2274 : ++nDate1;
370 : }
371 24 : PushDouble( ( double ) ( bReverse ? -nCnt : nCnt ) );
372 24 : }
373 : }
374 24 : }
375 :
376 30 : void ScInterpreter::ScWorkday_MS()
377 : {
378 30 : sal_uInt8 nParamCount = GetByte();
379 30 : if ( MustHaveParamCount( nParamCount, 2, 4 ) )
380 : {
381 30 : nFuncFmtType = NUMBERFORMAT_DATE;
382 30 : vector<double> nSortArray;
383 : bool bWeekendMask[ 7 ];
384 60 : OUString aWeekendDays;
385 30 : Date aNullDate = *( pFormatter->GetNullDate() );
386 30 : sal_uInt32 nNullDate = Date::DateToDays( aNullDate.GetDay(), aNullDate.GetMonth(), aNullDate.GetYear() );
387 : sal_uInt16 nErr = GetWeekendAndHolidayMasks( nParamCount, nNullDate,
388 30 : nSortArray , aWeekendDays, bWeekendMask );
389 30 : if ( nErr )
390 0 : PushError( nErr );
391 : else
392 : {
393 30 : sal_Int32 nDays = ::rtl::math::approxFloor( GetDouble() );
394 30 : sal_uInt32 nDate = ( sal_uInt32 )::rtl::math::approxFloor( GetDouble() ) + nNullDate;
395 :
396 30 : if ( !nDays )
397 0 : PushDouble( ( double ) ( nDate - nNullDate ) );
398 : else
399 : {
400 30 : size_t nMax = nSortArray.size();
401 30 : if ( nDays > 0 )
402 : {
403 30 : size_t nRef = 0;
404 239184 : while ( nDays )
405 : {
406 478326 : while ( nRef < nMax && nSortArray.at( nRef ) < nDate )
407 78 : nRef++;
408 239124 : if ( !( nRef < nMax && nSortArray.at( nRef ) == nDate ) || nRef >= nMax )
409 239082 : nDays--;
410 :
411 334786 : do
412 334786 : ++nDate;
413 334786 : while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
414 : }
415 : }
416 : else
417 : {
418 0 : sal_Int16 nRef = nMax - 1;
419 0 : while ( nDays )
420 : {
421 0 : while ( nRef >= 0 && nSortArray.at( nRef ) > nDate )
422 0 : nRef--;
423 0 : if ( !( nRef >= 0 && nSortArray.at( nRef ) == nDate ) || nRef < 0 )
424 0 : nDays++;
425 :
426 0 : do
427 0 : --nDate;
428 0 : while ( bWeekendMask[ GetDayOfWeek( nDate ) ] ); //jump over weekend day(s)
429 : }
430 : }
431 30 : PushDouble( ( double ) ( nDate - nNullDate ) );
432 : }
433 30 : }
434 : }
435 30 : }
436 :
437 114 : void ScInterpreter::ScGetDate()
438 : {
439 114 : nFuncFmtType = NUMBERFORMAT_DATE;
440 114 : if ( MustHaveParamCount( GetByte(), 3 ) )
441 : {
442 114 : sal_Int16 nDay = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
443 114 : sal_Int16 nMonth = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
444 114 : sal_Int16 nYear = (sal_Int16) ::rtl::math::approxFloor(GetDouble());
445 114 : if (nYear < 0)
446 0 : PushIllegalArgument();
447 : else
448 : {
449 114 : PushDouble(GetDateSerial(nYear, nMonth, nDay, false, true));
450 : }
451 : }
452 114 : }
453 :
454 2 : void ScInterpreter::ScGetTime()
455 : {
456 2 : nFuncFmtType = NUMBERFORMAT_TIME;
457 2 : if ( MustHaveParamCount( GetByte(), 3 ) )
458 : {
459 2 : double nSec = GetDouble();
460 2 : double nMin = GetDouble();
461 2 : double nHour = GetDouble();
462 2 : double fTime = fmod( (nHour * ::tools::Time::secondPerHour) + (nMin * ::tools::Time::secondPerMinute) + nSec, DATE_TIME_FACTOR) / DATE_TIME_FACTOR;
463 2 : if (fTime < 0)
464 0 : PushIllegalArgument();
465 : else
466 2 : PushDouble( fTime);
467 : }
468 2 : }
469 :
470 2 : void ScInterpreter::ScGetDiffDate()
471 : {
472 2 : if ( MustHaveParamCount( GetByte(), 2 ) )
473 : {
474 2 : double nDate2 = GetDouble();
475 2 : double nDate1 = GetDouble();
476 2 : PushDouble(nDate1 - nDate2);
477 : }
478 2 : }
479 :
480 2 : void ScInterpreter::ScGetDiffDate360()
481 : {
482 : /* Implementation follows
483 : * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf
484 : * Appendix B: Day-Count Bases, there are 7 different ways to calculate the
485 : * 30-days count. That document also claims that Excel implements the "PSA
486 : * 30" or "NASD 30" method (funny enough they also state that Excel is the
487 : * only tool that does so).
488 : *
489 : * Note that the definition given in
490 : * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp
491 : * is _not_ the way how it is actually calculated by Excel (that would not
492 : * even match any of the 7 methods mentioned above) and would result in the
493 : * following test cases producing wrong results according to that appendix B:
494 : *
495 : * 28-Feb-95 31-Aug-95 181 instead of 180
496 : * 29-Feb-96 31-Aug-96 181 instead of 180
497 : * 30-Jan-96 31-Mar-96 61 instead of 60
498 : * 31-Jan-96 31-Mar-96 61 instead of 60
499 : *
500 : * Still, there is a difference between OOoCalc and Excel:
501 : * In Excel:
502 : * 02-Feb-99 31-Mar-00 results in 419
503 : * 31-Mar-00 02-Feb-99 results in -418
504 : * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel.
505 : */
506 :
507 2 : sal_uInt8 nParamCount = GetByte();
508 2 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
509 : {
510 : bool bFlag;
511 2 : if (nParamCount == 3)
512 0 : bFlag = GetBool();
513 : else
514 2 : bFlag = false;
515 2 : double nDate2 = GetDouble();
516 2 : double nDate1 = GetDouble();
517 2 : if (nGlobalError)
518 0 : PushError( nGlobalError);
519 : else
520 : {
521 : double fSign;
522 : // #i84934# only for non-US European algorithm swap dates. Else
523 : // follow Excel's meaningless extrapolation for "interoperability".
524 2 : if (bFlag && (nDate2 < nDate1))
525 : {
526 0 : fSign = nDate1;
527 0 : nDate1 = nDate2;
528 0 : nDate2 = fSign;
529 0 : fSign = -1.0;
530 : }
531 : else
532 2 : fSign = 1.0;
533 2 : Date aDate1 = *(pFormatter->GetNullDate());
534 2 : aDate1 += (long) ::rtl::math::approxFloor(nDate1);
535 2 : Date aDate2 = *(pFormatter->GetNullDate());
536 2 : aDate2 += (long) ::rtl::math::approxFloor(nDate2);
537 2 : if (aDate1.GetDay() == 31)
538 0 : aDate1 -= (sal_uLong) 1;
539 2 : else if (!bFlag)
540 : {
541 2 : if (aDate1.GetMonth() == 2)
542 : {
543 0 : switch ( aDate1.GetDay() )
544 : {
545 : case 28 :
546 0 : if ( !aDate1.IsLeapYear() )
547 0 : aDate1.SetDay(30);
548 0 : break;
549 : case 29 :
550 0 : aDate1.SetDay(30);
551 0 : break;
552 : }
553 : }
554 : }
555 2 : if (aDate2.GetDay() == 31)
556 : {
557 0 : if (!bFlag )
558 : {
559 0 : if (aDate1.GetDay() == 30)
560 0 : aDate2 -= (sal_uLong) 1;
561 : }
562 : else
563 0 : aDate2.SetDay(30);
564 : }
565 : PushDouble( fSign * (double)
566 4 : ( (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 +
567 2 : (double) aDate2.GetYear() * 360.0
568 2 : - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0
569 2 : - (double)aDate1.GetYear() * 360.0) );
570 : }
571 : }
572 2 : }
573 :
574 : // fdo#44456 function DATEDIF as defined in ODF1.2 (Par. 6.10.3)
575 72 : void ScInterpreter::ScGetDateDif()
576 : {
577 72 : if ( MustHaveParamCount( GetByte(), 3 ) )
578 : {
579 72 : OUString aInterval = GetString().getString();
580 72 : double nDate2 = GetDouble();
581 72 : double nDate1 = GetDouble();
582 :
583 72 : if (nGlobalError)
584 : {
585 0 : PushError( nGlobalError);
586 0 : return;
587 : }
588 :
589 : // Excel doesn't swap dates or return negative numbers, so don't we.
590 72 : if (nDate1 > nDate2)
591 : {
592 4 : PushIllegalArgument();
593 4 : return;
594 : }
595 :
596 68 : long dd = nDate2 - nDate1;
597 : // Zero difference or number of days can be returned immediately.
598 68 : if (dd == 0 || aInterval.equalsIgnoreAsciiCase( "d" ))
599 : {
600 14 : PushDouble( dd );
601 14 : return;
602 : }
603 :
604 : // split dates in day, month, year for use with formats other than "d"
605 : sal_uInt16 d1, m1, y1, d2, m2, y2;
606 54 : Date aDate1( *( pFormatter->GetNullDate()));
607 54 : aDate1 += (long) ::rtl::math::approxFloor( nDate1 );
608 54 : y1 = aDate1.GetYear();
609 54 : m1 = aDate1.GetMonth();
610 54 : d1 = aDate1.GetDay();
611 54 : Date aDate2( *( pFormatter->GetNullDate()));
612 54 : aDate2 += (long) ::rtl::math::approxFloor( nDate2 );
613 54 : y2 = aDate2.GetYear();
614 54 : m2 = aDate2.GetMonth();
615 54 : d2 = aDate2.GetDay();
616 :
617 54 : if ( aInterval.equalsIgnoreAsciiCase( "m" ) )
618 : {
619 : // Return number of months.
620 18 : int md = m2 - m1 + 12 * (y2 - y1);
621 18 : if (d1 > d2)
622 2 : --md;
623 18 : PushInt( md );
624 : }
625 36 : else if ( aInterval.equalsIgnoreAsciiCase( "y" ) )
626 : {
627 : // Return number of years.
628 : int yd;
629 6 : if ( y2 > y1 )
630 : {
631 2 : if (m2 > m1 || (m2 == m1 && d2 >= d1))
632 2 : yd = y2 - y1; // complete years between dates
633 : else
634 0 : yd = y2 - y1 - 1; // one incomplete year
635 : }
636 : else
637 : {
638 : // Year is equal as we don't allow reversed arguments, no
639 : // complete year between dates.
640 4 : yd = 0;
641 : }
642 6 : PushInt( yd );
643 : }
644 30 : else if ( aInterval.equalsIgnoreAsciiCase( "md" ) )
645 : {
646 : // Return number of days, excluding months and years.
647 : // This is actually the remainder of days when subtracting years
648 : // and months from the difference of dates. Birthday-like 23 years
649 : // and 10 months and 19 days.
650 :
651 : // Algorithm's roll-over behavior extracted from Excel by try and
652 : // error..
653 : // If day1 <= day2 then simply day2 - day1.
654 : // If day1 > day2 then set month1 to month2-1 and year1 to
655 : // year2(-1) and subtract dates, e.g. for 2012-01-28,2012-03-01 set
656 : // 2012-02-28 and then (2012-03-01)-(2012-02-28) => 2 days (leap
657 : // year).
658 : // For 2011-01-29,2011-03-01 the non-existent 2011-02-29 rolls over
659 : // to 2011-03-01 so the result is 0. Same for day 31 in months with
660 : // only 30 days.
661 :
662 : long nd;
663 14 : if (d1 <= d2)
664 12 : nd = d2 - d1;
665 : else
666 : {
667 2 : if (m2 == 1)
668 : {
669 0 : aDate1.SetYear( y2 - 1 );
670 0 : aDate1.SetMonth( 12 );
671 : }
672 : else
673 : {
674 2 : aDate1.SetYear( y2 );
675 2 : aDate1.SetMonth( m2 - 1 );
676 : }
677 2 : aDate1.Normalize();
678 2 : nd = aDate2 - aDate1;
679 : }
680 14 : PushDouble( nd );
681 : }
682 16 : else if ( aInterval.equalsIgnoreAsciiCase( "ym" ) )
683 : {
684 : // Return number of months, excluding years.
685 6 : int md = m2 - m1 + 12 * (y2 - y1);
686 6 : if (d1 > d2)
687 2 : --md;
688 6 : md %= 12;
689 6 : PushInt( md );
690 : }
691 10 : else if ( aInterval.equalsIgnoreAsciiCase( "yd" ) )
692 : {
693 : // Return number of days, excluding years.
694 :
695 : /* TODO: check what Excel really does, though this seems to be
696 : * reasonable */
697 :
698 : // Condition corresponds with "y".
699 10 : if (m2 > m1 || (m2 == m1 && d2 >= d1))
700 10 : aDate1.SetYear( y2 );
701 : else
702 0 : aDate1.SetYear( y2 - 1 );
703 : // XXX NOTE: Excel for the case 1988-06-22,2012-05-11 returns
704 : // 323, whereas the result here is 324. Don't they use the leap
705 : // year of 2012?
706 : // http://www.cpearson.com/excel/datedif.aspx "DATEDIF And Leap
707 : // Years" is not correct and Excel 2010 correctly returns 0 in
708 : // both cases mentioned there. Also using year1 as mentioned
709 : // produces incorrect results in other cases and different from
710 : // Excel 2010. Apparently they fixed some calculations.
711 10 : aDate1.Normalize();
712 10 : double nd = aDate2 - aDate1;
713 10 : PushDouble( nd );
714 : }
715 : else
716 0 : PushIllegalArgument(); // unsupported format
717 : }
718 : }
719 :
720 8 : void ScInterpreter::ScGetTimeValue()
721 : {
722 8 : OUString aInputString = GetString().getString();
723 8 : sal_uInt32 nFIndex = 0; // damit default Land/Spr.
724 : double fVal;
725 8 : if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
726 : {
727 8 : short eType = pFormatter->GetType(nFIndex);
728 8 : if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME)
729 : {
730 8 : double fDateVal = rtl::math::approxFloor(fVal);
731 8 : double fTimeVal = fVal - fDateVal;
732 8 : PushDouble(fTimeVal);
733 : }
734 : else
735 0 : PushIllegalArgument();
736 : }
737 : else
738 0 : PushIllegalArgument();
739 8 : }
740 :
741 0 : void ScInterpreter::ScPlusMinus()
742 : {
743 0 : double nVal = GetDouble();
744 0 : short n = 0;
745 0 : if (nVal < 0.0)
746 0 : n = -1;
747 0 : else if (nVal > 0.0)
748 0 : n = 1;
749 0 : PushInt( n );
750 0 : }
751 :
752 10 : void ScInterpreter::ScAbs()
753 : {
754 10 : PushDouble(fabs(GetDouble()));
755 10 : }
756 :
757 0 : void ScInterpreter::ScInt()
758 : {
759 0 : PushDouble(::rtl::math::approxFloor(GetDouble()));
760 0 : }
761 :
762 6036 : void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode )
763 : {
764 6036 : sal_uInt8 nParamCount = GetByte();
765 6036 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
766 : {
767 6036 : double fVal = 0.0;
768 6036 : if (nParamCount == 1)
769 0 : fVal = ::rtl::math::round( GetDouble(), 0, eMode );
770 : else
771 : {
772 6036 : sal_Int32 nDec = (sal_Int32) ::rtl::math::approxFloor(GetDouble());
773 6036 : if( nDec < -20 || nDec > 20 )
774 0 : PushIllegalArgument();
775 : else
776 6036 : fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode );
777 : }
778 6036 : PushDouble(fVal);
779 : }
780 6036 : }
781 :
782 6036 : void ScInterpreter::ScRound()
783 : {
784 6036 : RoundNumber( rtl_math_RoundingMode_Corrected );
785 6036 : }
786 :
787 0 : void ScInterpreter::ScRoundDown()
788 : {
789 0 : RoundNumber( rtl_math_RoundingMode_Down );
790 0 : }
791 :
792 0 : void ScInterpreter::ScRoundUp()
793 : {
794 0 : RoundNumber( rtl_math_RoundingMode_Up );
795 0 : }
796 :
797 0 : void ScInterpreter::ScCeil()
798 : {
799 0 : sal_uInt8 nParamCount = GetByte();
800 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
801 : {
802 0 : bool bAbs = nParamCount == 3 && GetBool();
803 0 : double fDec = GetDouble();
804 0 : double fVal = GetDouble();
805 0 : if ( fDec == 0.0 )
806 0 : PushInt(0);
807 0 : else if (fVal*fDec < 0.0)
808 0 : PushIllegalArgument();
809 : else
810 : {
811 0 : if ( !bAbs && fVal < 0.0 )
812 0 : PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
813 : else
814 0 : PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
815 : }
816 : }
817 0 : }
818 :
819 12 : void ScInterpreter::ScCeil_MS()
820 : {
821 12 : sal_uInt8 nParamCount = GetByte();
822 12 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
823 : {
824 : double fDec, fVal;
825 12 : if ( nParamCount == 1 )
826 : {
827 0 : fVal = GetDouble();
828 0 : fDec = 1.0;
829 : }
830 : else
831 : {
832 12 : fDec = fabs( GetDoubleWithDefault( 1.0 ));
833 12 : fVal = GetDouble();
834 : }
835 12 : if ( fDec == 0.0 || fVal == 0.0 )
836 0 : PushInt( 0 );
837 : else
838 12 : PushDouble(::rtl::math::approxCeil( fVal / fDec ) * fDec );
839 : }
840 12 : }
841 :
842 0 : void ScInterpreter::ScFloor()
843 : {
844 0 : sal_uInt8 nParamCount = GetByte();
845 0 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
846 : {
847 0 : bool bAbs = nParamCount == 3 && GetBool();
848 0 : double fDec = GetDouble();
849 0 : double fVal = GetDouble();
850 0 : if ( fDec == 0.0 )
851 0 : PushInt(0);
852 0 : else if (fVal*fDec < 0.0)
853 0 : PushIllegalArgument();
854 : else
855 : {
856 0 : if ( !bAbs && fVal < 0.0 )
857 0 : PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec);
858 : else
859 0 : PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec);
860 : }
861 : }
862 0 : }
863 :
864 6 : void ScInterpreter::ScFloor_MS()
865 : {
866 6 : sal_uInt8 nParamCount = GetByte();
867 6 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
868 : {
869 : double fDec, fVal;
870 6 : if ( nParamCount == 1 )
871 : {
872 0 : fVal = GetDouble();
873 0 : fDec = 1.0;
874 : }
875 : else
876 : {
877 6 : fDec = fabs( GetDoubleWithDefault( 1.0 ));
878 6 : fVal = GetDouble();
879 : }
880 6 : if ( fDec == 0.0 || fVal == 0.0 )
881 0 : PushInt( 0 );
882 : else
883 6 : PushDouble(::rtl::math::approxFloor( fVal / fDec ) * fDec );
884 : }
885 6 : }
886 :
887 16 : void ScInterpreter::ScEven()
888 : {
889 16 : double fVal = GetDouble();
890 16 : if (fVal < 0.0)
891 4 : PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0);
892 : else
893 12 : PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0);
894 16 : }
895 :
896 16 : void ScInterpreter::ScOdd()
897 : {
898 16 : double fVal = GetDouble();
899 16 : if (fVal >= 0.0)
900 : {
901 12 : fVal = ::rtl::math::approxCeil(fVal);
902 12 : if (fmod(fVal, 2.0) == 0.0)
903 8 : fVal += 1.0;
904 : }
905 : else
906 : {
907 4 : fVal = ::rtl::math::approxFloor(fVal);
908 4 : if (fmod(fVal, 2.0) == 0.0)
909 2 : fVal -= 1.0;
910 : }
911 16 : PushDouble(fVal);
912 16 : }
913 :
914 0 : void ScInterpreter::ScArcTan2()
915 : {
916 0 : if ( MustHaveParamCount( GetByte(), 2 ) )
917 : {
918 0 : double nVal2 = GetDouble();
919 0 : double nVal1 = GetDouble();
920 0 : PushDouble(atan2(nVal2, nVal1));
921 : }
922 0 : }
923 :
924 0 : void ScInterpreter::ScLog()
925 : {
926 0 : sal_uInt8 nParamCount = GetByte();
927 0 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
928 : {
929 : double nBase;
930 0 : if (nParamCount == 2)
931 0 : nBase = GetDouble();
932 : else
933 0 : nBase = 10.0;
934 0 : double nVal = GetDouble();
935 0 : if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0)
936 0 : PushDouble(log(nVal) / log(nBase));
937 : else
938 0 : PushIllegalArgument();
939 : }
940 0 : }
941 :
942 0 : void ScInterpreter::ScLn()
943 : {
944 0 : double fVal = GetDouble();
945 0 : if (fVal > 0.0)
946 0 : PushDouble(log(fVal));
947 : else
948 0 : PushIllegalArgument();
949 0 : }
950 :
951 0 : void ScInterpreter::ScLog10()
952 : {
953 0 : double fVal = GetDouble();
954 0 : if (fVal > 0.0)
955 0 : PushDouble(log10(fVal));
956 : else
957 0 : PushIllegalArgument();
958 0 : }
959 :
960 2 : void ScInterpreter::ScNPV()
961 : {
962 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
963 2 : short nParamCount = GetByte();
964 2 : if ( MustHaveParamCount( nParamCount, 2, 31 ) )
965 : {
966 2 : double nVal = 0.0;
967 : //We turn the stack upside down!
968 : FormulaToken* pTemp[ 31 ];
969 10 : for( short i = 0; i < nParamCount; i++ )
970 8 : pTemp[ i ] = pStack[ sp - i - 1 ];
971 2 : memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) );
972 2 : if (nGlobalError == 0)
973 : {
974 2 : double nCount = 1.0;
975 2 : double nInterest = GetDouble();
976 2 : --nParamCount;
977 2 : size_t nRefInList = 0;
978 2 : ScRange aRange;
979 10 : while (nParamCount-- > 0)
980 : {
981 6 : switch (GetStackType())
982 : {
983 : case svDouble :
984 : {
985 6 : nVal += (GetDouble() / pow(1.0 + nInterest, (double)nCount));
986 6 : nCount++;
987 : }
988 6 : break;
989 : case svSingleRef :
990 : {
991 0 : ScAddress aAdr;
992 0 : PopSingleRef( aAdr );
993 0 : ScRefCellValue aCell;
994 0 : aCell.assign(*pDok, aAdr);
995 0 : if (!aCell.hasEmptyValue() && aCell.hasNumeric())
996 : {
997 0 : double nCellVal = GetCellValue(aAdr, aCell);
998 0 : nVal += (nCellVal / pow(1.0 + nInterest, (double)nCount));
999 0 : nCount++;
1000 0 : }
1001 : }
1002 0 : break;
1003 : case svDoubleRef :
1004 : case svRefList :
1005 : {
1006 0 : sal_uInt16 nErr = 0;
1007 : double nCellVal;
1008 0 : PopDoubleRef( aRange, nParamCount, nRefInList);
1009 0 : ScHorizontalValueIterator aValIter( pDok, aRange );
1010 0 : while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr))
1011 : {
1012 0 : nVal += (nCellVal / pow(1.0 + nInterest, (double)nCount));
1013 0 : nCount++;
1014 : }
1015 0 : if ( nErr != 0 )
1016 0 : SetError(nErr);
1017 : }
1018 0 : break;
1019 0 : default : SetError(errIllegalParameter); break;
1020 : }
1021 : }
1022 : }
1023 2 : PushDouble(nVal);
1024 : }
1025 2 : }
1026 :
1027 2 : void ScInterpreter::ScIRR()
1028 : {
1029 : double fEstimated;
1030 2 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1031 2 : sal_uInt8 nParamCount = GetByte();
1032 2 : if ( !MustHaveParamCount( nParamCount, 1, 2 ) )
1033 0 : return;
1034 2 : if (nParamCount == 2)
1035 0 : fEstimated = GetDouble();
1036 : else
1037 2 : fEstimated = 0.1;
1038 2 : sal_uInt16 sPos = sp; //memory the position of the stack
1039 2 : double fEps = 1.0;
1040 : double x, xNew, fValue, fNom, fDenom, nCount;
1041 2 : if (fEstimated == -1.0)
1042 0 : x = 0.1; // default result for divion by zero
1043 : else
1044 2 : x = fEstimated; // startvalue
1045 2 : switch (GetStackType())
1046 : {
1047 : case svDoubleRef :
1048 2 : break;
1049 : default:
1050 : {
1051 0 : PushIllegalParameter();
1052 0 : return;
1053 : }
1054 : }
1055 2 : const sal_uInt16 nIterationsMax = 20;
1056 2 : sal_uInt16 nItCount = 0;
1057 2 : ScRange aRange;
1058 10 : while (fEps > SCdEpsilon && nItCount < nIterationsMax)
1059 : { // Newtons method:
1060 6 : sp = sPos; // reset stack
1061 6 : nCount = 0.0;
1062 6 : fNom = 0.0;
1063 6 : fDenom = 0.0;
1064 6 : sal_uInt16 nErr = 0;
1065 6 : PopDoubleRef( aRange );
1066 6 : ScValueIterator aValIter(pDok, aRange, mnSubTotalFlags);
1067 6 : if (aValIter.GetFirst(fValue, nErr))
1068 : {
1069 6 : fNom += fValue / pow(1.0+x,(double)nCount);
1070 6 : fDenom += -nCount * fValue / pow(1.0+x,nCount+1.0);
1071 6 : nCount++;
1072 30 : while ((nErr == 0) && aValIter.GetNext(fValue, nErr))
1073 : {
1074 18 : fNom += fValue / pow(1.0+x,(double)nCount);
1075 18 : fDenom += -nCount * fValue / pow(1.0+x,nCount+1.0);
1076 18 : nCount++;
1077 : }
1078 6 : SetError(nErr);
1079 : }
1080 6 : xNew = x - fNom / fDenom; // x(i+1) = x(i)-f(x(i))/f'(x(i))
1081 6 : nItCount++;
1082 6 : fEps = fabs(xNew - x);
1083 6 : x = xNew;
1084 : }
1085 2 : if (fEstimated == 0.0 && fabs(x) < SCdEpsilon)
1086 0 : x = 0.0; // adjust to zero
1087 2 : if (fEps < SCdEpsilon)
1088 2 : PushDouble(x);
1089 : else
1090 0 : PushError( errNoConvergence);
1091 : }
1092 :
1093 2 : void ScInterpreter::ScMIRR()
1094 : { // range_of_values ; rate_invest ; rate_reinvest
1095 2 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1096 2 : if( MustHaveParamCount( GetByte(), 3 ) )
1097 : {
1098 2 : double fRate1_reinvest = GetDouble() + 1;
1099 2 : double fRate1_invest = GetDouble() + 1;
1100 :
1101 2 : ScRange aRange;
1102 2 : PopDoubleRef( aRange );
1103 :
1104 2 : if( nGlobalError )
1105 0 : PushError( nGlobalError);
1106 : else
1107 : {
1108 2 : double fNPV_reinvest = 0.0;
1109 2 : double fPow_reinvest = 1.0;
1110 2 : double fNPV_invest = 0.0;
1111 2 : double fPow_invest = 1.0;
1112 2 : ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags );
1113 : double fCellValue;
1114 2 : sal_uLong nCount = 0;
1115 2 : sal_uInt16 nIterError = 0;
1116 :
1117 2 : bool bLoop = aValIter.GetFirst( fCellValue, nIterError );
1118 12 : while( bLoop )
1119 : {
1120 8 : if( fCellValue > 0.0 ) // reinvestments
1121 6 : fNPV_reinvest += fCellValue * fPow_reinvest;
1122 2 : else if( fCellValue < 0.0 ) // investments
1123 2 : fNPV_invest += fCellValue * fPow_invest;
1124 8 : fPow_reinvest /= fRate1_reinvest;
1125 8 : fPow_invest /= fRate1_invest;
1126 8 : nCount++;
1127 :
1128 8 : bLoop = aValIter.GetNext( fCellValue, nIterError );
1129 : }
1130 2 : if( nIterError )
1131 0 : PushError( nIterError );
1132 : else
1133 : {
1134 2 : double fResult = -fNPV_reinvest / fNPV_invest;
1135 2 : fResult *= pow( fRate1_reinvest, (double) nCount - 1 );
1136 2 : fResult = pow( fResult, div( 1.0, (nCount - 1)) );
1137 2 : PushDouble( fResult - 1.0 );
1138 : }
1139 : }
1140 : }
1141 2 : }
1142 :
1143 2 : void ScInterpreter::ScISPMT()
1144 : { // rate ; period ; total_periods ; invest
1145 2 : if( MustHaveParamCount( GetByte(), 4 ) )
1146 : {
1147 2 : double fInvest = GetDouble();
1148 2 : double fTotal = GetDouble();
1149 2 : double fPeriod = GetDouble();
1150 2 : double fRate = GetDouble();
1151 :
1152 2 : if( nGlobalError )
1153 0 : PushError( nGlobalError);
1154 : else
1155 2 : PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) );
1156 : }
1157 2 : }
1158 :
1159 : // Finanzfunktionen
1160 2 : double ScInterpreter::ScGetBw(double fInterest, double fZzr, double fRmz,
1161 : double fZw, double fF)
1162 : {
1163 : double fBw;
1164 2 : if (fInterest == 0.0)
1165 0 : fBw = fZw + fRmz * fZzr;
1166 2 : else if (fF > 0.0)
1167 0 : fBw = (fZw * pow(1.0 + fInterest, -fZzr))
1168 0 : + (fRmz * (1.0 - pow(1.0 + fInterest, -fZzr + 1.0)) / fInterest)
1169 0 : + fRmz;
1170 : else
1171 2 : fBw = (fZw * pow(1.0 + fInterest, -fZzr))
1172 2 : + (fRmz * (1.0 - pow(1.0 + fInterest, -fZzr)) / fInterest);
1173 2 : return -fBw;
1174 : }
1175 :
1176 2 : void ScInterpreter::ScBW()
1177 : {
1178 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1179 2 : double nRmz, nZzr, nInterest, nZw = 0, nFlag = 0;
1180 2 : sal_uInt8 nParamCount = GetByte();
1181 2 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1182 2 : return;
1183 2 : if (nParamCount == 5)
1184 0 : nFlag = GetDouble();
1185 2 : if (nParamCount >= 4)
1186 2 : nZw = GetDouble();
1187 2 : nRmz = GetDouble();
1188 2 : nZzr = GetDouble();
1189 2 : nInterest = GetDouble();
1190 2 : PushDouble(ScGetBw(nInterest, nZzr, nRmz, nZw, nFlag));
1191 : }
1192 :
1193 2 : void ScInterpreter::ScDIA()
1194 : {
1195 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1196 2 : if ( MustHaveParamCount( GetByte(), 4 ) )
1197 : {
1198 2 : double nZr = GetDouble();
1199 2 : double nTimeLength = GetDouble();
1200 2 : double nRest = GetDouble();
1201 2 : double nValue = GetDouble();
1202 2 : double nDia = ((nValue - nRest) * (nTimeLength - nZr + 1.0)) /
1203 2 : ((nTimeLength * (nTimeLength + 1.0)) / 2.0);
1204 2 : PushDouble(nDia);
1205 : }
1206 2 : }
1207 :
1208 42 : double ScInterpreter::ScGetGDA(double fValue, double fRest, double fTimeLength,
1209 : double fPeriod, double fFactor)
1210 : {
1211 : double fGda, fInterest, fOldValue, fNewValue;
1212 42 : fInterest = fFactor / fTimeLength;
1213 42 : if (fInterest >= 1.0)
1214 : {
1215 0 : fInterest = 1.0;
1216 0 : if (fPeriod == 1.0)
1217 0 : fOldValue = fValue;
1218 : else
1219 0 : fOldValue = 0.0;
1220 : }
1221 : else
1222 42 : fOldValue = fValue * pow(1.0 - fInterest, fPeriod - 1.0);
1223 42 : fNewValue = fValue * pow(1.0 - fInterest, fPeriod);
1224 :
1225 42 : if (fNewValue < fRest)
1226 0 : fGda = fOldValue - fRest;
1227 : else
1228 42 : fGda = fOldValue - fNewValue;
1229 42 : if (fGda < 0.0)
1230 0 : fGda = 0.0;
1231 42 : return fGda;
1232 : }
1233 :
1234 2 : void ScInterpreter::ScGDA()
1235 : {
1236 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1237 2 : sal_uInt8 nParamCount = GetByte();
1238 2 : if ( MustHaveParamCount( nParamCount, 4, 5 ) )
1239 : {
1240 : double nFactor;
1241 2 : if (nParamCount == 5)
1242 2 : nFactor = GetDouble();
1243 : else
1244 0 : nFactor = 2.0;
1245 2 : double nPeriod = GetDouble();
1246 2 : double nTimeLength = GetDouble();
1247 2 : double nRest = GetDouble();
1248 2 : double nValue = GetDouble();
1249 2 : if (nValue < 0.0 || nRest < 0.0 || nFactor <= 0.0 || nRest > nValue
1250 2 : || nPeriod < 1.0 || nPeriod > nTimeLength)
1251 0 : PushIllegalArgument();
1252 : else
1253 2 : PushDouble(ScGetGDA(nValue, nRest, nTimeLength, nPeriod, nFactor));
1254 : }
1255 2 : }
1256 :
1257 2 : void ScInterpreter::ScGDA2()
1258 : {
1259 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1260 2 : sal_uInt8 nParamCount = GetByte();
1261 2 : if ( !MustHaveParamCount( nParamCount, 4, 5 ) )
1262 0 : return ;
1263 : double nMonths;
1264 2 : if (nParamCount == 4)
1265 0 : nMonths = 12.0;
1266 : else
1267 2 : nMonths = ::rtl::math::approxFloor(GetDouble());
1268 2 : double nPeriod = GetDouble();
1269 2 : double nTimeLength = GetDouble();
1270 2 : double nRest = GetDouble();
1271 2 : double nValue = GetDouble();
1272 4 : if (nMonths < 1.0 || nMonths > 12.0 || nTimeLength > 1200.0 || nRest < 0.0 ||
1273 4 : nPeriod > (nTimeLength + 1.0) || nRest > nValue || nValue < 0.0)
1274 : {
1275 0 : PushIllegalArgument();
1276 0 : return;
1277 : }
1278 2 : double nOffRate = 1.0 - pow(nRest / nValue, 1.0 / nTimeLength);
1279 2 : nOffRate = ::rtl::math::approxFloor((nOffRate * 1000.0) + 0.5) / 1000.0;
1280 2 : double nFirstOffRate = nValue * nOffRate * nMonths / 12.0;
1281 2 : double nGda2 = 0.0;
1282 2 : if (::rtl::math::approxFloor(nPeriod) == 1)
1283 2 : nGda2 = nFirstOffRate;
1284 : else
1285 : {
1286 0 : double nSumOffRate = nFirstOffRate;
1287 0 : double nMin = nTimeLength;
1288 0 : if (nMin > nPeriod) nMin = nPeriod;
1289 0 : sal_uInt16 iMax = (sal_uInt16)::rtl::math::approxFloor(nMin);
1290 0 : for (sal_uInt16 i = 2; i <= iMax; i++)
1291 : {
1292 0 : nGda2 = (nValue - nSumOffRate) * nOffRate;
1293 0 : nSumOffRate += nGda2;
1294 : }
1295 0 : if (nPeriod > nTimeLength)
1296 0 : nGda2 = ((nValue - nSumOffRate) * nOffRate * (12.0 - nMonths)) / 12.0;
1297 : }
1298 2 : PushDouble(nGda2);
1299 : }
1300 :
1301 4 : double ScInterpreter::ScInterVDB(double fValue,double fRest,double fTimeLength,
1302 : double fTimeLength1,double fPeriod,double fFactor)
1303 : {
1304 4 : double fVdb=0;
1305 4 : double fIntEnd = ::rtl::math::approxCeil(fPeriod);
1306 4 : sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
1307 :
1308 : double fTerm, fLia;
1309 4 : double fSalvageValue = fValue - fRest;
1310 4 : bool bNowLia = false;
1311 :
1312 : double fGda;
1313 : sal_uLong i;
1314 4 : fLia=0;
1315 44 : for ( i = 1; i <= nLoopEnd; i++)
1316 : {
1317 40 : if(!bNowLia)
1318 : {
1319 40 : fGda = ScGetGDA(fValue, fRest, fTimeLength, (double) i, fFactor);
1320 40 : fLia = fSalvageValue/ (fTimeLength1 - (double) (i-1));
1321 :
1322 40 : if (fLia > fGda)
1323 : {
1324 0 : fTerm = fLia;
1325 0 : bNowLia = true;
1326 : }
1327 : else
1328 : {
1329 40 : fTerm = fGda;
1330 40 : fSalvageValue -= fGda;
1331 : }
1332 : }
1333 : else
1334 : {
1335 0 : fTerm = fLia;
1336 : }
1337 :
1338 40 : if ( i == nLoopEnd)
1339 4 : fTerm *= ( fPeriod + 1.0 - fIntEnd );
1340 :
1341 40 : fVdb += fTerm;
1342 : }
1343 4 : return fVdb;
1344 : }
1345 :
1346 0 : inline double DblMin( double a, double b )
1347 : {
1348 0 : return (a < b) ? a : b;
1349 : }
1350 :
1351 2 : void ScInterpreter::ScVDB()
1352 : {
1353 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1354 2 : sal_uInt8 nParamCount = GetByte();
1355 2 : if ( MustHaveParamCount( nParamCount, 5, 7 ) )
1356 : {
1357 2 : double fValue, fRest, fTimeLength, fStart, fEnd, fFactor, fVdb = 0.0;
1358 : bool bFlag;
1359 2 : if (nParamCount == 7)
1360 0 : bFlag = GetBool();
1361 : else
1362 2 : bFlag = false;
1363 2 : if (nParamCount >= 6)
1364 2 : fFactor = GetDouble();
1365 : else
1366 0 : fFactor = 2.0;
1367 2 : fEnd = GetDouble();
1368 2 : fStart = GetDouble();
1369 2 : fTimeLength = GetDouble();
1370 2 : fRest = GetDouble();
1371 2 : fValue = GetDouble();
1372 2 : if (fStart < 0.0 || fEnd < fStart || fEnd > fTimeLength || fValue < 0.0
1373 2 : || fRest > fValue || fFactor <= 0.0)
1374 0 : PushIllegalArgument();
1375 : else
1376 : {
1377 2 : double fIntStart = ::rtl::math::approxFloor(fStart);
1378 2 : double fIntEnd = ::rtl::math::approxCeil(fEnd);
1379 2 : sal_uLong nLoopStart = (sal_uLong) fIntStart;
1380 2 : sal_uLong nLoopEnd = (sal_uLong) fIntEnd;
1381 :
1382 2 : fVdb = 0.0;
1383 2 : if (bFlag)
1384 : {
1385 0 : for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++)
1386 : {
1387 0 : double fTerm = ScGetGDA(fValue, fRest, fTimeLength, (double) i, fFactor);
1388 :
1389 : //respect partial period in the Beginning/ End:
1390 0 : if ( i == nLoopStart+1 )
1391 0 : fTerm *= ( DblMin( fEnd, fIntStart + 1.0 ) - fStart );
1392 0 : else if ( i == nLoopEnd )
1393 0 : fTerm *= ( fEnd + 1.0 - fIntEnd );
1394 :
1395 0 : fVdb += fTerm;
1396 : }
1397 : }
1398 : else
1399 : {
1400 :
1401 2 : double fTimeLength1=fTimeLength;
1402 :
1403 : //@ The question of all questions: 'Is this right'
1404 2 : if(!::rtl::math::approxEqual(fStart,::rtl::math::approxFloor(fStart)))
1405 : {
1406 0 : if(fFactor>1)
1407 : {
1408 0 : if(fStart>fTimeLength/2 || ::rtl::math::approxEqual(fStart,fTimeLength/2))
1409 : {
1410 0 : double fPart=fStart-fTimeLength/2;
1411 0 : fStart=fTimeLength/2;
1412 0 : fEnd-=fPart;
1413 0 : fTimeLength1+=1;
1414 : }
1415 : }
1416 : }
1417 :
1418 2 : fValue-=ScInterVDB(fValue,fRest,fTimeLength,fTimeLength1,fStart,fFactor);
1419 2 : fVdb=ScInterVDB(fValue,fRest,fTimeLength,fTimeLength-fStart,fEnd-fStart,fFactor);
1420 : }
1421 : }
1422 2 : PushDouble(fVdb);
1423 : }
1424 2 : }
1425 :
1426 2 : void ScInterpreter::ScLaufz()
1427 : {
1428 2 : if ( MustHaveParamCount( GetByte(), 3 ) )
1429 : {
1430 2 : double nFuture = GetDouble();
1431 2 : double nPresent = GetDouble();
1432 2 : double nInterest = GetDouble();
1433 2 : PushDouble(log(nFuture / nPresent) / boost::math::log1p(nInterest));
1434 : }
1435 2 : }
1436 :
1437 2 : void ScInterpreter::ScLIA()
1438 : {
1439 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1440 2 : if ( MustHaveParamCount( GetByte(), 3 ) )
1441 : {
1442 2 : double nTimeLength = GetDouble();
1443 2 : double nRest = GetDouble();
1444 2 : double nValue = GetDouble();
1445 2 : PushDouble((nValue - nRest) / nTimeLength);
1446 : }
1447 2 : }
1448 :
1449 18 : double ScInterpreter::ScGetRmz(double fRate, double fNper, double fPv,
1450 : double fFv, double fPaytype)
1451 : {
1452 : double fPayment;
1453 18 : if (fRate == 0.0)
1454 0 : fPayment = (fPv + fFv) / fNper;
1455 : else
1456 : {
1457 18 : if (fPaytype > 0.0) // payment in advance
1458 4 : fPayment = (fFv + fPv * exp( fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1459 4 : (::rtl::math::expm1( (fNper + 1) * ::rtl::math::log1p(fRate) ) - fRate);
1460 : else // payment in arrear
1461 14 : fPayment = (fFv + fPv * exp(fNper * ::rtl::math::log1p(fRate) ) ) * fRate /
1462 14 : ::rtl::math::expm1( fNper * ::rtl::math::log1p(fRate) );
1463 : }
1464 18 : return -fPayment;
1465 : }
1466 :
1467 2 : void ScInterpreter::ScRMZ()
1468 : {
1469 2 : double nInterest, nZzr, nBw, nZw = 0, nFlag = 0;
1470 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1471 2 : sal_uInt8 nParamCount = GetByte();
1472 2 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1473 2 : return;
1474 2 : if (nParamCount == 5)
1475 0 : nFlag = GetDouble();
1476 2 : if (nParamCount >= 4)
1477 0 : nZw = GetDouble();
1478 2 : nBw = GetDouble();
1479 2 : nZzr = GetDouble();
1480 2 : nInterest = GetDouble();
1481 2 : PushDouble(ScGetRmz(nInterest, nZzr, nBw, nZw, nFlag));
1482 : }
1483 :
1484 2 : void ScInterpreter::ScZGZ()
1485 : {
1486 2 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1487 2 : if ( MustHaveParamCount( GetByte(), 3 ) )
1488 : {
1489 2 : double nValueInFuture = GetDouble();
1490 2 : double nValueNow = GetDouble();
1491 2 : double nSpaceOfTime = GetDouble();
1492 2 : PushDouble(pow(nValueInFuture / nValueNow, 1.0 / nSpaceOfTime) - 1.0);
1493 : }
1494 2 : }
1495 :
1496 76 : double ScInterpreter::ScGetZw(double fInterest, double fZzr, double fRmz,
1497 : double fBw, double fF)
1498 : {
1499 : double fZw;
1500 76 : if (fInterest == 0.0)
1501 0 : fZw = fBw + fRmz * fZzr;
1502 : else
1503 : {
1504 76 : double fTerm = pow(1.0 + fInterest, fZzr);
1505 76 : if (fF > 0.0)
1506 6 : fZw = fBw * fTerm + fRmz*(1.0 + fInterest)*(fTerm - 1.0)/fInterest;
1507 : else
1508 70 : fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fInterest;
1509 : }
1510 76 : return -fZw;
1511 : }
1512 :
1513 2 : void ScInterpreter::ScZW()
1514 : {
1515 2 : double nInterest, nZzr, nRmz, nBw = 0, nFlag = 0;
1516 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1517 2 : sal_uInt8 nParamCount = GetByte();
1518 2 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1519 2 : return;
1520 2 : if (nParamCount == 5)
1521 0 : nFlag = GetDouble();
1522 2 : if (nParamCount >= 4)
1523 2 : nBw = GetDouble();
1524 2 : nRmz = GetDouble();
1525 2 : nZzr = GetDouble();
1526 2 : nInterest = GetDouble();
1527 2 : PushDouble(ScGetZw(nInterest, nZzr, nRmz, nBw, nFlag));
1528 : }
1529 :
1530 2 : void ScInterpreter::ScZZR()
1531 : {
1532 2 : double nInterest, nRmz, nBw, nZw = 0, nFlag = 0;
1533 2 : sal_uInt8 nParamCount = GetByte();
1534 2 : if ( !MustHaveParamCount( nParamCount, 3, 5 ) )
1535 2 : return;
1536 2 : if (nParamCount == 5)
1537 0 : nFlag = GetDouble();
1538 2 : if (nParamCount >= 4)
1539 0 : nZw = GetDouble();
1540 2 : nBw = GetDouble();
1541 2 : nRmz = GetDouble();
1542 2 : nInterest = GetDouble();
1543 2 : if (nInterest == 0.0)
1544 0 : PushDouble(-(nBw + nZw)/nRmz);
1545 2 : else if (nFlag > 0.0)
1546 0 : PushDouble(log(-(nInterest*nZw-nRmz*(1.0+nInterest))/(nInterest*nBw+nRmz*(1.0+nInterest)))
1547 0 : /boost::math::log1p(nInterest));
1548 : else
1549 2 : PushDouble(log(-(nInterest*nZw-nRmz)/(nInterest*nBw+nRmz))/boost::math::log1p(nInterest));
1550 : }
1551 :
1552 2 : bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv,
1553 : double fFv, double fPayType, double & fGuess )
1554 : {
1555 : // See also #i15090#
1556 : // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i))
1557 : // This solution handles integer and non-integer values of Nper different.
1558 : // If ODFF will constraint Nper to integer, the distinction of cases can be
1559 : // removed; only the integer-part is needed then.
1560 2 : bool bValid = true, bFound = false;
1561 : double fX, fXnew, fTerm, fTermDerivation;
1562 : double fGeoSeries, fGeoSeriesDerivation;
1563 2 : const sal_uInt16 nIterationsMax = 150;
1564 2 : sal_uInt16 nCount = 0;
1565 2 : const double fEpsilonSmall = 1.0E-14;
1566 : // convert any fPayType situation to fPayType == zero situation
1567 2 : fFv = fFv - fPayment * fPayType;
1568 2 : fPv = fPv + fPayment * fPayType;
1569 2 : if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected ))
1570 : { // Nper is an integer value
1571 2 : fX = fGuess;
1572 : double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1)
1573 22 : while (!bFound && nCount < nIterationsMax)
1574 : {
1575 18 : fPowNminus1 = pow( 1.0+fX, fNper-1.0);
1576 18 : fPowN = fPowNminus1 * (1.0+fX);
1577 18 : if (rtl::math::approxEqual( fabs(fX), 0.0))
1578 : {
1579 0 : fGeoSeries = fNper;
1580 0 : fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1581 : }
1582 : else
1583 : {
1584 18 : fGeoSeries = (fPowN-1.0)/fX;
1585 18 : fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX;
1586 : }
1587 18 : fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries;
1588 18 : fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation;
1589 18 : if (fabs(fTerm) < fEpsilonSmall)
1590 0 : bFound = true; // will catch root which is at an extreme
1591 : else
1592 : {
1593 18 : if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1594 0 : fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1595 : else
1596 18 : fXnew = fX - fTerm / fTermDerivation;
1597 18 : nCount++;
1598 : // more accuracy not possible in oscillating cases
1599 18 : bFound = (fabs(fXnew - fX) < SCdEpsilon);
1600 18 : fX = fXnew;
1601 : }
1602 : }
1603 : // Gnumeric returns roots < -1, Excel gives an error in that cases,
1604 : // ODFF says nothing about it. Enable the statement, if you want Excel's
1605 : // behavior.
1606 : //bValid =(fX >=-1.0);
1607 : // Update 2013-06-17: Gnumeric (v1.12.2) doesn't return roots <= -1
1608 : // anymore.
1609 2 : bValid = (fX > -1.0);
1610 : }
1611 : else
1612 : { // Nper is not an integer value.
1613 0 : fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX
1614 0 : while (bValid && !bFound && nCount < nIterationsMax)
1615 : {
1616 0 : if (rtl::math::approxEqual( fabs(fX), 0.0))
1617 : {
1618 0 : fGeoSeries = fNper;
1619 0 : fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0;
1620 : }
1621 : else
1622 : {
1623 0 : fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX;
1624 0 : fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX;
1625 : }
1626 0 : fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries;
1627 0 : fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation;
1628 0 : if (fabs(fTerm) < fEpsilonSmall)
1629 0 : bFound = true; // will catch root which is at an extreme
1630 : else
1631 : {
1632 0 : if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0))
1633 0 : fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope
1634 : else
1635 0 : fXnew = fX - fTerm / fTermDerivation;
1636 0 : nCount++;
1637 : // more accuracy not possible in oscillating cases
1638 0 : bFound = (fabs(fXnew - fX) < SCdEpsilon);
1639 0 : fX = fXnew;
1640 0 : bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail
1641 : }
1642 : }
1643 : }
1644 2 : fGuess = fX; // return approximate root
1645 2 : return bValid && bFound;
1646 : }
1647 :
1648 : // In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess)
1649 2 : void ScInterpreter::ScZins()
1650 : {
1651 : double fPv, fPayment, fNper;
1652 : // defaults for missing arguments, see ODFF spec
1653 2 : double fFv = 0, fPayType = 0, fGuess = 0.1, fOrigGuess = 0.1;
1654 2 : bool bValid = true;
1655 2 : bool bDefaultGuess = true;
1656 2 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1657 2 : sal_uInt8 nParamCount = GetByte();
1658 2 : if ( !MustHaveParamCount( nParamCount, 3, 6 ) )
1659 0 : return;
1660 2 : if (nParamCount == 6)
1661 : {
1662 0 : fOrigGuess = fGuess = GetDouble();
1663 0 : bDefaultGuess = false;
1664 : }
1665 2 : if (nParamCount >= 5)
1666 0 : fPayType = GetDouble();
1667 2 : if (nParamCount >= 4)
1668 0 : fFv = GetDouble();
1669 2 : fPv = GetDouble();
1670 2 : fPayment = GetDouble();
1671 2 : fNper = GetDouble();
1672 2 : if (fNper <= 0.0) // constraint from ODFF spec
1673 : {
1674 0 : PushIllegalArgument();
1675 0 : return;
1676 : }
1677 : // other values for fPayType might be meaningful,
1678 : // ODFF spec is not clear yet, enable statement if you want only 0 and 1
1679 : //if (fPayType != 0.0) fPayType = 1.0;
1680 2 : bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess);
1681 2 : if (!bValid)
1682 : {
1683 : /* TODO: try also for specified guess values, not only default? As is,
1684 : * a specified 0.1 guess may be error result but a default 0.1 guess
1685 : * may succeed. On the other hand, using a different guess value than
1686 : * the specified one may not be desired, even if that didn't match. */
1687 0 : if (bDefaultGuess)
1688 : {
1689 : /* TODO: this is rather ugly, instead of looping over different
1690 : * guess values and doing a Newton goal seek for each we could
1691 : * first insert the values into the RATE equation to obtain a set
1692 : * of y values and then do a bisecting goal seek, possibly using
1693 : * different algorithms. */
1694 0 : double fX = fOrigGuess;
1695 0 : for (int nStep = 2; nStep <= 10 && !bValid; ++nStep)
1696 : {
1697 0 : fGuess = fX * nStep;
1698 0 : bValid = RateIteration( fNper, fPayment, fPv, fFv, fPayType, fGuess);
1699 0 : if (!bValid)
1700 : {
1701 0 : fGuess = fX / nStep;
1702 0 : bValid = RateIteration( fNper, fPayment, fPv, fFv, fPayType, fGuess);
1703 : }
1704 : }
1705 : }
1706 0 : if (!bValid)
1707 0 : SetError(errNoConvergence);
1708 : }
1709 2 : PushDouble(fGuess);
1710 : }
1711 :
1712 4 : double ScInterpreter::ScGetCompoundInterest(double fInterest, double fZr, double fZzr, double fBw,
1713 : double fZw, double fF, double& fRmz)
1714 : {
1715 4 : fRmz = ScGetRmz(fInterest, fZzr, fBw, fZw, fF); // fuer kapz auch bei fZr == 1
1716 : double fCompoundInterest;
1717 4 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1718 4 : if (fZr == 1.0)
1719 : {
1720 2 : if (fF > 0.0)
1721 2 : fCompoundInterest = 0.0;
1722 : else
1723 0 : fCompoundInterest = -fBw;
1724 : }
1725 : else
1726 : {
1727 2 : if (fF > 0.0)
1728 0 : fCompoundInterest = ScGetZw(fInterest, fZr-2.0, fRmz, fBw, 1.0) - fRmz;
1729 : else
1730 2 : fCompoundInterest = ScGetZw(fInterest, fZr-1.0, fRmz, fBw, 0.0);
1731 : }
1732 4 : return fCompoundInterest * fInterest;
1733 : }
1734 :
1735 2 : void ScInterpreter::ScZinsZ()
1736 : {
1737 2 : double nInterest, nZr, nZzr, nBw, nZw = 0, nFlag = 0;
1738 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1739 2 : sal_uInt8 nParamCount = GetByte();
1740 2 : if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1741 2 : return;
1742 2 : if (nParamCount == 6)
1743 0 : nFlag = GetDouble();
1744 2 : if (nParamCount >= 5)
1745 0 : nZw = GetDouble();
1746 2 : nBw = GetDouble();
1747 2 : nZzr = GetDouble();
1748 2 : nZr = GetDouble();
1749 2 : nInterest = GetDouble();
1750 2 : if (nZr < 1.0 || nZr > nZzr)
1751 0 : PushIllegalArgument();
1752 : else
1753 : {
1754 : double nRmz;
1755 2 : PushDouble(ScGetCompoundInterest(nInterest, nZr, nZzr, nBw, nZw, nFlag, nRmz));
1756 : }
1757 : }
1758 :
1759 2 : void ScInterpreter::ScKapz()
1760 : {
1761 2 : double nInterest, nZr, nZzr, nBw, nZw = 0, nFlag = 0;
1762 2 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1763 2 : sal_uInt8 nParamCount = GetByte();
1764 2 : if ( !MustHaveParamCount( nParamCount, 4, 6 ) )
1765 2 : return;
1766 2 : if (nParamCount == 6)
1767 2 : nFlag = GetDouble();
1768 2 : if (nParamCount >= 5)
1769 2 : nZw = GetDouble();
1770 2 : nBw = GetDouble();
1771 2 : nZzr = GetDouble();
1772 2 : nZr = GetDouble();
1773 2 : nInterest = GetDouble();
1774 2 : if (nZr < 1.0 || nZr > nZzr)
1775 0 : PushIllegalArgument();
1776 : else
1777 : {
1778 : double nRmz;
1779 2 : double nInterestz = ScGetCompoundInterest(nInterest, nZr, nZzr, nBw, nZw, nFlag, nRmz);
1780 2 : PushDouble(nRmz - nInterestz);
1781 : }
1782 : }
1783 :
1784 6 : void ScInterpreter::ScKumZinsZ()
1785 : {
1786 6 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1787 6 : if ( MustHaveParamCount( GetByte(), 6 ) )
1788 : {
1789 : double fInterest, fZzr, fBw, fStart, fEnd, fF;
1790 6 : fF = GetDouble();
1791 6 : fEnd = ::rtl::math::approxFloor(GetDouble());
1792 6 : fStart = ::rtl::math::approxFloor(GetDouble());
1793 6 : fBw = GetDouble();
1794 6 : fZzr = GetDouble();
1795 6 : fInterest = GetDouble();
1796 6 : if (fStart < 1.0 || fEnd < fStart || fInterest <= 0.0 ||
1797 6 : fEnd > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1798 0 : PushIllegalArgument();
1799 : else
1800 : {
1801 6 : sal_uLong nStart = (sal_uLong) fStart;
1802 6 : sal_uLong nEnd = (sal_uLong) fEnd ;
1803 6 : double fRmz = ScGetRmz(fInterest, fZzr, fBw, 0.0, fF);
1804 6 : double fCompoundInterest = 0.0;
1805 6 : if (nStart == 1)
1806 : {
1807 2 : if (fF <= 0.0)
1808 2 : fCompoundInterest = -fBw;
1809 2 : nStart++;
1810 : }
1811 36 : for (sal_uLong i = nStart; i <= nEnd; i++)
1812 : {
1813 30 : if (fF > 0.0)
1814 6 : fCompoundInterest += ScGetZw(fInterest, (double)(i-2), fRmz, fBw, 1.0) - fRmz;
1815 : else
1816 24 : fCompoundInterest += ScGetZw(fInterest, (double)(i-1), fRmz, fBw, 0.0);
1817 : }
1818 6 : fCompoundInterest *= fInterest;
1819 6 : PushDouble(fCompoundInterest);
1820 : }
1821 : }
1822 6 : }
1823 :
1824 6 : void ScInterpreter::ScKumKapZ()
1825 : {
1826 6 : nFuncFmtType = NUMBERFORMAT_CURRENCY;
1827 6 : if ( MustHaveParamCount( GetByte(), 6 ) )
1828 : {
1829 : double fInterest, fZzr, fBw, fStart, fEnd, fF;
1830 6 : fF = GetDouble();
1831 6 : fEnd = ::rtl::math::approxFloor(GetDouble());
1832 6 : fStart = ::rtl::math::approxFloor(GetDouble());
1833 6 : fBw = GetDouble();
1834 6 : fZzr = GetDouble();
1835 6 : fInterest = GetDouble();
1836 6 : if (fStart < 1.0 || fEnd < fStart || fInterest <= 0.0 ||
1837 6 : fEnd > fZzr || fZzr <= 0.0 || fBw <= 0.0)
1838 0 : PushIllegalArgument();
1839 : else
1840 : {
1841 6 : double fRmz = ScGetRmz(fInterest, fZzr, fBw, 0.0, fF);
1842 6 : double fKapZ = 0.0;
1843 6 : sal_uLong nStart = (sal_uLong) fStart;
1844 6 : sal_uLong nEnd = (sal_uLong) fEnd;
1845 6 : if (nStart == 1)
1846 : {
1847 2 : if (fF <= 0.0)
1848 2 : fKapZ = fRmz + fBw * fInterest;
1849 : else
1850 0 : fKapZ = fRmz;
1851 2 : nStart++;
1852 : }
1853 48 : for (sal_uLong i = nStart; i <= nEnd; i++)
1854 : {
1855 42 : if (fF > 0.0)
1856 0 : fKapZ += fRmz - (ScGetZw(fInterest, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fInterest;
1857 : else
1858 42 : fKapZ += fRmz - ScGetZw(fInterest, (double)(i-1), fRmz, fBw, 0.0) * fInterest;
1859 : }
1860 6 : PushDouble(fKapZ);
1861 : }
1862 : }
1863 6 : }
1864 :
1865 4 : void ScInterpreter::ScEffektiv()
1866 : {
1867 4 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1868 4 : if ( MustHaveParamCount( GetByte(), 2 ) )
1869 : {
1870 4 : double fPeriods = GetDouble();
1871 4 : double fNominal = GetDouble();
1872 4 : if (fPeriods < 1.0 || fNominal <= 0.0)
1873 0 : PushIllegalArgument();
1874 : else
1875 : {
1876 4 : fPeriods = ::rtl::math::approxFloor(fPeriods);
1877 4 : PushDouble(pow(1.0 + fNominal/fPeriods, fPeriods) - 1.0);
1878 : }
1879 : }
1880 4 : }
1881 :
1882 4 : void ScInterpreter::ScNominal()
1883 : {
1884 4 : nFuncFmtType = NUMBERFORMAT_PERCENT;
1885 4 : if ( MustHaveParamCount( GetByte(), 2 ) )
1886 : {
1887 4 : double fPeriods = GetDouble();
1888 4 : double fEffective = GetDouble();
1889 4 : if (fPeriods < 1.0 || fEffective <= 0.0)
1890 0 : PushIllegalArgument();
1891 : else
1892 : {
1893 4 : fPeriods = ::rtl::math::approxFloor(fPeriods);
1894 4 : PushDouble( (pow(fEffective + 1.0, 1.0 / fPeriods) - 1.0) * fPeriods );
1895 : }
1896 : }
1897 4 : }
1898 :
1899 2 : void ScInterpreter::ScMod()
1900 : {
1901 2 : if ( MustHaveParamCount( GetByte(), 2 ) )
1902 : {
1903 2 : double fVal2 = GetDouble(); // Denominator
1904 2 : double fVal1 = GetDouble(); // Numerator
1905 2 : if (fVal2 == floor(fVal2)) // a pure integral number stored in double
1906 : {
1907 2 : double fResult = fmod(fVal1,fVal2);
1908 2 : if ( (fResult != 0.0) &&
1909 0 : ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0)))
1910 0 : fResult += fVal2 ;
1911 2 : PushDouble( fResult );
1912 : }
1913 : else
1914 : {
1915 : PushDouble( ::rtl::math::approxSub( fVal1,
1916 0 : ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2));
1917 : }
1918 : }
1919 2 : }
1920 :
1921 0 : void ScInterpreter::ScIntersect()
1922 : {
1923 0 : formula::FormulaTokenRef p2nd = PopToken();
1924 0 : formula::FormulaTokenRef p1st = PopToken();
1925 :
1926 0 : if (nGlobalError || !p2nd || !p1st)
1927 : {
1928 0 : PushIllegalArgument();
1929 0 : return;
1930 : }
1931 :
1932 0 : StackVar sv1 = p1st->GetType();
1933 0 : StackVar sv2 = p2nd->GetType();
1934 0 : if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
1935 0 : (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
1936 : {
1937 0 : PushIllegalArgument();
1938 0 : return;
1939 : }
1940 :
1941 0 : formula::FormulaToken* x1 = p1st.get();
1942 0 : formula::FormulaToken* x2 = p2nd.get();
1943 0 : if (sv1 == svRefList || sv2 == svRefList)
1944 : {
1945 : // Now this is a bit nasty but it simplifies things, and having
1946 : // intersections with lists isn't too common, if at all..
1947 : // Convert a reference to list.
1948 0 : formula::FormulaToken* xt[2] = { x1, x2 };
1949 0 : StackVar sv[2] = { sv1, sv2 };
1950 0 : for (size_t i=0; i<2; ++i)
1951 : {
1952 0 : if (sv[i] == svSingleRef)
1953 : {
1954 : ScComplexRefData aRef;
1955 0 : aRef.Ref1 = aRef.Ref2 = *xt[i]->GetSingleRef();
1956 0 : xt[i] = new ScRefListToken;
1957 0 : xt[i]->GetRefList()->push_back( aRef);
1958 : }
1959 0 : else if (sv[i] == svDoubleRef)
1960 : {
1961 0 : ScComplexRefData aRef = *xt[i]->GetDoubleRef();
1962 0 : xt[i] = new ScRefListToken;
1963 0 : xt[i]->GetRefList()->push_back( aRef);
1964 : }
1965 : }
1966 0 : x1 = xt[0], x2 = xt[1];
1967 :
1968 0 : ScTokenRef xRes = new ScRefListToken;
1969 0 : ScRefList* pRefList = xRes->GetRefList();
1970 0 : ScRefList::const_iterator end1( x1->GetRefList()->end());
1971 0 : ScRefList::const_iterator end2( x2->GetRefList()->end());
1972 0 : for (ScRefList::const_iterator it1( x1->GetRefList()->begin());
1973 : it1 != end1; ++it1)
1974 : {
1975 0 : const ScAddress& r11 = (*it1).Ref1.toAbs(aPos);
1976 0 : const ScAddress& r12 = (*it1).Ref2.toAbs(aPos);
1977 0 : for (ScRefList::const_iterator it2( x2->GetRefList()->begin());
1978 : it2 != end2; ++it2)
1979 : {
1980 0 : const ScAddress& r21 = (*it2).Ref1.toAbs(aPos);
1981 0 : const ScAddress& r22 = (*it2).Ref2.toAbs(aPos);
1982 0 : SCCOL nCol1 = ::std::max( r11.Col(), r21.Col());
1983 0 : SCROW nRow1 = ::std::max( r11.Row(), r21.Row());
1984 0 : SCTAB nTab1 = ::std::max( r11.Tab(), r21.Tab());
1985 0 : SCCOL nCol2 = ::std::min( r12.Col(), r22.Col());
1986 0 : SCROW nRow2 = ::std::min( r12.Row(), r22.Row());
1987 0 : SCTAB nTab2 = ::std::min( r12.Tab(), r22.Tab());
1988 0 : if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
1989 : ; // nothing
1990 : else
1991 : {
1992 : ScComplexRefData aRef;
1993 0 : aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
1994 0 : pRefList->push_back( aRef);
1995 : }
1996 : }
1997 : }
1998 0 : size_t n = pRefList->size();
1999 0 : if (!n)
2000 0 : PushError( errNoRef);
2001 0 : else if (n == 1)
2002 : {
2003 0 : const ScComplexRefData& rRef = (*pRefList)[0];
2004 0 : if (rRef.Ref1 == rRef.Ref2)
2005 0 : PushTempToken( new ScSingleRefToken( rRef.Ref1));
2006 : else
2007 0 : PushTempToken( new ScDoubleRefToken( rRef));
2008 : }
2009 : else
2010 0 : PushTempToken( xRes.get());
2011 : }
2012 : else
2013 : {
2014 0 : formula::FormulaToken* pt[2] = { x1, x2 };
2015 0 : StackVar sv[2] = { sv1, sv2 };
2016 : SCCOL nC1[2], nC2[2];
2017 : SCROW nR1[2], nR2[2];
2018 : SCTAB nT1[2], nT2[2];
2019 0 : for (size_t i=0; i<2; ++i)
2020 : {
2021 0 : switch (sv[i])
2022 : {
2023 : case svSingleRef:
2024 : case svDoubleRef:
2025 : {
2026 : {
2027 0 : const ScAddress& r = pt[i]->GetSingleRef()->toAbs(aPos);
2028 0 : nC1[i] = r.Col();
2029 0 : nR1[i] = r.Row();
2030 0 : nT1[i] = r.Tab();
2031 : }
2032 0 : if (sv[i] == svDoubleRef)
2033 : {
2034 0 : const ScAddress& r = pt[i]->GetSingleRef2()->toAbs(aPos);
2035 0 : nC2[i] = r.Col();
2036 0 : nR2[i] = r.Row();
2037 0 : nT2[i] = r.Tab();
2038 : }
2039 : else
2040 : {
2041 0 : nC2[i] = nC1[i];
2042 0 : nR2[i] = nR1[i];
2043 0 : nT2[i] = nT1[i];
2044 : }
2045 : }
2046 0 : break;
2047 : default:
2048 : ; // nothing, prevent compiler warning
2049 : }
2050 : }
2051 0 : SCCOL nCol1 = ::std::max( nC1[0], nC1[1]);
2052 0 : SCROW nRow1 = ::std::max( nR1[0], nR1[1]);
2053 0 : SCTAB nTab1 = ::std::max( nT1[0], nT1[1]);
2054 0 : SCCOL nCol2 = ::std::min( nC2[0], nC2[1]);
2055 0 : SCROW nRow2 = ::std::min( nR2[0], nR2[1]);
2056 0 : SCTAB nTab2 = ::std::min( nT2[0], nT2[1]);
2057 0 : if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1)
2058 0 : PushError( errNoRef);
2059 0 : else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1)
2060 0 : PushSingleRef( nCol1, nRow1, nTab1);
2061 : else
2062 0 : PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
2063 0 : }
2064 : }
2065 :
2066 0 : void ScInterpreter::ScRangeFunc()
2067 : {
2068 0 : formula::FormulaTokenRef x2 = PopToken();
2069 0 : formula::FormulaTokenRef x1 = PopToken();
2070 :
2071 0 : if (nGlobalError || !x2 || !x1)
2072 : {
2073 0 : PushIllegalArgument();
2074 0 : return;
2075 : }
2076 0 : FormulaTokenRef xRes = extendRangeReference( *x1, *x2, aPos, false);
2077 0 : if (!xRes)
2078 0 : PushIllegalArgument();
2079 : else
2080 0 : PushTempToken( xRes.get());
2081 : }
2082 :
2083 0 : void ScInterpreter::ScUnionFunc()
2084 : {
2085 0 : formula::FormulaTokenRef p2nd = PopToken();
2086 0 : formula::FormulaTokenRef p1st = PopToken();
2087 :
2088 0 : if (nGlobalError || !p2nd || !p1st)
2089 : {
2090 0 : PushIllegalArgument();
2091 0 : return;
2092 : }
2093 :
2094 0 : StackVar sv1 = p1st->GetType();
2095 0 : StackVar sv2 = p2nd->GetType();
2096 0 : if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) ||
2097 0 : (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
2098 : {
2099 0 : PushIllegalArgument();
2100 0 : return;
2101 : }
2102 :
2103 0 : formula::FormulaToken* x1 = p1st.get();
2104 0 : formula::FormulaToken* x2 = p2nd.get();
2105 :
2106 0 : ScTokenRef xRes;
2107 : // Append to an existing RefList if there is one.
2108 0 : if (sv1 == svRefList)
2109 : {
2110 0 : xRes = x1;
2111 0 : sv1 = svUnknown; // mark as handled
2112 : }
2113 0 : else if (sv2 == svRefList)
2114 : {
2115 0 : xRes = x2;
2116 0 : sv2 = svUnknown; // mark as handled
2117 : }
2118 : else
2119 0 : xRes = new ScRefListToken;
2120 0 : ScRefList* pRes = xRes->GetRefList();
2121 0 : formula::FormulaToken* pt[2] = { x1, x2 };
2122 0 : StackVar sv[2] = { sv1, sv2 };
2123 0 : for (size_t i=0; i<2; ++i)
2124 : {
2125 0 : if (pt[i] == xRes)
2126 0 : continue;
2127 0 : switch (sv[i])
2128 : {
2129 : case svSingleRef:
2130 : {
2131 : ScComplexRefData aRef;
2132 0 : aRef.Ref1 = aRef.Ref2 = *pt[i]->GetSingleRef();
2133 0 : pRes->push_back( aRef);
2134 : }
2135 0 : break;
2136 : case svDoubleRef:
2137 0 : pRes->push_back( *pt[i]->GetDoubleRef());
2138 0 : break;
2139 : case svRefList:
2140 : {
2141 0 : const ScRefList* p = pt[i]->GetRefList();
2142 0 : ScRefList::const_iterator it( p->begin());
2143 0 : ScRefList::const_iterator end( p->end());
2144 0 : for ( ; it != end; ++it)
2145 : {
2146 0 : pRes->push_back( *it);
2147 : }
2148 : }
2149 0 : break;
2150 : default:
2151 : ; // nothing, prevent compiler warning
2152 : }
2153 : }
2154 0 : ValidateRef( *pRes); // set #REF! if needed
2155 0 : PushTempToken( xRes.get());
2156 : }
2157 :
2158 2 : void ScInterpreter::ScCurrent()
2159 : {
2160 2 : FormulaTokenRef xTok( PopToken());
2161 2 : if (xTok)
2162 : {
2163 2 : PushTempToken( xTok.get());
2164 2 : PushTempToken( xTok.get());
2165 : }
2166 : else
2167 0 : PushError( errUnknownStackVariable);
2168 2 : }
2169 :
2170 0 : void ScInterpreter::ScStyle()
2171 : {
2172 0 : sal_uInt8 nParamCount = GetByte();
2173 0 : if (nParamCount >= 1 && nParamCount <= 3)
2174 : {
2175 0 : OUString aStyle2; // Template after timer
2176 0 : if (nParamCount >= 3)
2177 0 : aStyle2 = GetString().getString();
2178 0 : long nTimeOut = 0; // timeout
2179 0 : if (nParamCount >= 2)
2180 0 : nTimeOut = (long)(GetDouble()*1000.0);
2181 0 : OUString aStyle1 = GetString().getString(); // Template for immediate
2182 :
2183 0 : if (nTimeOut < 0)
2184 0 : nTimeOut = 0;
2185 :
2186 : // Execute request to apply template
2187 0 : if ( !pDok->IsClipOrUndo() )
2188 : {
2189 0 : SfxObjectShell* pShell = pDok->GetDocumentShell();
2190 0 : if (pShell)
2191 : {
2192 : //! notify object shell directly
2193 :
2194 0 : ScRange aRange(aPos);
2195 0 : ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 );
2196 0 : pShell->Broadcast( aHint );
2197 : }
2198 : }
2199 :
2200 0 : PushDouble(0.0);
2201 : }
2202 : else
2203 0 : PushIllegalParameter();
2204 0 : }
2205 :
2206 16 : static ScDdeLink* lcl_GetDdeLink( sfx2::LinkManager* pLinkMgr,
2207 : const OUString& rA, const OUString& rT, const OUString& rI, sal_uInt8 nM )
2208 : {
2209 16 : size_t nCount = pLinkMgr->GetLinks().size();
2210 16 : for (size_t i=0; i<nCount; i++ )
2211 : {
2212 10 : ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i];
2213 10 : if (pBase->ISA(ScDdeLink))
2214 : {
2215 10 : ScDdeLink* pLink = static_cast<ScDdeLink*>(pBase);
2216 30 : if ( pLink->GetAppl() == rA &&
2217 20 : pLink->GetTopic() == rT &&
2218 30 : pLink->GetItem() == rI &&
2219 10 : pLink->GetMode() == nM )
2220 10 : return pLink;
2221 : }
2222 : }
2223 :
2224 6 : return NULL;
2225 : }
2226 :
2227 16 : void ScInterpreter::ScDde()
2228 : {
2229 : // application, file, scope
2230 : // application, Topic, Item
2231 :
2232 16 : sal_uInt8 nParamCount = GetByte();
2233 16 : if ( MustHaveParamCount( nParamCount, 3, 4 ) )
2234 : {
2235 16 : sal_uInt8 nMode = SC_DDE_DEFAULT;
2236 16 : if (nParamCount == 4)
2237 0 : nMode = (sal_uInt8) ::rtl::math::approxFloor(GetDouble());
2238 16 : OUString aItem = GetString().getString();
2239 32 : OUString aTopic = GetString().getString();
2240 32 : OUString aAppl = GetString().getString();
2241 :
2242 16 : if (nMode > SC_DDE_TEXT)
2243 0 : nMode = SC_DDE_DEFAULT;
2244 :
2245 : // temporary documents (ScFunctionAccess) have no DocShell
2246 : // and no LinkManager -> abort
2247 :
2248 16 : sfx2::LinkManager* pLinkMgr = pDok->GetLinkManager();
2249 16 : if (!pLinkMgr)
2250 : {
2251 0 : PushNoValue();
2252 16 : return;
2253 : }
2254 :
2255 : // Need to reinterpret after loading (build links)
2256 :
2257 16 : if ( rArr.IsRecalcModeNormal() )
2258 0 : rArr.SetExclusiveRecalcModeOnLoad();
2259 :
2260 : // while the link ist not evaluated idle must be disabled (to avoid circular references)
2261 :
2262 16 : bool bOldEnabled = pDok->IsIdleEnabled();
2263 16 : pDok->EnableIdle(false);
2264 :
2265 : // Get/ Create link object
2266 :
2267 16 : ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode );
2268 :
2269 : //! Save Dde-links (in addition) more efficient at document !!!!!
2270 : // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem );
2271 :
2272 16 : bool bWasError = ( pMyFormulaCell && pMyFormulaCell->GetRawError() != 0 );
2273 :
2274 16 : if (!pLink)
2275 : {
2276 6 : pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode );
2277 6 : pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem );
2278 6 : if ( pLinkMgr->GetLinks().size() == 1 ) // erster ?
2279 : {
2280 6 : SfxBindings* pBindings = pDok->GetViewBindings();
2281 6 : if (pBindings)
2282 6 : pBindings->Invalidate( SID_LINKS ); // Link-Manager enablen
2283 : }
2284 :
2285 : //! evaluate asynchron ???
2286 6 : pLink->TryUpdate(); // TryUpdate doesn't call Update multiple times
2287 :
2288 6 : if (pMyFormulaCell)
2289 : {
2290 : // StartListening after the Update to avoid circular references
2291 6 : pMyFormulaCell->StartListening( *pLink );
2292 : }
2293 : }
2294 : else
2295 : {
2296 10 : if (pMyFormulaCell)
2297 10 : pMyFormulaCell->StartListening( *pLink );
2298 : }
2299 :
2300 : // If an new Error from Reschedule appears when the link is executed then reset the errorflag
2301 :
2302 :
2303 16 : if ( pMyFormulaCell && pMyFormulaCell->GetRawError() && !bWasError )
2304 0 : pMyFormulaCell->SetErrCode(0);
2305 :
2306 : // check the value
2307 :
2308 16 : const ScMatrix* pLinkMat = pLink->GetResult();
2309 16 : if (pLinkMat)
2310 : {
2311 : SCSIZE nC, nR;
2312 16 : pLinkMat->GetDimensions(nC, nR);
2313 16 : ScMatrixRef pNewMat = GetNewMat( nC, nR);
2314 16 : if (pNewMat)
2315 : {
2316 16 : pLinkMat->MatCopy(*pNewMat); // copy
2317 16 : PushMatrix( pNewMat );
2318 : }
2319 : else
2320 0 : PushIllegalArgument();
2321 : }
2322 : else
2323 0 : PushNA();
2324 :
2325 16 : pDok->EnableIdle(bOldEnabled);
2326 32 : pLinkMgr->CloseCachedComps();
2327 : }
2328 : }
2329 :
2330 6 : void ScInterpreter::ScBase()
2331 : { // Value, Base [, MinLen]
2332 6 : sal_uInt8 nParamCount = GetByte();
2333 6 : if ( MustHaveParamCount( nParamCount, 2, 3 ) )
2334 : {
2335 : static const sal_Unicode pDigits[] = {
2336 : '0','1','2','3','4','5','6','7','8','9',
2337 : 'A','B','C','D','E','F','G','H','I','J','K','L','M',
2338 : 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
2339 : 0
2340 : };
2341 : static const int nDigits = (sizeof (pDigits)/sizeof(pDigits[0]))-1;
2342 : sal_Int32 nMinLen;
2343 6 : if ( nParamCount == 3 )
2344 : {
2345 4 : double fLen = ::rtl::math::approxFloor( GetDouble() );
2346 4 : if ( 1.0 <= fLen && fLen < SAL_MAX_UINT16 )
2347 4 : nMinLen = (sal_Int32) fLen;
2348 0 : else if ( fLen == 0.0 )
2349 0 : nMinLen = 1;
2350 : else
2351 0 : nMinLen = 0; // Error
2352 : }
2353 : else
2354 2 : nMinLen = 1;
2355 6 : double fBase = ::rtl::math::approxFloor( GetDouble() );
2356 6 : double fVal = ::rtl::math::approxFloor( GetDouble() );
2357 6 : double fChars = ((fVal > 0.0 && fBase > 0.0) ?
2358 6 : (ceil( log( fVal ) / log( fBase ) ) + 2.0) :
2359 12 : 2.0);
2360 6 : if ( fChars >= SAL_MAX_UINT16 )
2361 0 : nMinLen = 0; // Error
2362 :
2363 6 : if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal )
2364 : {
2365 6 : const sal_Int32 nConstBuf = 128;
2366 : sal_Unicode aBuf[nConstBuf];
2367 6 : sal_Int32 nBuf = std::max<sal_Int32>( fChars, nMinLen + 1 );
2368 6 : sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]);
2369 40 : for ( sal_Int32 j = 0; j < nBuf; ++j )
2370 : {
2371 34 : pBuf[j] = '0';
2372 : }
2373 6 : sal_Unicode* p = pBuf + nBuf - 1;
2374 6 : *p = 0;
2375 6 : if ( fVal <= (sal_uLong)(~0) )
2376 : {
2377 6 : sal_uLong nVal = (sal_uLong) fVal;
2378 6 : sal_uLong nBase = (sal_uLong) fBase;
2379 30 : while ( nVal && p > pBuf )
2380 : {
2381 18 : *--p = pDigits[ nVal % nBase ];
2382 18 : nVal /= nBase;
2383 : }
2384 6 : fVal = (double) nVal;
2385 : }
2386 : else
2387 : {
2388 0 : bool bDirt = false;
2389 0 : while ( fVal && p > pBuf )
2390 : {
2391 : //! roundoff error starting with numbers greater than 2**48
2392 : // double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) );
2393 : // a little bit better:
2394 0 : double fInt = ::rtl::math::approxFloor( fVal / fBase );
2395 0 : double fMult = fInt * fBase;
2396 : #if OSL_DEBUG_LEVEL > 1
2397 : // =BASIS(1e308;36) => GPF with
2398 : // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult );
2399 : // in spite off previous test if fVal >= fMult
2400 : double fDebug1 = fVal - fMult;
2401 : // fVal := 7,5975311883090e+290
2402 : // fMult := 7,5975311883090e+290
2403 : // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error
2404 : // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE
2405 : double fDebug2 = ::rtl::math::approxSub( fVal, fMult );
2406 : // und ::rtl::math::approxSub( fVal, fMult ) == 0
2407 : double fDebug3 = ( fInt ? fVal / fInt : 0.0 );
2408 :
2409 : // Actual after strange fDebug1 and fVal < fMult is fDebug2 == fBase, but
2410 : // anyway it can't be compared, then bDirt is executed an everything is good...
2411 :
2412 : // prevent compiler warnings
2413 : (void)fDebug1; (void)fDebug2; (void)fDebug3;
2414 : #endif
2415 : size_t nDig;
2416 0 : if ( fVal < fMult )
2417 : { // something is wrong there
2418 0 : bDirt = true;
2419 0 : nDig = 0;
2420 : }
2421 : else
2422 : {
2423 0 : double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) );
2424 0 : if ( bDirt )
2425 : {
2426 0 : bDirt = false;
2427 0 : --fDig;
2428 : }
2429 0 : if ( fDig <= 0.0 )
2430 0 : nDig = 0;
2431 0 : else if ( fDig >= fBase )
2432 0 : nDig = ((size_t) fBase) - 1;
2433 : else
2434 0 : nDig = (size_t) fDig;
2435 : }
2436 0 : *--p = pDigits[ nDig ];
2437 0 : fVal = fInt;
2438 : }
2439 : }
2440 6 : if ( fVal )
2441 0 : PushError( errStringOverflow );
2442 : else
2443 : {
2444 6 : if ( nBuf - (p - pBuf) <= nMinLen )
2445 4 : p = pBuf + nBuf - 1 - nMinLen;
2446 6 : PushStringBuffer( p );
2447 : }
2448 6 : if ( pBuf != aBuf )
2449 0 : delete [] pBuf;
2450 : }
2451 : else
2452 0 : PushIllegalArgument();
2453 : }
2454 6 : }
2455 :
2456 6 : void ScInterpreter::ScDecimal()
2457 : { // Text, Base
2458 6 : if ( MustHaveParamCount( GetByte(), 2 ) )
2459 : {
2460 6 : double fBase = ::rtl::math::approxFloor( GetDouble() );
2461 6 : OUString aStr = GetString().getString();
2462 6 : if ( !nGlobalError && 2 <= fBase && fBase <= 36 )
2463 : {
2464 6 : double fVal = 0.0;
2465 6 : int nBase = (int) fBase;
2466 6 : const sal_Unicode* p = aStr.getStr();
2467 12 : while ( *p == ' ' || *p == '\t' )
2468 0 : p++; // strip leading white space
2469 6 : if ( nBase == 16 )
2470 : { // evtl. hex-prefix strippen
2471 2 : if ( *p == 'x' || *p == 'X' )
2472 0 : p++;
2473 2 : else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') )
2474 0 : p += 2;
2475 : }
2476 32 : while ( *p )
2477 : {
2478 : int n;
2479 20 : if ( '0' <= *p && *p <= '9' )
2480 12 : n = *p - '0';
2481 8 : else if ( 'A' <= *p && *p <= 'Z' )
2482 8 : n = 10 + (*p - 'A');
2483 0 : else if ( 'a' <= *p && *p <= 'z' )
2484 0 : n = 10 + (*p - 'a');
2485 : else
2486 0 : n = nBase;
2487 20 : if ( nBase <= n )
2488 : {
2489 0 : if ( *(p+1) == 0 &&
2490 0 : ( (nBase == 2 && (*p == 'b' || *p == 'B'))
2491 0 : ||(nBase == 16 && (*p == 'h' || *p == 'H')) )
2492 : )
2493 : ; // 101b and F00Dh are ok
2494 : else
2495 : {
2496 0 : PushIllegalArgument();
2497 6 : return ;
2498 : }
2499 : }
2500 : else
2501 20 : fVal = fVal * fBase + n;
2502 20 : p++;
2503 :
2504 : }
2505 6 : PushDouble( fVal );
2506 : }
2507 : else
2508 0 : PushIllegalArgument();
2509 : }
2510 : }
2511 :
2512 0 : void ScInterpreter::ScConvert()
2513 : { // Value, FromUnit, ToUnit
2514 0 : if ( MustHaveParamCount( GetByte(), 3 ) )
2515 : {
2516 0 : OUString aToUnit = GetString().getString();
2517 0 : OUString aFromUnit = GetString().getString();
2518 0 : double fVal = GetDouble();
2519 0 : if ( nGlobalError )
2520 0 : PushError( nGlobalError);
2521 : else
2522 : {
2523 : // first of all search for the given order; if it can't be found then search for the inverse
2524 : double fConv;
2525 0 : if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) )
2526 0 : PushDouble( fVal * fConv );
2527 0 : else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) )
2528 0 : PushDouble( fVal / fConv );
2529 : else
2530 0 : PushNA();
2531 0 : }
2532 : }
2533 0 : }
2534 :
2535 12 : void ScInterpreter::ScRoman()
2536 : { // Value [Mode]
2537 12 : sal_uInt8 nParamCount = GetByte();
2538 12 : if( MustHaveParamCount( nParamCount, 1, 2 ) )
2539 : {
2540 12 : double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0;
2541 12 : double fVal = ::rtl::math::approxFloor( GetDouble() );
2542 12 : if( nGlobalError )
2543 0 : PushError( nGlobalError);
2544 12 : else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) )
2545 : {
2546 : static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
2547 : static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 };
2548 : static const sal_uInt16 nMaxIndex = (sal_uInt16)((sizeof(pValues)/sizeof(pValues[0])) - 1);
2549 :
2550 12 : OUString aRoman;
2551 12 : sal_uInt16 nVal = (sal_uInt16) fVal;
2552 12 : sal_uInt16 nMode = (sal_uInt16) fMode;
2553 :
2554 60 : for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ )
2555 : {
2556 48 : sal_uInt16 nIndex = 2 * i;
2557 48 : sal_uInt16 nDigit = nVal / pValues[ nIndex ];
2558 :
2559 48 : if( (nDigit % 5) == 4 )
2560 : {
2561 : // assert can't happen with nVal<4000 precondition
2562 : assert( ((nDigit == 4) ? (nIndex >= 1) : (nIndex >= 2)));
2563 :
2564 28 : sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2;
2565 28 : sal_uInt16 nSteps = 0;
2566 78 : while( (nSteps < nMode) && (nIndex < nMaxIndex) )
2567 : {
2568 22 : nSteps++;
2569 22 : if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal )
2570 22 : nIndex++;
2571 : else
2572 0 : nSteps = nMode;
2573 : }
2574 28 : aRoman += OUString( pChars[ nIndex ] );
2575 28 : aRoman += OUString( pChars[ nIndex2 ] );
2576 28 : nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] );
2577 28 : nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] );
2578 : }
2579 : else
2580 : {
2581 20 : if( nDigit > 4 )
2582 : {
2583 : // assert can't happen with nVal<4000 precondition
2584 : assert( nIndex >= 1 );
2585 0 : aRoman += OUString( pChars[ nIndex - 1 ] );
2586 : }
2587 20 : sal_Int32 nPad = nDigit % 5;
2588 20 : if (nPad)
2589 : {
2590 0 : OUStringBuffer aBuf(aRoman);
2591 0 : comphelper::string::padToLength(aBuf, aBuf.getLength() + nPad,
2592 0 : pChars[nIndex]);
2593 0 : aRoman = aBuf.makeStringAndClear();
2594 : }
2595 20 : nVal %= pValues[ nIndex ];
2596 : }
2597 : }
2598 :
2599 12 : PushString( aRoman );
2600 : }
2601 : else
2602 0 : PushIllegalArgument();
2603 : }
2604 12 : }
2605 :
2606 26 : static bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, bool& rbIsDec )
2607 : {
2608 26 : switch( cChar )
2609 : {
2610 8 : case 'M': rnValue = 1000; rbIsDec = true; break;
2611 0 : case 'D': rnValue = 500; rbIsDec = false; break;
2612 0 : case 'C': rnValue = 100; rbIsDec = true; break;
2613 0 : case 'L': rnValue = 50; rbIsDec = false; break;
2614 4 : case 'X': rnValue = 10; rbIsDec = true; break;
2615 2 : case 'V': rnValue = 5; rbIsDec = false; break;
2616 12 : case 'I': rnValue = 1; rbIsDec = true; break;
2617 0 : default: return false;
2618 : }
2619 26 : return true;
2620 : }
2621 :
2622 4 : void ScInterpreter::ScArabic()
2623 : {
2624 4 : OUString aRoman = GetString().getString();
2625 4 : if( nGlobalError )
2626 0 : PushError( nGlobalError);
2627 : else
2628 : {
2629 4 : aRoman = aRoman.toAsciiUpperCase();
2630 :
2631 4 : sal_uInt16 nValue = 0;
2632 4 : sal_uInt16 nValidRest = 3999;
2633 4 : sal_Int32 nCharIndex = 0;
2634 4 : sal_Int32 nCharCount = aRoman.getLength();
2635 4 : bool bValid = true;
2636 :
2637 22 : while( bValid && (nCharIndex < nCharCount) )
2638 : {
2639 14 : sal_uInt16 nDigit1 = 0;
2640 14 : sal_uInt16 nDigit2 = 0;
2641 14 : bool bIsDec1 = false;
2642 14 : bValid = lcl_GetArabicValue( aRoman[nCharIndex], nDigit1, bIsDec1 );
2643 14 : if( bValid && (nCharIndex + 1 < nCharCount) )
2644 : {
2645 12 : bool bIsDec2 = false;
2646 12 : bValid = lcl_GetArabicValue( aRoman[nCharIndex + 1], nDigit2, bIsDec2 );
2647 : }
2648 14 : if( bValid )
2649 : {
2650 14 : if( nDigit1 >= nDigit2 )
2651 : {
2652 12 : nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 );
2653 12 : nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2));
2654 12 : bValid = (nValidRest >= nDigit1);
2655 12 : if( bValid )
2656 12 : nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 );
2657 12 : nCharIndex++;
2658 : }
2659 2 : else if( nDigit1 * 2 != nDigit2 )
2660 : {
2661 2 : sal_uInt16 nDiff = nDigit2 - nDigit1;
2662 2 : nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff );
2663 2 : bValid = (nValidRest >= nDiff);
2664 2 : if( bValid )
2665 2 : nValidRest = nDigit1 - 1;
2666 2 : nCharIndex += 2;
2667 : }
2668 : else
2669 0 : bValid = false;
2670 : }
2671 : }
2672 4 : if( bValid )
2673 4 : PushInt( nValue );
2674 : else
2675 0 : PushIllegalArgument();
2676 4 : }
2677 4 : }
2678 :
2679 0 : void ScInterpreter::ScHyperLink()
2680 : {
2681 0 : sal_uInt8 nParamCount = GetByte();
2682 0 : if ( MustHaveParamCount( nParamCount, 1, 2 ) )
2683 : {
2684 0 : double fVal = 0.0;
2685 0 : svl::SharedString aStr;
2686 0 : ScMatValType nResultType = SC_MATVAL_STRING;
2687 :
2688 0 : if ( nParamCount == 2 )
2689 : {
2690 0 : switch ( GetStackType() )
2691 : {
2692 : case svDouble:
2693 0 : fVal = GetDouble();
2694 0 : nResultType = SC_MATVAL_VALUE;
2695 0 : break;
2696 : case svString:
2697 0 : aStr = GetString();
2698 0 : break;
2699 : case svSingleRef:
2700 : case svDoubleRef:
2701 : {
2702 0 : ScAddress aAdr;
2703 0 : if ( !PopDoubleRefOrSingleRef( aAdr ) )
2704 0 : break;
2705 :
2706 0 : ScRefCellValue aCell;
2707 0 : aCell.assign(*pDok, aAdr);
2708 0 : if (aCell.hasEmptyValue())
2709 0 : nResultType = SC_MATVAL_EMPTY;
2710 : else
2711 : {
2712 0 : sal_uInt16 nErr = GetCellErrCode(aCell);
2713 0 : if (nErr)
2714 0 : SetError( nErr);
2715 0 : else if (aCell.hasNumeric())
2716 : {
2717 0 : fVal = GetCellValue(aAdr, aCell);
2718 0 : nResultType = SC_MATVAL_VALUE;
2719 : }
2720 : else
2721 0 : GetCellString(aStr, aCell);
2722 0 : }
2723 : }
2724 0 : break;
2725 : case svMatrix:
2726 0 : nResultType = GetDoubleOrStringFromMatrix( fVal, aStr);
2727 0 : break;
2728 : case svMissing:
2729 : case svEmptyCell:
2730 0 : Pop();
2731 : // mimic xcl
2732 0 : fVal = 0.0;
2733 0 : nResultType = SC_MATVAL_VALUE;
2734 0 : break;
2735 : default:
2736 0 : PopError();
2737 0 : SetError( errIllegalArgument);
2738 : }
2739 : }
2740 0 : svl::SharedString aUrl = GetString();
2741 0 : ScMatrixRef pResMat = GetNewMat( 1, 2);
2742 0 : if (nGlobalError)
2743 : {
2744 0 : fVal = CreateDoubleError( nGlobalError);
2745 0 : nResultType = SC_MATVAL_VALUE;
2746 : }
2747 0 : if (nParamCount == 2 || nGlobalError)
2748 : {
2749 0 : if (ScMatrix::IsValueType( nResultType))
2750 0 : pResMat->PutDouble( fVal, 0);
2751 0 : else if (ScMatrix::IsRealStringType( nResultType))
2752 0 : pResMat->PutString(aStr, 0);
2753 : else // EmptyType, EmptyPathType, mimic xcl
2754 0 : pResMat->PutDouble( 0.0, 0 );
2755 : }
2756 : else
2757 0 : pResMat->PutString(aUrl, 0);
2758 0 : pResMat->PutString(aUrl, 1);
2759 0 : bMatrixFormula = true;
2760 0 : PushMatrix(pResMat);
2761 : }
2762 0 : }
2763 :
2764 : /** Resources at the website of the European Commission:
2765 : http://ec.europa.eu/economy_finance/euro/adoption/conversion/
2766 : http://ec.europa.eu/economy_finance/euro/countries/
2767 : */
2768 0 : static bool lclConvertMoney( const OUString& aSearchUnit, double& rfRate, int& rnDec )
2769 : {
2770 : struct ConvertInfo
2771 : {
2772 : const sal_Char* pCurrText;
2773 : double fRate;
2774 : int nDec;
2775 : };
2776 : static const ConvertInfo aConvertTable[] = {
2777 : { "EUR", 1.0, 2 },
2778 : { "ATS", 13.7603, 2 },
2779 : { "BEF", 40.3399, 0 },
2780 : { "DEM", 1.95583, 2 },
2781 : { "ESP", 166.386, 0 },
2782 : { "FIM", 5.94573, 2 },
2783 : { "FRF", 6.55957, 2 },
2784 : { "IEP", 0.787564, 2 },
2785 : { "ITL", 1936.27, 0 },
2786 : { "LUF", 40.3399, 0 },
2787 : { "NLG", 2.20371, 2 },
2788 : { "PTE", 200.482, 2 },
2789 : { "GRD", 340.750, 2 },
2790 : { "SIT", 239.640, 2 },
2791 : { "MTL", 0.429300, 2 },
2792 : { "CYP", 0.585274, 2 },
2793 : { "SKK", 30.1260, 2 },
2794 : { "EEK", 15.6466, 2 },
2795 : { "LVL", 0.702804, 2 },
2796 : { "LTL", 3.45280, 2 }
2797 : };
2798 :
2799 : static const size_t nConversionCount = sizeof( aConvertTable ) / sizeof( aConvertTable[0] );
2800 0 : for ( size_t i = 0; i < nConversionCount; ++i )
2801 0 : if ( aSearchUnit.equalsIgnoreAsciiCaseAscii( aConvertTable[i].pCurrText ) )
2802 : {
2803 0 : rfRate = aConvertTable[i].fRate;
2804 0 : rnDec = aConvertTable[i].nDec;
2805 0 : return true;
2806 : }
2807 0 : return false;
2808 : }
2809 :
2810 0 : void ScInterpreter::ScEuroConvert()
2811 : { //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]]
2812 0 : sal_uInt8 nParamCount = GetByte();
2813 0 : if ( MustHaveParamCount( nParamCount, 3, 5 ) )
2814 : {
2815 0 : double nPrecision = 0.0;
2816 0 : if ( nParamCount == 5 )
2817 : {
2818 0 : nPrecision = ::rtl::math::approxFloor(GetDouble());
2819 0 : if ( nPrecision < 3 )
2820 : {
2821 0 : PushIllegalArgument();
2822 0 : return;
2823 : }
2824 : }
2825 0 : bool bFullPrecision = false;
2826 0 : if ( nParamCount >= 4 )
2827 0 : bFullPrecision = GetBool();
2828 0 : OUString aToUnit = GetString().getString();
2829 0 : OUString aFromUnit = GetString().getString();
2830 0 : double fVal = GetDouble();
2831 0 : if ( nGlobalError )
2832 0 : PushError( nGlobalError);
2833 : else
2834 : {
2835 : double fFromRate;
2836 : double fToRate;
2837 : int nFromDec;
2838 : int nToDec;
2839 0 : OUString aEur( "EUR");
2840 0 : if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec )
2841 0 : && lclConvertMoney( aToUnit, fToRate, nToDec ) )
2842 : {
2843 : double fRes;
2844 0 : if ( aFromUnit.equalsIgnoreAsciiCase( aToUnit ) )
2845 0 : fRes = fVal;
2846 : else
2847 : {
2848 0 : if ( aFromUnit.equalsIgnoreAsciiCase( aEur ) )
2849 0 : fRes = fVal * fToRate;
2850 : else
2851 : {
2852 0 : double fIntermediate = fVal / fFromRate;
2853 0 : if ( nPrecision )
2854 : fIntermediate = ::rtl::math::round( fIntermediate,
2855 0 : (int) nPrecision );
2856 0 : fRes = fIntermediate * fToRate;
2857 : }
2858 0 : if ( !bFullPrecision )
2859 0 : fRes = ::rtl::math::round( fRes, nToDec );
2860 : }
2861 0 : PushDouble( fRes );
2862 : }
2863 : else
2864 0 : PushIllegalArgument();
2865 0 : }
2866 : }
2867 : }
2868 :
2869 : // BAHTTEXT
2870 : #define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214"
2871 : #define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207"
2872 : #define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207"
2873 : #define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241"
2874 : #define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210"
2875 : #define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262"
2876 : #define UTF8_TH_6 "\340\270\253\340\270\201"
2877 : #define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224"
2878 : #define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224"
2879 : #define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262"
2880 : #define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232"
2881 : #define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224"
2882 : #define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210"
2883 : #define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242"
2884 : #define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231"
2885 : #define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231"
2886 : #define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231"
2887 : #define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231"
2888 : #define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231"
2889 : #define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227"
2890 : #define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214"
2891 : #define UTF8_TH_MINUS "\340\270\245\340\270\232"
2892 :
2893 : // local functions
2894 : namespace {
2895 :
2896 0 : inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize )
2897 : {
2898 0 : rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 );
2899 0 : }
2900 :
2901 : /** Appends a digit (0 to 9) to the passed string. */
2902 0 : void lclAppendDigit( OStringBuffer& rText, sal_Int32 nDigit )
2903 : {
2904 0 : switch( nDigit )
2905 : {
2906 0 : case 0: rText.append( UTF8_TH_0 ); break;
2907 0 : case 1: rText.append( UTF8_TH_1 ); break;
2908 0 : case 2: rText.append( UTF8_TH_2 ); break;
2909 0 : case 3: rText.append( UTF8_TH_3 ); break;
2910 0 : case 4: rText.append( UTF8_TH_4 ); break;
2911 0 : case 5: rText.append( UTF8_TH_5 ); break;
2912 0 : case 6: rText.append( UTF8_TH_6 ); break;
2913 0 : case 7: rText.append( UTF8_TH_7 ); break;
2914 0 : case 8: rText.append( UTF8_TH_8 ); break;
2915 0 : case 9: rText.append( UTF8_TH_9 ); break;
2916 : default: OSL_FAIL( "lclAppendDigit - illegal digit" );
2917 : }
2918 0 : }
2919 :
2920 : /** Appends a value raised to a power of 10: nDigit*10^nPow10.
2921 : @param nDigit A digit in the range from 1 to 9.
2922 : @param nPow10 A value in the range from 2 to 5.
2923 : */
2924 0 : void lclAppendPow10( OStringBuffer& rText, sal_Int32 nDigit, sal_Int32 nPow10 )
2925 : {
2926 : OSL_ENSURE( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" );
2927 0 : lclAppendDigit( rText, nDigit );
2928 0 : switch( nPow10 )
2929 : {
2930 0 : case 2: rText.append( UTF8_TH_1E2 ); break;
2931 0 : case 3: rText.append( UTF8_TH_1E3 ); break;
2932 0 : case 4: rText.append( UTF8_TH_1E4 ); break;
2933 0 : case 5: rText.append( UTF8_TH_1E5 ); break;
2934 : default: OSL_FAIL( "lclAppendPow10 - illegal power" );
2935 : }
2936 0 : }
2937 :
2938 : /** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */
2939 0 : void lclAppendBlock( OStringBuffer& rText, sal_Int32 nValue )
2940 : {
2941 : OSL_ENSURE( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" );
2942 0 : if( nValue >= 100000 )
2943 : {
2944 0 : lclAppendPow10( rText, nValue / 100000, 5 );
2945 0 : nValue %= 100000;
2946 : }
2947 0 : if( nValue >= 10000 )
2948 : {
2949 0 : lclAppendPow10( rText, nValue / 10000, 4 );
2950 0 : nValue %= 10000;
2951 : }
2952 0 : if( nValue >= 1000 )
2953 : {
2954 0 : lclAppendPow10( rText, nValue / 1000, 3 );
2955 0 : nValue %= 1000;
2956 : }
2957 0 : if( nValue >= 100 )
2958 : {
2959 0 : lclAppendPow10( rText, nValue / 100, 2 );
2960 0 : nValue %= 100;
2961 : }
2962 0 : if( nValue > 0 )
2963 : {
2964 0 : sal_Int32 nTen = nValue / 10;
2965 0 : sal_Int32 nOne = nValue % 10;
2966 0 : if( nTen >= 1 )
2967 : {
2968 0 : if( nTen >= 3 )
2969 0 : lclAppendDigit( rText, nTen );
2970 0 : else if( nTen == 2 )
2971 0 : rText.append( UTF8_TH_20 );
2972 0 : rText.append( UTF8_TH_10 );
2973 : }
2974 0 : if( (nTen > 0) && (nOne == 1) )
2975 0 : rText.append( UTF8_TH_11 );
2976 0 : else if( nOne > 0 )
2977 0 : lclAppendDigit( rText, nOne );
2978 : }
2979 0 : }
2980 :
2981 : } // namespace
2982 :
2983 0 : void ScInterpreter::ScBahtText()
2984 : {
2985 0 : sal_uInt8 nParamCount = GetByte();
2986 0 : if ( MustHaveParamCount( nParamCount, 1 ) )
2987 : {
2988 0 : double fValue = GetDouble();
2989 0 : if( nGlobalError )
2990 : {
2991 0 : PushError( nGlobalError);
2992 0 : return;
2993 : }
2994 :
2995 : // sign
2996 0 : bool bMinus = fValue < 0.0;
2997 0 : fValue = fabs( fValue );
2998 :
2999 : // round to 2 digits after decimal point, fValue contains Satang as integer
3000 0 : fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 );
3001 :
3002 : // split Baht and Satang
3003 0 : double fBaht = 0.0;
3004 0 : sal_Int32 nSatang = 0;
3005 0 : lclSplitBlock( fBaht, nSatang, fValue, 100.0 );
3006 :
3007 0 : OStringBuffer aText;
3008 :
3009 : // generate text for Baht value
3010 0 : if( fBaht == 0.0 )
3011 : {
3012 0 : if( nSatang == 0 )
3013 0 : aText.append( UTF8_TH_0 );
3014 : }
3015 0 : else while( fBaht > 0.0 )
3016 : {
3017 0 : OStringBuffer aBlock;
3018 0 : sal_Int32 nBlock = 0;
3019 0 : lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 );
3020 0 : if( nBlock > 0 )
3021 0 : lclAppendBlock( aBlock, nBlock );
3022 : // add leading "million", if there will come more blocks
3023 0 : if( fBaht > 0.0 )
3024 0 : aBlock.insert( 0, OString(UTF8_TH_1E6 ) );
3025 :
3026 0 : aText.insert(0, aBlock.makeStringAndClear());
3027 0 : }
3028 0 : if (!aText.isEmpty())
3029 0 : aText.append( UTF8_TH_BAHT );
3030 :
3031 : // generate text for Satang value
3032 0 : if( nSatang == 0 )
3033 : {
3034 0 : aText.append( UTF8_TH_DOT0 );
3035 : }
3036 : else
3037 : {
3038 0 : lclAppendBlock( aText, nSatang );
3039 0 : aText.append( UTF8_TH_SATANG );
3040 : }
3041 :
3042 : // add the minus sign
3043 0 : if( bMinus )
3044 0 : aText.insert( 0, OString( UTF8_TH_MINUS ) );
3045 :
3046 0 : PushString( OStringToOUString(aText.makeStringAndClear(), RTL_TEXTENCODING_UTF8) );
3047 : }
3048 : }
3049 :
3050 62 : void ScInterpreter::ScGetPivotData()
3051 : {
3052 62 : sal_uInt8 nParamCount = GetByte();
3053 :
3054 62 : if (!MustHaveParamCount(nParamCount, 2, 30) || (nParamCount % 2) == 1)
3055 : {
3056 0 : PushError(errNoRef);
3057 0 : return;
3058 : }
3059 :
3060 62 : bool bOldSyntax = false;
3061 62 : if (nParamCount == 2)
3062 : {
3063 : // if the first parameter is a ref, assume old syntax
3064 30 : StackVar eFirstType = GetStackType(2);
3065 30 : if (eFirstType == svSingleRef || eFirstType == svDoubleRef)
3066 24 : bOldSyntax = true;
3067 : }
3068 :
3069 62 : std::vector<sheet::DataPilotFieldFilter> aFilters;
3070 124 : OUString aDataFieldName;
3071 62 : ScRange aBlock;
3072 :
3073 62 : if (bOldSyntax)
3074 : {
3075 24 : aDataFieldName = GetString().getString();
3076 :
3077 24 : switch (GetStackType())
3078 : {
3079 : case svDoubleRef :
3080 0 : PopDoubleRef(aBlock);
3081 0 : break;
3082 : case svSingleRef :
3083 : {
3084 24 : ScAddress aAddr;
3085 24 : PopSingleRef(aAddr);
3086 24 : aBlock = aAddr;
3087 : }
3088 24 : break;
3089 : default:
3090 0 : PushError(errNoRef);
3091 0 : return;
3092 : }
3093 : }
3094 : else
3095 : {
3096 : // Standard syntax: separate name/value pairs
3097 :
3098 38 : sal_uInt16 nFilterCount = nParamCount / 2 - 1;
3099 38 : aFilters.resize(nFilterCount);
3100 :
3101 38 : sal_uInt16 i = nFilterCount;
3102 108 : while (i-- > 0)
3103 : {
3104 : //! should allow numeric constraint values
3105 32 : aFilters[i].MatchValue = GetString().getString();
3106 32 : aFilters[i].FieldName = GetString().getString();
3107 : }
3108 :
3109 38 : switch (GetStackType())
3110 : {
3111 : case svDoubleRef :
3112 0 : PopDoubleRef(aBlock);
3113 0 : break;
3114 : case svSingleRef :
3115 : {
3116 38 : ScAddress aAddr;
3117 38 : PopSingleRef(aAddr);
3118 38 : aBlock = aAddr;
3119 : }
3120 38 : break;
3121 : default:
3122 0 : PushError(errNoRef);
3123 0 : return;
3124 : }
3125 :
3126 38 : aDataFieldName = GetString().getString(); // First parameter is data field name.
3127 : }
3128 :
3129 : // NOTE : MS Excel docs claim to use the 'most recent' which is not
3130 : // exactly the same as what we do in ScDocument::GetDPAtBlock
3131 : // However we do need to use GetDPABlock
3132 62 : ScDPObject* pDPObj = pDok->GetDPAtBlock(aBlock);
3133 62 : if (!pDPObj)
3134 : {
3135 0 : PushError(errNoRef);
3136 0 : return;
3137 : }
3138 :
3139 62 : if (bOldSyntax)
3140 : {
3141 24 : OUString aFilterStr = aDataFieldName;
3142 48 : std::vector<sheet::GeneralFunction> aFilterFuncs;
3143 24 : if (!pDPObj->ParseFilters(aDataFieldName, aFilters, aFilterFuncs, aFilterStr))
3144 : {
3145 0 : PushError(errNoRef);
3146 0 : return;
3147 24 : }
3148 :
3149 : // TODO : For now, we ignore filter functions since we couldn't find a
3150 : // live example of how they are supposed to be used. We'll support
3151 : // this again once we come across a real-world example.
3152 : }
3153 :
3154 62 : double fVal = pDPObj->GetPivotData(aDataFieldName, aFilters);
3155 62 : if (rtl::math::isNan(fVal))
3156 : {
3157 0 : PushError(errNoRef);
3158 0 : return;
3159 : }
3160 124 : PushDouble(fVal);
3161 228 : }
3162 :
3163 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|