xref: /AOO41X/main/sw/source/core/bastyp/calc.cxx (revision 47148b3bc50811ceb41802e4cc50a5db21535900)
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 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <cctype>
29 #if defined(MACOSX)
30 #include <stdlib.h>
31 #endif
32 #include <cstdlib>
33 #include <climits>
34 // #include <cmath>
35 #include <cfloat>
36 #include <hintids.hxx>
37 #include <osl/diagnose.hxx>
38 #include <rtl/math.hxx>
39 #include <editeng/langitem.hxx>
40 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
41 #include <comphelper/processfactory.hxx>
42 #include <unotools/localedatawrapper.hxx>
43 #include <unotools/charclass.hxx>
44 #include <editeng/unolingu.hxx>
45 #include <editeng/scripttypeitem.hxx>
46 #include <unotools/useroptions.hxx>
47 #include <tools/datetime.hxx>
48 #include <svl/zforlist.hxx>
49 #include <swmodule.hxx>
50 #include <doc.hxx>
51 #include <viewsh.hxx>
52 #include <docstat.hxx>
53 #include <calc.hxx>
54 #include <shellres.hxx>
55 #include <dbfld.hxx>
56 #include <expfld.hxx>
57 #include <usrfld.hxx>
58 #ifndef _DBMGR_HXX
59 #include <dbmgr.hxx>
60 #endif
61 #include <docfld.hxx>
62 #include <swunodef.hxx>
63 #include <swtypes.hxx>
64 
65 using namespace ::com::sun::star;
66 
67 // tippt sich schneller
68 #define RESOURCE ViewShell::GetShellRes()
69 
70 const sal_Char __FAR_DATA sCalc_Add[]   =   "add";
71 const sal_Char __FAR_DATA sCalc_Sub[]   =   "sub";
72 const sal_Char __FAR_DATA sCalc_Mul[]   =   "mul";
73 const sal_Char __FAR_DATA sCalc_Div[]   =   "div";
74 const sal_Char __FAR_DATA sCalc_Phd[]   =   "phd";
75 const sal_Char __FAR_DATA sCalc_Sqrt[]  =   "sqrt";
76 const sal_Char __FAR_DATA sCalc_Pow[]   =   "pow";
77 const sal_Char __FAR_DATA sCalc_Or[]    =   "or";
78 const sal_Char __FAR_DATA sCalc_Xor[]   =   "xor";
79 const sal_Char __FAR_DATA sCalc_And[]   =   "and";
80 const sal_Char __FAR_DATA sCalc_Not[]   =   "not";
81 const sal_Char __FAR_DATA sCalc_Eq[]    =   "eq";
82 const sal_Char __FAR_DATA sCalc_Neq[]   =   "neq";
83 const sal_Char __FAR_DATA sCalc_Leq[]   =   "leq";
84 const sal_Char __FAR_DATA sCalc_Geq[]   =   "geq";
85 const sal_Char __FAR_DATA sCalc_L[]     =   "l";
86 const sal_Char __FAR_DATA sCalc_G[]     =   "g";
87 const sal_Char __FAR_DATA sCalc_Sum[]   =   "sum";
88 const sal_Char __FAR_DATA sCalc_Mean[]  =   "mean";
89 const sal_Char __FAR_DATA sCalc_Min[]   =   "min";
90 const sal_Char __FAR_DATA sCalc_Max[]   =   "max";
91 const sal_Char __FAR_DATA sCalc_Sin[]   =   "sin";
92 const sal_Char __FAR_DATA sCalc_Cos[]   =   "cos";
93 const sal_Char __FAR_DATA sCalc_Tan[]   =   "tan";
94 const sal_Char __FAR_DATA sCalc_Asin[]  =   "asin";
95 const sal_Char __FAR_DATA sCalc_Acos[]  =   "acos";
96 const sal_Char __FAR_DATA sCalc_Atan[]  =   "atan";
97 const sal_Char __FAR_DATA sCalc_Round[] =   "round";
98 const sal_Char __FAR_DATA sCalc_Date[]  =   "date";
99 
100 
101 
102 //!!!!! ACHTUNG - Sortierte Liste aller Operatoren !!!!!
103 struct _CalcOp
104 {
105     union{
106         const sal_Char* pName;
107         const String* pUName;
108     };
109     SwCalcOper eOp;
110 };
111 
112 _CalcOp __READONLY_DATA aOpTable[] = {
113 /* ACOS */    {{sCalc_Acos},       CALC_ACOS},  // Arcuscosinus
114 /* ADD */     {{sCalc_Add},        CALC_PLUS},  // Addition
115 /* AND */     {{sCalc_And},        CALC_AND},   // log. und
116 /* ASIN */    {{sCalc_Asin},       CALC_ASIN},  // Arcussinus
117 /* ATAN */    {{sCalc_Atan},       CALC_ATAN},  // Arcustangens
118 /* COS */     {{sCalc_Cos},        CALC_COS},   // Cosinus
119 /* DATE */    {{sCalc_Date},       CALC_DATE},  // Date
120 /* DIV */     {{sCalc_Div},        CALC_DIV},   // Dividieren
121 /* EQ */      {{sCalc_Eq},         CALC_EQ},    // gleich
122 /* G */       {{sCalc_G},          CALC_GRE},   // groesser
123 /* GEQ */     {{sCalc_Geq},        CALC_GEQ},   // groesser gleich
124 /* L */       {{sCalc_L},          CALC_LES},   // kleiner
125 /* LEQ */     {{sCalc_Leq},        CALC_LEQ},   // kleiner gleich
126 /* MAX */     {{sCalc_Max},        CALC_MAX},   // Maximalwert
127 /* MEAN */    {{sCalc_Mean},       CALC_MEAN},  // Mittelwert
128 /* MIN */     {{sCalc_Min},        CALC_MIN},   // Minimalwert
129 /* MUL */     {{sCalc_Mul},        CALC_MUL},   // Multiplizieren
130 /* NEQ */     {{sCalc_Neq},        CALC_NEQ},   // nicht gleich
131 /* NOT */     {{sCalc_Not},        CALC_NOT},   // log. nicht
132 /* OR */      {{sCalc_Or},         CALC_OR},    // log. oder
133 /* PHD */     {{sCalc_Phd},        CALC_PHD},   // Prozent
134 /* POW */     {{sCalc_Pow},        CALC_POW},   // Potenzieren
135 /* ROUND */   {{sCalc_Round},      CALC_ROUND}, // Runden
136 /* SIN */     {{sCalc_Sin},        CALC_SIN},   // Sinus
137 /* SQRT */    {{sCalc_Sqrt},       CALC_SQRT},  // Wurzel
138 /* SUB */     {{sCalc_Sub},        CALC_MINUS}, // Subtraktion
139 /* SUM */     {{sCalc_Sum},        CALC_SUM},   // Summe
140 /* TAN */     {{sCalc_Tan},        CALC_TAN},   // Tangens
141 /* XOR */     {{sCalc_Xor},        CALC_XOR}    // log. xoder
142 };
143 
144 double __READONLY_DATA nRoundVal[] = {
145     5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
146     0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
147     0.5e-15,0.5e-16
148 };
149 
150 double __READONLY_DATA nKorrVal[] = {
151     9, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8,
152     9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14
153 };
154 
155     // First character may be any alphabetic or underscore.
156 const sal_Int32 coStartFlags =
157         i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
158         i18n::KParseTokens::ASC_UNDERSCORE |
159         i18n::KParseTokens::IGNORE_LEADING_WS;
160 
161     // Continuing characters may be any alphanumeric or underscore or dot.
162 const sal_Int32 coContFlags =
163     ( coStartFlags | i18n::KParseTokens::ASC_DOT )
164         & ~i18n::KParseTokens::IGNORE_LEADING_WS;
165 
166 
167 extern "C" {
168 static int
169 #if defined( WNT )
170  __cdecl
171 #endif
172 #if defined( ICC )
173  _Optlink
174 #endif
OperatorCompare(const void * pFirst,const void * pSecond)175     OperatorCompare( const void *pFirst, const void *pSecond)
176 {
177     int nRet = 0;
178     if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
179     {
180         if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
181             nRet = ((_CalcOp*)pFirst)->pUName->CompareTo(
182                             *((_CalcOp*)pSecond)->pUName );
183         else
184             nRet = ((_CalcOp*)pFirst)->pUName->CompareToAscii(
185                             ((_CalcOp*)pSecond)->pName );
186     }
187     else
188     {
189         if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
190             nRet = -1 * ((_CalcOp*)pSecond)->pUName->CompareToAscii(
191                             ((_CalcOp*)pFirst)->pName );
192         else
193             nRet = strcmp( ((_CalcOp*)pFirst)->pName,
194                             ((_CalcOp*)pSecond)->pName );
195     }
196     return nRet;
197 }
198 
199 }// extern "C"
200 
FindOperator(const String & rSrch)201 _CalcOp* FindOperator( const String& rSrch )
202 {
203     _CalcOp aSrch;
204     aSrch.pUName = &rSrch;
205     aSrch.eOp = CALC_NAME;
206 
207     return (_CalcOp*)bsearch(   (void*) &aSrch,
208                                 (void*) aOpTable,
209                                 sizeof( aOpTable ) / sizeof( _CalcOp ),
210                                 sizeof( _CalcOp ),
211                                 OperatorCompare );
212 }
213 
214 
215 //-----------------------------------------------------------------------------
216 
Find(const String & rStr,SwHash ** ppTable,sal_uInt16 nTblSize,sal_uInt16 * pPos)217 SwHash* Find( const String& rStr, SwHash** ppTable, sal_uInt16 nTblSize,
218                 sal_uInt16* pPos )
219 {
220     sal_uLong ii = 0;
221     for( xub_StrLen n = 0; n < rStr.Len(); ++n )
222         ii = ii << 1 ^ rStr.GetChar( n );
223     ii %= nTblSize;
224 
225     if( pPos )
226         *pPos = (sal_uInt16)ii;
227 
228     for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
229         if( rStr == pEntry->aStr )
230             return pEntry;
231     return 0;
232 }
233 
GetDocAppScriptLang(SwDoc & rDoc)234 inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
235 {
236     return ((SvxLanguageItem&)rDoc.GetDefault(
237                             GetWhichOfScript( RES_CHRATR_LANGUAGE,
238                                 GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ))
239             )).GetLanguage();
240 }
241 
lcl_ConvertToDateValue(SwDoc & rDoc,sal_Int32 nDate)242 double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
243 {
244     double nRet = 0;
245     SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
246     if( pFormatter )
247     {
248         Date* pNull = pFormatter->GetNullDate();
249         Date aDate( nDate >> 24, (nDate & 0x00FF0000) >> 16, nDate & 0x0000FFFF );
250         nRet = aDate - *pNull;
251     }
252     return nRet;
253 }
254 
255 //-----------------------------------------------------------------------------
256 
257 /******************************************************************************
258 |*
259 |*  SwCalc::SwCalc( SwDoc* pD ) :
260 |*
261 |*  Erstellung          OK 12-02-93 11:04am
262 |*  Letzte Aenderung    JP 03.11.95
263 |*
264 |******************************************************************************/
265 
SwCalc(SwDoc & rD)266 SwCalc::SwCalc( SwDoc& rD )
267     :
268     aErrExpr( aEmptyStr, SwSbxValue(), 0 ),
269     rDoc( rD ),
270     pLclData( m_aSysLocale.GetLocaleDataPtr() ),
271     pCharClass( &GetAppCharClass() ),
272     nListPor( 0 ),
273     eError( CALC_NOERR )
274 {
275     aErrExpr.aStr.AssignAscii( "~C_ERR~" );
276     memset( VarTable, 0, sizeof(VarTable) );
277     LanguageType eLang = GetDocAppScriptLang( rDoc );
278 
279     if( eLang != SvxLocaleToLanguage( pLclData->getLocale() ) ||
280         eLang != SvxLocaleToLanguage( pCharClass->getLocale() ) )
281     {
282         STAR_NMSPC::lang::Locale aLocale( SvxCreateLocale( eLang ));
283         STAR_REFERENCE( lang::XMultiServiceFactory ) xMSF(
284                             ::comphelper::getProcessServiceFactory() );
285         pCharClass = new CharClass( xMSF, aLocale );
286         pLclData = new LocaleDataWrapper( xMSF, aLocale );
287     }
288 
289     sCurrSym = pLclData->getCurrSymbol();
290     sCurrSym.EraseLeadingChars().EraseTrailingChars();
291     pCharClass->toLower( sCurrSym );
292 
293 static sal_Char __READONLY_DATA
294     sNType0[] = "false",
295     sNType1[] = "true",
296     sNType2[] = "pi",
297     sNType3[] = "e",
298     sNType4[] = "tables",
299     sNType5[] = "graf",
300     sNType6[] = "ole",
301     sNType7[] = "page",
302     sNType8[] = "para",
303     sNType9[] = "word",
304     sNType10[]= "char",
305 
306     sNType11[] = "user_firstname" ,
307     sNType12[] = "user_lastname" ,
308     sNType13[] = "user_initials" ,
309     sNType14[] = "user_company" ,
310     sNType15[] = "user_street" ,
311     sNType16[] = "user_country" ,
312     sNType17[] = "user_zipcode" ,
313     sNType18[] = "user_city" ,
314     sNType19[] = "user_title" ,
315     sNType20[] = "user_position" ,
316     sNType21[] = "user_tel_work" ,
317     sNType22[] = "user_tel_home" ,
318     sNType23[] = "user_fax" ,
319     sNType24[] = "user_email" ,
320     sNType25[] = "user_state" ,
321     sNType26[] = "graph"
322     ;
323 
324 static const sal_Char* __READONLY_DATA sNTypeTab[ 27 ] =
325 {
326     sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
327     sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
328     sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
329     sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
330     sNType24,
331 
332     // diese sind mit doppelten HashIds
333     sNType25, sNType26
334 };
335 static sal_uInt16 __READONLY_DATA aHashValue[ 27 ] =
336 {
337     34, 38, 43,  7, 18, 32, 22, 29, 30, 33,  3,
338     28, 24, 40,  9, 11, 26, 45,  4, 23, 36, 44, 19,  5,  1,
339     // diese sind mit doppelten HashIds
340     11, 38
341 };
342 static sal_uInt16 __READONLY_DATA aAdrToken[ 12 ] =
343 {
344     USER_OPT_COMPANY, USER_OPT_STREET, USER_OPT_COUNTRY, USER_OPT_ZIP,
345     USER_OPT_CITY, USER_OPT_TITLE, USER_OPT_POSITION, USER_OPT_TELEPHONEWORK,
346     USER_OPT_TELEPHONEHOME, USER_OPT_FAX, USER_OPT_EMAIL, USER_OPT_STATE
347 };
348 
349 static sal_uInt16 SwDocStat::* __READONLY_DATA aDocStat1[ 3 ] =
350 {
351     &SwDocStat::nTbl, &SwDocStat::nGrf, &SwDocStat::nOLE
352 };
353 static sal_uLong SwDocStat::* __READONLY_DATA aDocStat2[ 4 ] =
354 {
355     &SwDocStat::nPage, &SwDocStat::nPara,
356     &SwDocStat::nWord, &SwDocStat::nChar
357 };
358 
359 #if TBLSZ != 47
360 #error Alle Hashwerte angepasst?
361 #endif
362 
363     const SwDocStat& rDocStat = rDoc.GetDocStat();
364 
365     SwSbxValue nVal;
366     String sTmpStr;
367     sal_uInt16 n;
368 
369     for( n = 0; n < 25; ++n )
370     {
371         sTmpStr.AssignAscii( sNTypeTab[ n ] );
372         VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
373     }
374 
375     ((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( sal_False );
376     ((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( sal_True );
377     ((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
378     ((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
379 
380     for( n = 0; n < 3; ++n )
381         ((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ]  );
382     for( n = 0; n < 4; ++n )
383         ((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ]  );
384 
385     SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
386 
387     ((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( (String)rUserOptions.GetFirstName() );
388     ((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( (String)rUserOptions.GetLastName() );
389     ((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( (String)rUserOptions.GetID() );
390 
391     for( n = 0; n < 11; ++n )
392         ((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
393                                         (String)rUserOptions.GetToken( aAdrToken[ n ] ));
394 
395     nVal.PutString( (String)rUserOptions.GetToken( aAdrToken[ 11 ] ));
396     sTmpStr.AssignAscii( sNTypeTab[ 25 ] );
397     VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
398 
399 // at time its better not to use "graph", because then the im-/export have
400 // to change in all formulas this name.
401 //  nVal.PutLong( rDocStat.*aDocStat1[ 1 ]  );
402 //  VarTable[ aHashValue[ 26 ] ]->pNext = new SwCalcExp(
403 //                                              sNTypeTab[ 26 ], nVal, 0 );
404 }
405 
406 /******************************************************************************
407 |*
408 |*  SwCalc::~SwCalc()
409 |*
410 |*  Erstellung          OK 12-02-93 11:04am
411 |*  Letzte Aenderung    OK 12-02-93 11:04am
412 |*
413 |******************************************************************************/
414 
~SwCalc()415 SwCalc::~SwCalc()
416 {
417     for( sal_uInt16 n = 0; n < TBLSZ; ++n )
418         delete VarTable[n];
419     if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
420         delete pLclData;
421     if( pCharClass != &GetAppCharClass() )
422         delete pCharClass;
423 }
424 
425 /******************************************************************************
426 |*
427 |*  SwSbxValue SwCalc::Calculate( const String& rStr )
428 |*
429 |*  Erstellung          OK 12-02-93 11:04am
430 |*  Letzte Aenderung    OK 12-02-93 11:04am
431 |*
432 |******************************************************************************/
433 
Calculate(const String & rStr)434 SwSbxValue SwCalc::Calculate( const String& rStr )
435 {
436     eError = CALC_NOERR;
437     SwSbxValue nResult;
438 
439     if( !rStr.Len() )
440         return nResult;
441 
442     nListPor = 0;
443     eCurrListOper = CALC_PLUS;          // defaulten auf Summe
444 
445     sCommand = rStr;
446     nCommandPos = 0;
447 
448     while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
449         nResult = Expr();
450 
451     if( eError )
452         nResult.PutDouble( DBL_MAX );
453 
454     return nResult;
455 }
456 
457 /******************************************************************************
458 |*
459 |*  String SwCalc::GetStrResult( SwSbxValue nValue, sal_Bool bRound = sal_True )
460 |*  Beschreibung        Der Parameter bRound ist auf sal_True defaultet und darf
461 |*                      nur beim errechnen von Tabellenzellen auf sal_False gesetzt
462 |*                      werden, damit keine Rundungsfehler beim zusammenstellen
463 |*                      der Formel entstehen.
464 |*  Erstellung          OK 12-02-93 11:04am
465 |*  Letzte Aenderung    JP 19.02.98
466 |*
467 |******************************************************************************/
468 
GetStrResult(const SwSbxValue & rVal,sal_Bool bRound)469 String SwCalc::GetStrResult( const SwSbxValue& rVal, sal_Bool bRound )
470 {
471     if( !rVal.IsDouble() )
472         return rVal.GetString();
473 
474     return GetStrResult( rVal.GetDouble(), bRound );
475 }
476 
477 
GetStrResult(double nValue,sal_Bool)478 String SwCalc::GetStrResult( double nValue, sal_Bool )
479 {
480     if( nValue >= DBL_MAX )
481         switch( eError )
482         {
483             case CALC_SYNTAX    :   return RESOURCE->aCalc_Syntax;
484             case CALC_ZERODIV   :   return RESOURCE->aCalc_ZeroDiv;
485             case CALC_BRACK     :   return RESOURCE->aCalc_Brack;
486             case CALC_POWERR    :   return RESOURCE->aCalc_Pow;
487             case CALC_VARNFND   :   return RESOURCE->aCalc_VarNFnd;
488             case CALC_OVERFLOW  :   return RESOURCE->aCalc_Overflow;
489             case CALC_WRONGTIME :   return RESOURCE->aCalc_WrongTime;
490             default             :   return RESOURCE->aCalc_Default;
491         }
492 
493     sal_uInt16  nDec = 15; //pLclData->getNumDigits();
494     String  aRetStr( ::rtl::math::doubleToUString( nValue,
495                 rtl_math_StringFormat_Automatic,
496                 nDec,
497                 pLclData->getNumDecimalSep().GetChar(0),
498                 true ));
499 
500     return aRetStr;
501 }
502 
503 /******************************************************************************
504 |*
505 |*  SwCalcExp* SwCalc::VarLook( const String& )
506 |*
507 |*  Erstellung          OK 12-02-93 11:04am
508 |*  Letzte Aenderung    JP 15.11.99
509 |*
510 |******************************************************************************/
511 
VarInsert(const String & rStr)512 SwCalcExp* SwCalc::VarInsert( const String &rStr )
513 {
514     String aStr( rStr );
515     pCharClass->toLower( aStr );
516     return VarLook( aStr, 1 );
517 }
518 
519 /******************************************************************************
520 |*
521 |*  SwCalcExp* SwCalc::VarLook( const String& , sal_uInt16 ins )
522 |*
523 |*  Erstellung          OK 12-02-93 11:04am
524 |*  Letzte Aenderung    JP 15.11.99
525 |*
526 |******************************************************************************/
VarLook(const String & rStr,sal_uInt16 ins)527 SwCalcExp* SwCalc::VarLook( const String& rStr, sal_uInt16 ins )
528 {
529     aErrExpr.nValue.SetVoidValue(false);
530 
531     sal_uInt16 ii = 0;
532     String aStr( rStr );
533     pCharClass->toLower( aStr );
534 
535     SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
536 
537     if( !pFnd )
538     {
539         // dann sehen wir mal im Doc nach:
540         SwHash** ppDocTbl = rDoc.GetUpdtFlds().GetFldTypeTable();
541         for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
542             if( aStr == pEntry->aStr )
543             {
544                 // dann hier zufuegen
545                 pFnd = new SwCalcExp( aStr, SwSbxValue(),
546                                     ((SwCalcFldType*)pEntry)->pFldType );
547                 pFnd->pNext = *(VarTable+ii);
548                 *(VarTable+ii) = pFnd;
549                 break;
550             }
551     }
552 
553     if( pFnd )
554     {
555         SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
556 
557         if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
558         {
559             SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
560             if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
561                 pFndExp->nValue.PutString( pUFld->GetContent() );
562             else if( !pUFld->IsValid() )
563             {
564                 // Die aktuellen Werte sichern . . .
565                 sal_uInt16          nOld_ListPor        = nListPor;
566                 SwSbxValue      nOld_LastLeft       = nLastLeft;
567                 SwSbxValue      nOld_NumberValue    = nNumberValue;
568                 xub_StrLen      nOld_CommandPos     = nCommandPos;
569                 SwCalcOper      eOld_CurrOper       = eCurrOper;
570                 SwCalcOper      eOld_CurrListOper   = eCurrListOper;
571 
572                 pFndExp->nValue.PutDouble( pUFld->GetValue( *this ) );
573 
574                 // . . . und zurueck damit.
575                 nListPor        = nOld_ListPor;
576                 nLastLeft       = nOld_LastLeft;
577                 nNumberValue    = nOld_NumberValue;
578                 nCommandPos     = nOld_CommandPos;
579                 eCurrOper       = eOld_CurrOper;
580                 eCurrListOper   = eOld_CurrListOper;
581             }
582             else
583                 pFndExp->nValue.PutDouble( pUFld->GetValue() );
584         }
585         return pFndExp;
586     }
587 
588     // Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
589     // DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
590     // #101436#: At this point the "real" case variable has to be used
591     String sTmpName( rStr );
592     ::ReplacePoint( sTmpName );
593 
594     if( !ins )
595     {
596         SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
597 
598         // Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
599         // DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
600         String sDBName(GetDBName( sTmpName ));
601         String sSourceName(sDBName.GetToken(0, DB_DELIM));
602         String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
603         if( pMgr && sSourceName.Len() && sTableName.Len() &&
604             pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
605         {
606             String sColumnName( GetColumnName( sTmpName ));
607             ASSERT (sColumnName.Len(), "DB-Spaltenname fehlt!");
608 
609             String sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
610             pCharClass->toLower(sDBNum);
611 
612             // Hier nochmal initialisieren, da das nicht mehr in docfld
613             // fuer Felder != RES_DBFLD geschieht. Z.B. wenn ein Expressionfield
614             // vor einem DB_Field in einem Dok vorkommt.
615             VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
616 
617             if( sDBNum.EqualsIgnoreCaseAscii(sColumnName) )
618             {
619                 aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
620                 return &aErrExpr;
621             }
622 
623             sal_uLong nTmpRec = 0;
624             if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
625                 nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
626 
627             String sResult;
628             double nNumber = DBL_MAX;
629 
630             long nLang = SvxLocaleToLanguage( pLclData->getLocale() );
631             if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
632                                     nTmpRec, nLang, sResult, &nNumber ))
633             {
634                 if (nNumber != DBL_MAX)
635                     aErrExpr.nValue.PutDouble( nNumber );
636                 else
637                     aErrExpr.nValue.PutString( sResult );
638 
639                 return &aErrExpr;
640             }
641         }
642         else
643         {
644             //data source was not available - set return to "NoValue"
645             aErrExpr.nValue.SetVoidValue(true);
646         }
647         // auf keinen fall eintragen!!
648         return &aErrExpr;
649     }
650 
651 
652     SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
653     pNewExp->pNext = VarTable[ ii ];
654     VarTable[ ii ] = pNewExp;
655 
656     String sColumnName( GetColumnName( sTmpName ));
657     ASSERT( sColumnName.Len(), "DB-Spaltenname fehlt!" );
658     if( sColumnName.EqualsIgnoreCaseAscii(
659                             SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
660     {
661         SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
662         String sDBName(GetDBName( sTmpName ));
663         String sSourceName(sDBName.GetToken(0, DB_DELIM));
664         String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
665         if( pMgr && sSourceName.Len() && sTableName.Len() &&
666             pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
667             !pMgr->IsInMerge())
668             pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
669         else
670             pNewExp->nValue.SetVoidValue(true);
671     }
672 
673     return pNewExp;
674 }
675 
676 /******************************************************************************
677 |*
678 |*  sal_Bool SwCalc::VarChange( const String& rStr, const SwSbxValue nValue )
679 |*
680 |*  Erstellung          OK 12-02-93 11:04am
681 |*  Letzte Aenderung    OK 12-02-93 11:04am
682 |*
683 |******************************************************************************/
684 
VarChange(const String & rStr,double nValue)685 void SwCalc::VarChange( const String& rStr, double nValue )
686 {
687     SwSbxValue aVal( nValue );
688     VarChange( rStr, aVal );
689 }
690 
VarChange(const String & rStr,const SwSbxValue & rValue)691 void SwCalc::VarChange( const String& rStr, const SwSbxValue& rValue )
692 {
693     String aStr( rStr );
694     pCharClass->toLower( aStr );
695 
696     sal_uInt16 nPos = 0;
697     SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
698 
699     if( !pFnd )
700     {
701         pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
702         pFnd->pNext = VarTable[ nPos ];
703         VarTable[ nPos ] = pFnd;
704     }
705     else
706         pFnd->nValue = rValue;
707 }
708 
709 /******************************************************************************
710 |*
711 |*  sal_Bool SwCalc::Push( const void* pPtr )
712 |*
713 |*  Erstellung          OK 12-02-93 11:05am
714 |*  Letzte Aenderung    OK 12-02-93 11:05am
715 |*
716 |******************************************************************************/
717 
Push(const VoidPtr pPtr)718 sal_Bool SwCalc::Push( const VoidPtr pPtr )
719 {
720     if( USHRT_MAX != aRekurStk.GetPos( pPtr ) )
721         return sal_False;
722 
723     aRekurStk.Insert( pPtr, aRekurStk.Count() );
724     return sal_True;
725 }
726 
727 /******************************************************************************
728 |*
729 |*  void SwCalc::Pop( const void* pPtr )
730 |*
731 |*  Erstellung          OK 12-02-93 11:05am
732 |*  Letzte Aenderung    OK 12-02-93 11:05am
733 |*
734 |******************************************************************************/
735 
Pop(const VoidPtr)736 void SwCalc::Pop( const VoidPtr )
737 {
738     ASSERT( aRekurStk.Count(), "SwCalc: Pop auf ungueltigen Ptr" );
739 
740     aRekurStk.Remove( aRekurStk.Count() - 1 );
741 }
742 
743 
744 /******************************************************************************
745 |*
746 |*  SwCalcOper SwCalc::GetToken()
747 |*
748 |*  Erstellung          OK 12-02-93 11:05am
749 |*  Letzte Aenderung    JP 03.11.95
750 |*
751 |******************************************************************************/
752 
GetToken()753 SwCalcOper SwCalc::GetToken()
754 {
755 #if OSL_DEBUG_LEVEL > 1
756 //JP 25.01.2001: static for switch back to the "old" implementation of the
757 //              calculator, which don't use the I18N routines.
758 static int nUseOld = 0;
759 if( !nUseOld )
760 {
761 #endif
762 
763     if( nCommandPos >= sCommand.Len() )
764         return eCurrOper = CALC_ENDCALC;
765 
766     using namespace ::com::sun::star::i18n;
767     {
768         // Parse any token.
769         ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
770                                                     coStartFlags, aEmptyStr,
771                                                     coContFlags, aEmptyStr );
772 
773         sal_Bool bSetError = sal_True;
774         xub_StrLen nRealStt = nCommandPos + (xub_StrLen)aRes.LeadingWhiteSpace;
775         if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
776         {
777             nNumberValue.PutDouble( aRes.Value );
778             eCurrOper = CALC_NUMBER;
779             bSetError = sal_False;
780         }
781         else if( aRes.TokenType & KParseType::IDENTNAME )
782         {
783             String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
784             //#101436#: the variable may contain a database name it must not be converted to lower case
785             // instead all further comparisons must be done case-insensitive
786             //pCharClass->toLower( aName );
787             String sLowerCaseName(aName);
788             pCharClass->toLower( sLowerCaseName );
789             // Currency-Symbol abfangen
790             if( sLowerCaseName == sCurrSym )
791             {
792                 nCommandPos = (xub_StrLen)aRes.EndPos;
793                 return GetToken();  // also nochmal aufrufen
794             }
795 
796             // Operations abfangen
797             _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
798             if( pFnd )
799             {
800                 switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
801                 {
802                     case CALC_SUM:
803                     case CALC_MEAN:
804                         eCurrListOper = CALC_PLUS;
805                         break;
806                     case CALC_MIN:
807                         eCurrListOper = CALC_MIN_IN;
808                         break;
809                     case CALC_MAX:
810                         eCurrListOper = CALC_MAX_IN;
811                         break;
812                     case CALC_DATE:
813                         eCurrListOper = CALC_MONTH;
814                         break;
815                     default:
816                         break;
817                 }
818                 nCommandPos = (xub_StrLen)aRes.EndPos;
819                 return eCurrOper;
820             }
821             aVarName = aName;
822             eCurrOper = CALC_NAME;
823             bSetError = sal_False;
824         }
825         else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
826         {
827             nNumberValue.PutString( String( aRes.DequotedNameOrString ));
828             eCurrOper = CALC_NUMBER;
829             bSetError = sal_False;
830         }
831         else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
832         {
833             String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
834             if( 1 == aName.Len() )
835             {
836                 bSetError = sal_False;
837                 sal_Unicode ch = aName.GetChar( 0 );
838                 switch( ch )
839                 {
840                 case ';': if( CALC_MONTH == eCurrListOper ||
841                               CALC_DAY == eCurrListOper )
842                           {
843                               eCurrOper = eCurrListOper;
844                               break;
845                           }
846                 case '\n':
847                             eCurrOper = CALC_PRINT;
848                             break;
849                 case '%':
850                 case '^':
851                 case '*':
852                 case '/':
853                 case '+':
854                 case '-':
855                 case '(':
856                 case ')':   eCurrOper = SwCalcOper(ch);
857                             break;
858 
859                 case '=':
860                 case '!':
861                         {
862                             SwCalcOper eTmp2;
863                             if( '=' == ch )
864                                 eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
865                             else
866                                 eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
867 
868                             if( aRes.EndPos < sCommand.Len() &&
869                                 '=' == sCommand.GetChar( (xub_StrLen)aRes.EndPos ) )
870                             {
871                                 eCurrOper = eTmp2;
872                                 ++aRes.EndPos;
873                             }
874                         }
875                         break;
876 
877                 case cListDelim :
878                         eCurrOper = eCurrListOper;
879                         break;
880 
881                 case '[':
882                         if( aRes.EndPos < sCommand.Len() )
883                         {
884                             aVarName.Erase();
885                             xub_StrLen nFndPos = (xub_StrLen)aRes.EndPos,
886                                         nSttPos = nFndPos;
887 
888                             do{
889                                 if( STRING_NOTFOUND != ( nFndPos =
890                                     sCommand.Search( ']', nFndPos )) )
891                                 {
892                                     // ignore the ]
893                                     if( '\\' == sCommand.GetChar(nFndPos-1))
894                                     {
895                                         aVarName += sCommand.Copy( nSttPos,
896                                                     nFndPos - nSttPos - 1 );
897                                         nSttPos = ++nFndPos;
898                                     }
899                                     else
900                                         break;
901                                 }
902                             } while( STRING_NOTFOUND != nFndPos );
903 
904                             if( STRING_NOTFOUND != nFndPos )
905                             {
906                                 if( nSttPos != nFndPos )
907                                     aVarName += sCommand.Copy( nSttPos,
908                                                     nFndPos - nSttPos );
909                                 aRes.EndPos = nFndPos + 1;
910                                 eCurrOper = CALC_NAME;
911                             }
912                             else
913                                 bSetError = sal_True;
914                         }
915                         else
916                             bSetError = sal_True;
917                         break;
918 
919                 default:
920                     bSetError = sal_True;
921                     break;
922                 }
923             }
924         }
925         else if( aRes.TokenType & KParseType::BOOLEAN )
926         {
927             String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
928             if( aName.Len() )
929             {
930                 sal_Unicode ch = aName.GetChar(0);
931 
932                 bSetError = sal_True;
933                 if ('<' == ch || '>' == ch)
934                 {
935                     bSetError = sal_False;
936 
937                     SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
938                     eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
939 
940                     if( 2 == aName.Len() && '=' == aName.GetChar(1) )
941                         eCurrOper = eTmp2;
942                     else if( 1 != aName.Len() )
943                         bSetError = sal_True;
944                 }
945             }
946         }
947         else if( nRealStt == sCommand.Len() )
948         {
949             eCurrOper = CALC_ENDCALC;
950             bSetError = sal_False;
951         }
952 
953         if( bSetError )
954         {
955             eError = CALC_SYNTAX;
956             eCurrOper = CALC_PRINT;
957         }
958         nCommandPos = (xub_StrLen)aRes.EndPos;
959     };
960 
961 #if OSL_DEBUG_LEVEL > 1
962 
963 #define NextCh( s, n )  (nCommandPos < sCommand.Len() ? sCommand.GetChar( nCommandPos++ ) : 0)
964 
965 }
966 else
967 {
968     sal_Unicode ch;
969     sal_Unicode cTSep = pLclData->getNumThousandSep().GetChar(0),
970                 cDSep = pLclData->getNumDecimalSep().GetChar(0);
971 
972     do {
973         if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
974             return eCurrOper = CALC_ENDCALC;
975     } while ( ch == '\t' || ch == ' ' || ch == cTSep );
976 
977     if( ch == cDSep )
978         ch = '.';
979 
980     switch( ch )
981     {
982         case ';': if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
983                   {
984                       eCurrOper = eCurrListOper;
985                       break;
986                   } // else .. no break
987         case '\n':
988                     {
989                         sal_Unicode c;
990                         while( nCommandPos < sCommand.Len() && ( ( c =
991                                 sCommand.GetChar( nCommandPos ) ) == ' ' ||
992                                 c == '\t' || c == '\x0a' || c == '\x0d' ))
993                             ++nCommandPos;
994                         eCurrOper = CALC_PRINT;
995                     }
996                     break;
997         case '%':
998         case '^':
999         case '*':
1000         case '/':
1001         case '+':
1002         case '-':
1003         case '(':
1004         case ')':   eCurrOper = SwCalcOper(ch);
1005                     break;
1006 
1007         case '=':   if( '=' == sCommand.GetChar( nCommandPos ) )
1008                     {
1009                         ++nCommandPos;
1010                         eCurrOper = CALC_EQ;
1011                     }
1012                     else
1013                         eCurrOper = SwCalcOper(ch);
1014                     break;
1015 
1016         case '!':   if( '=' == sCommand.GetChar( nCommandPos ) )
1017                     {
1018                         ++nCommandPos;
1019                         eCurrOper = CALC_NEQ;
1020                     }
1021                     else
1022                         eCurrOper = CALC_NOT;
1023                     break;
1024 
1025         case '>':
1026         case '<':   eCurrOper = '>' == ch  ? CALC_GRE : CALC_LES;
1027                     if( '=' == (ch = sCommand.GetChar( nCommandPos ) ) )
1028                     {
1029                         ++nCommandPos;
1030                         eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
1031                     }
1032                     else if( ' ' != ch )
1033                     {
1034                         eError = CALC_SYNTAX;
1035                         eCurrOper = CALC_PRINT;
1036                     }
1037                     break;
1038 
1039         case cListDelim :
1040                     eCurrOper = eCurrListOper;
1041                     break;
1042 
1043         case '0':   case '1':   case '2':   case '3':   case '4':
1044         case '5':   case '6':   case '7':   case '8':   case '9':
1045         case ',':
1046         case '.':   {
1047                         double nVal;
1048                         --nCommandPos;      //  auf das 1. Zeichen zurueck
1049                         if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
1050                         {
1051                             nNumberValue.PutDouble( nVal );
1052                             eCurrOper = CALC_NUMBER;
1053                         }
1054                         else
1055                         {
1056                             // fehlerhafte Zahl
1057                             eError = CALC_SYNTAX;
1058                             eCurrOper = CALC_PRINT;
1059                         }
1060                     }
1061                     break;
1062 
1063         case '[':   {
1064                         String aStr;
1065                         sal_Bool bIgnore = sal_False;
1066                         do {
1067                             while( 0 != ( ch = NextCh( sCommand, nCommandPos  ))
1068                                     && ch != ']' )
1069                             {
1070                                 if( !bIgnore && '\\' == ch )
1071                                     bIgnore = sal_True;
1072                                 else if( bIgnore )
1073                                     bIgnore = sal_False;
1074                                 aStr += ch;
1075                             }
1076 
1077                             if( !bIgnore )
1078                                 break;
1079 
1080                             aStr.SetChar( aStr.Len() - 1, ch );
1081                         } while( ch );
1082 
1083                         aVarName = aStr;
1084                         eCurrOper = CALC_NAME;
1085                     }
1086                     break;
1087 
1088         case '"':   {
1089                         xub_StrLen nStt = nCommandPos;
1090                         while( 0 != ( ch = NextCh( sCommand, nCommandPos ) )
1091                                 && '"' != ch )
1092                             ;
1093 
1094                         xub_StrLen nLen = nCommandPos - nStt;
1095                         if( '"' == ch )
1096                             --nLen;
1097                         nNumberValue.PutString( sCommand.Copy( nStt, nLen ));
1098                         eCurrOper = CALC_NUMBER;
1099                     }
1100                     break;
1101 
1102         default:    if( ch && pCharClass->isLetter( sCommand, nCommandPos - 1)
1103                             || '_' == ch )
1104                     {
1105                         xub_StrLen nStt = nCommandPos-1;
1106                         while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
1107                                (pCharClass->isLetterNumeric(
1108                                                 sCommand, nCommandPos - 1) ||
1109                                 ch == '_' || ch == '.' ) )
1110                             ;
1111 
1112                         if( ch )
1113                             --nCommandPos;
1114 
1115                         String aStr( sCommand.Copy( nStt, nCommandPos-nStt ));
1116                         pCharClass->toLower( aStr );
1117 
1118 
1119                         // Currency-Symbol abfangen
1120                         if( aStr == sCurrSym )
1121                             return GetToken();  // also nochmal aufrufen
1122 
1123                         // Operations abfangen
1124                         _CalcOp* pFnd = ::FindOperator( aStr );
1125                         if( pFnd )
1126                         {
1127                             switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
1128                             {
1129                                 case CALC_SUM  :
1130                                 case CALC_MEAN : eCurrListOper = CALC_PLUS;
1131                                                     break;
1132                                 case CALC_MIN  : eCurrListOper = CALC_MIN_IN;
1133                                                     break;
1134                                 case CALC_MAX  : eCurrListOper = CALC_MAX_IN;
1135                                                     break;
1136                                 case CALC_DATE  : eCurrListOper = CALC_MONTH;
1137                                                     break;
1138                                 default :
1139                                     break;
1140                             }
1141                             return eCurrOper;
1142                         }
1143                         aVarName = aStr;
1144                         eCurrOper = CALC_NAME;
1145                     }
1146                     else
1147                     {
1148                         eError = CALC_SYNTAX;
1149                         eCurrOper = CALC_PRINT;
1150                     }
1151                     break;
1152     }
1153 
1154 }
1155 #endif
1156     return eCurrOper;
1157 }
1158 
1159 /******************************************************************************
1160 |*
1161 |*  SwSbxValue SwCalc::Term()
1162 |*
1163 |*  Erstellung          OK 12-02-93 11:05am
1164 |*  Letzte Aenderung    JP 16.01.96
1165 |*
1166 |******************************************************************************/
1167 
Term()1168 SwSbxValue SwCalc::Term()
1169 {
1170     SwSbxValue left( Prim() );
1171     nLastLeft = left;
1172     for(;;)
1173     {
1174         sal_uInt16 nSbxOper = USHRT_MAX;
1175 
1176         switch( eCurrOper )
1177         {
1178 // wir haben kein Bitweises verodern, oder ?
1179 //          case CALC_AND:  eSbxOper = SbxAND;  break;
1180 //          case CALC_OR:   eSbxOper = SbxOR;   break;
1181 //          case CALC_XOR:  eSbxOper = SbxXOR;  break;
1182             case CALC_AND:  {
1183                                 GetToken();
1184                                 sal_Bool bB = Prim().GetBool();
1185                                 left.PutBool( left.GetBool() && bB );
1186                             }
1187                             break;
1188             case CALC_OR:   {
1189                                 GetToken();
1190                                 sal_Bool bB = Prim().GetBool();
1191                                 left.PutBool( left.GetBool() || bB );
1192                             }
1193                             break;
1194             case CALC_XOR:  {
1195                                 GetToken();
1196                                 sal_Bool bR = Prim().GetBool();
1197                                 sal_Bool bL = left.GetBool();
1198                                 left.PutBool( (bL && !bR) || (!bL && bR) );
1199                             }
1200                             break;
1201 
1202             case CALC_EQ:   nSbxOper = SbxEQ;   break;
1203             case CALC_NEQ:  nSbxOper = SbxNE;   break;
1204             case CALC_LEQ:  nSbxOper = SbxLE;   break;
1205             case CALC_GEQ:  nSbxOper = SbxGE;   break;
1206             case CALC_GRE:  nSbxOper = SbxGT;   break;
1207             case CALC_LES:  nSbxOper = SbxLT;   break;
1208 
1209             case CALC_MUL:  nSbxOper = SbxMUL;  break;
1210             case CALC_DIV:  nSbxOper = SbxDIV;  break;
1211 
1212             case CALC_MIN_IN:
1213                             {
1214                                 GetToken();
1215                                 SwSbxValue e = Prim();
1216                                 left = left.GetDouble() < e.GetDouble()
1217                                             ? left : e;
1218                             }
1219                             break;
1220             case CALC_MAX_IN:
1221                             {
1222                                 GetToken();
1223                                 SwSbxValue e = Prim();
1224                                 left = left.GetDouble() > e.GetDouble()
1225                                             ? left : e;
1226                             }
1227                             break;
1228             case CALC_MONTH:
1229                             {
1230                                 GetToken();
1231                                 SwSbxValue e = Prim();
1232                                 sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
1233                                 nYear = nYear & 0x0000FFFF;
1234                                 sal_Int32 nMonth = (sal_Int32) floor( e.GetDouble() );
1235                                 nMonth = ( nMonth & 0x000000FF ) << 16;
1236                                 left.PutLong( nMonth + nYear );
1237                                 eCurrOper = CALC_DAY;
1238                             }
1239                             break;
1240             case CALC_DAY:
1241                             {
1242                                 GetToken();
1243                                 SwSbxValue e = Prim();
1244                                 sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
1245                                 nYearMonth = nYearMonth & 0x00FFFFFF;
1246                                 sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
1247                                 nDay = ( nDay & 0x000000FF ) << 24;
1248                                 left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
1249                             }
1250                             break;
1251             case CALC_ROUND:
1252                             {
1253                                 GetToken();
1254                                 SwSbxValue e = Prim();
1255 
1256                                 double fVal = 0;
1257                                 double fFac = 1;
1258                                 sal_Int32 nDec = (sal_Int32) floor( e.GetDouble() );
1259                                 if( nDec < -20 || nDec > 20 )
1260                                 {
1261                                     eError = CALC_OVERFLOW;
1262                                     left.Clear();
1263                                     return left;
1264                                 }
1265                                 fVal = left.GetDouble();
1266                                 sal_uInt16 i;
1267                                 if( nDec >= 0)
1268                                     for (i = 0; i < (sal_uInt16) nDec; ++i )
1269                                         fFac *= 10.0;
1270                                 else
1271                                     for (i = 0; i < (sal_uInt16) -nDec; ++i )
1272                                         fFac /= 10.0;
1273 
1274                                 fVal *= fFac;
1275 
1276                                 sal_Bool bSign;
1277                                 if (fVal < 0.0)
1278                                 {
1279                                     fVal *= -1.0;
1280                                     bSign = sal_True;
1281                                 }
1282                                 else
1283                                     bSign = sal_False;
1284 
1285                                 // runden
1286                                 double fNum = fVal;             // find the exponent
1287                                 int nExp = 0;
1288                                 if( fNum > 0 )
1289                                 {
1290                                     while( fNum < 1.0 ) fNum *= 10.0, --nExp;
1291                                     while( fNum >= 10.0 ) fNum /= 10.0, ++nExp;
1292                                 }
1293                                 nExp = 15 - nExp;
1294                                 if( nExp > 15 )
1295                                     nExp = 15;
1296                                 else if( nExp <= 1 )
1297                                     nExp = 0;
1298                                 fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1299 
1300                                 if (bSign)
1301                                     fVal *= -1.0;
1302 
1303                                 fVal /= fFac;
1304 
1305                                 left.PutDouble( fVal );
1306                             }
1307                             break;
1308 
1309 /*
1310 // removed here because of #77448# (=2*3^2 != 18)
1311             case CALC_POW:  {
1312                                 GetToken();
1313                                 double fraction, integer;
1314                                 double right = Prim().GetDouble(),
1315                                        dleft = left.GetDouble();
1316 
1317                                 fraction = modf( right, &integer );
1318                                 if( ( dleft < 0.0 && 0.0 != fraction ) ||
1319                                     ( 0.0 == dleft && right < 0.0 ) )
1320                                 {
1321                                     eError = CALC_OVERFLOW;
1322                                     left.Clear();
1323                                     return left;
1324                                 }
1325                                 dleft = pow(dleft, right );
1326                                 if( dleft == HUGE_VAL )
1327                                 {
1328                                     eError = CALC_POWERR;
1329                                     left.Clear();
1330                                     return left;
1331                                 }
1332                                 left.PutDouble( dleft );
1333                             }
1334                             break;
1335 */
1336             default:        return left;
1337         }
1338 
1339         if( USHRT_MAX != nSbxOper )
1340         {
1341             // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1342             SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1343 
1344             GetToken();
1345             if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1346                 left.PutBool( left.Compare( eSbxOper, Prim() ));
1347             else
1348             {
1349                 SwSbxValue aRight( Prim() );
1350                 aRight.MakeDouble();
1351                 left.MakeDouble();
1352 
1353                 if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1354                     eError = CALC_ZERODIV;
1355                 else
1356                     left.Compute( eSbxOper, aRight );
1357             }
1358         }
1359     }
1360 }
1361 
1362 /******************************************************************************
1363 |*
1364 |*  SwSbxValue SwCalc::Prim()
1365 |*
1366 |*  Erstellung          OK 12-02-93 11:05am
1367 |*  Letzte Aenderung    JP 03.11.95
1368 |*
1369 |******************************************************************************/
1370 
1371 extern "C" typedef double (*pfCalc)( double );
1372 
Prim()1373 SwSbxValue SwCalc::Prim()
1374 {
1375     SwSbxValue nErg;
1376 
1377     pfCalc pFnc = 0;
1378 
1379     sal_Bool bChkTrig = sal_False, bChkPow = sal_False;
1380 
1381     switch( eCurrOper )
1382     {
1383         case CALC_SIN:      pFnc = &sin;                        break;
1384         case CALC_COS:      pFnc = &cos;                        break;
1385         case CALC_TAN:      pFnc = &tan;                        break;
1386         case CALC_ATAN:     pFnc = &atan;                       break;
1387         case CALC_ASIN:     pFnc = &asin;   bChkTrig = sal_True;    break;
1388         case CALC_ACOS:     pFnc = &acos;   bChkTrig = sal_True;    break;
1389 
1390         case CALC_NOT:      {
1391                                 GetToken();
1392                                 nErg = Prim();
1393                                 if( SbxSTRING == nErg.GetType() )
1394                                     nErg.PutBool( 0 == nErg.GetString().Len() );
1395                                 else if(SbxBOOL == nErg.GetType() )
1396                                     nErg.PutBool(!nErg.GetBool());
1397                                 // evaluate arguments manually so that the binary NOT below
1398                                 // does not get called.
1399                                 // We want a BOOLEAN NOT.
1400                                 else if (nErg.IsNumeric())
1401                                     nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1402                                 else
1403                                 {
1404                                     DBG_ERROR( "unexpected case. computing binary NOT" );
1405                                     //!! computes a binary NOT
1406                                     nErg.Compute( SbxNOT, nErg );
1407                                 }
1408                             }
1409                             break;
1410 
1411         case CALC_NUMBER:   if( GetToken() == CALC_PHD )
1412                             {
1413                                 double aTmp = nNumberValue.GetDouble();
1414                                 aTmp *= 0.01;
1415                                 nErg.PutDouble( aTmp );
1416                                 GetToken();
1417                             }
1418                             else if( eCurrOper == CALC_NAME )
1419                                 eError = CALC_SYNTAX;
1420                             else
1421                             {
1422                                 nErg = nNumberValue;
1423                                 bChkPow = sal_True;
1424                             }
1425                             break;
1426 
1427         case CALC_NAME:     if( GetToken() == CALC_ASSIGN )
1428                             {
1429                                 SwCalcExp* n = VarInsert( aVarName );
1430                                 GetToken();
1431                                 nErg = n->nValue = Expr();
1432                             }
1433                             else
1434                             {
1435                                 nErg = VarLook( aVarName )->nValue;
1436                                 bChkPow = sal_True;
1437                             }
1438                             break;
1439 
1440         case CALC_MINUS:    GetToken();
1441                             nErg.PutDouble( -(Prim().GetDouble()) );
1442                             break;
1443 
1444         case CALC_LP:       {
1445                                 GetToken();
1446                                 nErg = Expr();
1447                                 if( eCurrOper != CALC_RP )
1448                                     eError = CALC_BRACK;
1449                                 else
1450                                 {
1451                                     GetToken();
1452                                     bChkPow = sal_True; // in order for =(7)^2 to work
1453                                 }
1454                             }
1455                             break;
1456 
1457         case CALC_MEAN:     {
1458                                 nListPor = 1;
1459                                 GetToken();
1460                                 nErg = Expr();
1461                                 double aTmp = nErg.GetDouble();
1462                                 aTmp /= nListPor;
1463                                 nErg.PutDouble( aTmp );
1464                             }
1465                             break;
1466 
1467         case CALC_SQRT:     {
1468                                 GetToken();
1469                                 nErg = Prim();
1470                                 if( nErg.GetDouble() < 0 )
1471                                     eError = CALC_OVERFLOW;
1472                                 else
1473                                     nErg.PutDouble( sqrt( nErg.GetDouble() ));
1474                             }
1475                             break;
1476 
1477         case CALC_SUM:
1478         case CALC_DATE:
1479         case CALC_MIN:
1480         case CALC_MAX:      GetToken();
1481                             nErg = Expr();
1482                             break;
1483 
1484         case CALC_ENDCALC:  nErg.Clear();
1485                             break;
1486 
1487         default:            eError = CALC_SYNTAX;
1488                             break;
1489     }
1490 
1491     if( pFnc )
1492     {
1493         GetToken();
1494         double nVal = Prim().GetDouble();
1495         if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1496             nErg.PutDouble( (*pFnc)( nVal ) );
1497         else
1498             eError = CALC_OVERFLOW;
1499     }
1500 
1501     // added here because of #77448# (=2*3^2 should be 18)
1502     if( bChkPow && eCurrOper == CALC_POW )
1503     {
1504         double dleft = nErg.GetDouble();
1505         GetToken();
1506         double right = Prim().GetDouble();
1507 
1508         double fraction, integer;
1509         fraction = modf( right, &integer );
1510         if( ( dleft < 0.0 && 0.0 != fraction ) ||
1511             ( 0.0 == dleft && right < 0.0 ) )
1512         {
1513             eError = CALC_OVERFLOW;
1514             nErg.Clear();
1515         }
1516         else
1517         {
1518             dleft = pow(dleft, right );
1519             if( dleft == HUGE_VAL )
1520             {
1521                 eError = CALC_POWERR;
1522                 nErg.Clear();
1523             }
1524             else
1525             {
1526                 nErg.PutDouble( dleft );
1527 //              GetToken();
1528             }
1529         }
1530     }
1531 
1532     return nErg;
1533 }
1534 
1535 /******************************************************************************
1536 |*
1537 |*  SwSbxValue  SwCalc::Expr()
1538 |*
1539 |*  Erstellung          OK 12-02-93 11:06am
1540 |*  Letzte Aenderung    JP 03.11.95
1541 |*
1542 |******************************************************************************/
1543 
Expr()1544 SwSbxValue  SwCalc::Expr()
1545 {
1546     SwSbxValue left = Term(), right;
1547     nLastLeft = left;
1548     for(;;)
1549         switch(eCurrOper)
1550         {
1551             case CALC_PLUS:     GetToken();
1552                                 // erzeuge zum addieren auf jedenfall einen
1553                                 // Double-Wert
1554                                 left.MakeDouble();
1555                                 ( right = Term() ).MakeDouble();
1556                                 left.Compute( SbxPLUS, right );
1557                                 nListPor++;
1558                                 break;
1559 
1560             case CALC_MINUS:    GetToken();
1561                                 // erzeuge zum addieren auf jedenfall einen
1562                                 // Double-Wert
1563                                 left.MakeDouble();
1564                                 ( right = Term() ).MakeDouble();
1565                                 left.Compute( SbxMINUS, right );
1566                                 break;
1567 
1568             default:            return left;
1569         }
1570 }
1571 
1572 //------------------------------------------------------------------------------
1573 
GetColumnName(const String & rName)1574 String SwCalc::GetColumnName(const String& rName)
1575 {
1576     xub_StrLen nPos = rName.Search(DB_DELIM);
1577     if( STRING_NOTFOUND != nPos )
1578     {
1579         nPos = rName.Search(DB_DELIM, nPos + 1);
1580 
1581         if( STRING_NOTFOUND != nPos )
1582             return rName.Copy(nPos + 1);
1583     }
1584     return rName;
1585 }
1586 
1587 //------------------------------------------------------------------------------
1588 
GetDBName(const String & rName)1589 String SwCalc::GetDBName(const String& rName)
1590 {
1591     xub_StrLen nPos = rName.Search(DB_DELIM);
1592     if( STRING_NOTFOUND != nPos )
1593     {
1594         nPos = rName.Search(DB_DELIM, nPos + 1);
1595 
1596         if( STRING_NOTFOUND != nPos )
1597             return rName.Copy( 0, nPos );
1598     }
1599     SwDBData aData = rDoc.GetDBData();
1600     String sRet = aData.sDataSource;
1601     sRet += DB_DELIM;
1602     sRet += String(aData.sCommand);
1603     return sRet;
1604 }
1605 
1606 //------------------------------------------------------------------------------
1607 
1608 namespace
1609 {
1610 
1611 static bool
lcl_Str2Double(const String & rCommand,xub_StrLen & rCommandPos,double & rVal,const LocaleDataWrapper * const pLclData)1612 lcl_Str2Double( const String& rCommand, xub_StrLen& rCommandPos, double& rVal,
1613         const LocaleDataWrapper* const pLclData )
1614 {
1615     OSL_ASSERT(pLclData);
1616     const xub_Unicode nCurrCmdPos = rCommandPos;
1617     rtl_math_ConversionStatus eStatus;
1618     const sal_Unicode* pEnd;
1619     rVal = rtl_math_uStringToDouble( rCommand.GetBuffer() + rCommandPos,
1620             rCommand.GetBuffer() + rCommand.Len(),
1621             pLclData->getNumDecimalSep().GetChar(0),
1622             pLclData->getNumThousandSep().GetChar(0),
1623             &eStatus, &pEnd );
1624     rCommandPos = static_cast<xub_StrLen>(pEnd - rCommand.GetBuffer());
1625 
1626     return rtl_math_ConversionStatus_Ok == eStatus && nCurrCmdPos != rCommandPos;
1627 }
1628 
1629 }
1630 
1631 /******************************************************************************
1632  *  Methode     :   sal_Bool SwCalc::Str2Double( double& )
1633  *  Beschreibung:
1634  *  Erstellt    :   OK 07.06.94 12:56
1635  *  Aenderung   :   JP 27.10.98
1636  ******************************************************************************/
Str2Double(const String & rCommand,xub_StrLen & rCommandPos,double & rVal,const LocaleDataWrapper * const pLclData)1637 bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1638                             double& rVal, const LocaleDataWrapper* const pLclData )
1639 {
1640     const SvtSysLocale aSysLocale;
1641     return lcl_Str2Double( rCommand, rCommandPos, rVal,
1642             pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
1643 }
1644 
Str2Double(const String & rCommand,xub_StrLen & rCommandPos,double & rVal,SwDoc * const pDoc)1645 bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1646                             double& rVal, SwDoc* const pDoc )
1647 {
1648     const SvtSysLocale aSysLocale;
1649     ::std::auto_ptr<const LocaleDataWrapper> pLclD;
1650     if( pDoc )
1651     {
1652         LanguageType eLang = GetDocAppScriptLang( *pDoc );
1653         if (eLang !=
1654                 SvxLocaleToLanguage(aSysLocale.GetLocaleData().getLocale()))
1655         {
1656             pLclD.reset( new LocaleDataWrapper(
1657                             ::comphelper::getProcessServiceFactory(),
1658                             SvxCreateLocale( eLang ) ) );
1659         }
1660     }
1661 
1662     bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
1663             (pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
1664 
1665     return bRet;
1666 }
1667 
1668 //------------------------------------------------------------------------------
1669 
IsValidVarName(const String & rStr,String * pValidName)1670 sal_Bool SwCalc::IsValidVarName( const String& rStr,
1671                                     String* pValidName )
1672 {
1673     sal_Bool bRet = sal_False;
1674     using namespace ::com::sun::star::i18n;
1675     {
1676         // Parse any token.
1677         ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1678                                                     coStartFlags, aEmptyStr,
1679                                                     coContFlags, aEmptyStr );
1680 
1681         if( aRes.TokenType & KParseType::IDENTNAME )
1682         {
1683             bRet = aRes.EndPos == rStr.Len();
1684             if( pValidName )
1685             {
1686                 xub_StrLen nRealStt = (xub_StrLen)aRes.LeadingWhiteSpace;
1687                 *pValidName = rStr.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt );
1688             }
1689         }
1690         else if( pValidName )
1691             pValidName->Erase();
1692     }
1693     return bRet;
1694 }
1695 
1696 //------------------------------------------------------------------------------
1697 
1698 /******************************************************************************
1699 |*
1700 |*  CTOR DTOR der SwHash classes
1701 |*
1702 |*  Ersterstellung      OK 25.06.93 12:20
1703 |*  Letzte Aenderung    OK 25.06.93 12:20
1704 |*
1705 ******************************************************************************/
1706 
SwHash(const String & rStr)1707 SwHash::SwHash( const String& rStr ) :
1708     aStr( rStr ),
1709     pNext( 0 )
1710 {}
1711 
~SwHash()1712 SwHash::~SwHash()
1713 {
1714     if( pNext )
1715         delete pNext;
1716 }
1717 
DeleteHashTable(SwHash ** ppHashTable,sal_uInt16 nCount)1718 void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
1719 {
1720     for ( sal_uInt16 i = 0; i < nCount; ++i )
1721         delete *(ppHashTable+i);
1722     delete [] ppHashTable;
1723 }
1724 
SwCalcExp(const String & rStr,const SwSbxValue & rVal,const SwFieldType * pType)1725 SwCalcExp::SwCalcExp( const String& rStr, const SwSbxValue& rVal,
1726                     const SwFieldType* pType )
1727     : SwHash( rStr ),
1728     nValue( rVal ),
1729     pFldType( pType )
1730 {
1731 }
1732 
1733 
~SwSbxValue()1734 SwSbxValue::~SwSbxValue()
1735 {
1736 }
1737 
GetBool() const1738 sal_Bool SwSbxValue::GetBool() const
1739 {
1740     return SbxSTRING == GetType() ? 0 != GetString().Len()
1741                                   : 0 != SbxValue::GetBool();
1742 }
1743 
GetDouble() const1744 double SwSbxValue::GetDouble() const
1745 {
1746     double nRet;
1747     if( SbxSTRING == GetType() )
1748     {
1749         xub_StrLen nStt = 0;
1750         SwCalc::Str2Double( GetString(), nStt, nRet );
1751     }
1752     else if (IsBool())
1753     {
1754         nRet = 0 != GetBool() ? 1.0 : 0.0;
1755     }
1756     else
1757         nRet = SbxValue::GetDouble();
1758     return nRet;
1759 }
1760 
MakeDouble()1761 SwSbxValue& SwSbxValue::MakeDouble()
1762 {
1763     if( SbxSTRING == GetType() || SbxBOOL == GetType() )
1764         PutDouble( GetDouble() );
1765     return *this;
1766 }
1767 
1768 #ifdef STANDALONE_HASHCALC
1769 
1770 // dies ist der Beispielcode zu erzeugen der HashValues im CTOR:
1771 
1772 #include <stdio.h>
1773 
main()1774 void main()
1775 {
1776 static sal_Char
1777     sNType0[] = "false",    sNType1[] = "true",     sNType2[] = "pi",
1778     sNType3[] = "e",        sNType4[] = "tables",   sNType5[] = "graf",
1779     sNType6[] = "ole",      sNType7[] = "page",     sNType8[] = "para",
1780     sNType9[] = "word",     sNType10[]= "char",
1781     sNType11[] = "user_company" ,       sNType12[] = "user_firstname" ,
1782     sNType13[] = "user_lastname" ,      sNType14[] = "user_initials",
1783     sNType15[] = "user_street" ,        sNType16[] = "user_country" ,
1784     sNType17[] = "user_zipcode" ,       sNType18[] = "user_city" ,
1785     sNType19[] = "user_title" ,         sNType20[] = "user_position" ,
1786     sNType21[] = "user_tel_home",       sNType22[] = "user_tel_work",
1787     sNType23[] = "user_fax" ,           sNType24[] = "user_email" ,
1788     sNType25[] = "user_state",          sNType26[] = "graph"
1789     ;
1790 
1791 static const sal_Char* sNTypeTab[ 27 ] =
1792 {
1793     sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1794     sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1795     sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1796     sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1797     sNType24, sNType25, sNType26
1798 };
1799 
1800     const unsigned short nTblSize = 47;
1801     int aArr[ nTblSize ] = { 0 };
1802     sal_Char ch;
1803 
1804     for( int n = 0; n < 27; ++n )
1805     {
1806         unsigned long ii = 0;
1807         const sal_Char* pp = sNTypeTab[ n ];
1808 
1809         while( *pp )
1810             ii = ii << 1 ^ *pp++;
1811         ii %= nTblSize;
1812 
1813         ch = aArr[ ii ] ? 'X' : ' ';
1814         aArr[ ii ] = 1;
1815         printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1816     }
1817 }
1818 
1819 #endif
1820 
1821 
1822 
1823