blob: 10d63e9f5607ad1292b0cef19616b93308581ac3 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <cctype>
#if defined(MACOSX)
#include <stdlib.h>
#endif
#include <cstdlib>
#include <climits>
// #include <cmath>
#include <cfloat>
#include <hintids.hxx>
#include <osl/diagnose.hxx>
#include <rtl/math.hxx>
#include <editeng/langitem.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/processfactory.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/charclass.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/scripttypeitem.hxx>
#include <unotools/useroptions.hxx>
#include <tools/datetime.hxx>
#include <svl/zforlist.hxx>
#include <swmodule.hxx>
#include <doc.hxx>
#include <viewsh.hxx>
#include <docstat.hxx>
#include <calc.hxx>
#include <shellres.hxx>
#include <dbfld.hxx>
#include <expfld.hxx>
#include <usrfld.hxx>
#ifndef _DBMGR_HXX
#include <dbmgr.hxx>
#endif
#include <docfld.hxx>
#include <swunodef.hxx>
#include <swtypes.hxx>
using namespace ::com::sun::star;
// tippt sich schneller
#define RESOURCE ViewShell::GetShellRes()
const sal_Char __FAR_DATA sCalc_Add[] = "add";
const sal_Char __FAR_DATA sCalc_Sub[] = "sub";
const sal_Char __FAR_DATA sCalc_Mul[] = "mul";
const sal_Char __FAR_DATA sCalc_Div[] = "div";
const sal_Char __FAR_DATA sCalc_Phd[] = "phd";
const sal_Char __FAR_DATA sCalc_Sqrt[] = "sqrt";
const sal_Char __FAR_DATA sCalc_Pow[] = "pow";
const sal_Char __FAR_DATA sCalc_Or[] = "or";
const sal_Char __FAR_DATA sCalc_Xor[] = "xor";
const sal_Char __FAR_DATA sCalc_And[] = "and";
const sal_Char __FAR_DATA sCalc_Not[] = "not";
const sal_Char __FAR_DATA sCalc_Eq[] = "eq";
const sal_Char __FAR_DATA sCalc_Neq[] = "neq";
const sal_Char __FAR_DATA sCalc_Leq[] = "leq";
const sal_Char __FAR_DATA sCalc_Geq[] = "geq";
const sal_Char __FAR_DATA sCalc_L[] = "l";
const sal_Char __FAR_DATA sCalc_G[] = "g";
const sal_Char __FAR_DATA sCalc_Sum[] = "sum";
const sal_Char __FAR_DATA sCalc_Mean[] = "mean";
const sal_Char __FAR_DATA sCalc_Min[] = "min";
const sal_Char __FAR_DATA sCalc_Max[] = "max";
const sal_Char __FAR_DATA sCalc_Sin[] = "sin";
const sal_Char __FAR_DATA sCalc_Cos[] = "cos";
const sal_Char __FAR_DATA sCalc_Tan[] = "tan";
const sal_Char __FAR_DATA sCalc_Asin[] = "asin";
const sal_Char __FAR_DATA sCalc_Acos[] = "acos";
const sal_Char __FAR_DATA sCalc_Atan[] = "atan";
const sal_Char __FAR_DATA sCalc_Round[] = "round";
const sal_Char __FAR_DATA sCalc_Date[] = "date";
//!!!!! ACHTUNG - Sortierte Liste aller Operatoren !!!!!
struct _CalcOp
{
union{
const sal_Char* pName;
const String* pUName;
};
SwCalcOper eOp;
};
_CalcOp __READONLY_DATA aOpTable[] = {
/* ACOS */ {{sCalc_Acos}, CALC_ACOS}, // Arcuscosinus
/* ADD */ {{sCalc_Add}, CALC_PLUS}, // Addition
/* AND */ {{sCalc_And}, CALC_AND}, // log. und
/* ASIN */ {{sCalc_Asin}, CALC_ASIN}, // Arcussinus
/* ATAN */ {{sCalc_Atan}, CALC_ATAN}, // Arcustangens
/* COS */ {{sCalc_Cos}, CALC_COS}, // Cosinus
/* DATE */ {{sCalc_Date}, CALC_DATE}, // Date
/* DIV */ {{sCalc_Div}, CALC_DIV}, // Dividieren
/* EQ */ {{sCalc_Eq}, CALC_EQ}, // gleich
/* G */ {{sCalc_G}, CALC_GRE}, // groesser
/* GEQ */ {{sCalc_Geq}, CALC_GEQ}, // groesser gleich
/* L */ {{sCalc_L}, CALC_LES}, // kleiner
/* LEQ */ {{sCalc_Leq}, CALC_LEQ}, // kleiner gleich
/* MAX */ {{sCalc_Max}, CALC_MAX}, // Maximalwert
/* MEAN */ {{sCalc_Mean}, CALC_MEAN}, // Mittelwert
/* MIN */ {{sCalc_Min}, CALC_MIN}, // Minimalwert
/* MUL */ {{sCalc_Mul}, CALC_MUL}, // Multiplizieren
/* NEQ */ {{sCalc_Neq}, CALC_NEQ}, // nicht gleich
/* NOT */ {{sCalc_Not}, CALC_NOT}, // log. nicht
/* OR */ {{sCalc_Or}, CALC_OR}, // log. oder
/* PHD */ {{sCalc_Phd}, CALC_PHD}, // Prozent
/* POW */ {{sCalc_Pow}, CALC_POW}, // Potenzieren
/* ROUND */ {{sCalc_Round}, CALC_ROUND}, // Runden
/* SIN */ {{sCalc_Sin}, CALC_SIN}, // Sinus
/* SQRT */ {{sCalc_Sqrt}, CALC_SQRT}, // Wurzel
/* SUB */ {{sCalc_Sub}, CALC_MINUS}, // Subtraktion
/* SUM */ {{sCalc_Sum}, CALC_SUM}, // Summe
/* TAN */ {{sCalc_Tan}, CALC_TAN}, // Tangens
/* XOR */ {{sCalc_Xor}, CALC_XOR} // log. xoder
};
double __READONLY_DATA nRoundVal[] = {
5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6,
0.5e-7, 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,
0.5e-15,0.5e-16
};
double __READONLY_DATA nKorrVal[] = {
9, 9e-1, 9e-2, 9e-3, 9e-4, 9e-5, 9e-6, 9e-7, 9e-8,
9e-9, 9e-10, 9e-11, 9e-12, 9e-13, 9e-14
};
// First character may be any alphabetic or underscore.
const sal_Int32 coStartFlags =
i18n::KParseTokens::ANY_LETTER_OR_NUMBER |
i18n::KParseTokens::ASC_UNDERSCORE |
i18n::KParseTokens::IGNORE_LEADING_WS;
// Continuing characters may be any alphanumeric or underscore or dot.
const sal_Int32 coContFlags =
( coStartFlags | i18n::KParseTokens::ASC_DOT )
& ~i18n::KParseTokens::IGNORE_LEADING_WS;
extern "C" {
static int
#if defined( WNT )
__cdecl
#endif
#if defined( ICC )
_Optlink
#endif
OperatorCompare( const void *pFirst, const void *pSecond)
{
int nRet = 0;
if( CALC_NAME == ((_CalcOp*)pFirst)->eOp )
{
if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
nRet = ((_CalcOp*)pFirst)->pUName->CompareTo(
*((_CalcOp*)pSecond)->pUName );
else
nRet = ((_CalcOp*)pFirst)->pUName->CompareToAscii(
((_CalcOp*)pSecond)->pName );
}
else
{
if( CALC_NAME == ((_CalcOp*)pSecond)->eOp )
nRet = -1 * ((_CalcOp*)pSecond)->pUName->CompareToAscii(
((_CalcOp*)pFirst)->pName );
else
nRet = strcmp( ((_CalcOp*)pFirst)->pName,
((_CalcOp*)pSecond)->pName );
}
return nRet;
}
}// extern "C"
_CalcOp* FindOperator( const String& rSrch )
{
_CalcOp aSrch;
aSrch.pUName = &rSrch;
aSrch.eOp = CALC_NAME;
return (_CalcOp*)bsearch( (void*) &aSrch,
(void*) aOpTable,
sizeof( aOpTable ) / sizeof( _CalcOp ),
sizeof( _CalcOp ),
OperatorCompare );
}
//-----------------------------------------------------------------------------
SwHash* Find( const String& rStr, SwHash** ppTable, sal_uInt16 nTblSize,
sal_uInt16* pPos )
{
sal_uLong ii = 0;
for( xub_StrLen n = 0; n < rStr.Len(); ++n )
ii = ii << 1 ^ rStr.GetChar( n );
ii %= nTblSize;
if( pPos )
*pPos = (sal_uInt16)ii;
for( SwHash* pEntry = *(ppTable+ii); pEntry; pEntry = pEntry->pNext )
if( rStr == pEntry->aStr )
return pEntry;
return 0;
}
inline LanguageType GetDocAppScriptLang( SwDoc& rDoc )
{
return ((SvxLanguageItem&)rDoc.GetDefault(
GetWhichOfScript( RES_CHRATR_LANGUAGE,
GetI18NScriptTypeOfLanguage( (sal_uInt16)GetAppLanguage() ))
)).GetLanguage();
}
double lcl_ConvertToDateValue( SwDoc& rDoc, sal_Int32 nDate )
{
double nRet = 0;
SvNumberFormatter* pFormatter = rDoc.GetNumberFormatter();
if( pFormatter )
{
Date* pNull = pFormatter->GetNullDate();
Date aDate( nDate >> 24, (nDate & 0x00FF0000) >> 16, nDate & 0x0000FFFF );
nRet = aDate - *pNull;
}
return nRet;
}
//-----------------------------------------------------------------------------
/******************************************************************************
|*
|* SwCalc::SwCalc( SwDoc* pD ) :
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung JP 03.11.95
|*
|******************************************************************************/
SwCalc::SwCalc( SwDoc& rD )
:
aErrExpr( aEmptyStr, SwSbxValue(), 0 ),
rDoc( rD ),
pLclData( m_aSysLocale.GetLocaleDataPtr() ),
pCharClass( &GetAppCharClass() ),
nListPor( 0 ),
eError( CALC_NOERR )
{
aErrExpr.aStr.AssignAscii( "~C_ERR~" );
memset( VarTable, 0, sizeof(VarTable) );
LanguageType eLang = GetDocAppScriptLang( rDoc );
if( eLang != SvxLocaleToLanguage( pLclData->getLocale() ) ||
eLang != SvxLocaleToLanguage( pCharClass->getLocale() ) )
{
STAR_NMSPC::lang::Locale aLocale( SvxCreateLocale( eLang ));
STAR_REFERENCE( lang::XMultiServiceFactory ) xMSF(
::comphelper::getProcessServiceFactory() );
pCharClass = new CharClass( xMSF, aLocale );
pLclData = new LocaleDataWrapper( xMSF, aLocale );
}
sCurrSym = pLclData->getCurrSymbol();
sCurrSym.EraseLeadingChars().EraseTrailingChars();
pCharClass->toLower( sCurrSym );
static sal_Char __READONLY_DATA
sNType0[] = "false",
sNType1[] = "true",
sNType2[] = "pi",
sNType3[] = "e",
sNType4[] = "tables",
sNType5[] = "graf",
sNType6[] = "ole",
sNType7[] = "page",
sNType8[] = "para",
sNType9[] = "word",
sNType10[]= "char",
sNType11[] = "user_firstname" ,
sNType12[] = "user_lastname" ,
sNType13[] = "user_initials" ,
sNType14[] = "user_company" ,
sNType15[] = "user_street" ,
sNType16[] = "user_country" ,
sNType17[] = "user_zipcode" ,
sNType18[] = "user_city" ,
sNType19[] = "user_title" ,
sNType20[] = "user_position" ,
sNType21[] = "user_tel_work" ,
sNType22[] = "user_tel_home" ,
sNType23[] = "user_fax" ,
sNType24[] = "user_email" ,
sNType25[] = "user_state" ,
sNType26[] = "graph"
;
static const sal_Char* __READONLY_DATA sNTypeTab[ 27 ] =
{
sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
sNType24,
// diese sind mit doppelten HashIds
sNType25, sNType26
};
static sal_uInt16 __READONLY_DATA aHashValue[ 27 ] =
{
34, 38, 43, 7, 18, 32, 22, 29, 30, 33, 3,
28, 24, 40, 9, 11, 26, 45, 4, 23, 36, 44, 19, 5, 1,
// diese sind mit doppelten HashIds
11, 38
};
static sal_uInt16 __READONLY_DATA aAdrToken[ 12 ] =
{
USER_OPT_COMPANY, USER_OPT_STREET, USER_OPT_COUNTRY, USER_OPT_ZIP,
USER_OPT_CITY, USER_OPT_TITLE, USER_OPT_POSITION, USER_OPT_TELEPHONEWORK,
USER_OPT_TELEPHONEHOME, USER_OPT_FAX, USER_OPT_EMAIL, USER_OPT_STATE
};
static sal_uInt16 SwDocStat::* __READONLY_DATA aDocStat1[ 3 ] =
{
&SwDocStat::nTbl, &SwDocStat::nGrf, &SwDocStat::nOLE
};
static sal_uLong SwDocStat::* __READONLY_DATA aDocStat2[ 4 ] =
{
&SwDocStat::nPage, &SwDocStat::nPara,
&SwDocStat::nWord, &SwDocStat::nChar
};
#if TBLSZ != 47
#error Alle Hashwerte angepasst?
#endif
const SwDocStat& rDocStat = rDoc.GetDocStat();
SwSbxValue nVal;
String sTmpStr;
sal_uInt16 n;
for( n = 0; n < 25; ++n )
{
sTmpStr.AssignAscii( sNTypeTab[ n ] );
VarTable[ aHashValue[ n ] ] = new SwCalcExp( sTmpStr, nVal, 0 );
}
((SwCalcExp*)VarTable[ aHashValue[ 0 ] ])->nValue.PutBool( sal_False );
((SwCalcExp*)VarTable[ aHashValue[ 1 ] ])->nValue.PutBool( sal_True );
((SwCalcExp*)VarTable[ aHashValue[ 2 ] ])->nValue.PutDouble( F_PI );
((SwCalcExp*)VarTable[ aHashValue[ 3 ] ])->nValue.PutDouble( 2.7182818284590452354 );
for( n = 0; n < 3; ++n )
((SwCalcExp*)VarTable[ aHashValue[ n + 4 ] ])->nValue.PutLong( rDocStat.*aDocStat1[ n ] );
for( n = 0; n < 4; ++n )
((SwCalcExp*)VarTable[ aHashValue[ n + 7 ] ])->nValue.PutLong( rDocStat.*aDocStat2[ n ] );
SvtUserOptions& rUserOptions = SW_MOD()->GetUserOptions();
((SwCalcExp*)VarTable[ aHashValue[ 11 ] ])->nValue.PutString( (String)rUserOptions.GetFirstName() );
((SwCalcExp*)VarTable[ aHashValue[ 12 ] ])->nValue.PutString( (String)rUserOptions.GetLastName() );
((SwCalcExp*)VarTable[ aHashValue[ 13 ] ])->nValue.PutString( (String)rUserOptions.GetID() );
for( n = 0; n < 11; ++n )
((SwCalcExp*)VarTable[ aHashValue[ n + 14 ] ])->nValue.PutString(
(String)rUserOptions.GetToken( aAdrToken[ n ] ));
nVal.PutString( (String)rUserOptions.GetToken( aAdrToken[ 11 ] ));
sTmpStr.AssignAscii( sNTypeTab[ 25 ] );
VarTable[ aHashValue[ 25 ] ]->pNext = new SwCalcExp( sTmpStr, nVal, 0 );
// at time its better not to use "graph", because then the im-/export have
// to change in all formulas this name.
// nVal.PutLong( rDocStat.*aDocStat1[ 1 ] );
// VarTable[ aHashValue[ 26 ] ]->pNext = new SwCalcExp(
// sNTypeTab[ 26 ], nVal, 0 );
}
/******************************************************************************
|*
|* SwCalc::~SwCalc()
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung OK 12-02-93 11:04am
|*
|******************************************************************************/
SwCalc::~SwCalc()
{
for( sal_uInt16 n = 0; n < TBLSZ; ++n )
delete VarTable[n];
if( pLclData != m_aSysLocale.GetLocaleDataPtr() )
delete pLclData;
if( pCharClass != &GetAppCharClass() )
delete pCharClass;
}
/******************************************************************************
|*
|* SwSbxValue SwCalc::Calculate( const String& rStr )
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung OK 12-02-93 11:04am
|*
|******************************************************************************/
SwSbxValue SwCalc::Calculate( const String& rStr )
{
eError = CALC_NOERR;
SwSbxValue nResult;
if( !rStr.Len() )
return nResult;
nListPor = 0;
eCurrListOper = CALC_PLUS; // defaulten auf Summe
sCommand = rStr;
nCommandPos = 0;
while( (eCurrOper = GetToken()) != CALC_ENDCALC && eError == CALC_NOERR )
nResult = Expr();
if( eError )
nResult.PutDouble( DBL_MAX );
return nResult;
}
/******************************************************************************
|*
|* String SwCalc::GetStrResult( SwSbxValue nValue, sal_Bool bRound = sal_True )
|* Beschreibung Der Parameter bRound ist auf sal_True defaultet und darf
|* nur beim errechnen von Tabellenzellen auf sal_False gesetzt
|* werden, damit keine Rundungsfehler beim zusammenstellen
|* der Formel entstehen.
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung JP 19.02.98
|*
|******************************************************************************/
String SwCalc::GetStrResult( const SwSbxValue& rVal, sal_Bool bRound )
{
if( !rVal.IsDouble() )
return rVal.GetString();
return GetStrResult( rVal.GetDouble(), bRound );
}
String SwCalc::GetStrResult( double nValue, sal_Bool )
{
if( nValue >= DBL_MAX )
switch( eError )
{
case CALC_SYNTAX : return RESOURCE->aCalc_Syntax;
case CALC_ZERODIV : return RESOURCE->aCalc_ZeroDiv;
case CALC_BRACK : return RESOURCE->aCalc_Brack;
case CALC_POWERR : return RESOURCE->aCalc_Pow;
case CALC_VARNFND : return RESOURCE->aCalc_VarNFnd;
case CALC_OVERFLOW : return RESOURCE->aCalc_Overflow;
case CALC_WRONGTIME : return RESOURCE->aCalc_WrongTime;
default : return RESOURCE->aCalc_Default;
}
sal_uInt16 nDec = 15; //pLclData->getNumDigits();
String aRetStr( ::rtl::math::doubleToUString( nValue,
rtl_math_StringFormat_Automatic,
nDec,
pLclData->getNumDecimalSep().GetChar(0),
true ));
return aRetStr;
}
/******************************************************************************
|*
|* SwCalcExp* SwCalc::VarLook( const String& )
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung JP 15.11.99
|*
|******************************************************************************/
SwCalcExp* SwCalc::VarInsert( const String &rStr )
{
String aStr( rStr );
pCharClass->toLower( aStr );
return VarLook( aStr, 1 );
}
/******************************************************************************
|*
|* SwCalcExp* SwCalc::VarLook( const String& , sal_uInt16 ins )
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung JP 15.11.99
|*
|******************************************************************************/
SwCalcExp* SwCalc::VarLook( const String& rStr, sal_uInt16 ins )
{
aErrExpr.nValue.SetVoidValue(false);
sal_uInt16 ii = 0;
String aStr( rStr );
pCharClass->toLower( aStr );
SwHash* pFnd = Find( aStr, VarTable, TBLSZ, &ii );
if( !pFnd )
{
// dann sehen wir mal im Doc nach:
SwHash** ppDocTbl = rDoc.GetUpdtFlds().GetFldTypeTable();
for( SwHash* pEntry = *(ppDocTbl+ii); pEntry; pEntry = pEntry->pNext )
if( aStr == pEntry->aStr )
{
// dann hier zufuegen
pFnd = new SwCalcExp( aStr, SwSbxValue(),
((SwCalcFldType*)pEntry)->pFldType );
pFnd->pNext = *(VarTable+ii);
*(VarTable+ii) = pFnd;
break;
}
}
if( pFnd )
{
SwCalcExp* pFndExp = (SwCalcExp*)pFnd;
if( pFndExp->pFldType && pFndExp->pFldType->Which() == RES_USERFLD )
{
SwUserFieldType* pUFld = (SwUserFieldType*)pFndExp->pFldType;
if( nsSwGetSetExpType::GSE_STRING & pUFld->GetType() )
pFndExp->nValue.PutString( pUFld->GetContent() );
else if( !pUFld->IsValid() )
{
// Die aktuellen Werte sichern . . .
sal_uInt16 nOld_ListPor = nListPor;
SwSbxValue nOld_LastLeft = nLastLeft;
SwSbxValue nOld_NumberValue = nNumberValue;
xub_StrLen nOld_CommandPos = nCommandPos;
SwCalcOper eOld_CurrOper = eCurrOper;
SwCalcOper eOld_CurrListOper = eCurrListOper;
pFndExp->nValue.PutDouble( pUFld->GetValue( *this ) );
// . . . und zurueck damit.
nListPor = nOld_ListPor;
nLastLeft = nOld_LastLeft;
nNumberValue = nOld_NumberValue;
nCommandPos = nOld_CommandPos;
eCurrOper = eOld_CurrOper;
eCurrListOper = eOld_CurrListOper;
}
else
pFndExp->nValue.PutDouble( pUFld->GetValue() );
}
return pFndExp;
}
// Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
// DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
// #101436#: At this point the "real" case variable has to be used
String sTmpName( rStr );
::ReplacePoint( sTmpName );
if( !ins )
{
SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
// Name(p)=Adress.PLZ oder Adress.DATENSATZNUMMER
// DBSETNUMBERFLD = DatenSATZ-nummernfeld (NICHT "setze Datensatznummer!!!")
String sDBName(GetDBName( sTmpName ));
String sSourceName(sDBName.GetToken(0, DB_DELIM));
String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
if( pMgr && sSourceName.Len() && sTableName.Len() &&
pMgr->OpenDataSource(sSourceName, sTableName, -1, false))
{
String sColumnName( GetColumnName( sTmpName ));
ASSERT (sColumnName.Len(), "DB-Spaltenname fehlt!");
String sDBNum( SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD) );
pCharClass->toLower(sDBNum);
// Hier nochmal initialisieren, da das nicht mehr in docfld
// fuer Felder != RES_DBFLD geschieht. Z.B. wenn ein Expressionfield
// vor einem DB_Field in einem Dok vorkommt.
VarChange( sDBNum, pMgr->GetSelectedRecordId(sSourceName, sTableName));
if( sDBNum.EqualsIgnoreCaseAscii(sColumnName) )
{
aErrExpr.nValue.PutLong(long(pMgr->GetSelectedRecordId(sSourceName, sTableName)));
return &aErrExpr;
}
sal_uLong nTmpRec = 0;
if( 0 != ( pFnd = Find( sDBNum, VarTable, TBLSZ ) ) )
nTmpRec = ((SwCalcExp*)pFnd)->nValue.GetULong();
String sResult;
double nNumber = DBL_MAX;
long nLang = SvxLocaleToLanguage( pLclData->getLocale() );
if(pMgr->GetColumnCnt( sSourceName, sTableName, sColumnName,
nTmpRec, nLang, sResult, &nNumber ))
{
if (nNumber != DBL_MAX)
aErrExpr.nValue.PutDouble( nNumber );
else
aErrExpr.nValue.PutString( sResult );
return &aErrExpr;
}
}
else
{
//data source was not available - set return to "NoValue"
aErrExpr.nValue.SetVoidValue(true);
}
// auf keinen fall eintragen!!
return &aErrExpr;
}
SwCalcExp* pNewExp = new SwCalcExp( aStr, SwSbxValue(), 0 );
pNewExp->pNext = VarTable[ ii ];
VarTable[ ii ] = pNewExp;
String sColumnName( GetColumnName( sTmpName ));
ASSERT( sColumnName.Len(), "DB-Spaltenname fehlt!" );
if( sColumnName.EqualsIgnoreCaseAscii(
SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ))
{
SwNewDBMgr *pMgr = rDoc.GetNewDBMgr();
String sDBName(GetDBName( sTmpName ));
String sSourceName(sDBName.GetToken(0, DB_DELIM));
String sTableName(sDBName.GetToken(0).GetToken(1, DB_DELIM));
if( pMgr && sSourceName.Len() && sTableName.Len() &&
pMgr->OpenDataSource(sSourceName, sTableName, -1, false) &&
!pMgr->IsInMerge())
pNewExp->nValue.PutULong( pMgr->GetSelectedRecordId(sSourceName, sTableName));
else
pNewExp->nValue.SetVoidValue(true);
}
return pNewExp;
}
/******************************************************************************
|*
|* sal_Bool SwCalc::VarChange( const String& rStr, const SwSbxValue nValue )
|*
|* Erstellung OK 12-02-93 11:04am
|* Letzte Aenderung OK 12-02-93 11:04am
|*
|******************************************************************************/
void SwCalc::VarChange( const String& rStr, double nValue )
{
SwSbxValue aVal( nValue );
VarChange( rStr, aVal );
}
void SwCalc::VarChange( const String& rStr, const SwSbxValue& rValue )
{
String aStr( rStr );
pCharClass->toLower( aStr );
sal_uInt16 nPos = 0;
SwCalcExp* pFnd = (SwCalcExp*)Find( aStr, VarTable, TBLSZ, &nPos );
if( !pFnd )
{
pFnd = new SwCalcExp( aStr, SwSbxValue( rValue ), 0 );
pFnd->pNext = VarTable[ nPos ];
VarTable[ nPos ] = pFnd;
}
else
pFnd->nValue = rValue;
}
/******************************************************************************
|*
|* sal_Bool SwCalc::Push( const void* pPtr )
|*
|* Erstellung OK 12-02-93 11:05am
|* Letzte Aenderung OK 12-02-93 11:05am
|*
|******************************************************************************/
sal_Bool SwCalc::Push( const VoidPtr pPtr )
{
if( USHRT_MAX != aRekurStk.GetPos( pPtr ) )
return sal_False;
aRekurStk.Insert( pPtr, aRekurStk.Count() );
return sal_True;
}
/******************************************************************************
|*
|* void SwCalc::Pop( const void* pPtr )
|*
|* Erstellung OK 12-02-93 11:05am
|* Letzte Aenderung OK 12-02-93 11:05am
|*
|******************************************************************************/
void SwCalc::Pop( const VoidPtr )
{
ASSERT( aRekurStk.Count(), "SwCalc: Pop auf ungueltigen Ptr" );
aRekurStk.Remove( aRekurStk.Count() - 1 );
}
/******************************************************************************
|*
|* SwCalcOper SwCalc::GetToken()
|*
|* Erstellung OK 12-02-93 11:05am
|* Letzte Aenderung JP 03.11.95
|*
|******************************************************************************/
SwCalcOper SwCalc::GetToken()
{
#if OSL_DEBUG_LEVEL > 1
//JP 25.01.2001: static for switch back to the "old" implementation of the
// calculator, which don't use the I18N routines.
static int nUseOld = 0;
if( !nUseOld )
{
#endif
if( nCommandPos >= sCommand.Len() )
return eCurrOper = CALC_ENDCALC;
using namespace ::com::sun::star::i18n;
{
// Parse any token.
ParseResult aRes = pCharClass->parseAnyToken( sCommand, nCommandPos,
coStartFlags, aEmptyStr,
coContFlags, aEmptyStr );
sal_Bool bSetError = sal_True;
xub_StrLen nRealStt = nCommandPos + (xub_StrLen)aRes.LeadingWhiteSpace;
if( aRes.TokenType & (KParseType::ASC_NUMBER | KParseType::UNI_NUMBER) )
{
nNumberValue.PutDouble( aRes.Value );
eCurrOper = CALC_NUMBER;
bSetError = sal_False;
}
else if( aRes.TokenType & KParseType::IDENTNAME )
{
String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
//#101436#: the variable may contain a database name it must not be converted to lower case
// instead all further comparisons must be done case-insensitive
//pCharClass->toLower( aName );
String sLowerCaseName(aName);
pCharClass->toLower( sLowerCaseName );
// Currency-Symbol abfangen
if( sLowerCaseName == sCurrSym )
{
nCommandPos = (xub_StrLen)aRes.EndPos;
return GetToken(); // also nochmal aufrufen
}
// Operations abfangen
_CalcOp* pFnd = ::FindOperator( sLowerCaseName );
if( pFnd )
{
switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
{
case CALC_SUM:
case CALC_MEAN:
eCurrListOper = CALC_PLUS;
break;
case CALC_MIN:
eCurrListOper = CALC_MIN_IN;
break;
case CALC_MAX:
eCurrListOper = CALC_MAX_IN;
break;
case CALC_DATE:
eCurrListOper = CALC_MONTH;
break;
default:
break;
}
nCommandPos = (xub_StrLen)aRes.EndPos;
return eCurrOper;
}
aVarName = aName;
eCurrOper = CALC_NAME;
bSetError = sal_False;
}
else if ( aRes.TokenType & KParseType::DOUBLE_QUOTE_STRING )
{
nNumberValue.PutString( String( aRes.DequotedNameOrString ));
eCurrOper = CALC_NUMBER;
bSetError = sal_False;
}
else if( aRes.TokenType & KParseType::ONE_SINGLE_CHAR )
{
String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
if( 1 == aName.Len() )
{
bSetError = sal_False;
sal_Unicode ch = aName.GetChar( 0 );
switch( ch )
{
case ';': if( CALC_MONTH == eCurrListOper ||
CALC_DAY == eCurrListOper )
{
eCurrOper = eCurrListOper;
break;
}
case '\n':
eCurrOper = CALC_PRINT;
break;
case '%':
case '^':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')': eCurrOper = SwCalcOper(ch);
break;
case '=':
case '!':
{
SwCalcOper eTmp2;
if( '=' == ch )
eCurrOper = SwCalcOper('='), eTmp2 = CALC_EQ;
else
eCurrOper = CALC_NOT, eTmp2 = CALC_NEQ;
if( aRes.EndPos < sCommand.Len() &&
'=' == sCommand.GetChar( (xub_StrLen)aRes.EndPos ) )
{
eCurrOper = eTmp2;
++aRes.EndPos;
}
}
break;
case cListDelim :
eCurrOper = eCurrListOper;
break;
case '[':
if( aRes.EndPos < sCommand.Len() )
{
aVarName.Erase();
xub_StrLen nFndPos = (xub_StrLen)aRes.EndPos,
nSttPos = nFndPos;
do{
if( STRING_NOTFOUND != ( nFndPos =
sCommand.Search( ']', nFndPos )) )
{
// ignore the ]
if( '\\' == sCommand.GetChar(nFndPos-1))
{
aVarName += sCommand.Copy( nSttPos,
nFndPos - nSttPos - 1 );
nSttPos = ++nFndPos;
}
else
break;
}
} while( STRING_NOTFOUND != nFndPos );
if( STRING_NOTFOUND != nFndPos )
{
if( nSttPos != nFndPos )
aVarName += sCommand.Copy( nSttPos,
nFndPos - nSttPos );
aRes.EndPos = nFndPos + 1;
eCurrOper = CALC_NAME;
}
else
bSetError = sal_True;
}
else
bSetError = sal_True;
break;
default:
bSetError = sal_True;
break;
}
}
}
else if( aRes.TokenType & KParseType::BOOLEAN )
{
String aName( sCommand.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt ));
if( aName.Len() )
{
sal_Unicode ch = aName.GetChar(0);
bSetError = sal_True;
if ('<' == ch || '>' == ch)
{
bSetError = sal_False;
SwCalcOper eTmp2 = ('<' == ch) ? CALC_LEQ : CALC_GEQ;
eCurrOper = ('<' == ch) ? CALC_LES : CALC_GRE;
if( 2 == aName.Len() && '=' == aName.GetChar(1) )
eCurrOper = eTmp2;
else if( 1 != aName.Len() )
bSetError = sal_True;
}
}
}
else if( nRealStt == sCommand.Len() )
{
eCurrOper = CALC_ENDCALC;
bSetError = sal_False;
}
if( bSetError )
{
eError = CALC_SYNTAX;
eCurrOper = CALC_PRINT;
}
nCommandPos = (xub_StrLen)aRes.EndPos;
};
#if OSL_DEBUG_LEVEL > 1
#define NextCh( s, n ) (nCommandPos < sCommand.Len() ? sCommand.GetChar( nCommandPos++ ) : 0)
}
else
{
sal_Unicode ch;
sal_Unicode cTSep = pLclData->getNumThousandSep().GetChar(0),
cDSep = pLclData->getNumDecimalSep().GetChar(0);
do {
if( 0 == ( ch = NextCh( sCommand, nCommandPos ) ) )
return eCurrOper = CALC_ENDCALC;
} while ( ch == '\t' || ch == ' ' || ch == cTSep );
if( ch == cDSep )
ch = '.';
switch( ch )
{
case ';': if( CALC_MONTH == eCurrListOper || CALC_DAY == eCurrListOper )
{
eCurrOper = eCurrListOper;
break;
} // else .. no break
case '\n':
{
sal_Unicode c;
while( nCommandPos < sCommand.Len() && ( ( c =
sCommand.GetChar( nCommandPos ) ) == ' ' ||
c == '\t' || c == '\x0a' || c == '\x0d' ))
++nCommandPos;
eCurrOper = CALC_PRINT;
}
break;
case '%':
case '^':
case '*':
case '/':
case '+':
case '-':
case '(':
case ')': eCurrOper = SwCalcOper(ch);
break;
case '=': if( '=' == sCommand.GetChar( nCommandPos ) )
{
++nCommandPos;
eCurrOper = CALC_EQ;
}
else
eCurrOper = SwCalcOper(ch);
break;
case '!': if( '=' == sCommand.GetChar( nCommandPos ) )
{
++nCommandPos;
eCurrOper = CALC_NEQ;
}
else
eCurrOper = CALC_NOT;
break;
case '>':
case '<': eCurrOper = '>' == ch ? CALC_GRE : CALC_LES;
if( '=' == (ch = sCommand.GetChar( nCommandPos ) ) )
{
++nCommandPos;
eCurrOper = CALC_GRE == eCurrOper ? CALC_GEQ : CALC_LEQ;
}
else if( ' ' != ch )
{
eError = CALC_SYNTAX;
eCurrOper = CALC_PRINT;
}
break;
case cListDelim :
eCurrOper = eCurrListOper;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case ',':
case '.': {
double nVal;
--nCommandPos; // auf das 1. Zeichen zurueck
if( Str2Double( sCommand, nCommandPos, nVal, pLclData ))
{
nNumberValue.PutDouble( nVal );
eCurrOper = CALC_NUMBER;
}
else
{
// fehlerhafte Zahl
eError = CALC_SYNTAX;
eCurrOper = CALC_PRINT;
}
}
break;
case '[': {
String aStr;
sal_Bool bIgnore = sal_False;
do {
while( 0 != ( ch = NextCh( sCommand, nCommandPos ))
&& ch != ']' )
{
if( !bIgnore && '\\' == ch )
bIgnore = sal_True;
else if( bIgnore )
bIgnore = sal_False;
aStr += ch;
}
if( !bIgnore )
break;
aStr.SetChar( aStr.Len() - 1, ch );
} while( ch );
aVarName = aStr;
eCurrOper = CALC_NAME;
}
break;
case '"': {
xub_StrLen nStt = nCommandPos;
while( 0 != ( ch = NextCh( sCommand, nCommandPos ) )
&& '"' != ch )
;
xub_StrLen nLen = nCommandPos - nStt;
if( '"' == ch )
--nLen;
nNumberValue.PutString( sCommand.Copy( nStt, nLen ));
eCurrOper = CALC_NUMBER;
}
break;
default: if( ch && pCharClass->isLetter( sCommand, nCommandPos - 1)
|| '_' == ch )
{
xub_StrLen nStt = nCommandPos-1;
while( 0 != (ch = NextCh( sCommand, nCommandPos )) &&
(pCharClass->isLetterNumeric(
sCommand, nCommandPos - 1) ||
ch == '_' || ch == '.' ) )
;
if( ch )
--nCommandPos;
String aStr( sCommand.Copy( nStt, nCommandPos-nStt ));
pCharClass->toLower( aStr );
// Currency-Symbol abfangen
if( aStr == sCurrSym )
return GetToken(); // also nochmal aufrufen
// Operations abfangen
_CalcOp* pFnd = ::FindOperator( aStr );
if( pFnd )
{
switch( ( eCurrOper = ((_CalcOp*)pFnd)->eOp ) )
{
case CALC_SUM :
case CALC_MEAN : eCurrListOper = CALC_PLUS;
break;
case CALC_MIN : eCurrListOper = CALC_MIN_IN;
break;
case CALC_MAX : eCurrListOper = CALC_MAX_IN;
break;
case CALC_DATE : eCurrListOper = CALC_MONTH;
break;
default :
break;
}
return eCurrOper;
}
aVarName = aStr;
eCurrOper = CALC_NAME;
}
else
{
eError = CALC_SYNTAX;
eCurrOper = CALC_PRINT;
}
break;
}
}
#endif
return eCurrOper;
}
/******************************************************************************
|*
|* SwSbxValue SwCalc::Term()
|*
|* Erstellung OK 12-02-93 11:05am
|* Letzte Aenderung JP 16.01.96
|*
|******************************************************************************/
SwSbxValue SwCalc::Term()
{
SwSbxValue left( Prim() );
nLastLeft = left;
for(;;)
{
sal_uInt16 nSbxOper = USHRT_MAX;
switch( eCurrOper )
{
// wir haben kein Bitweises verodern, oder ?
// case CALC_AND: eSbxOper = SbxAND; break;
// case CALC_OR: eSbxOper = SbxOR; break;
// case CALC_XOR: eSbxOper = SbxXOR; break;
case CALC_AND: {
GetToken();
sal_Bool bB = Prim().GetBool();
left.PutBool( left.GetBool() && bB );
}
break;
case CALC_OR: {
GetToken();
sal_Bool bB = Prim().GetBool();
left.PutBool( left.GetBool() || bB );
}
break;
case CALC_XOR: {
GetToken();
sal_Bool bR = Prim().GetBool();
sal_Bool bL = left.GetBool();
left.PutBool( (bL && !bR) || (!bL && bR) );
}
break;
case CALC_EQ: nSbxOper = SbxEQ; break;
case CALC_NEQ: nSbxOper = SbxNE; break;
case CALC_LEQ: nSbxOper = SbxLE; break;
case CALC_GEQ: nSbxOper = SbxGE; break;
case CALC_GRE: nSbxOper = SbxGT; break;
case CALC_LES: nSbxOper = SbxLT; break;
case CALC_MUL: nSbxOper = SbxMUL; break;
case CALC_DIV: nSbxOper = SbxDIV; break;
case CALC_MIN_IN:
{
GetToken();
SwSbxValue e = Prim();
left = left.GetDouble() < e.GetDouble()
? left : e;
}
break;
case CALC_MAX_IN:
{
GetToken();
SwSbxValue e = Prim();
left = left.GetDouble() > e.GetDouble()
? left : e;
}
break;
case CALC_MONTH:
{
GetToken();
SwSbxValue e = Prim();
sal_Int32 nYear = (sal_Int32) floor( left.GetDouble() );
nYear = nYear & 0x0000FFFF;
sal_Int32 nMonth = (sal_Int32) floor( e.GetDouble() );
nMonth = ( nMonth & 0x000000FF ) << 16;
left.PutLong( nMonth + nYear );
eCurrOper = CALC_DAY;
}
break;
case CALC_DAY:
{
GetToken();
SwSbxValue e = Prim();
sal_Int32 nYearMonth = (sal_Int32) floor( left.GetDouble() );
nYearMonth = nYearMonth & 0x00FFFFFF;
sal_Int32 nDay = (sal_Int32) floor( e.GetDouble() );
nDay = ( nDay & 0x000000FF ) << 24;
left = lcl_ConvertToDateValue( rDoc, nDay + nYearMonth );
}
break;
case CALC_ROUND:
{
GetToken();
SwSbxValue e = Prim();
double fVal = 0;
double fFac = 1;
sal_Int32 nDec = (sal_Int32) floor( e.GetDouble() );
if( nDec < -20 || nDec > 20 )
{
eError = CALC_OVERFLOW;
left.Clear();
return left;
}
fVal = left.GetDouble();
sal_uInt16 i;
if( nDec >= 0)
for (i = 0; i < (sal_uInt16) nDec; ++i )
fFac *= 10.0;
else
for (i = 0; i < (sal_uInt16) -nDec; ++i )
fFac /= 10.0;
fVal *= fFac;
sal_Bool bSign;
if (fVal < 0.0)
{
fVal *= -1.0;
bSign = sal_True;
}
else
bSign = sal_False;
// runden
double fNum = fVal; // find the exponent
int nExp = 0;
if( fNum > 0 )
{
while( fNum < 1.0 ) fNum *= 10.0, --nExp;
while( fNum >= 10.0 ) fNum /= 10.0, ++nExp;
}
nExp = 15 - nExp;
if( nExp > 15 )
nExp = 15;
else if( nExp <= 1 )
nExp = 0;
fVal = floor( fVal+ 0.5 + nRoundVal[ nExp ] );
if (bSign)
fVal *= -1.0;
fVal /= fFac;
left.PutDouble( fVal );
}
break;
/*
// removed here because of #77448# (=2*3^2 != 18)
case CALC_POW: {
GetToken();
double fraction, integer;
double right = Prim().GetDouble(),
dleft = left.GetDouble();
fraction = modf( right, &integer );
if( ( dleft < 0.0 && 0.0 != fraction ) ||
( 0.0 == dleft && right < 0.0 ) )
{
eError = CALC_OVERFLOW;
left.Clear();
return left;
}
dleft = pow(dleft, right );
if( dleft == HUGE_VAL )
{
eError = CALC_POWERR;
left.Clear();
return left;
}
left.PutDouble( dleft );
}
break;
*/
default: return left;
}
if( USHRT_MAX != nSbxOper )
{
// #i47706: cast to SbxOperator AFTER comparing to USHRT_MAX
SbxOperator eSbxOper = (SbxOperator)nSbxOper;
GetToken();
if( SbxEQ <= eSbxOper && eSbxOper <= SbxGE )
left.PutBool( left.Compare( eSbxOper, Prim() ));
else
{
SwSbxValue aRight( Prim() );
aRight.MakeDouble();
left.MakeDouble();
if( SbxDIV == eSbxOper && !aRight.GetDouble() )
eError = CALC_ZERODIV;
else
left.Compute( eSbxOper, aRight );
}
}
}
}
/******************************************************************************
|*
|* SwSbxValue SwCalc::Prim()
|*
|* Erstellung OK 12-02-93 11:05am
|* Letzte Aenderung JP 03.11.95
|*
|******************************************************************************/
extern "C" typedef double (*pfCalc)( double );
SwSbxValue SwCalc::Prim()
{
SwSbxValue nErg;
pfCalc pFnc = 0;
sal_Bool bChkTrig = sal_False, bChkPow = sal_False;
switch( eCurrOper )
{
case CALC_SIN: pFnc = &sin; break;
case CALC_COS: pFnc = &cos; break;
case CALC_TAN: pFnc = &tan; break;
case CALC_ATAN: pFnc = &atan; break;
case CALC_ASIN: pFnc = &asin; bChkTrig = sal_True; break;
case CALC_ACOS: pFnc = &acos; bChkTrig = sal_True; break;
case CALC_NOT: {
GetToken();
nErg = Prim();
if( SbxSTRING == nErg.GetType() )
nErg.PutBool( 0 == nErg.GetString().Len() );
else if(SbxBOOL == nErg.GetType() )
nErg.PutBool(!nErg.GetBool());
// evaluate arguments manually so that the binary NOT below
// does not get called.
// We want a BOOLEAN NOT.
else if (nErg.IsNumeric())
nErg.PutLong( nErg.GetDouble() == 0.0 ? 1 : 0 );
else
{
DBG_ERROR( "unexpected case. computing binary NOT" );
//!! computes a binary NOT
nErg.Compute( SbxNOT, nErg );
}
}
break;
case CALC_NUMBER: if( GetToken() == CALC_PHD )
{
double aTmp = nNumberValue.GetDouble();
aTmp *= 0.01;
nErg.PutDouble( aTmp );
GetToken();
}
else if( eCurrOper == CALC_NAME )
eError = CALC_SYNTAX;
else
{
nErg = nNumberValue;
bChkPow = sal_True;
}
break;
case CALC_NAME: if( GetToken() == CALC_ASSIGN )
{
SwCalcExp* n = VarInsert( aVarName );
GetToken();
nErg = n->nValue = Expr();
}
else
{
nErg = VarLook( aVarName )->nValue;
bChkPow = sal_True;
}
break;
case CALC_MINUS: GetToken();
nErg.PutDouble( -(Prim().GetDouble()) );
break;
case CALC_LP: {
GetToken();
nErg = Expr();
if( eCurrOper != CALC_RP )
eError = CALC_BRACK;
else
{
GetToken();
bChkPow = sal_True; // in order for =(7)^2 to work
}
}
break;
case CALC_MEAN: {
nListPor = 1;
GetToken();
nErg = Expr();
double aTmp = nErg.GetDouble();
aTmp /= nListPor;
nErg.PutDouble( aTmp );
}
break;
case CALC_SQRT: {
GetToken();
nErg = Prim();
if( nErg.GetDouble() < 0 )
eError = CALC_OVERFLOW;
else
nErg.PutDouble( sqrt( nErg.GetDouble() ));
}
break;
case CALC_SUM:
case CALC_DATE:
case CALC_MIN:
case CALC_MAX: GetToken();
nErg = Expr();
break;
case CALC_ENDCALC: nErg.Clear();
break;
default: eError = CALC_SYNTAX;
break;
}
if( pFnc )
{
GetToken();
double nVal = Prim().GetDouble();
if( !bChkTrig || ( nVal > -1 && nVal < 1 ) )
nErg.PutDouble( (*pFnc)( nVal ) );
else
eError = CALC_OVERFLOW;
}
// added here because of #77448# (=2*3^2 should be 18)
if( bChkPow && eCurrOper == CALC_POW )
{
double dleft = nErg.GetDouble();
GetToken();
double right = Prim().GetDouble();
double fraction, integer;
fraction = modf( right, &integer );
if( ( dleft < 0.0 && 0.0 != fraction ) ||
( 0.0 == dleft && right < 0.0 ) )
{
eError = CALC_OVERFLOW;
nErg.Clear();
}
else
{
dleft = pow(dleft, right );
if( dleft == HUGE_VAL )
{
eError = CALC_POWERR;
nErg.Clear();
}
else
{
nErg.PutDouble( dleft );
// GetToken();
}
}
}
return nErg;
}
/******************************************************************************
|*
|* SwSbxValue SwCalc::Expr()
|*
|* Erstellung OK 12-02-93 11:06am
|* Letzte Aenderung JP 03.11.95
|*
|******************************************************************************/
SwSbxValue SwCalc::Expr()
{
SwSbxValue left = Term(), right;
nLastLeft = left;
for(;;)
switch(eCurrOper)
{
case CALC_PLUS: GetToken();
// erzeuge zum addieren auf jedenfall einen
// Double-Wert
left.MakeDouble();
( right = Term() ).MakeDouble();
left.Compute( SbxPLUS, right );
nListPor++;
break;
case CALC_MINUS: GetToken();
// erzeuge zum addieren auf jedenfall einen
// Double-Wert
left.MakeDouble();
( right = Term() ).MakeDouble();
left.Compute( SbxMINUS, right );
break;
default: return left;
}
}
//------------------------------------------------------------------------------
String SwCalc::GetColumnName(const String& rName)
{
xub_StrLen nPos = rName.Search(DB_DELIM);
if( STRING_NOTFOUND != nPos )
{
nPos = rName.Search(DB_DELIM, nPos + 1);
if( STRING_NOTFOUND != nPos )
return rName.Copy(nPos + 1);
}
return rName;
}
//------------------------------------------------------------------------------
String SwCalc::GetDBName(const String& rName)
{
xub_StrLen nPos = rName.Search(DB_DELIM);
if( STRING_NOTFOUND != nPos )
{
nPos = rName.Search(DB_DELIM, nPos + 1);
if( STRING_NOTFOUND != nPos )
return rName.Copy( 0, nPos );
}
SwDBData aData = rDoc.GetDBData();
String sRet = aData.sDataSource;
sRet += DB_DELIM;
sRet += String(aData.sCommand);
return sRet;
}
//------------------------------------------------------------------------------
namespace
{
static bool
lcl_Str2Double( const String& rCommand, xub_StrLen& rCommandPos, double& rVal,
const LocaleDataWrapper* const pLclData )
{
OSL_ASSERT(pLclData);
const xub_Unicode nCurrCmdPos = rCommandPos;
rtl_math_ConversionStatus eStatus;
const sal_Unicode* pEnd;
rVal = rtl_math_uStringToDouble( rCommand.GetBuffer() + rCommandPos,
rCommand.GetBuffer() + rCommand.Len(),
pLclData->getNumDecimalSep().GetChar(0),
pLclData->getNumThousandSep().GetChar(0),
&eStatus, &pEnd );
rCommandPos = static_cast<xub_StrLen>(pEnd - rCommand.GetBuffer());
return rtl_math_ConversionStatus_Ok == eStatus && nCurrCmdPos != rCommandPos;
}
}
/******************************************************************************
* Methode : sal_Bool SwCalc::Str2Double( double& )
* Beschreibung:
* Erstellt : OK 07.06.94 12:56
* Aenderung : JP 27.10.98
******************************************************************************/
bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
double& rVal, const LocaleDataWrapper* const pLclData )
{
const SvtSysLocale aSysLocale;
return lcl_Str2Double( rCommand, rCommandPos, rVal,
pLclData ? pLclData : aSysLocale.GetLocaleDataPtr() );
}
bool SwCalc::Str2Double( const String& rCommand, xub_StrLen& rCommandPos,
double& rVal, SwDoc* const pDoc )
{
const SvtSysLocale aSysLocale;
::std::auto_ptr<const LocaleDataWrapper> pLclD;
if( pDoc )
{
LanguageType eLang = GetDocAppScriptLang( *pDoc );
if (eLang !=
SvxLocaleToLanguage(aSysLocale.GetLocaleData().getLocale()))
{
pLclD.reset( new LocaleDataWrapper(
::comphelper::getProcessServiceFactory(),
SvxCreateLocale( eLang ) ) );
}
}
bool const bRet = lcl_Str2Double( rCommand, rCommandPos, rVal,
(pLclD.get()) ? pLclD.get() : aSysLocale.GetLocaleDataPtr() );
return bRet;
}
//------------------------------------------------------------------------------
sal_Bool SwCalc::IsValidVarName( const String& rStr,
String* pValidName )
{
sal_Bool bRet = sal_False;
using namespace ::com::sun::star::i18n;
{
// Parse any token.
ParseResult aRes = GetAppCharClass().parseAnyToken( rStr, 0,
coStartFlags, aEmptyStr,
coContFlags, aEmptyStr );
if( aRes.TokenType & KParseType::IDENTNAME )
{
bRet = aRes.EndPos == rStr.Len();
if( pValidName )
{
xub_StrLen nRealStt = (xub_StrLen)aRes.LeadingWhiteSpace;
*pValidName = rStr.Copy( nRealStt, static_cast<xub_StrLen>(aRes.EndPos) - nRealStt );
}
}
else if( pValidName )
pValidName->Erase();
}
return bRet;
}
//------------------------------------------------------------------------------
/******************************************************************************
|*
|* CTOR DTOR der SwHash classes
|*
|* Ersterstellung OK 25.06.93 12:20
|* Letzte Aenderung OK 25.06.93 12:20
|*
******************************************************************************/
SwHash::SwHash( const String& rStr ) :
aStr( rStr ),
pNext( 0 )
{}
SwHash::~SwHash()
{
if( pNext )
delete pNext;
}
void DeleteHashTable( SwHash **ppHashTable, sal_uInt16 nCount )
{
for ( sal_uInt16 i = 0; i < nCount; ++i )
delete *(ppHashTable+i);
delete [] ppHashTable;
}
SwCalcExp::SwCalcExp( const String& rStr, const SwSbxValue& rVal,
const SwFieldType* pType )
: SwHash( rStr ),
nValue( rVal ),
pFldType( pType )
{
}
SwSbxValue::~SwSbxValue()
{
}
sal_Bool SwSbxValue::GetBool() const
{
return SbxSTRING == GetType() ? 0 != GetString().Len()
: 0 != SbxValue::GetBool();
}
double SwSbxValue::GetDouble() const
{
double nRet;
if( SbxSTRING == GetType() )
{
xub_StrLen nStt = 0;
SwCalc::Str2Double( GetString(), nStt, nRet );
}
else if (IsBool())
{
nRet = 0 != GetBool() ? 1.0 : 0.0;
}
else
nRet = SbxValue::GetDouble();
return nRet;
}
SwSbxValue& SwSbxValue::MakeDouble()
{
if( SbxSTRING == GetType() || SbxBOOL == GetType() )
PutDouble( GetDouble() );
return *this;
}
#ifdef STANDALONE_HASHCALC
// dies ist der Beispielcode zu erzeugen der HashValues im CTOR:
#include <stdio.h>
void main()
{
static sal_Char
sNType0[] = "false", sNType1[] = "true", sNType2[] = "pi",
sNType3[] = "e", sNType4[] = "tables", sNType5[] = "graf",
sNType6[] = "ole", sNType7[] = "page", sNType8[] = "para",
sNType9[] = "word", sNType10[]= "char",
sNType11[] = "user_company" , sNType12[] = "user_firstname" ,
sNType13[] = "user_lastname" , sNType14[] = "user_initials",
sNType15[] = "user_street" , sNType16[] = "user_country" ,
sNType17[] = "user_zipcode" , sNType18[] = "user_city" ,
sNType19[] = "user_title" , sNType20[] = "user_position" ,
sNType21[] = "user_tel_home", sNType22[] = "user_tel_work",
sNType23[] = "user_fax" , sNType24[] = "user_email" ,
sNType25[] = "user_state", sNType26[] = "graph"
;
static const sal_Char* sNTypeTab[ 27 ] =
{
sNType0, sNType1, sNType2, sNType3, sNType4, sNType5,
sNType6, sNType7, sNType8, sNType9, sNType10, sNType11,
sNType12, sNType13, sNType14, sNType15, sNType16, sNType17,
sNType18, sNType19, sNType20, sNType21, sNType22, sNType23,
sNType24, sNType25, sNType26
};
const unsigned short nTblSize = 47;
int aArr[ nTblSize ] = { 0 };
sal_Char ch;
for( int n = 0; n < 27; ++n )
{
unsigned long ii = 0;
const sal_Char* pp = sNTypeTab[ n ];
while( *pp )
ii = ii << 1 ^ *pp++;
ii %= nTblSize;
ch = aArr[ ii ] ? 'X' : ' ';
aArr[ ii ] = 1;
printf( "%-20s -> %3d [%c]\n", sNTypeTab[ n ], ii, ch );
}
}
#endif