diff options
author | Oliver Bolte <obo@openoffice.org> | 2005-04-13 08:24:07 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2005-04-13 08:24:07 +0000 |
commit | 827f20eb2ebe2a17c515539d834cb62375cb2de2 (patch) | |
tree | fd644a44d40d05be561dc8e3601c2bce021e379a /basic | |
parent | 79d3bc479950127ecfd40f73978c0fc84c1e7908 (diff) |
INTEGRATION: CWS visibility03 (1.1.2); FILE ADDED
2005/03/24 18:04:28 mhu 1.1.2.1: #i45006# Moved from svtools/source/sbx/
Diffstat (limited to 'basic')
-rw-r--r-- | basic/source/sbx/sbxexec.cxx | 439 | ||||
-rw-r--r-- | basic/source/sbx/sbxform.cxx | 1179 | ||||
-rw-r--r-- | basic/source/sbx/sbxint.cxx | 1029 |
3 files changed, 2647 insertions, 0 deletions
diff --git a/basic/source/sbx/sbxexec.cxx b/basic/source/sbx/sbxexec.cxx new file mode 100644 index 000000000000..4836b4006946 --- /dev/null +++ b/basic/source/sbx/sbxexec.cxx @@ -0,0 +1,439 @@ +/************************************************************************* + * + * $RCSfile: sbxexec.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2005-04-13 09:22:17 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _ERRCODE_HXX //autogen +#include <tools/errcode.hxx> +#endif +#ifndef _INTN_HXX //autogen +#include <tools/intn.hxx> +#endif +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#include "sbx.hxx" +#include <tools/isolang.hxx> + + +class SbxSimpleCharClass +{ +public: + BOOL isAlpha( sal_Unicode c ) const + { + BOOL bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + return bRet; + } + + BOOL isDigit( sal_Unicode c ) const + { + BOOL bRet = (c >= '0' && c <= '9'); + return bRet; + } + + BOOL isAlphaNumeric( sal_Unicode c ) const + { + BOOL bRet = isDigit( c ) || isAlpha( c ); + return bRet; + } +}; + + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType, const SbxSimpleCharClass& rCharClass ); + +static const xub_Unicode* SkipWhitespace( const xub_Unicode* p ) +{ + while( *p && ( *p == ' ' || *p == '\t' ) ) + p++; + return p; +} + +// Scannen eines Symbol. Das Symbol wird in rSym eingetragen, der Returnwert +// ist die neue Scanposition. Bei Fehlern ist das Symbol leer. + +static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass ) +{ + USHORT nLen = 0; + // Haben wir ein Sondersymbol? + if( *p == '[' ) + { + rSym = ++p; + while( *p && *p != ']' ) + p++, nLen++; + p++; + } + else + { + // Ein Symbol muss mit einem Buchstaben oder einem Underline beginnen + if( !rCharClass.isAlpha( *p ) && *p != '_' ) + SbxBase::SetError( SbxERR_SYNTAX ); + else + { + rSym = p; + // Dann darf es Buchstaben, Zahlen oder Underlines enthalten + while( *p && rCharClass.isAlphaNumeric( *p ) || *p == '_' ) + p++, nLen++; + // BASIC-Standard-Suffixe werden ignoriert + if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) ) + p++; + } + } + rSym.Erase( nLen ); + return p; +} + +// Qualifizierter Name. Element.Element.... + +static SbxVariable* QualifiedName + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar; + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' ) + { + // Element einlesen + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + while( refVar.Is() && *p == '.' || *p == '!' ) + { + // Es folgt noch ein Objektelement. Das aktuelle Element + // muss also ein SBX-Objekt sein oder liefern! + pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar); + if( !pObj ) + // Dann muss es ein Objekt liefern + pObj = PTR_CAST(SbxObject,refVar->GetObject()); + refVar.Clear(); + if( !pObj ) + break; + p++; + // Und das naechste Element bitte + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + } + } + else + SbxBase::SetError( SbxERR_SYNTAX ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Operanden. Dies kann eine Zahl, ein String oder +// eine Funktion (mit optionalen Parametern) sein. + +static SbxVariable* Operand + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, BOOL bVar ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar( new SbxVariable ); + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( !bVar && ( aCharClass.isDigit( *p ) + || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) ) + || *p == '-' + || *p == '&' ) ) + { + // Eine Zahl kann direkt eingescant werden! + USHORT nLen; + if( !refVar->Scan( XubString( p ), &nLen ) ) + refVar.Clear(); + else + p += nLen; + } + else if( !bVar && *p == '"' ) + { + // Ein String + XubString aString; + p++; + for( ;; ) + { + // Das ist wohl ein Fehler + if( !*p ) + return NULL; + // Doppelte Quotes sind OK + if( *p == '"' ) + if( *++p != '"' ) + break; + aString += *p++; + } + refVar->PutString( aString ); + } + else + refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen einer einfachen Term. Die Operatoren +, -, * und / +// werden unterstuetzt. + +static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, FALSE ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '*' || *p == '/' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( Operand( pObj, pGbl, &p, FALSE ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '*' ) + *refVar *= *refVar2; + else + *refVar /= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '+' || *p == '-' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '+' ) + *refVar += *refVar2; + else + *refVar -= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, TRUE ) ); + p = SkipWhitespace( p ); + if( refVar.Is() ) + { + if( *p == '=' ) + { + // Nur auf Props zuweisen! + if( refVar->GetClass() != SbxCLASS_PROPERTY ) + { + SbxBase::SetError( SbxERR_BAD_ACTION ); + refVar.Clear(); + } + else + { + p++; + SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + SbxVariable* pVar = refVar; + SbxVariable* pVar2 = refVar2; + *pVar = *pVar2; + pVar->SetParameters( NULL ); + } + } + } + else + // Einfacher Aufruf: einmal aktivieren + refVar->Broadcast( SBX_HINT_DATAWANTED ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Elements. Dies ist ein Symbol, optional gefolgt +// von einer Parameterliste. Das Symbol wird im angegebenen Objekt +// gesucht und die Parameterliste wird ggf. angefuegt. + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType t, const SbxSimpleCharClass& rCharClass ) +{ + XubString aSym; + const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass ); + SbxVariableRef refVar; + if( aSym.Len() ) + { + USHORT nOld = pObj->GetFlags(); + if( pObj == pGbl ) + pObj->SetFlag( SBX_GBLSEARCH ); + refVar = pObj->Find( aSym, t ); + pObj->SetFlags( nOld ); + if( refVar.Is() ) + { + refVar->SetParameters( NULL ); + // folgen noch Parameter? + p = SkipWhitespace( p ); + if( *p == '(' ) + { + p++; + SbxArrayRef refPar = new SbxArray; + USHORT nArg = 0; + // Wird sind mal relaxed und akzeptieren auch + // das Zeilen- oder Komandoende als Begrenzer + // Parameter immer global suchen! + while( *p && *p != ')' && *p != ']' ) + { + SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p ); + if( !refArg ) + { + // Fehler beim Parsing + refVar.Clear(); break; + } + else + { + // Man kopiere den Parameter, damit + // man den aktuellen Zustand hat (loest auch + // den Aufruf per Zugriff aus) + SbxVariable* pArg = refArg; + refPar->Put( new SbxVariable( *pArg ), ++nArg ); + } + p = SkipWhitespace( p ); + if( *p == ',' ) + p++; + } + if( *p == ')' ) + p++; + if( refVar.Is() ) + refVar->SetParameters( refPar ); + } + } + else + SbxBase::SetError( SbxERR_NO_METHOD ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Hauptroutine + +SbxVariable* SbxObject::Execute( const XubString& rTxt ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rTxt.GetBuffer(); + for( ;; ) + { + p = SkipWhitespace( p ); + if( !*p ) + break; + if( *p++ != '[' ) + { + SetError( SbxERR_SYNTAX ); break; + } + pVar = Assign( this, this, &p ); + if( !pVar ) + break; + p = SkipWhitespace( p ); + if( *p++ != ']' ) + { + SetError( SbxERR_SYNTAX ); break; + } + } + return pVar; +} + +SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rName.GetBuffer(); + p = SkipWhitespace( p ); + if( !*p ) + return NULL;; + pVar = QualifiedName( this, this, &p, t ); + p = SkipWhitespace( p ); + if( *p ) + SetError( SbxERR_SYNTAX ); + return pVar; +} + diff --git a/basic/source/sbx/sbxform.cxx b/basic/source/sbx/sbxform.cxx new file mode 100644 index 000000000000..11e7f1a4d443 --- /dev/null +++ b/basic/source/sbx/sbxform.cxx @@ -0,0 +1,1179 @@ +/************************************************************************* + * + * $RCSfile: sbxform.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2005-04-13 09:22:31 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdlib.h> + +#include "sbxform.hxx" + +/* +TODO: gibt es noch irgend welche Star-Basic Besonderheiten ? + + was bedeutet: * als Platzhalter + +BEMERKUNG: Visual-Basic behandelt folgende (ung"ultige) Format-Strings + wie angezeigt: + + ##0##.##0## --> ##000.000## + + (diese Klasse verh"alt sich genau so). +*/ + +#include <stdio.h> // f"ur: sprintf() +#include <float.h> // f"ur: DBL_DIG, DBL_EPSILON +#include <math.h> // f"ur: floor(), fabs(), log10(), pow() + +//================================================================= +//=========================== DEFINES ============================= +//================================================================= + +#if defined(MAC) && defined(__MWERKS__) +#undef DBL_DIG +#define DBL_DIG 15 +#endif + +#define _NO_DIGIT -1 + +#define MAX_NO_OF_EXP_DIGITS 5 + // +4 wegen dem Wertebereich: zwischen -308 und +308 + // +1 f"ur abschliessende 0 +#define MAX_NO_OF_DIGITS DBL_DIG +#define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9 + // +1 f"ur Vorzeichen + // +1 f"ur Ziffer vor dem Dezimal-Punkt + // +1 f"ur Dezimal-Punkt + // +2 f"ur Exponent E und Exp. Vorzeichen + // +3 f"ur den Wert des Exponenten + // +1 f"ur abschliessende 0 + +// Defines f"ur die Ziffern: +#define ASCII_0 '0' // 48 +#define ASCII_9 '9' // 57 + +#define CREATE_1000SEP_CHAR '@' + +#define FORMAT_SEPARATOR ';' + +// vordefinierte Formate f"ur den Format$()-Befehl: +#define BASICFORMAT_GENERALNUMBER "General Number" +#define BASICFORMAT_CURRENCY "Currency" +#define BASICFORMAT_FIXED "Fixed" +#define BASICFORMAT_STANDARD "Standard" +#define BASICFORMAT_PERCENT "Percent" +#define BASICFORMAT_SCIENTIFIC "Scientific" +#define BASICFORMAT_YESNO "Yes/No" +#define BASICFORMAT_TRUEFALSE "True/False" +#define BASICFORMAT_ONOFF "On/Off" + +#define EMPTYFORMATSTRING "" + +// Bem.: Visual-Basic hat bei Floating-Point-Zahlen maximal 12 Stellen +// nach dem Dezimal-Punkt. +// Alle Format-Strings sind kompatibel zu Visual-Basic: +#define GENERALNUMBER_FORMAT "0.############" + // max. 12 Stellen in Visual-Basic ! +#define CURRENCY_FORMAT "@$0.00;@($0.00)" +#define FIXED_FORMAT "0.00" +#define STANDARD_FORMAT "@0.00" +#define PERCENT_FORMAT "0.00%" +#define SCIENTIFIC_FORMAT "#.00E+00" +// BEMERKUNG: das Zeichen @ bedeutet, das Tausender-Separatoren erzeugt +// weden sollen. Dies ist eine StarBasic 'Erweiterung'. + +//================================================================= + +// zur Bestimmung der Anzahl Stellen in dNumber +double get_number_of_digits( double dNumber ) +//double floor_log10_fabs( double dNumber ) +{ + if( dNumber==0.0 ) + // 0 hat zumindest auch eine Stelle ! + return 0.0; //ehemals 1.0, jetzt 0.0 wegen #40025; + else + return floor( log10( fabs( dNumber ) ) ); +} + +//================================================================= +//======================= IMPLEMENTATION ========================== +//================================================================= + +SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep, + String _sOnStrg, + String _sOffStrg, + String _sYesStrg, + String _sNoStrg, + String _sTrueStrg, + String _sFalseStrg, + String _sCurrencyStrg, + String _sCurrencyFormatStrg ) +{ + cDecPoint = _cDecPoint; + cThousandSep = _cThousandSep; + sOnStrg = _sOnStrg; + sOffStrg = _sOffStrg; + sYesStrg = _sYesStrg; + sNoStrg = _sNoStrg; + sTrueStrg = _sTrueStrg; + sFalseStrg = _sFalseStrg; + sCurrencyStrg = _sCurrencyStrg; + sCurrencyFormatStrg = _sCurrencyFormatStrg; +} + +// Funktion zur Ausgabe eines Fehler-Textes (zum Debuggen) +/* +void SbxBasicFormater::ShowError( char * sErrMsg ) +{ +// cout << "ERROR in Format$(): " << sErrMsg << endl; +} +*/ +// verschiebt alle Zeichen des Strings, angefangen von der nStartPos, +// um eine Position zu gr"osseren Indizes, d.h. es wird Platz f"ur +// ein neues (einzuf"ugendes) Zeichen geschafft. +// ACHTUNG: der String MUSS gross genug sein ! +inline void SbxBasicFormater::ShiftString( String& sStrg, USHORT nStartPos ) +{ + sStrg.Erase( nStartPos,1 ); +} + +// Funktion um ein Zeichen an einen String anzuh"angen +inline void SbxBasicFormater::StrAppendChar( String& sStrg, sal_Unicode ch ) +{ + sStrg.Insert( ch ); +} + +// h"angt die "ubergebene Ziffer nDigit an den "ubergebenen String sStrg +// an, dabei wird "uberpr"uft ob nDigit eine g"ultige Ziffer ist, +// falls dies nicht der Fall ist, wird nichts gemacht. +void SbxBasicFormater::AppendDigit( String& sStrg, short nDigit ) +{ + if( nDigit>=0 && nDigit<=9 ) + StrAppendChar( sStrg, (sal_Unicode)(nDigit+ASCII_0) ); +} + +// verschiebt den Dezimal-Punkt um eine Stelle nach links +void SbxBasicFormater::LeftShiftDecimalPoint( String& sStrg ) +{ + USHORT nPos = sStrg.Search( cDecPoint ); + + if( nPos!=STRING_NOTFOUND ) + { + // vertausche Dezimal-Punkt + sStrg.SetChar( nPos, sStrg.GetChar( nPos - 1 ) ); + sStrg.SetChar( nPos-1, cDecPoint ); + } +} + +// rundet in einem String die Ziffer an der angegebenen Stelle, +// es wird ein Flag zur"uckgeliefert, falls ein Overflow auftrat, +// d.h. 99.99 --> 100.00, d.h. ein Gr"ossenordung ge"andert wurde +// (geschieht beim Runden einer 9). +void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos, BOOL& bOverflow ) +{ + // wurde ggf ein falscher Index uebergeben --> Aufruf ignorieren + if( nPos<0 ) + return; + + bOverflow = FALSE; + // "uberspringe den Dezimalpunkt und Tausender-Trennzeichen + sal_Unicode c = sStrg.GetChar( nPos ); + if( nPos>0 && (c == cDecPoint || c == cThousandSep) ) + { + StrRoundDigit( sStrg,nPos-1,bOverflow ); + // AENDERUNG ab 9.3.1997: nach rekursivem Call die Methode SOFORT beenden ! + return; + } + // "uberspringe alle nicht-Ziffern: + // BEMERKUNG: + // in einem g"ultigen Format-String sollte die Ausgabe + // der Zahl an einem St"uck geschen, d.h. Sonderzeichen sollten + // NUR vor ODER nach der Zahl stehen und nicht mitten in der + // Format-Angabe f"ur die Zahl + while( nPos>=0 && (sStrg.GetChar( nPos )<ASCII_0 || sStrg.GetChar( nPos )>ASCII_9) ) + nPos--; + // muss ggf. noch Platz f"ur eine weitere (f"uhrende) Ziffer + // geschaffen werden ? + if( nPos==-1 ) + { + ShiftString( sStrg,0 ); + // f"uhrende 1 einf"ugen: z.B. 99.99 f"ur 0.0 + sStrg.SetChar( 0, '1' ); + bOverflow = TRUE; + } + else + { + // ist die zu rundende Position eine Ziffer ? + sal_Unicode c = sStrg.GetChar( nPos ); + if( c >= ASCII_0 && c <= ASCII_9 ) + { + // muss eine 9 gerundet werden? Falls: Ja --> rekursiver Aufruf + if( c == ASCII_9 ) + { + sStrg.SetChar( nPos, '0' ); + StrRoundDigit( sStrg,nPos-1,bOverflow ); + } + else + sStrg.SetChar( nPos, c+1 ); + } + else + { + // --> Nein, d.h. Platz f"ur Ziffer schaffen: z.B. -99.99 f"ur #0.0 + // da gerundet wird MUSS es immer eine g"ultige Position + // nPos+1 geben ! + ShiftString( sStrg,nPos+1 ); + // f"uhrende 1 einf"ugen + sStrg.SetChar( nPos+1, '1' ); + bOverflow = TRUE; + } + } +} + +// rundet in einem String die Ziffer an der angegebenen Stelle +void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos ) +{ + BOOL bOverflow; + + StrRoundDigit( sStrg,nPos,bOverflow ); +} + +// parse den Formatstring von der "ubergebenen Position zur"uck +// und l"osche ggf. "uberf"ussige 0en, z.B. 4.50 in 0.0# +void SbxBasicFormater::ParseBack( String& sStrg, const String& sFormatStrg, + short nFormatPos ) +{ + // WICHTIG: nFormatPos kann auch negativ sein, in diesem Fall Aufruf ignorieren + for( short i=nFormatPos; + i>0 && sFormatStrg.GetChar( i ) == '#' && sStrg.GetChar( (sStrg.Len()-1) ) == '0'; + i-- ) + { sStrg.Erase( sStrg.Len()-1 ); } +} + +#ifdef _with_sprintf + +/* + Bemerkung: + Zahl wird mit maximaler (sinnvollen) Genauigkeit in einen String + umgewandelt (mit sprintf()), dieser String wird dann im Schleifen- + Durchlauf nach der entsprechenden Ziffer durchsucht. +*/ +// initialisiert die Daten der Klasse um einen Scan-Durchlauf durchzuf"uhren +void SbxBasicFormater::InitScan( double _dNum ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + + dNum = _dNum; + InitExp( get_number_of_digits( dNum ) ); + // maximal 15 Nachkomma-Stellen, Format-Beispiel: -1.234000000000000E-001 + /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum ); + sSciNumStrg.AssignAscii( sBuffer ); +} + +void SbxBasicFormater::InitExp( double _dNewExp ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + // bestimme den Exponenten (kann immer GENAU durch int dargestellt werden) + nNumExp = (short)_dNewExp; + // und dessen String + /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp ); + sNumExpStrg.AssignAscii( sBuffer ); + // bestimme die Anzahl der Stellen im Exponenten + nExpExp = (short)get_number_of_digits( (double)nNumExp ); +} + +// bestimmt die Ziffer an der angegebenen Stelle (gedacht zur Anwendung im +// Scan-Durchlauf) +short SbxBasicFormater::GetDigitAtPosScan( short nPos, BOOL& bFoundFirstDigit ) +{ + // Versuch eine gr"ossere Ziffer zu lesen, + // z.B. Stelle 4 in 1.234, + // oder eine Ziffer ausserhalb der Aufl"osung der + // Zahl (double) zu lesen (z.B. max. 15 Stellen). + if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS ) + return _NO_DIGIT; + // bestimme den Index der Stelle in dem Number-String: + // "uberlese das Vorzeichen + USHORT no = 1; + // falls notwendig den Dezimal-Punkt "uberlesen: + if( nPos<nNumExp ) + no++; + no += nNumExp-nPos; + // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen + if( nPos==nNumExp ) + bFoundFirstDigit = TRUE; + return (short)(sSciNumStrg.GetChar( no ) - ASCII_0); +} + +short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, BOOL& bFoundFirstDigit ) +{ + // ist die abgefragte Stelle zu gross f"ur den Exponenten ? + if( nPos>nExpExp ) + return -1; + + // bestimme den Index der Stelle in dem Number-String: + // "uberlese das Vorzeichen + USHORT no = 1; + no += nExpExp-nPos; + // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen + if( nPos==nExpExp ) + bFoundFirstDigit = TRUE; + return (short)(sNumExpStrg.GetChar( no ) - ASCII_0); +} + +// es kann ein Wert f"ur den Exponent angegeben werden, da ggf. die +// Zahl ggf. NICHT normiert (z.B. 1.2345e-03) dargestellt werden soll, +// sondern eventuell 123.345e-3 ! +short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos, + BOOL& bFoundFirstDigit ) +{ + // neuer Exponent wurde "ubergeben, aktualisiere + // die tempor"aren Klassen-Variablen + InitExp( dNewExponent ); + // und jetzt die Stelle bestimmen + return GetDigitAtPosExpScan( nPos,bFoundFirstDigit ); +} + +#else + +/* Probleme mit der folgenden Methode: + +TODO: ggf einen 'intelligenten' Peek-Parser um Rundungsfehler bei + double-Zahlen herauszufinden ? z.B. f"ur 0.00115 #.#e-000 + + Problem mit: format( 0.3345 , "0.000" ) + Problem mit: format( 0.00115 , "0.0000" ) + +*/ +// liefert die Ziffer an der angegebenen '10er System'-Position, +// d.h. positive nPos f"ur Stellen vor dem Komma und negative +// f"ur Stellen nach dem Komma. +// nPos==0 bedeutet erste Stelle vor dem Komma, also 10^0. +// liefert 0..9 f"ur g"ultige Ziffern und -1 f"ur nicht vorhanden, +// d.h. falls die "ubergebene Zahl zu klein ist +// (z.B. Stelle 5 bei dNumber=123). +// Weiter wird in dNextNumber die um die f"uhrenden Stellen +// (bis nPos) gek"urzte Zahl zur"uckgeliefert, z.B. +// GetDigitAtPos( 3434.565 , 2 , dNewNumber ) --> dNewNumber = 434.565 +// dies kann f"ur Schleifenabarbeitung g"unstiger sein, d.h. +// die Zahlen immer von der gr"ossten Stelle abarbeiten/scanen. +// In bFoundFirstDigit wird ggf. ein Flag gesetzt wenn eine Ziffer +// gefunden wurde, dies wird dazu verwendet um 'Fehler' beim Parsen 202 +// zu vermeiden, die +// +// ACHTUNG: anscheinend gibt es manchmal noch Probleme mit Rundungs-Fehlern! +short SbxBasicFormater::GetDigitAtPos( double dNumber, short nPos, + double& dNextNumber, BOOL& bFoundFirstDigit ) +// ACHTUNG: nPos kann auch negativ werden, f"ur Stellen nach dem Dezimal-Punkt +{ + double dTemp = dNumber; + double dDigit,dPos; + short nMaxDigit; + + // erst mal aus der Zahl eine positive Zahl machen: + dNumber = fabs( dNumber ); + dPos = (double)nPos; + + // "uberpr"ufe ob Zahl zu klein f"ur angegebene Stelle ist + nMaxDigit = (short)get_number_of_digits( dNumber ); + // f"uhrende Ziffern 'l"oschen' + // Bem.: Fehler nur bei Zahlen gr"osser 0, d.h. bei Ziffern vor dem + // Dezimal-Punkt + if( nMaxDigit<nPos && !bFoundFirstDigit && nPos>=0 ) + return _NO_DIGIT; + // Ziffer gefunden, setze Flag: + bFoundFirstDigit = TRUE; + for( short i=nMaxDigit; i>=nPos; i-- ) + { + double dI = (double)i; + double dTemp1 = pow( 10.0,dI ); + // pr"apariere nun die gesuchte Ziffer: + dDigit = floor( pow( 10.0,log10( fabs( dNumber ) )-dI ) ); + dNumber -= dTemp1 * dDigit; + } + // Zuweisung f"ur optimierte Schleifen-Durchl"aufe + dNextNumber = dNumber; + // und zum Schluss noch die float-Rundungsungenauigkeiten heraus filtern + return RoundDigit( dDigit ); +} + +// rundet eine double-Zahl zwischen 0 und 9 auf die genaue +// Integer-Zahl, z.B. 2.8 -> 3 und 2.2 -> 2 +short SbxBasicFormater::RoundDigit( double dNumber ) +{ + // ist der Wertebereich g"ultig ? + if( dNumber<0.0 || dNumber>10.0 ) + return -1; + short nTempHigh = (short)(dNumber+0.5); // ggf. floor( ) + return nTempHigh; +} + +#endif + +// kopiert den entsprechenden Teil des Format-Strings, falls vorhanden, +// und liefert diesen zur"uck. +// Somit wird ein neuer String erzeugt, der vom Aufrufer wieder freigegeben +// werden muss +String SbxBasicFormater::GetPosFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + // der Format-String f"ur die positiven Zahlen ist alles + // vor dem ersten ';' + return sFormatStrg.Copy( 0,nPos ); + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::GetNegFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die negative Zahlen ist alles + // zwischen dem ersten und dem zweiten ';'. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + bFound = TRUE; + if( nPos==STRING_NOTFOUND ) + // keins gefunden, liefere alles... + return sTempStrg; + else + // ansonsten den String zwischen den beiden ';' liefern + return sTempStrg.Copy( 0,nPos ); + } + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::Get0FormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die Null ist alles + // was nach dem zweiten ';' kommt. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + sTempStrg = sTempStrg.Copy( nPos+1 ); + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos==STRING_NOTFOUND ) + // keins gefunden, liefere alles... + return sTempStrg; + else + return sTempStrg.Copy( 0,nPos ); + } + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::GetNullFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die Null ist alles + // was nach dem dritten ';' kommt. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + // und suche nun nach dem dritten ';' + sTempStrg = sTempStrg.Copy( nPos+1 ); + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + return sTempStrg.Copy( nPos+1 ); + } + } + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// analysiert den Format-String, liefert Wert <> 0 falls ein Fehler +// aufgetreten ist +short SbxBasicFormater::AnalyseFormatString( const String& sFormatStrg, + short& nNoOfDigitsLeft, short& nNoOfDigitsRight, + short& nNoOfOptionalDigitsLeft, + short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits, + BOOL& bPercent, BOOL& bCurrency, BOOL& bScientific, + BOOL& bGenerateThousandSeparator, + short& nMultipleThousandSeparators ) +{ + USHORT nLen; + short nState = 0; + + nLen = sFormatStrg.Len(); + // initialisiere alle Z"ahler und Flags + nNoOfDigitsLeft = 0; + nNoOfDigitsRight = 0; + nNoOfOptionalDigitsLeft = 0; + nNoOfExponentDigits = 0; + nNoOfOptionalExponentDigits = 0; + bPercent = FALSE; + bCurrency = FALSE; + bScientific = FALSE; + // ab 11.7.97: sobald ein Komma in dem Format String gefunden wird, + // werden alle 3 Zehnerpotenzen markiert (d.h. tausender, milionen, ...) + // bisher wurde nur an den gesetzten Position ein Tausender-Separator + // ausgegeben oder wenn ein @ im Format-String stand. + // Dies war ein Missverstaendnis der VB Kompatiblitaet. + bGenerateThousandSeparator = sFormatStrg.Search( ',' ) != STRING_NOTFOUND; + nMultipleThousandSeparators = 0; + // und untersuche den Format-String nach den gew"unschten Informationen + for( USHORT i=0; i<nLen; i++ ) + { + sal_Unicode c = sFormatStrg.GetChar( i ); + switch( c ) { + case '#': + case '0': + if( nState==0 ) + { + nNoOfDigitsLeft++; +// TODO hier ggf. bessere Fehler-"Uberpr"ufung der Mantisse auf g"ultige Syntax (siehe Grammatik) + // ACHTUNG: 'undefiniertes' Verhalten falls # und 0 + // gemischt werden !!! + // BEMERKUNG: eigentlich sind #-Platzhalter bei Scientific + // Darstellung vor dem Dezimal-Punkt sinnlos ! + if( c=='#' ) + nNoOfOptionalDigitsLeft++; + } + else if( nState==1 ) + nNoOfDigitsRight++; + else if( nState==-1 ) // suche 0 im Exponent + { + if( c=='#' ) // # schaltet den Zustand weiter + { + nNoOfOptionalExponentDigits++; + nState = -2; + } + nNoOfExponentDigits++; + } + else if( nState==-2 ) // suche # im Exponent + { + if( c=='0' ) + // ERROR: 0 nach # im Exponent ist NICHT erlaubt !! + return -4; + nNoOfOptionalExponentDigits++; + nNoOfExponentDigits++; + } + break; + case '.': + nState++; + if( nState>1 ) + return -1; // ERROR: zu viele Dezimal-Punkte + break; + case '%': + bPercent = TRUE; + /* old: + bPercent++; + if( bPercent>1 ) + return -2; // ERROR: zu viele Prozent-Zeichen + */ + break; + case '(': + bCurrency = TRUE; + break; + case ',': + { + sal_Unicode ch = sFormatStrg.GetChar( i+1 ); + // vorl"aufig wird NUR auf zwei aufeinanderfolgede + // Zeichen gepr"uft + if( ch!=0 && (ch==',' || ch=='.') ) + nMultipleThousandSeparators++; + } break; + case 'e': + case 'E': + // #i13821 not when no digits before + if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 ) + { + nState = -1; // breche jetzt das Z"ahlen der Stellen ab + bScientific = TRUE; + } + /* old: + bScientific++; + if( bScientific>1 ) + return -3; // ERROR: zu viele Exponent-Zeichen + */ + break; + // EIGENES Kommando-Zeichen, das die Erzeugung der + // Tausender-Trennzeichen einschaltet + case '\\': + // Ignore next char + i++; + break; + case CREATE_1000SEP_CHAR: + bGenerateThousandSeparator = TRUE; + break; + } + } + return 0; +} + +// das Flag bCreateSign zeigt an, dass bei der Mantisse ein Vorzeichen +// erzeugt werden soll +void SbxBasicFormater::ScanFormatString( double dNumber, + const String& sFormatStrg, String& sReturnStrg, + BOOL bCreateSign ) +{ + short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft, + nNoOfExponentDigits,nNoOfOptionalExponentDigits, + nMultipleThousandSeparators; + BOOL bPercent,bCurrency,bScientific,bGenerateThousandSeparator; + + // Initialisiere den Return-String + sReturnStrg = String(); + + // analysiere den Format-String, d.h. bestimme folgende Werte: + /* + - Anzahl der Ziffern vor dem Komma + - Anzahl der Ziffern nach dem Komma + - optionale Ziffern vor dem Komma + - Anzahl der Ziffern im Exponent + - optionale Ziffern im Exponent + - Prozent-Zeichen gefunden ? + - () f"ur negatives Vorzeichen ? + - Exponetial-Schreibweise ? + - sollen Tausender-Separatoren erzeugt werden ? + - wird ein Prozent-Zeichen gefunden ? --> dNumber *= 100.0; + - gibt es aufeinanderfolgende Tausender-Trennzeichen ? + ,, oder ,. --> dNumber /= 1000.0; + - sonstige Fehler ? mehrfache Dezimalpunkte, E's, etc. + --> Fehler werden zur Zeit einfach ignoriert + */ + /*nErr =*/ AnalyseFormatString( sFormatStrg,nNoOfDigitsLeft,nNoOfDigitsRight, + nNoOfOptionalDigitsLeft,nNoOfExponentDigits, + nNoOfOptionalExponentDigits, + bPercent,bCurrency,bScientific,bGenerateThousandSeparator, + nMultipleThousandSeparators ); + /* es werden alle Fehler ignoriert, wie in Visual-Basic + if( nErr!=0 ) + { + char sBuffer[512]; + + //sprintf( sBuffer,"bad format-string >%s< err=%i",sFormatStrg,nErr ); + strcpy( sBuffer,"bad format-string" ); + ShowError( sBuffer ); + } + else + */ + { + // Spezialbehandlung f"ur Spezialzeichen + if( bPercent ) + dNumber *= 100.0; +// TODO: diese Vorgabe (,, oder ,.) ist NICHT Visual-Basic kompatibel ! + // Frage: soll das hier stehen bleiben (Anforderungen) ? + if( nMultipleThousandSeparators ) + dNumber /= 1000.0; + + // einige Arbeits-Variablen + double dExponent; + short i,nLen; + short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit; + BOOL bFirstDigit,bFirstExponentDigit,bFoundFirstDigit, + bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative; + + // Initialisierung der Arbeits-Variablen + bSignHappend = FALSE; + bFoundFirstDigit = FALSE; + bIsNegative = dNumber<0.0; + nLen = sFormatStrg.Len(); + dExponent = get_number_of_digits( dNumber ); + nMaxDigit = (short)dExponent; + bDigitPosNegative = false; + if( bScientific ) + { + //if( nNoOfOptionalDigitsLeft>0 ) + // ShowError( "# in scientific-format in front of the decimal-point has no effect" ); + // beim Exponent ggf. "uberz"ahlige Stellen vor dem Komma abziehen + dExponent = dExponent - (double)(nNoOfDigitsLeft-1); + nDigitPos = nMaxDigit; + nMaxExponentDigit = (short)get_number_of_digits( dExponent ); + nExponentPos = nNoOfExponentDigits-1 - nNoOfOptionalExponentDigits; + } + else + { + nDigitPos = nNoOfDigitsLeft-1; // Z"ahlweise f"angt bei 0 an, 10^0 + // hier ben"otigt man keine Exponent-Daten ! + bDigitPosNegative = (nDigitPos < 0); + } + bFirstDigit = TRUE; + bFirstExponentDigit = TRUE; + nState = 0; // 0 --> Mantisse; 1 --> Exponent + bZeroSpaceOn = 0; + + +#ifdef _with_sprintf + InitScan( dNumber ); +#endif + // scanne jetzt den Format-String: + sal_Unicode cForce = 0; + for( i=0; i<nLen; i++ ) + { + sal_Unicode c; + if( cForce ) + { + c = cForce; + cForce = 0; + } + else + { + c = sFormatStrg.GetChar( i ); + } + switch( c ) { + case '0': + case '#': + if( nState==0 ) + { + // Behandlung der Mantisse + if( bFirstDigit ) + { + //org:bFirstDigit = FALSE; + // ggf. Vorzeichen erzeugen + // Bem.: bei bCurrency soll das negative + // Vorzeichen durch () angezeigt werden + if( bIsNegative && !bCreateSign/*!bCurrency*/ && !bSignHappend ) + { + // nur einmal ein Vorzeichen ausgeben + bSignHappend = TRUE; + StrAppendChar( sReturnStrg,'-' ); + } + // hier jetzt "uberz"ahlige Stellen ausgeben, + // d.h. vom Format-String nicht erfasste Stellen + if( nMaxDigit>nDigitPos ) + { + for( short j=nMaxDigit; j>nDigitPos; j-- ) + { + short nTempDigit; +#ifdef _with_sprintf + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( j,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,j,dNumber,bFoundFirstDigit ) ); +#endif + // wurde wirklich eine Ziffer eingefuegt ? + if( nTempDigit!=_NO_DIGIT ) + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && j>0 && (j % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + } + } + // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ? + if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) ) + { + AppendDigit( sReturnStrg,0 ); // Ja + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + bZeroSpaceOn = 1; + // BEM.: bei Visual-Basic schaltet die erste 0 f"ur alle + // nachfolgenden # (bis zum Dezimal-Punkt) die 0 ein, + // dieses Verhalten wird hier mit dem Flag simmuliert. + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + else + { + short nTempDigit; +#ifdef _with_sprintf + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ) ); +#endif + // wurde wirklich eine Ziffer eingefuegt ? + if( nTempDigit!=_NO_DIGIT ) + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + // und Position aktualisieren + nDigitPos--; + } + else + { + // Behandlung des Exponenten + if( bFirstExponentDigit ) + { + // Vorzeichen wurde schon bei e/E ausgegeben + bFirstExponentDigit = FALSE; + if( nMaxExponentDigit>nExponentPos ) + // hier jetzt "uberz"ahlige Stellen ausgeben, + // d.h. vom Format-String nicht erfasste Stellen + { + for( short j=nMaxExponentDigit; j>nExponentPos; j-- ) + { +#ifdef _with_sprintf + AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,j,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,j,dExponent,bFoundFirstDigit ) ); +#endif + } + } + } + // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ? + if( nMaxExponentDigit<nExponentPos && c=='0' ) + AppendDigit( sReturnStrg,0 ); // Ja + else +#ifdef _with_sprintf + AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,nExponentPos,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,nExponentPos,dExponent,bFoundFirstDigit ) ); +#endif + nExponentPos--; + } + break; + case '.': + if( bDigitPosNegative ) // #i13821: If no digits before . + { + bDigitPosNegative = false; + nDigitPos = 0; + cForce = '#'; + i-=2; + break; + } + // gebe Komma aus + StrAppendChar( sReturnStrg,cDecPoint ); + break; + case '%': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // gebe Prozent-Zeichen aus + sReturnStrg.Insert('%'); + break; + case 'e': + case 'E': + // muss Mantisse noch gerundet werden, bevor der Exponent angezeigt wird ? + { + // gibt es ueberhaupt eine Mantisse ? + if( bFirstDigit ) + { + // anscheinend nicht, d.h. ungueltiger Format String, z.B. E000.00 + // d.h. ignoriere diese e bzw. E Zeichen + // ggf. einen Fehler (wie Visual Basic) ausgeben ? + + // #i13821: VB 6 behaviour + StrAppendChar( sReturnStrg,c ); + break; + } + + BOOL bOverflow = FALSE; +#ifdef _with_sprintf + short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ); +#else + short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ); +#endif + if( nNextDigit>=5 ) + StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1,bOverflow ); + if( bOverflow ) + { + // es wurde eine f"uhrende 9 gerundet, d.h. + // verschiebe den Dezimal-Punkt um eine Stelle nach links + LeftShiftDecimalPoint( sReturnStrg ); + // und l"osche die letzte Ziffer, diese wird + // duch die f"uhrende 1 ersetzt: + sReturnStrg.SetChar( sReturnStrg.Len()-1 , 0 ); + // der Exponent muss um 1 erh"oht werden, + // da der Dezimalpunkt verschoben wurde + dExponent += 1.0; + } + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + } + // "andere Zustand des Scanners + nState++; + // gebe Exponent-Zeichen aus + StrAppendChar( sReturnStrg,c ); + // i++; // MANIPULATION der Schleifen-Variable ! + c = sFormatStrg.GetChar( ++i ); + // und gebe Vorzeichen / Exponent aus + if( c!=0 ) + { + if( c=='-' ) + { + // falls Exponent < 0 gebe - aus + if( dExponent<0.0 ) + StrAppendChar( sReturnStrg,'-' ); + } + else if( c=='+' ) + { + // gebe auf jeden Fall das Vorzeichen des Exponenten aus ! + if( dExponent<0.0 ) + StrAppendChar( sReturnStrg,'-' ); + else + StrAppendChar( sReturnStrg,'+' ); + } + //else + // ShowError( "operator e/E did not find + or -" ); + } + //else + // ShowError( "operator e/E ended with 0" ); + break; + case ',': + // ACHTUNG: nur falls Zahl bisher ausgegeben wurde + // das Zeichen ausgeben + ////--> Siehe Kommentar vom 11.7. in AnalyseFormatString() + ////if( !bFirstDigit ) + //// // gebe Tausender-Trennzeichen aus + //// StrAppendChar( sReturnStrg,cThousandSep ); + break; + case ';': + break; + case '(': + case ')': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + if( bIsNegative ) + StrAppendChar( sReturnStrg,c ); + break; + case '$': + // den String fuer die Waehrung dranhengen: + sReturnStrg += sCurrencyStrg; + break; + case ' ': + case '-': + case '+': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // gebe das jeweilige Zeichen direkt aus + StrAppendChar( sReturnStrg,c ); + break; + case '\\': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + // falls Sonderzeichen am Ende oder mitten in + // Format-String vorkommen + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // Sonderzeichen gefunden, gebe N"ACHSTES + // Zeichen direkt aus (falls es existiert) + // i++; + c = sFormatStrg.GetChar( ++i ); + if( c!=0 ) + StrAppendChar( sReturnStrg,c ); + //else + // ShowError( "operator \\ ended with 0" ); + break; + case CREATE_1000SEP_CHAR: + // hier ignorieren, Aktion wurde schon in + // AnalyseFormatString durchgef"uhrt + break; + default: + // auch die Zeichen und Ziffern ausgeben (wie in Visual-Basic) + if( ( c>='a' && c<='z' ) || + ( c>='A' && c<='Z' ) || + ( c>='1' && c<='9' ) ) + StrAppendChar( sReturnStrg,c ); + // else + // ignorieren ! + // ehemals: ShowError( "bad character in format-string" ); + } + } + // Format-String wurde vollst"andig gescanned, + // muss die letzte Stelle nun gerundet werden ? + // Dies hier ist jedoch NUR notwendig, falls das + // Zahlenformat NICHT Scientific-Format ist ! + if( !bScientific ) + { +#ifdef _with_sprintf + short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ); +#else + short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ); +#endif + if( nNextDigit>=5 ) + StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1 ); + } + // und ganz zum Schluss: + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00#, + // ABER nur Stellen nach dem Dezimal-Punkt k"onnen gel"oscht werden + if( nNoOfDigitsRight>0 ) + ParseBack( sReturnStrg,sFormatStrg,sFormatStrg.Len()-1 ); + } +} + +String SbxBasicFormater::BasicFormatNull( String sFormatStrg ) +{ + BOOL bNullFormatFound; + String sNullFormatStrg = GetNullFormatString( sFormatStrg,bNullFormatFound ); + + if( bNullFormatFound ) + return sNullFormatStrg; + String aRetStr; + aRetStr.AssignAscii( "null" ); + return aRetStr; +} + +String SbxBasicFormater::BasicFormat( double dNumber, String sFormatStrg ) +{ + BOOL bPosFormatFound,bNegFormatFound,b0FormatFound,bNullFormatFound; + + // analysiere Format-String auf vordefinierte Formate: + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) ) + sFormatStrg.AssignAscii( GENERALNUMBER_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) ) + sFormatStrg = sCurrencyFormatStrg; // old: CURRENCY_FORMAT; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) ) + sFormatStrg.AssignAscii( FIXED_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) ) + sFormatStrg.AssignAscii( STANDARD_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) ) + sFormatStrg.AssignAscii( PERCENT_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) ) + sFormatStrg.AssignAscii( SCIENTIFIC_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) ) + return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) ) + return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) ) + return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ; + + // analysiere Format-String auf ';', d.h. Format-Strings f"ur + // positive-, negative- und 0-Werte + String sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound ); + String sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound ); + String s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound ); + //String sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound ); + + String sReturnStrg; + String sTempStrg; + + if( dNumber==0.0 ) + { + sTempStrg = sFormatStrg; + if( b0FormatFound ) + { + // wurde ggf. Leer-String uebergeben ? + if( s0FormatStrg.Len() == 0 && bPosFormatFound ) + // --> Ja, dann verwende String fuer positive Werte + sTempStrg = sPosFormatStrg; + else + sTempStrg = s0FormatStrg; + } + else if( bPosFormatFound ) + { + // verwende String fuer positive Werte + sTempStrg = sPosFormatStrg; + } + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/FALSE ); + } + else + { + if( dNumber<0.0 ) + { + if( bNegFormatFound ) + { + // wurde ggf. Leer-String uebergeben ? + if( sNegFormatStrg.Len() == 0 && bPosFormatFound ) + { + // --> Ja, dann verwende String fuer positive Werte + // und setzte Minus-Zeichen davor ! + sTempStrg = String::CreateFromAscii("-"); + sTempStrg += sPosFormatStrg; + } + else + sTempStrg = sNegFormatStrg; + } + else + sTempStrg = sFormatStrg; + // falls KEIN Format-String speziell f"ur negative Werte angegeben + // wurde, so soll das Vorzeichen ausgegeben werden + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ ); + } + else // if( dNumber>0.0 ) + { + ScanFormatString( dNumber, + (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg), + sReturnStrg,/*bCreateSign=*/FALSE ); + } + } + return sReturnStrg; +} + diff --git a/basic/source/sbx/sbxint.cxx b/basic/source/sbx/sbxint.cxx new file mode 100644 index 000000000000..aef9dbf2fffa --- /dev/null +++ b/basic/source/sbx/sbxint.cxx @@ -0,0 +1,1029 @@ +/************************************************************************* + * + * $RCSfile: sbxint.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2005-04-13 09:24:07 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _ERRCODE_HXX //autogen +#include <tools/errcode.hxx> +#endif +#include "sbx.hxx" +#include "sbxconv.hxx" + +double ImpRound( double d ) +{ + return d + ( d < 0 ? -0.5 : 0.5 ); +} + +INT16 ImpGetInteger( const SbxValues* p ) +{ + SbxValues aTmp; + INT16 nRes; +start: + switch( p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + if( p->nUShort > (USHORT) SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->nUShort; + break; + case SbxLONG: + if( p->nLong > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nLong < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) p->nLong; + break; + case SbxULONG: + if( p->nULong > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->nULong; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nSingle < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( p->nSingle ); + break; + case SbxSALINT64: + if( p->nInt64 > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nInt64 < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) p->nInt64; + break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->uInt64; + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( dVal < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( dVal ); + break; + } + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( d < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( d ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetInteger(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + + // ab hier muss getestet werden + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutInteger( SbxValues* p, INT16 n ) +{ + SbxValues aTmp; +start: + switch( p->eType ) + { + // hier muss getestet werden + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxINTEGER: + case SbxBOOL: + p->nInteger = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxULONG64: + p->nULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxLONG64: + p->nLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxCURRENCY: + p->nLong64 = ImpDoubleToCurrency( (double)n ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setInt( n ); + break; + + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutInteger( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (char) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + *p->pInteger = n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); *p->puInt64 = 0; + } + else + *p->puInt64 = n; + break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxULONG64: + *p->pULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxBYREF | SbxLONG64: + *p->pLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + + +// sal_Int64 / hyper + +sal_Int64 ImpDoubleToSalInt64( double d ) +{ + sal_Int64 nRes; + if( d > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALINT64; + } + else if( d < SbxMINSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINSALINT64; + } + else + nRes = (sal_Int64) ImpRound( d ); + return nRes; +} + +sal_uInt64 ImpDoubleToSalUInt64( double d ) +{ + sal_uInt64 nRes; + if( d > SbxMAXSALUINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALUINT64; + } + else if( d < 0.0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) ImpRound( d ); + return nRes; +} + +double ImpSalUInt64ToDouble( sal_uInt64 n ) +{ + double d = 0.0; + if( n > SbxMAXSALINT64 ) + SbxBase::SetError( SbxERR_CONVERSION ); + else + d = (double)(sal_Int64) n; + return d; +} + + +sal_Int64 ImpGetInt64( const SbxValues* p ) +{ + SbxValues aTmp; + sal_Int64 nRes; +start: + switch( p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + nRes = (sal_Int64) p->nULong; break; + case SbxSINGLE: + nRes = ImpDoubleToSalInt64( (double)p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + nRes = ImpDoubleToSalInt64( dVal ); + break; + } + case SbxSALINT64: + nRes = p->nInt64; break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALINT64; + } + else + nRes = (sal_Int64) p->uInt64; + break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + ::rtl::OUString aOUStr( *p->pString ); + ::rtl::OString aOStr = ::rtl::OUStringToOString + ( aOUStr, RTL_TEXTENCODING_ASCII_US ); + nRes = aOStr.toInt64(); + if( nRes == 0 ) + { + // Check if really 0 or invalid conversion + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else + nRes = ImpDoubleToSalInt64( d ); + } + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetInt64(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxSALINT64: + nRes = *p->pnInt64; break; + + // from here the values has to be checked + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutInt64( SbxValues* p, sal_Int64 n ) +{ + SbxValues aTmp; + +start: + switch( p->eType ) + { + // Check neccessary + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxLONG: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // Check not neccessary + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSINGLE: + p->nSingle = (float) n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = (double) n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + { + if( !p->pString ) + p->pString = new XubString; + + ::rtl::OString aOStr = ::rtl::OString::valueOf( n ); + ::rtl::OUString aOUStr = ::rtl::OStringToOUString + ( aOStr, RTL_TEXTENCODING_ASCII_US ); + (*p->pString) = aOUStr; + break; + } + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutInt64( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMINCURR; + } + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->puInt64 = (sal_Int64) n; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + +sal_uInt64 ImpGetUInt64( const SbxValues* p ) +{ + SbxValues aTmp; + sal_uInt64 nRes; +start: + switch( p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + nRes = (sal_uInt64) p->nULong; break; + case SbxSINGLE: + nRes = ImpDoubleToSalUInt64( (double)p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + nRes = ImpDoubleToSalUInt64( dVal ); + break; + } + case SbxSALINT64: + if( p->nInt64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) p->nInt64; + case SbxSALUINT64: + nRes = p->uInt64; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + ::rtl::OUString aOUStr( *p->pString ); + ::rtl::OString aOStr = ::rtl::OUStringToOString + ( aOUStr, RTL_TEXTENCODING_ASCII_US ); + sal_Int64 n64 = aOStr.toInt64(); + if( n64 == 0 ) + { + // Check if really 0 or invalid conversion + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXSALUINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALUINT64; + } + else if( d < 0.0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) ImpRound( d ); + } + else if( n64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + { + nRes = n64; + } + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetUInt64(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxSALUINT64: + nRes = *p->puInt64; break; + + // from here the values has to be checked + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutUInt64( SbxValues* p, sal_uInt64 n ) +{ + SbxValues aTmp; + +start: + switch( p->eType ) + { + // Check neccessary + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxLONG: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALINT64: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSINGLE: + aTmp.pSingle = &p->nSingle; goto direct; + case SbxDATE: + case SbxDOUBLE: + aTmp.pDouble = &p->nDouble; goto direct; + + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // Check not neccessary + case SbxSALUINT64: + p->uInt64 = n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + if( n > SbxMAXSALINT64 ) + SbxBase::SetError( SbxERR_CONVERSION ); + else + { + ::rtl::OString aOStr = ::rtl::OString::valueOf( (sal_Int64)n ); + ::rtl::OUString aOUStr = ::rtl::OStringToOUString + ( aOStr, RTL_TEXTENCODING_ASCII_US ); + (*p->pString) = aOUStr; + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutUInt64( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pDouble = (float)ImpSalUInt64ToDouble( n ); break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = ImpSalUInt64ToDouble( n ); break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXSALINT64 || (sal_Int64)n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMAXCURR; + } + *p->pLong64 = ImpDoubleToCurrency( (double)(sal_Int64) n ); break; + + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxSALINT64: + if( n > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pnInt64 = (sal_Int64) n; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + + |