Update ooo320-m1
[ooovba.git] / sw / source / core / bastyp / calc.cxx
blobbb81f9116c7d6cc5ab92b90129cd728aec9f7254
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: calc.cxx,v $
10 * $Revision: 1.44.174.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <cctype>
36 #if defined(MACOSX)
37 #include <stdlib.h>
38 #endif
39 #include <cstdlib>
40 #include <climits>
41 // #include <cmath>
42 #include <cfloat>
43 #include <hintids.hxx>
44 #include <rtl/math.hxx>
45 #include <svx/langitem.hxx>
46 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 #include <comphelper/processfactory.hxx>
48 #include <unotools/localedatawrapper.hxx>
49 #include <unotools/charclass.hxx>
50 #include <svx/unolingu.hxx>
51 #include <svx/scripttypeitem.hxx>
52 #include <svtools/useroptions.hxx>
53 #include <tools/datetime.hxx>
54 #include <svtools/zforlist.hxx>
55 #include <swmodule.hxx>
56 #include <doc.hxx>
57 #include <viewsh.hxx>
58 #include <docstat.hxx>
59 #include <calc.hxx>
60 #include <shellres.hxx>
61 #include <dbfld.hxx>
62 #include <expfld.hxx>
63 #include <usrfld.hxx>
64 #ifndef _DBMGR_HXX
65 #include <dbmgr.hxx>
66 #endif
67 #include <docfld.hxx>
68 #include <swunodef.hxx>
69 #include <swtypes.hxx>
71 using namespace ::com::sun::star;
73 // tippt sich schneller
74 #define RESOURCE ViewShell::GetShellRes()
76 const sal_Char __FAR_DATA sCalc_Add[] = "add";
77 const sal_Char __FAR_DATA sCalc_Sub[] = "sub";
78 const sal_Char __FAR_DATA sCalc_Mul[] = "mul";
79 const sal_Char __FAR_DATA sCalc_Div[] = "div";
80 const sal_Char __FAR_DATA sCalc_Phd[] = "phd";
81 const sal_Char __FAR_DATA sCalc_Sqrt[] = "sqrt";
82 const sal_Char __FAR_DATA sCalc_Pow[] = "pow";
83 const sal_Char __FAR_DATA sCalc_Or[] = "or";
84 const sal_Char __FAR_DATA sCalc_Xor[] = "xor";
85 const sal_Char __FAR_DATA sCalc_And[] = "and";
86 const sal_Char __FAR_DATA sCalc_Not[] = "not";
87 const sal_Char __FAR_DATA sCalc_Eq[] = "eq";
88 const sal_Char __FAR_DATA sCalc_Neq[] = "neq";
89 const sal_Char __FAR_DATA sCalc_Leq[] = "leq";
90 const sal_Char __FAR_DATA sCalc_Geq[] = "geq";
91 const sal_Char __FAR_DATA sCalc_L[] = "l";
92 const sal_Char __FAR_DATA sCalc_G[] = "g";
93 const sal_Char __FAR_DATA sCalc_Sum[] = "sum";
94 const sal_Char __FAR_DATA sCalc_Mean[] = "mean";
95 const sal_Char __FAR_DATA sCalc_Min[] = "min";
96 const sal_Char __FAR_DATA sCalc_Max[] = "max";
97 const sal_Char __FAR_DATA sCalc_Sin[] = "sin";
98 const sal_Char __FAR_DATA sCalc_Cos[] = "cos";
99 const sal_Char __FAR_DATA sCalc_Tan[] = "tan";
100 const sal_Char __FAR_DATA sCalc_Asin[] = "asin";
101 const sal_Char __FAR_DATA sCalc_Acos[] = "acos";
102 const sal_Char __FAR_DATA sCalc_Atan[] = "atan";
103 const sal_Char __FAR_DATA sCalc_Round[] = "round";
104 const sal_Char __FAR_DATA sCalc_Date[] = "date";
108 //!!!!! ACHTUNG - Sortierte Liste aller Operatoren !!!!!
109 struct _CalcOp
111 union{
112 const sal_Char* pName;
113 const String* pUName;
115 SwCalcOper eOp;
118 _CalcOp __READONLY_DATA aOpTable[] = {
119 /* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arcuscosinus
120 /* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
121 /* AND */ {{sCalc_And}, CALC_AND}, // log. und
122 /* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arcussinus
123 /* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arcustangens
124 /* COS */ {{sCalc_Cos}, CALC_COS}, // Cosinus
125 /* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
126 /* DIV */ {{sCalc_Div}, CALC_DIV}, // Dividieren
127 /* EQ */ {{sCalc_Eq}, CALC_EQ}, // gleich
128 /* G */ {{sCalc_G}, CALC_GRE}, // groesser
129 /* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // groesser gleich
130 /* L */ {{sCalc_L}, CALC_LES}, // kleiner
131 /* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // kleiner gleich
132 /* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximalwert
133 /* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mittelwert
134 /* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimalwert
135 /* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplizieren
136 /* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // nicht gleich
137 /* NOT */ {{sCalc_Not}, CALC_NOT}, // log. nicht
138 /* OR */ {{sCalc_Or}, CALC_OR}, // log. oder
139 /* PHD */ {{sCalc_Phd}, CALC_PHD}, // Prozent
140 /* POW */ {{sCalc_Pow}, CALC_POW}, // Potenzieren
141 /* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Runden
142 /* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sinus
143 /* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Wurzel
144 /* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraktion
145 /* SUM */ {{sCalc_Sum}, CALC_SUM}, // Summe
146 /* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangens
147 /* XOR */ {{sCalc_Xor}, CALC_XOR} // log. xoder
150 double __READONLY_DATA nRoundVal[] = {
151 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
152 0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
153 0.5e-15,0.5e-16
156 double __READONLY_DATA nKorrVal[] = {
157 9, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8,
158 9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14
161 // First character may be any alphabetic or underscore.
162 const sal_Int32 coStartFlags =
163 i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
164 i18n::KParseTokens::ASC_UNDERSCORE |
165 i18n::KParseTokens::IGNORE_LEADING_WS;
167 // Continuing characters may be any alphanumeric or underscore or dot.
168 const sal_Int32 coContFlags =
169 ( coStartFlags | i18n::KParseTokens::ASC_DOT )
170 & ~i18n::KParseTokens::IGNORE_LEADING_WS;
173 extern "C" {
174 static int
175 #if defined( WNT )
176 __cdecl
177 #endif
178 #if defined( ICC )
179 _Optlink
180 #endif
181 OperatorCompare( const void *pFirst, const void *pSecond)
183 int nRet = 0;
184 if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
186 if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
187 nRet = ((_CalcOp*)pFirst)->pUName->CompareTo(
188 *((_CalcOp*)pSecond)->pUName );
189 else
190 nRet = ((_CalcOp*)pFirst)->pUName->CompareToAscii(
191 ((_CalcOp*)pSecond)->pName );
193 else
195 if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
196 nRet = -1 * ((_CalcOp*)pSecond)->pUName->CompareToAscii(
197 ((_CalcOp*)pFirst)->pName );
198 else
199 nRet = strcmp( ((_CalcOp*)pFirst)->pName,
200 ((_CalcOp*)pSecond)->pName );
202 return nRet;
205 }// extern "C"
207 _CalcOp* FindOperator( const String& rSrch )
209 _CalcOp aSrch;
210 aSrch.pUName = &rSrch;
211 aSrch.eOp = CALC_NAME;
213 return (_CalcOp*)bsearch( (void*) &aSrch,
214 (void*) aOpTable,
215 sizeof( aOpTable ) / sizeof( _CalcOp ),
216 sizeof( _CalcOp ),
217 OperatorCompare );
221 //-----------------------------------------------------------------------------
223 SwHash* Find( const String& rStr, SwHash** ppTable, USHORT nTblSize,
224 USHORT* pPos )
226 ULONG ii = 0;
227 for( xub_StrLen n = 0; n < rStr.Len(); ++n )
228 ii = ii << 1 ^ rStr.GetChar( n );
229 ii %= nTblSize;
231 if( pPos )
232 *pPos = (USHORT)ii;
234 for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
235 if( rStr == pEntry->aStr )
236 return pEntry;
237 return 0;
240 inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
242 return ((SvxLanguageItem&)rDoc.GetDefault(
243 GetWhichOfScript( RES_CHRATR_LANGUAGE,
244 GetI18NScriptTypeOfLanguage( (USHORT)GetAppLanguage() ))
245 )).GetLanguage();
248 double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
250 double nRet = 0;
251 SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
252 if( pFormatter )
254 Date* pNull = pFormatter->GetNullDate();
255 Date aDate( nDate >> 24, (nDate & 0x00FF0000) >> 16, nDate & 0x0000FFFF );
256 nRet = aDate - *pNull;
258 return nRet;
261 //-----------------------------------------------------------------------------
263 /******************************************************************************
265 |* SwCalc::SwCalc( SwDoc* pD ) :
267 |* Erstellung OK 12-02-93 11:04am
268 |* Letzte Aenderung JP 03.11.95
270 |******************************************************************************/
272 SwCalc::SwCalc( SwDoc& rD )
274 aErrExpr( aEmptyStr, SwSbxValue(), 0 ),
275 rDoc( rD ),
276 pLclData( &SvtSysLocale().GetLocaleData() ),
277 pCharClass( &GetAppCharClass() ),
278 nListPor( 0 ),
279 eError( CALC_NOERR )
281 aErrExpr.aStr.AssignAscii( "~C_ERR~" );
282 memset( VarTable, 0, sizeof(VarTable) );
283 LanguageType eLang = GetDocAppScriptLang( rDoc );
285 if( eLang != SvxLocaleToLanguage( pLclData->getLocale() ) ||
286 eLang != SvxLocaleToLanguage( pCharClass->getLocale() ) )
288 STAR_NMSPC::lang::Locale aLocale( SvxCreateLocale( eLang ));
289 STAR_REFERENCE( lang::XMultiServiceFactory ) xMSF(
290 ::comphelper::getProcessServiceFactory() );
291 pCharClass = new CharClass( xMSF, aLocale );
292 pLclData = new LocaleDataWrapper( xMSF, aLocale );
295 sCurrSym = pLclData->getCurrSymbol();
296 sCurrSym.EraseLeadingChars().EraseTrailingChars();
297 pCharClass->toLower( sCurrSym );
299 static sal_Char __READONLY_DATA
300 sNType0[] = "false",
301 sNType1[] = "true",
302 sNType2[] = "pi",
303 sNType3[] = "e",
304 sNType4[] = "tables",
305 sNType5[] = "graf",
306 sNType6[] = "ole",
307 sNType7[] = "page",
308 sNType8[] = "para",
309 sNType9[] = "word",
310 sNType10[]= "char",
312 sNType11[] = "user_firstname" ,
313 sNType12[] = "user_lastname" ,
314 sNType13[] = "user_initials" ,
315 sNType14[] = "user_company" ,
316 sNType15[] = "user_street" ,
317 sNType16[] = "user_country" ,
318 sNType17[] = "user_zipcode" ,
319 sNType18[] = "user_city" ,
320 sNType19[] = "user_title" ,
321 sNType20[] = "user_position" ,
322 sNType21[] = "user_tel_work" ,
323 sNType22[] = "user_tel_home" ,
324 sNType23[] = "user_fax" ,
325 sNType24[] = "user_email" ,
326 sNType25[] = "user_state" ,
327 sNType26[] = "graph"
330 static const sal_Char* __READONLY_DATA sNTypeTab[ 27 ] =
332 sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
333 sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
334 sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
335 sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
336 sNType24,
338 // diese sind mit doppelten HashIds
339 sNType25, sNType26
341 static USHORT __READONLY_DATA aHashValue[ 27 ] =
343 34, 38, 43, 7, 18, 32, 22, 29, 30, 33, 3,
344 28, 24, 40, 9, 11, 26, 45, 4, 23, 36, 44, 19, 5, 1,
345 // diese sind mit doppelten HashIds
346 11, 38
348 static USHORT __READONLY_DATA aAdrToken[ 12 ] =
350 USER_OPT_COMPANY, USER_OPT_STREET, USER_OPT_COUNTRY, USER_OPT_ZIP,
351 USER_OPT_CITY, USER_OPT_TITLE, USER_OPT_POSITION, USER_OPT_TELEPHONEWORK,
352 USER_OPT_TELEPHONEHOME, USER_OPT_FAX, USER_OPT_EMAIL, USER_OPT_STATE
355 static USHORT SwDocStat::* __READONLY_DATA aDocStat1[ 3 ] =
357 &SwDocStat::nTbl, &SwDocStat::nGrf, &SwDocStat::nOLE
359 static ULONG SwDocStat::* __READONLY_DATA aDocStat2[ 4 ] =
361 &SwDocStat::nPage, &SwDocStat::nPara,
362 &SwDocStat::nWord, &SwDocStat::nChar
365 #if TBLSZ != 47
366 #error Alle Hashwerte angepasst?
367 #endif
369 const SwDocStat& rDocStat = rDoc.GetDocStat();
371 SwSbxValue nVal;
372 String sTmpStr;
373 USHORT n;
375 for( n = 0; n < 25; ++n )
377 sTmpStr.AssignAscii( sNTypeTab[ n ] );
378 VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
381 ((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( FALSE );
382 ((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( TRUE );
383 ((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
384 ((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
386 for( n = 0; n < 3; ++n )
387 ((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
388 for( n = 0; n < 4; ++n )
389 ((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
391 SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
393 ((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( (String)rUserOptions.GetFirstName() );
394 ((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( (String)rUserOptions.GetLastName() );
395 ((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( (String)rUserOptions.GetID() );
397 for( n = 0; n < 11; ++n )
398 ((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
399 (String)rUserOptions.GetToken( aAdrToken[ n ] ));
401 nVal.PutString( (String)rUserOptions.GetToken( aAdrToken[ 11 ] ));
402 sTmpStr.AssignAscii( sNTypeTab[ 25 ] );
403 VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
405 // at time its better not to use "graph", because then the im-/export have
406 // to change in all formulas this name.
407 // nVal.PutLong( rDocStat.*aDocStat1[ 1 ] );
408 // VarTable[ aHashValue[ 26 ] ]->pNext = new SwCalcExp(
409 // sNTypeTab[ 26 ], nVal, 0 );
412 /******************************************************************************
414 |* SwCalc::~SwCalc()
416 |* Erstellung OK 12-02-93 11:04am
417 |* Letzte Aenderung OK 12-02-93 11:04am
419 |******************************************************************************/
421 SwCalc::~SwCalc()
423 for( USHORT n = 0; n < TBLSZ; ++n )
424 delete VarTable[n];
425 if( pLclData != &SvtSysLocale().GetLocaleData() )
426 delete pLclData;
427 if( pCharClass != &GetAppCharClass() )
428 delete pCharClass;
431 /******************************************************************************
433 |* SwSbxValue SwCalc::Calculate( const String& rStr )
435 |* Erstellung OK 12-02-93 11:04am
436 |* Letzte Aenderung OK 12-02-93 11:04am
438 |******************************************************************************/
440 SwSbxValue SwCalc::Calculate( const String& rStr )
442 eError = CALC_NOERR;
443 SwSbxValue nResult;
445 if( !rStr.Len() )
446 return nResult;
448 nListPor = 0;
449 eCurrListOper = CALC_PLUS; // defaulten auf Summe
451 sCommand = rStr;
452 nCommandPos = 0;
454 while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
455 nResult = Expr();
457 if( eError )
458 nResult.PutDouble( DBL_MAX );
460 return nResult;
463 /******************************************************************************
465 |* String SwCalc::GetStrResult( SwSbxValue nValue, BOOL bRound = TRUE )
466 |* Beschreibung Der Parameter bRound ist auf TRUE defaultet und darf
467 |* nur beim errechnen von Tabellenzellen auf FALSE gesetzt
468 |* werden, damit keine Rundungsfehler beim zusammenstellen
469 |* der Formel entstehen.
470 |* Erstellung OK 12-02-93 11:04am
471 |* Letzte Aenderung JP 19.02.98
473 |******************************************************************************/
475 String SwCalc::GetStrResult( const SwSbxValue& rVal, BOOL bRound )
477 if( !rVal.IsDouble() )
478 return rVal.GetString();
480 return GetStrResult( rVal.GetDouble(), bRound );
484 String SwCalc::GetStrResult( double nValue, BOOL )
486 if( nValue >= DBL_MAX )
487 switch( eError )
489 case CALC_SYNTAX : return RESOURCE->aCalc_Syntax;
490 case CALC_ZERODIV : return RESOURCE->aCalc_ZeroDiv;
491 case CALC_BRACK : return RESOURCE->aCalc_Brack;
492 case CALC_POWERR : return RESOURCE->aCalc_Pow;
493 case CALC_VARNFND : return RESOURCE->aCalc_VarNFnd;
494 case CALC_OVERFLOW : return RESOURCE->aCalc_Overflow;
495 case CALC_WRONGTIME : return RESOURCE->aCalc_WrongTime;
496 default : return RESOURCE->aCalc_Default;
499 USHORT nDec = 15; //pLclData->getNumDigits();
500 String aRetStr( ::rtl::math::doubleToUString( nValue,
501 rtl_math_StringFormat_Automatic,
502 nDec,
503 pLclData->getNumDecimalSep().GetChar(0),
504 true ));
506 return aRetStr;
509 /******************************************************************************
511 |* SwCalcExp* SwCalc::VarLook( const String& )
513 |* Erstellung OK 12-02-93 11:04am
514 |* Letzte Aenderung JP 15.11.99
516 |******************************************************************************/
518 SwCalcExp* SwCalc::VarInsert( const String &rStr )
520 String aStr( rStr );
521 pCharClass->toLower( aStr );
522 return VarLook( aStr, 1 );
525 /******************************************************************************
527 |* SwCalcExp* SwCalc::VarLook( const String& , USHORT ins )
529 |* Erstellung OK 12-02-93 11:04am
530 |* Letzte Aenderung JP 15.11.99
532 |******************************************************************************/
533 SwCalcExp* SwCalc::VarLook( const String& rStr, USHORT ins )
535 aErrExpr.nValue.SetVoidValue(false);
537 USHORT ii = 0;
538 String aStr( rStr );
539 pCharClass->toLower( aStr );
541 SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
543 if( !pFnd )
545 // dann sehen wir mal im Doc nach:
546 SwHash** ppDocTbl = rDoc.GetUpdtFlds().GetFldTypeTable();
547 for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
548 if( aStr == pEntry->aStr )
550 // dann hier zufuegen
551 pFnd = new SwCalcExp( aStr, SwSbxValue(),
552 ((SwCalcFldType*)pEntry)->pFldType );
553 pFnd->pNext = *(VarTable+ii);
554 *(VarTable+ii) = pFnd;
555 break;
559 if( pFnd )
561 SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
563 if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
565 SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
566 if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
567 pFndExp->nValue.PutString( pUFld->GetContent() );
568 else if( !pUFld->IsValid() )
570 // Die aktuellen Werte sichern . . .
571 USHORT nOld_ListPor = nListPor;
572 SwSbxValue nOld_LastLeft = nLastLeft;
573 SwSbxValue nOld_NumberValue = nNumberValue;
574 xub_StrLen nOld_CommandPos = nCommandPos;
575 SwCalcOper eOld_CurrOper = eCurrOper;
576 SwCalcOper eOld_CurrListOper = eCurrListOper;
578 pFndExp->nValue.PutDouble( pUFld->GetValue( *this ) );
580 // . . . und zurueck damit.
581 nListPor = nOld_ListPor;
582 nLastLeft = nOld_LastLeft;
583 nNumberValue = nOld_NumberValue;
584 nCommandPos = nOld_CommandPos;
585 eCurrOper = eOld_CurrOper;
586 eCurrListOper = eOld_CurrListOper;
588 else
589 pFndExp->nValue.PutDouble( pUFld->GetValue() );
591 return pFndExp;
594 // Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
595 // DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
596 // #101436#: At this point the "real" case variable has to be used
597 String sTmpName( rStr );
598 ::ReplacePoint( sTmpName );
600 if( !ins )
602 SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
604 // Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
605 // DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
606 String sDBName(GetDBName( sTmpName ));
607 String sSourceName(sDBName.GetToken(0, DB_DELIM));
608 String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
609 if( pMgr && sSourceName.Len() && sTableName.Len() &&
610 pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
612 String sColumnName( GetColumnName( sTmpName ));
613 ASSERT (sColumnName.Len(), "DB-Spaltenname fehlt!");
615 String sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
616 pCharClass->toLower(sDBNum);
618 // Hier nochmal initialisieren, da das nicht mehr in docfld
619 // fuer Felder != RES_DBFLD geschieht. Z.B. wenn ein Expressionfield
620 // vor einem DB_Field in einem Dok vorkommt.
621 VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
623 if( sDBNum.EqualsIgnoreCaseAscii(sColumnName) )
625 aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
626 return &aErrExpr;
629 ULONG nTmpRec = 0;
630 if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
631 nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
633 String sResult;
634 double nNumber = DBL_MAX;
636 long nLang = SvxLocaleToLanguage( pLclData->getLocale() );
637 if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
638 nTmpRec, nLang, sResult, &nNumber ))
640 if (nNumber != DBL_MAX)
641 aErrExpr.nValue.PutDouble( nNumber );
642 else
643 aErrExpr.nValue.PutString( sResult );
645 return &aErrExpr;
648 else
650 //data source was not available - set return to "NoValue"
651 aErrExpr.nValue.SetVoidValue(true);
653 // auf keinen fall eintragen!!
654 return &aErrExpr;
658 SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
659 pNewExp->pNext = VarTable[ ii ];
660 VarTable[ ii ] = pNewExp;
662 String sColumnName( GetColumnName( sTmpName ));
663 ASSERT( sColumnName.Len(), "DB-Spaltenname fehlt!" );
664 if( sColumnName.EqualsIgnoreCaseAscii(
665 SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
667 SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
668 String sDBName(GetDBName( sTmpName ));
669 String sSourceName(sDBName.GetToken(0, DB_DELIM));
670 String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
671 if( pMgr && sSourceName.Len() && sTableName.Len() &&
672 pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
673 !pMgr->IsInMerge())
674 pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
675 else
676 pNewExp->nValue.SetVoidValue(true);
679 return pNewExp;
682 /******************************************************************************
684 |* BOOL SwCalc::VarChange( const String& rStr, const SwSbxValue nValue )
686 |* Erstellung OK 12-02-93 11:04am
687 |* Letzte Aenderung OK 12-02-93 11:04am
689 |******************************************************************************/
691 void SwCalc::VarChange( const String& rStr, double nValue )
693 SwSbxValue aVal( nValue );
694 VarChange( rStr, aVal );
697 void SwCalc::VarChange( const String& rStr, const SwSbxValue& rValue )
699 String aStr( rStr );
700 pCharClass->toLower( aStr );
702 USHORT nPos = 0;
703 SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
705 if( !pFnd )
707 pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
708 pFnd->pNext = VarTable[ nPos ];
709 VarTable[ nPos ] = pFnd;
711 else
712 pFnd->nValue = rValue;
715 /******************************************************************************
717 |* BOOL SwCalc::Push( const void* pPtr )
719 |* Erstellung OK 12-02-93 11:05am
720 |* Letzte Aenderung OK 12-02-93 11:05am
722 |******************************************************************************/
724 BOOL SwCalc::Push( const VoidPtr pPtr )
726 if( USHRT_MAX != aRekurStk.GetPos( pPtr ) )
727 return FALSE;
729 aRekurStk.Insert( pPtr, aRekurStk.Count() );
730 return TRUE;
733 /******************************************************************************
735 |* void SwCalc::Pop( const void* pPtr )
737 |* Erstellung OK 12-02-93 11:05am
738 |* Letzte Aenderung OK 12-02-93 11:05am
740 |******************************************************************************/
742 void SwCalc::Pop( const VoidPtr )
744 ASSERT( aRekurStk.Count(), "SwCalc: Pop auf ungueltigen Ptr" );
746 aRekurStk.Remove( aRekurStk.Count() - 1 );
750 /******************************************************************************
752 |* SwCalcOper SwCalc::GetToken()
754 |* Erstellung OK 12-02-93 11:05am
755 |* Letzte Aenderung JP 03.11.95
757 |******************************************************************************/
759 SwCalcOper SwCalc::GetToken()
761 #if OSL_DEBUG_LEVEL > 1
762 //JP 25.01.2001: static for switch back to the "old" implementation of the
763 // calculator, which don't use the I18N routines.
764 static int nUseOld = 0;
765 if( !nUseOld )
767 #endif
769 if( nCommandPos >= sCommand.Len() )
770 return eCurrOper = CALC_ENDCALC;
772 using namespace ::com::sun::star::i18n;
774 // Parse any token.
775 ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
776 coStartFlags, aEmptyStr,
777 coContFlags, aEmptyStr );
779 BOOL bSetError = TRUE;
780 xub_StrLen nRealStt = nCommandPos + (xub_StrLen)aRes.LeadingWhiteSpace;
781 if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
783 nNumberValue.PutDouble( aRes.Value );
784 eCurrOper = CALC_NUMBER;
785 bSetError = FALSE;
787 else if( aRes.TokenType & KParseType::IDENTNAME )
789 String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
790 //#101436#: the variable may contain a database name it must not be converted to lower case
791 // instead all further comparisons must be done case-insensitive
792 //pCharClass->toLower( aName );
793 String sLowerCaseName(aName);
794 pCharClass->toLower( sLowerCaseName );
795 // Currency-Symbol abfangen
796 if( sLowerCaseName == sCurrSym )
798 nCommandPos = (xub_StrLen)aRes.EndPos;
799 return GetToken(); // also nochmal aufrufen
802 // Operations abfangen
803 _CalcOp* pFnd = ::FindOperator( sLowerCaseName );
804 if( pFnd )
806 switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
808 case CALC_SUM:
809 case CALC_MEAN:
810 eCurrListOper = CALC_PLUS;
811 break;
812 case CALC_MIN:
813 eCurrListOper = CALC_MIN_IN;
814 break;
815 case CALC_MAX:
816 eCurrListOper = CALC_MAX_IN;
817 break;
818 case CALC_DATE:
819 eCurrListOper = CALC_MONTH;
820 break;
821 default:
822 break;
824 nCommandPos = (xub_StrLen)aRes.EndPos;
825 return eCurrOper;
827 aVarName = aName;
828 eCurrOper = CALC_NAME;
829 bSetError = FALSE;
831 else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
833 nNumberValue.PutString( String( aRes.DequotedNameOrString ));
834 eCurrOper = CALC_NUMBER;
835 bSetError = FALSE;
837 else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
839 String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
840 if( 1 == aName.Len() )
842 bSetError = FALSE;
843 sal_Unicode ch = aName.GetChar( 0 );
844 switch( ch )
846 case ';': if( CALC_MONTH == eCurrListOper ||
847 CALC_DAY == eCurrListOper )
849 eCurrOper = eCurrListOper;
850 break;
852 case '\n':
853 eCurrOper = CALC_PRINT;
854 break;
855 case '%':
856 case '^':
857 case '*':
858 case '/':
859 case '+':
860 case '-':
861 case '(':
862 case ')': eCurrOper = SwCalcOper(ch);
863 break;
865 case '=':
866 case '!':
868 SwCalcOper eTmp2;
869 if( '=' == ch )
870 eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
871 else
872 eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
874 if( aRes.EndPos < sCommand.Len() &&
875 '=' == sCommand.GetChar( (xub_StrLen)aRes.EndPos ) )
877 eCurrOper = eTmp2;
878 ++aRes.EndPos;
881 break;
883 case cListDelim :
884 eCurrOper = eCurrListOper;
885 break;
887 case '[':
888 if( aRes.EndPos < sCommand.Len() )
890 aVarName.Erase();
891 xub_StrLen nFndPos = (xub_StrLen)aRes.EndPos,
892 nSttPos = nFndPos;
895 if( STRING_NOTFOUND != ( nFndPos =
896 sCommand.Search( ']', nFndPos )) )
898 // ignore the ]
899 if( '\\' == sCommand.GetChar(nFndPos-1))
901 aVarName += sCommand.Copy( nSttPos,
902 nFndPos - nSttPos - 1 );
903 nSttPos = ++nFndPos;
905 else
906 break;
908 } while( STRING_NOTFOUND != nFndPos );
910 if( STRING_NOTFOUND != nFndPos )
912 if( nSttPos != nFndPos )
913 aVarName += sCommand.Copy( nSttPos,
914 nFndPos - nSttPos );
915 aRes.EndPos = nFndPos + 1;
916 eCurrOper = CALC_NAME;
918 else
919 bSetError = TRUE;
921 else
922 bSetError = TRUE;
923 break;
925 default:
926 bSetError = TRUE;
927 break;
931 else if( aRes.TokenType & KParseType::BOOLEAN )
933 String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
934 if( aName.Len() )
936 sal_Unicode ch = aName.GetChar(0);
938 bSetError = TRUE;
939 if ('<' == ch || '>' == ch)
941 bSetError = FALSE;
943 SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
944 eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
946 if( 2 == aName.Len() && '=' == aName.GetChar(1) )
947 eCurrOper = eTmp2;
948 else if( 1 != aName.Len() )
949 bSetError = TRUE;
953 else if( nRealStt == sCommand.Len() )
955 eCurrOper = CALC_ENDCALC;
956 bSetError = FALSE;
959 if( bSetError )
961 eError = CALC_SYNTAX;
962 eCurrOper = CALC_PRINT;
964 nCommandPos = (xub_StrLen)aRes.EndPos;
967 #if OSL_DEBUG_LEVEL > 1
969 #define NextCh( s, n ) (nCommandPos < sCommand.Len() ? sCommand.GetChar( nCommandPos++ ) : 0)
972 else
974 sal_Unicode ch;
975 sal_Unicode cTSep = pLclData->getNumThousandSep().GetChar(0),
976 cDSep = pLclData->getNumDecimalSep().GetChar(0);
978 do {
979 if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
980 return eCurrOper = CALC_ENDCALC;
981 } while ( ch == '\t' || ch == ' ' || ch == cTSep );
983 if( ch == cDSep )
984 ch = '.';
986 switch( ch )
988 case ';': if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
990 eCurrOper = eCurrListOper;
991 break;
992 } // else .. no break
993 case '\n':
995 sal_Unicode c;
996 while( nCommandPos < sCommand.Len() && ( ( c =
997 sCommand.GetChar( nCommandPos ) ) == ' ' ||
998 c == '\t' || c == '\x0a' || c == '\x0d' ))
999 ++nCommandPos;
1000 eCurrOper = CALC_PRINT;
1002 break;
1003 case '%':
1004 case '^':
1005 case '*':
1006 case '/':
1007 case '+':
1008 case '-':
1009 case '(':
1010 case ')': eCurrOper = SwCalcOper(ch);
1011 break;
1013 case '=': if( '=' == sCommand.GetChar( nCommandPos ) )
1015 ++nCommandPos;
1016 eCurrOper = CALC_EQ;
1018 else
1019 eCurrOper = SwCalcOper(ch);
1020 break;
1022 case '!': if( '=' == sCommand.GetChar( nCommandPos ) )
1024 ++nCommandPos;
1025 eCurrOper = CALC_NEQ;
1027 else
1028 eCurrOper = CALC_NOT;
1029 break;
1031 case '>':
1032 case '<': eCurrOper = '>' == ch ? CALC_GRE : CALC_LES;
1033 if( '=' == (ch = sCommand.GetChar( nCommandPos ) ) )
1035 ++nCommandPos;
1036 eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
1038 else if( ' ' != ch )
1040 eError = CALC_SYNTAX;
1041 eCurrOper = CALC_PRINT;
1043 break;
1045 case cListDelim :
1046 eCurrOper = eCurrListOper;
1047 break;
1049 case '0': case '1': case '2': case '3': case '4':
1050 case '5': case '6': case '7': case '8': case '9':
1051 case ',':
1052 case '.': {
1053 double nVal;
1054 --nCommandPos; // auf das 1. Zeichen zurueck
1055 if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
1057 nNumberValue.PutDouble( nVal );
1058 eCurrOper = CALC_NUMBER;
1060 else
1062 // fehlerhafte Zahl
1063 eError = CALC_SYNTAX;
1064 eCurrOper = CALC_PRINT;
1067 break;
1069 case '[': {
1070 String aStr;
1071 BOOL bIgnore = FALSE;
1072 do {
1073 while( 0 != ( ch = NextCh( sCommand, nCommandPos ))
1074 && ch != ']' )
1076 if( !bIgnore && '\\' == ch )
1077 bIgnore = TRUE;
1078 else if( bIgnore )
1079 bIgnore = FALSE;
1080 aStr += ch;
1083 if( !bIgnore )
1084 break;
1086 aStr.SetChar( aStr.Len() - 1, ch );
1087 } while( ch );
1089 aVarName = aStr;
1090 eCurrOper = CALC_NAME;
1092 break;
1094 case '"': {
1095 xub_StrLen nStt = nCommandPos;
1096 while( 0 != ( ch = NextCh( sCommand, nCommandPos ) )
1097 && '"' != ch )
1100 xub_StrLen nLen = nCommandPos - nStt;
1101 if( '"' == ch )
1102 --nLen;
1103 nNumberValue.PutString( sCommand.Copy( nStt, nLen ));
1104 eCurrOper = CALC_NUMBER;
1106 break;
1108 default: if( ch && pCharClass->isLetter( sCommand, nCommandPos - 1)
1109 || '_' == ch )
1111 xub_StrLen nStt = nCommandPos-1;
1112 while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
1113 (pCharClass->isLetterNumeric(
1114 sCommand, nCommandPos - 1) ||
1115 ch == '_' || ch == '.' ) )
1118 if( ch )
1119 --nCommandPos;
1121 String aStr( sCommand.Copy( nStt, nCommandPos-nStt ));
1122 pCharClass->toLower( aStr );
1125 // Currency-Symbol abfangen
1126 if( aStr == sCurrSym )
1127 return GetToken(); // also nochmal aufrufen
1129 // Operations abfangen
1130 _CalcOp* pFnd = ::FindOperator( aStr );
1131 if( pFnd )
1133 switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
1135 case CALC_SUM :
1136 case CALC_MEAN : eCurrListOper = CALC_PLUS;
1137 break;
1138 case CALC_MIN : eCurrListOper = CALC_MIN_IN;
1139 break;
1140 case CALC_MAX : eCurrListOper = CALC_MAX_IN;
1141 break;
1142 case CALC_DATE : eCurrListOper = CALC_MONTH;
1143 break;
1144 default :
1145 break;
1147 return eCurrOper;
1149 aVarName = aStr;
1150 eCurrOper = CALC_NAME;
1152 else
1154 eError = CALC_SYNTAX;
1155 eCurrOper = CALC_PRINT;
1157 break;
1161 #endif
1162 return eCurrOper;
1165 /******************************************************************************
1167 |* SwSbxValue SwCalc::Term()
1169 |* Erstellung OK 12-02-93 11:05am
1170 |* Letzte Aenderung JP 16.01.96
1172 |******************************************************************************/
1174 SwSbxValue SwCalc::Term()
1176 SwSbxValue left( Prim() );
1177 nLastLeft = left;
1178 for(;;)
1180 USHORT nSbxOper = USHRT_MAX;
1182 switch( eCurrOper )
1184 // wir haben kein Bitweises verodern, oder ?
1185 // case CALC_AND: eSbxOper = SbxAND; break;
1186 // case CALC_OR: eSbxOper = SbxOR; break;
1187 // case CALC_XOR: eSbxOper = SbxXOR; break;
1188 case CALC_AND: {
1189 GetToken();
1190 BOOL bB = Prim().GetBool();
1191 left.PutBool( left.GetBool() && bB );
1193 break;
1194 case CALC_OR: {
1195 GetToken();
1196 BOOL bB = Prim().GetBool();
1197 left.PutBool( left.GetBool() || bB );
1199 break;
1200 case CALC_XOR: {
1201 GetToken();
1202 BOOL bR = Prim().GetBool();
1203 BOOL bL = left.GetBool();
1204 left.PutBool( (bL && !bR) || (!bL && bR) );
1206 break;
1208 case CALC_EQ: nSbxOper = SbxEQ; break;
1209 case CALC_NEQ: nSbxOper = SbxNE; break;
1210 case CALC_LEQ: nSbxOper = SbxLE; break;
1211 case CALC_GEQ: nSbxOper = SbxGE; break;
1212 case CALC_GRE: nSbxOper = SbxGT; break;
1213 case CALC_LES: nSbxOper = SbxLT; break;
1215 case CALC_MUL: nSbxOper = SbxMUL; break;
1216 case CALC_DIV: nSbxOper = SbxDIV; break;
1218 case CALC_MIN_IN:
1220 GetToken();
1221 SwSbxValue e = Prim();
1222 left = left.GetDouble() < e.GetDouble()
1223 ? left : e;
1225 break;
1226 case CALC_MAX_IN:
1228 GetToken();
1229 SwSbxValue e = Prim();
1230 left = left.GetDouble() > e.GetDouble()
1231 ? left : e;
1233 break;
1234 case CALC_MONTH:
1236 GetToken();
1237 SwSbxValue e = Prim();
1238 sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
1239 nYear = nYear & 0x0000FFFF;
1240 sal_Int32 nMonth = (INT32) floor( e.GetDouble() );
1241 nMonth = ( nMonth & 0x000000FF ) << 16;
1242 left.PutLong( nMonth + nYear );
1243 eCurrOper = CALC_DAY;
1245 break;
1246 case CALC_DAY:
1248 GetToken();
1249 SwSbxValue e = Prim();
1250 sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
1251 nYearMonth = nYearMonth & 0x00FFFFFF;
1252 sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
1253 nDay = ( nDay & 0x000000FF ) << 24;
1254 left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
1256 break;
1257 case CALC_ROUND:
1259 GetToken();
1260 SwSbxValue e = Prim();
1262 double fVal = 0;
1263 double fFac = 1;
1264 INT32 nDec = (INT32) floor( e.GetDouble() );
1265 if( nDec < -20 || nDec > 20 )
1267 eError = CALC_OVERFLOW;
1268 left.Clear();
1269 return left;
1271 fVal = left.GetDouble();
1272 USHORT i;
1273 if( nDec >= 0)
1274 for (i = 0; i < (USHORT) nDec; ++i )
1275 fFac *= 10.0;
1276 else
1277 for (i = 0; i < (USHORT) -nDec; ++i )
1278 fFac /= 10.0;
1280 fVal *= fFac;
1282 BOOL bSign;
1283 if (fVal < 0.0)
1285 fVal *= -1.0;
1286 bSign = TRUE;
1288 else
1289 bSign = FALSE;
1291 // runden
1292 double fNum = fVal; // find the exponent
1293 int nExp = 0;
1294 if( fNum > 0 )
1296 while( fNum < 1.0 ) fNum *= 10.0, --nExp;
1297 while( fNum >= 10.0 ) fNum /= 10.0, ++nExp;
1299 nExp = 15 - nExp;
1300 if( nExp > 15 )
1301 nExp = 15;
1302 else if( nExp <= 1 )
1303 nExp = 0;
1304 fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
1306 if (bSign)
1307 fVal *= -1.0;
1309 fVal /= fFac;
1311 left.PutDouble( fVal );
1313 break;
1316 // removed here because of #77448# (=2*3^2 != 18)
1317 case CALC_POW: {
1318 GetToken();
1319 double fraction, integer;
1320 double right = Prim().GetDouble(),
1321 dleft = left.GetDouble();
1323 fraction = modf( right, &integer );
1324 if( ( dleft < 0.0 && 0.0 != fraction ) ||
1325 ( 0.0 == dleft && right < 0.0 ) )
1327 eError = CALC_OVERFLOW;
1328 left.Clear();
1329 return left;
1331 dleft = pow(dleft, right );
1332 if( dleft == HUGE_VAL )
1334 eError = CALC_POWERR;
1335 left.Clear();
1336 return left;
1338 left.PutDouble( dleft );
1340 break;
1342 default: return left;
1345 if( USHRT_MAX != nSbxOper )
1347 // #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
1348 SbxOperator eSbxOper = (SbxOperator)nSbxOper;
1350 GetToken();
1351 if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
1352 left.PutBool( left.Compare( eSbxOper, Prim() ));
1353 else
1355 SwSbxValue aRight( Prim() );
1356 aRight.MakeDouble();
1357 left.MakeDouble();
1359 if( SbxDIV == eSbxOper && !aRight.GetDouble() )
1360 eError = CALC_ZERODIV;
1361 else
1362 left.Compute( eSbxOper, aRight );
1368 /******************************************************************************
1370 |* SwSbxValue SwCalc::Prim()
1372 |* Erstellung OK 12-02-93 11:05am
1373 |* Letzte Aenderung JP 03.11.95
1375 |******************************************************************************/
1377 extern "C" typedef double (*pfCalc)( double );
1379 SwSbxValue SwCalc::Prim()
1381 SwSbxValue nErg;
1383 pfCalc pFnc = 0;
1385 BOOL bChkTrig = FALSE, bChkPow = FALSE;
1387 switch( eCurrOper )
1389 case CALC_SIN: pFnc = &sin; break;
1390 case CALC_COS: pFnc = &cos; break;
1391 case CALC_TAN: pFnc = &tan; break;
1392 case CALC_ATAN: pFnc = &atan; break;
1393 case CALC_ASIN: pFnc = &asin; bChkTrig = TRUE; break;
1394 case CALC_ACOS: pFnc = &acos; bChkTrig = TRUE; break;
1396 case CALC_NOT: {
1397 GetToken();
1398 nErg = Prim();
1399 if( SbxSTRING == nErg.GetType() )
1400 nErg.PutBool( 0 == nErg.GetString().Len() );
1401 else if(SbxBOOL == nErg.GetType() )
1402 nErg.PutBool(!nErg.GetBool());
1403 // evaluate arguments manually so that the binary NOT below
1404 // does not get called.
1405 // We want a BOOLEAN NOT.
1406 else if (nErg.IsNumeric())
1407 nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
1408 else
1410 DBG_ERROR( "unexpected case. computing binary NOT" );
1411 //!! computes a binary NOT
1412 nErg.Compute( SbxNOT, nErg );
1415 break;
1417 case CALC_NUMBER: if( GetToken() == CALC_PHD )
1419 double aTmp = nNumberValue.GetDouble();
1420 aTmp *= 0.01;
1421 nErg.PutDouble( aTmp );
1422 GetToken();
1424 else if( eCurrOper == CALC_NAME )
1425 eError = CALC_SYNTAX;
1426 else
1428 nErg = nNumberValue;
1429 bChkPow = TRUE;
1431 break;
1433 case CALC_NAME: if( GetToken() == CALC_ASSIGN )
1435 SwCalcExp* n = VarInsert( aVarName );
1436 GetToken();
1437 nErg = n->nValue = Expr();
1439 else
1441 nErg = VarLook( aVarName )->nValue;
1442 bChkPow = TRUE;
1444 break;
1446 case CALC_MINUS: GetToken();
1447 nErg.PutDouble( -(Prim().GetDouble()) );
1448 break;
1450 case CALC_LP: {
1451 GetToken();
1452 nErg = Expr();
1453 if( eCurrOper != CALC_RP )
1454 eError = CALC_BRACK;
1455 else
1457 GetToken();
1458 bChkPow = TRUE; // in order for =(7)^2 to work
1461 break;
1463 case CALC_MEAN: {
1464 nListPor = 1;
1465 GetToken();
1466 nErg = Expr();
1467 double aTmp = nErg.GetDouble();
1468 aTmp /= nListPor;
1469 nErg.PutDouble( aTmp );
1471 break;
1473 case CALC_SQRT: {
1474 GetToken();
1475 nErg = Prim();
1476 if( nErg.GetDouble() < 0 )
1477 eError = CALC_OVERFLOW;
1478 else
1479 nErg.PutDouble( sqrt( nErg.GetDouble() ));
1481 break;
1483 case CALC_SUM:
1484 case CALC_DATE:
1485 case CALC_MIN:
1486 case CALC_MAX: GetToken();
1487 nErg = Expr();
1488 break;
1490 case CALC_ENDCALC: nErg.Clear();
1491 break;
1493 default: eError = CALC_SYNTAX;
1494 break;
1497 if( pFnc )
1499 GetToken();
1500 double nVal = Prim().GetDouble();
1501 if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
1502 nErg.PutDouble( (*pFnc)( nVal ) );
1503 else
1504 eError = CALC_OVERFLOW;
1507 // added here because of #77448# (=2*3^2 should be 18)
1508 if( bChkPow && eCurrOper == CALC_POW )
1510 double dleft = nErg.GetDouble();
1511 GetToken();
1512 double right = Prim().GetDouble();
1514 double fraction, integer;
1515 fraction = modf( right, &integer );
1516 if( ( dleft < 0.0 && 0.0 != fraction ) ||
1517 ( 0.0 == dleft && right < 0.0 ) )
1519 eError = CALC_OVERFLOW;
1520 nErg.Clear();
1522 else
1524 dleft = pow(dleft, right );
1525 if( dleft == HUGE_VAL )
1527 eError = CALC_POWERR;
1528 nErg.Clear();
1530 else
1532 nErg.PutDouble( dleft );
1533 // GetToken();
1538 return nErg;
1541 /******************************************************************************
1543 |* SwSbxValue SwCalc::Expr()
1545 |* Erstellung OK 12-02-93 11:06am
1546 |* Letzte Aenderung JP 03.11.95
1548 |******************************************************************************/
1550 SwSbxValue SwCalc::Expr()
1552 SwSbxValue left = Term(), right;
1553 nLastLeft = left;
1554 for(;;)
1555 switch(eCurrOper)
1557 case CALC_PLUS: GetToken();
1558 // erzeuge zum addieren auf jedenfall einen
1559 // Double-Wert
1560 left.MakeDouble();
1561 ( right = Term() ).MakeDouble();
1562 left.Compute( SbxPLUS, right );
1563 nListPor++;
1564 break;
1566 case CALC_MINUS: GetToken();
1567 // erzeuge zum addieren auf jedenfall einen
1568 // Double-Wert
1569 left.MakeDouble();
1570 ( right = Term() ).MakeDouble();
1571 left.Compute( SbxMINUS, right );
1572 break;
1574 default: return left;
1578 //------------------------------------------------------------------------------
1580 String SwCalc::GetColumnName(const String& rName)
1582 xub_StrLen nPos = rName.Search(DB_DELIM);
1583 if( STRING_NOTFOUND != nPos )
1585 nPos = rName.Search(DB_DELIM, nPos + 1);
1587 if( STRING_NOTFOUND != nPos )
1588 return rName.Copy(nPos + 1);
1590 return rName;
1593 //------------------------------------------------------------------------------
1595 String SwCalc::GetDBName(const String& rName)
1597 xub_StrLen nPos = rName.Search(DB_DELIM);
1598 if( STRING_NOTFOUND != nPos )
1600 nPos = rName.Search(DB_DELIM, nPos + 1);
1602 if( STRING_NOTFOUND != nPos )
1603 return rName.Copy( 0, nPos );
1605 SwDBData aData = rDoc.GetDBData();
1606 String sRet = aData.sDataSource;
1607 sRet += DB_DELIM;
1608 sRet += String(aData.sCommand);
1609 return sRet;
1612 //------------------------------------------------------------------------------
1614 /******************************************************************************
1615 * Methode : BOOL SwCalc::Str2Double( double& )
1616 * Beschreibung:
1617 * Erstellt : OK 07.06.94 12:56
1618 * Aenderung : JP 27.10.98
1619 ******************************************************************************/
1620 BOOL SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1621 double& rVal, const LocaleDataWrapper* pLclData )
1623 const LocaleDataWrapper* pLclD = pLclData;
1624 if( !pLclD )
1625 pLclD = &SvtSysLocale().GetLocaleData();
1627 const xub_Unicode nCurrCmdPos = rCommandPos;
1628 rtl_math_ConversionStatus eStatus;
1629 const sal_Unicode* pEnd;
1630 rVal = rtl_math_uStringToDouble( rCommand.GetBuffer() + rCommandPos,
1631 rCommand.GetBuffer() + rCommand.Len(),
1632 pLclD->getNumDecimalSep().GetChar(0),
1633 pLclD->getNumThousandSep().GetChar(0),
1634 &eStatus, &pEnd );
1635 rCommandPos = static_cast<xub_StrLen>(pEnd - rCommand.GetBuffer());
1637 if( !pLclData && pLclD != &SvtSysLocale().GetLocaleData() )
1638 delete (LocaleDataWrapper*)pLclD;
1640 return rtl_math_ConversionStatus_Ok == eStatus && nCurrCmdPos != rCommandPos;
1643 BOOL SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
1644 double& rVal, SwDoc* pDoc )
1646 const LocaleDataWrapper* pLclD = &SvtSysLocale().GetLocaleData();
1647 if( pDoc )
1650 LanguageType eLang = GetDocAppScriptLang( *pDoc );
1651 if( eLang != SvxLocaleToLanguage( pLclD->getLocale() ) )
1652 pLclD = new LocaleDataWrapper(
1653 ::comphelper::getProcessServiceFactory(),
1654 SvxCreateLocale( eLang ) );
1657 const xub_Unicode nCurrCmdPos = rCommandPos;
1658 rtl_math_ConversionStatus eStatus;
1659 const sal_Unicode* pEnd;
1660 rVal = rtl_math_uStringToDouble( rCommand.GetBuffer() + rCommandPos,
1661 rCommand.GetBuffer() + rCommand.Len(),
1662 pLclD->getNumDecimalSep().GetChar(0),
1663 pLclD->getNumThousandSep().GetChar(0),
1664 &eStatus, &pEnd );
1665 rCommandPos = static_cast<xub_StrLen>(pEnd - rCommand.GetBuffer());
1667 if( pLclD != &SvtSysLocale().GetLocaleData() )
1668 delete (LocaleDataWrapper*)pLclD;
1670 return rtl_math_ConversionStatus_Ok == eStatus && nCurrCmdPos != rCommandPos;
1673 //------------------------------------------------------------------------------
1675 BOOL SwCalc::IsValidVarName( const String& rStr,
1676 String* pValidName )
1678 BOOL bRet = FALSE;
1679 using namespace ::com::sun::star::i18n;
1681 // Parse any token.
1682 ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
1683 coStartFlags, aEmptyStr,
1684 coContFlags, aEmptyStr );
1686 if( aRes.TokenType & KParseType::IDENTNAME )
1688 bRet = aRes.EndPos == rStr.Len();
1689 if( pValidName )
1691 xub_StrLen nRealStt = (xub_StrLen)aRes.LeadingWhiteSpace;
1692 *pValidName = rStr.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt );
1695 else if( pValidName )
1696 pValidName->Erase();
1698 return bRet;
1701 //------------------------------------------------------------------------------
1703 /******************************************************************************
1705 |* CTOR DTOR der SwHash classes
1707 |* Ersterstellung OK 25.06.93 12:20
1708 |* Letzte Aenderung OK 25.06.93 12:20
1710 ******************************************************************************/
1712 SwHash::SwHash( const String& rStr ) :
1713 aStr( rStr ),
1714 pNext( 0 )
1717 SwHash::~SwHash()
1719 if( pNext )
1720 delete pNext;
1723 void DeleteHashTable( SwHash **ppHashTable, USHORT nCount )
1725 for ( USHORT i = 0; i < nCount; ++i )
1726 delete *(ppHashTable+i);
1727 delete [] ppHashTable;
1730 SwCalcExp::SwCalcExp( const String& rStr, const SwSbxValue& rVal,
1731 const SwFieldType* pType )
1732 : SwHash( rStr ),
1733 nValue( rVal ),
1734 pFldType( pType )
1739 SwSbxValue::~SwSbxValue()
1743 BOOL SwSbxValue::GetBool() const
1745 return SbxSTRING == GetType() ? 0 != GetString().Len()
1746 : 0 != SbxValue::GetBool();
1749 double SwSbxValue::GetDouble() const
1751 double nRet;
1752 if( SbxSTRING == GetType() )
1754 xub_StrLen nStt = 0;
1755 SwCalc::Str2Double( GetString(), nStt, nRet );
1757 else if (IsBool())
1759 nRet = 0 != GetBool() ? 1.0 : 0.0;
1761 else
1762 nRet = SbxValue::GetDouble();
1763 return nRet;
1766 SwSbxValue& SwSbxValue::MakeDouble()
1768 if( SbxSTRING == GetType() )
1769 PutDouble( GetDouble() );
1770 return *this;
1773 #ifdef STANDALONE_HASHCALC
1775 // dies ist der Beispielcode zu erzeugen der HashValues im CTOR:
1777 #include <stdio.h>
1779 void main()
1781 static sal_Char
1782 sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
1783 sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
1784 sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
1785 sNType9[] = "word", sNType10[]= "char",
1786 sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
1787 sNType13[] = "user_lastname" , sNType14[] = "user_initials",
1788 sNType15[] = "user_street" , sNType16[] = "user_country" ,
1789 sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
1790 sNType19[] = "user_title" , sNType20[] = "user_position" ,
1791 sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
1792 sNType23[] = "user_fax" , sNType24[] = "user_email" ,
1793 sNType25[] = "user_state", sNType26[] = "graph"
1796 static const sal_Char* sNTypeTab[ 27 ] =
1798 sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
1799 sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
1800 sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
1801 sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
1802 sNType24, sNType25, sNType26
1805 const unsigned short nTblSize = 47;
1806 int aArr[ nTblSize ] = { 0 };
1807 sal_Char ch;
1809 for( int n = 0; n < 27; ++n )
1811 unsigned long ii = 0;
1812 const sal_Char* pp = sNTypeTab[ n ];
1814 while( *pp )
1815 ii = ii << 1 ^ *pp++;
1816 ii %= nTblSize;
1818 ch = aArr[ ii ] ? 'X' : ' ';
1819 aArr[ ii ] = 1;
1820 printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
1824 #endif