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