2005-04-13 08:24:07 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2010-02-12 15:01:35 +01:00
|
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* This file is part of OpenOffice.org.
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
|
|
* only, as published by the Free Software Foundation.
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* OpenOffice.org 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 version 3 for more details
|
|
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
2008-04-11 11:15:28 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
|
|
* <http://www.openoffice.org/license.html>
|
|
|
|
* for a copy of the LGPLv3 License.
|
2005-04-13 08:24:07 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-09-17 09:10:10 +00:00
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
|
|
#include "precompiled_basic.hxx"
|
|
|
|
|
2005-04-13 08:24:07 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2007-06-27 13:32:32 +00:00
|
|
|
#include <basic/sbxform.hxx>
|
2005-04-13 08:24:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
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 =============================
|
|
|
|
//=================================================================
|
|
|
|
|
|
|
|
#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 ?
|
2006-06-19 16:50:25 +00:00
|
|
|
sal_Unicode c2 = sStrg.GetChar( nPos );
|
|
|
|
if( c2 >= ASCII_0 && c2 <= ASCII_9 )
|
2005-04-13 08:24:07 +00:00
|
|
|
{
|
|
|
|
// muss eine 9 gerundet werden? Falls: Ja --> rekursiver Aufruf
|
2006-06-19 16:50:25 +00:00
|
|
|
if( c2 == ASCII_9 )
|
2005-04-13 08:24:07 +00:00
|
|
|
{
|
|
|
|
sStrg.SetChar( nPos, '0' );
|
|
|
|
StrRoundDigit( sStrg,nPos-1,bOverflow );
|
|
|
|
}
|
|
|
|
else
|
2006-06-19 16:50:25 +00:00
|
|
|
sStrg.SetChar( nPos, c2+1 );
|
2005-04-13 08:24:07 +00:00
|
|
|
}
|
|
|
|
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 );
|
2006-06-19 16:50:25 +00:00
|
|
|
nExponentPos = 0;
|
|
|
|
nMaxExponentDigit = 0;
|
2005-04-13 08:24:07 +00:00
|
|
|
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 )
|
|
|
|
{
|
2006-06-19 16:50:25 +00:00
|
|
|
BOOL bPosFormatFound,bNegFormatFound,b0FormatFound;
|
2005-04-13 08:24:07 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2008-01-28 13:01:00 +00:00
|
|
|
BOOL SbxBasicFormater::isBasicFormat( String sFormatStrg )
|
|
|
|
{
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) )
|
|
|
|
return TRUE;
|
|
|
|
if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) )
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|