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