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