xref: /trunk/main/sc/source/core/tool/interpr2.cxx (revision d666495c4f609ab94ddded8b0141831070b22d11)
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