xref: /AOO41X/main/basic/source/sbx/sbxform.cxx (revision e1f63238eb022c8a12b30d46a012444ff20e0951)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 
27 #include <stdlib.h>
28 
29 #include <basic/sbxform.hxx>
30 
31 /*
32 TODO: gibt es noch irgend welche Star-Basic Besonderheiten ?
33 
34         was bedeutet: * als Platzhalter
35 
36 BEMERKUNG: Visual-Basic behandelt folgende (ung"ultige) Format-Strings
37       wie angezeigt:
38 
39         ##0##.##0##     --> ##000.000##
40 
41       (diese Klasse verh"alt sich genau so).
42 */
43 
44 #include <stdio.h>          // f"ur: sprintf()
45 #include <float.h>          // f"ur: DBL_DIG, DBL_EPSILON
46 #include <math.h>           // f"ur: floor(), fabs(), log10(), pow()
47 
48 //=================================================================
49 //=========================== DEFINES =============================
50 //=================================================================
51 
52 #define _NO_DIGIT                   -1
53 
54 #define MAX_NO_OF_EXP_DIGITS        5
55                     // +4 wegen dem Wertebereich: zwischen -308 und +308
56                     // +1 f"ur abschliessende 0
57 #define MAX_NO_OF_DIGITS            DBL_DIG
58 #define MAX_DOUBLE_BUFFER_LENGTH    MAX_NO_OF_DIGITS + 9
59                     // +1 f"ur Vorzeichen
60                     // +1 f"ur Ziffer vor dem Dezimal-Punkt
61                     // +1 f"ur Dezimal-Punkt
62                     // +2 f"ur Exponent E und Exp. Vorzeichen
63                     // +3 f"ur den Wert des Exponenten
64                     // +1 f"ur abschliessende 0
65 
66 // Defines f"ur die Ziffern:
67 #define ASCII_0                     '0' // 48
68 #define ASCII_9                     '9' // 57
69 
70 #define CREATE_1000SEP_CHAR         '@'
71 
72 #define FORMAT_SEPARATOR            ';'
73 
74 // vordefinierte Formate f"ur den Format$()-Befehl:
75 #define BASICFORMAT_GENERALNUMBER   "General Number"
76 #define BASICFORMAT_CURRENCY        "Currency"
77 #define BASICFORMAT_FIXED           "Fixed"
78 #define BASICFORMAT_STANDARD        "Standard"
79 #define BASICFORMAT_PERCENT         "Percent"
80 #define BASICFORMAT_SCIENTIFIC      "Scientific"
81 #define BASICFORMAT_YESNO           "Yes/No"
82 #define BASICFORMAT_TRUEFALSE       "True/False"
83 #define BASICFORMAT_ONOFF           "On/Off"
84 
85 #define EMPTYFORMATSTRING           ""
86 
87 // Bem.: Visual-Basic hat bei Floating-Point-Zahlen maximal 12 Stellen
88 //       nach dem Dezimal-Punkt.
89 // Alle Format-Strings sind kompatibel zu Visual-Basic:
90 #define GENERALNUMBER_FORMAT        "0.############"
91             // max. 12 Stellen in Visual-Basic !
92 #define CURRENCY_FORMAT             "@$0.00;@($0.00)"
93 #define FIXED_FORMAT                "0.00"
94 #define STANDARD_FORMAT             "@0.00"
95 #define PERCENT_FORMAT              "0.00%"
96 #define SCIENTIFIC_FORMAT           "#.00E+00"
97 // BEMERKUNG: das Zeichen @ bedeutet, das Tausender-Separatoren erzeugt
98 //            weden sollen. Dies ist eine StarBasic 'Erweiterung'.
99 
100 //=================================================================
101 
102 // zur Bestimmung der Anzahl Stellen in dNumber
get_number_of_digits(double dNumber)103 double get_number_of_digits( double dNumber )
104 //double floor_log10_fabs( double dNumber )
105 {
106     if( dNumber==0.0 )
107         // 0 hat zumindest auch eine Stelle !
108         return 0.0; //ehemals 1.0, jetzt 0.0 wegen #40025;
109     else
110         return floor( log10( fabs( dNumber ) ) );
111 }
112 
113 //=================================================================
114 //======================= IMPLEMENTATION ==========================
115 //=================================================================
116 
SbxBasicFormater(sal_Unicode _cDecPoint,sal_Unicode _cThousandSep,String _sOnStrg,String _sOffStrg,String _sYesStrg,String _sNoStrg,String _sTrueStrg,String _sFalseStrg,String _sCurrencyStrg,String _sCurrencyFormatStrg)117 SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
118                       String _sOnStrg,
119                       String _sOffStrg,
120                       String _sYesStrg,
121                       String _sNoStrg,
122                       String _sTrueStrg,
123                       String _sFalseStrg,
124                       String _sCurrencyStrg,
125                       String _sCurrencyFormatStrg )
126 {
127     cDecPoint = _cDecPoint;
128     cThousandSep = _cThousandSep;
129     sOnStrg = _sOnStrg;
130     sOffStrg = _sOffStrg;
131     sYesStrg = _sYesStrg;
132     sNoStrg = _sNoStrg;
133     sTrueStrg = _sTrueStrg;
134     sFalseStrg = _sFalseStrg;
135     sCurrencyStrg = _sCurrencyStrg;
136     sCurrencyFormatStrg = _sCurrencyFormatStrg;
137 }
138 
139 // Funktion zur Ausgabe eines Fehler-Textes (zum Debuggen)
140 /*
141 void SbxBasicFormater::ShowError( char * sErrMsg )
142 {
143 //  cout << "ERROR in Format$(): " << sErrMsg << endl;
144 }
145 */
146 // verschiebt alle Zeichen des Strings, angefangen von der nStartPos,
147 // um eine Position zu gr"osseren Indizes, d.h. es wird Platz f"ur
148 // ein neues (einzuf"ugendes) Zeichen geschafft.
149 // ACHTUNG: der String MUSS gross genug sein !
ShiftString(String & sStrg,sal_uInt16 nStartPos)150 inline void SbxBasicFormater::ShiftString( String& sStrg, sal_uInt16 nStartPos )
151 {
152     sStrg.Erase( nStartPos,1 );
153 }
154 
155 // Funktion um ein Zeichen an einen String anzuh"angen
StrAppendChar(String & sStrg,sal_Unicode ch)156 inline void SbxBasicFormater::StrAppendChar( String& sStrg, sal_Unicode ch )
157 {
158     sStrg.Insert( ch );
159 }
160 
161 // h"angt die "ubergebene Ziffer nDigit an den "ubergebenen String sStrg
162 // an, dabei wird "uberpr"uft ob nDigit eine g"ultige Ziffer ist,
163 // falls dies nicht der Fall ist, wird nichts gemacht.
AppendDigit(String & sStrg,short nDigit)164 void SbxBasicFormater::AppendDigit( String& sStrg, short nDigit )
165 {
166     if( nDigit>=0 && nDigit<=9 )
167         StrAppendChar( sStrg, (sal_Unicode)(nDigit+ASCII_0) );
168 }
169 
170 // verschiebt den Dezimal-Punkt um eine Stelle nach links
LeftShiftDecimalPoint(String & sStrg)171 void SbxBasicFormater::LeftShiftDecimalPoint( String& sStrg )
172 {
173     sal_uInt16 nPos = sStrg.Search( cDecPoint );
174 
175     if( nPos!=STRING_NOTFOUND )
176     {
177         // vertausche Dezimal-Punkt
178         sStrg.SetChar( nPos, sStrg.GetChar( nPos - 1 ) );
179         sStrg.SetChar( nPos-1, cDecPoint );
180     }
181 }
182 
183 // rundet in einem String die Ziffer an der angegebenen Stelle,
184 // es wird ein Flag zur"uckgeliefert, falls ein Overflow auftrat,
185 // d.h. 99.99 --> 100.00, d.h. ein Gr"ossenordung ge"andert wurde
186 // (geschieht beim Runden einer 9).
StrRoundDigit(String & sStrg,short nPos,sal_Bool & bOverflow)187 void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos, sal_Bool& bOverflow )
188 {
189     // wurde ggf ein falscher Index uebergeben --> Aufruf ignorieren
190     if( nPos<0 )
191         return;
192 
193     bOverflow = sal_False;
194     // "uberspringe den Dezimalpunkt und Tausender-Trennzeichen
195     sal_Unicode c = sStrg.GetChar( nPos );
196     if( nPos>0 && (c == cDecPoint || c == cThousandSep) )
197     {
198         StrRoundDigit( sStrg,nPos-1,bOverflow );
199         // AENDERUNG ab 9.3.1997: nach rekursivem Call die Methode SOFORT beenden !
200         return;
201     }
202     // "uberspringe alle nicht-Ziffern:
203     // BEMERKUNG:
204     // in einem g"ultigen Format-String sollte die Ausgabe
205     // der Zahl an einem St"uck geschen, d.h. Sonderzeichen sollten
206     // NUR vor ODER nach der Zahl stehen und nicht mitten in der
207     // Format-Angabe f"ur die Zahl
208     while( nPos>=0 && (sStrg.GetChar( nPos )<ASCII_0 || sStrg.GetChar( nPos )>ASCII_9) )
209         nPos--;
210     // muss ggf. noch Platz f"ur eine weitere (f"uhrende) Ziffer
211     // geschaffen werden ?
212     if( nPos==-1 )
213     {
214         ShiftString( sStrg,0 );
215         // f"uhrende 1 einf"ugen: z.B. 99.99 f"ur 0.0
216         sStrg.SetChar( 0, '1' );
217         bOverflow = sal_True;
218     }
219     else
220     {
221         // ist die zu rundende Position eine Ziffer ?
222         sal_Unicode c2 = sStrg.GetChar( nPos );
223         if( c2 >= ASCII_0 && c2 <= ASCII_9 )
224         {
225             // muss eine 9 gerundet werden? Falls: Ja --> rekursiver Aufruf
226             if( c2 == ASCII_9 )
227             {
228                 sStrg.SetChar( nPos, '0' );
229                 StrRoundDigit( sStrg,nPos-1,bOverflow );
230             }
231             else
232                 sStrg.SetChar( nPos, c2+1 );
233         }
234         else
235         {
236         // --> Nein, d.h. Platz f"ur Ziffer schaffen: z.B. -99.99 f"ur #0.0
237             // da gerundet wird MUSS es immer eine g"ultige Position
238             // nPos+1 geben !
239             ShiftString( sStrg,nPos+1 );
240             // f"uhrende 1 einf"ugen
241             sStrg.SetChar( nPos+1, '1' );
242             bOverflow = sal_True;
243         }
244     }
245 }
246 
247 // rundet in einem String die Ziffer an der angegebenen Stelle
StrRoundDigit(String & sStrg,short nPos)248 void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos )
249 {
250     sal_Bool bOverflow;
251 
252     StrRoundDigit( sStrg,nPos,bOverflow );
253 }
254 
255 // parse den Formatstring von der "ubergebenen Position zur"uck
256 // und l"osche ggf. "uberf"ussige 0en, z.B. 4.50 in 0.0#
ParseBack(String & sStrg,const String & sFormatStrg,short nFormatPos)257 void SbxBasicFormater::ParseBack( String& sStrg, const String& sFormatStrg,
258                                   short nFormatPos )
259 {
260     // WICHTIG: nFormatPos kann auch negativ sein, in diesem Fall Aufruf ignorieren
261     for( short i=nFormatPos;
262          i>0 && sFormatStrg.GetChar( i ) == '#' && sStrg.GetChar( (sStrg.Len()-1) ) == '0';
263          i-- )
264          { sStrg.Erase( sStrg.Len()-1 ); }
265 }
266 
267 #ifdef _with_sprintf
268 
269 /*
270     Bemerkung:
271     Zahl wird mit maximaler (sinnvollen) Genauigkeit in einen String
272     umgewandelt (mit sprintf()), dieser String wird dann im Schleifen-
273     Durchlauf nach der entsprechenden Ziffer durchsucht.
274 */
275 // initialisiert die Daten der Klasse um einen Scan-Durchlauf durchzuf"uhren
InitScan(double _dNum)276 void SbxBasicFormater::InitScan( double _dNum )
277 {
278     char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
279 
280     dNum = _dNum;
281     InitExp( get_number_of_digits( dNum ) );
282     // maximal 15 Nachkomma-Stellen, Format-Beispiel: -1.234000000000000E-001
283     /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum );
284     sSciNumStrg.AssignAscii( sBuffer );
285 }
286 
InitExp(double _dNewExp)287 void SbxBasicFormater::InitExp( double _dNewExp )
288 {
289     char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
290     // bestimme den Exponenten (kann immer GENAU durch int dargestellt werden)
291     nNumExp = (short)_dNewExp;
292     // und dessen String
293     /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp );
294     sNumExpStrg.AssignAscii( sBuffer );
295     // bestimme die Anzahl der Stellen im Exponenten
296     nExpExp = (short)get_number_of_digits( (double)nNumExp );
297 }
298 
299 // bestimmt die Ziffer an der angegebenen Stelle (gedacht zur Anwendung im
300 // Scan-Durchlauf)
GetDigitAtPosScan(short nPos,sal_Bool & bFoundFirstDigit)301 short SbxBasicFormater::GetDigitAtPosScan( short nPos, sal_Bool& bFoundFirstDigit )
302 {
303     // Versuch eine gr"ossere Ziffer zu lesen,
304     // z.B. Stelle 4 in 1.234,
305     // oder eine Ziffer ausserhalb der Aufl"osung der
306     // Zahl (double) zu lesen (z.B. max. 15 Stellen).
307     if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS )
308         return _NO_DIGIT;
309     // bestimme den Index der Stelle in dem Number-String:
310     // "uberlese das Vorzeichen
311     sal_uInt16 no = 1;
312     // falls notwendig den Dezimal-Punkt "uberlesen:
313     if( nPos<nNumExp )
314         no++;
315     no += nNumExp-nPos;
316     // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen
317     if( nPos==nNumExp )
318         bFoundFirstDigit = sal_True;
319     return (short)(sSciNumStrg.GetChar( no ) - ASCII_0);
320 }
321 
GetDigitAtPosExpScan(short nPos,sal_Bool & bFoundFirstDigit)322 short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, sal_Bool& bFoundFirstDigit )
323 {
324     // ist die abgefragte Stelle zu gross f"ur den Exponenten ?
325     if( nPos>nExpExp )
326         return -1;
327 
328     // bestimme den Index der Stelle in dem Number-String:
329     // "uberlese das Vorzeichen
330     sal_uInt16 no = 1;
331     no += nExpExp-nPos;
332     // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen
333     if( nPos==nExpExp )
334         bFoundFirstDigit = sal_True;
335     return (short)(sNumExpStrg.GetChar( no ) - ASCII_0);
336 }
337 
338 // es kann ein Wert f"ur den Exponent angegeben werden, da ggf. die
339 // Zahl ggf. NICHT normiert (z.B. 1.2345e-03) dargestellt werden soll,
340 // sondern eventuell 123.345e-3 !
GetDigitAtPosExpScan(double dNewExponent,short nPos,sal_Bool & bFoundFirstDigit)341 short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos,
342                                               sal_Bool& bFoundFirstDigit )
343 {
344     // neuer Exponent wurde "ubergeben, aktualisiere
345     // die tempor"aren Klassen-Variablen
346     InitExp( dNewExponent );
347     // und jetzt die Stelle bestimmen
348     return GetDigitAtPosExpScan( nPos,bFoundFirstDigit );
349 }
350 
351 #else
352 
353 /* Probleme mit der folgenden Methode:
354 
355 TODO: ggf einen 'intelligenten' Peek-Parser um Rundungsfehler bei
356       double-Zahlen herauszufinden ? z.B. f"ur  0.00115 #.#e-000
357 
358   Problem mit: format( 0.3345 ,  "0.000" )
359   Problem mit: format( 0.00115 , "0.0000" )
360 
361 */
362 // liefert die Ziffer an der angegebenen '10er System'-Position,
363 // d.h. positive nPos f"ur Stellen vor dem Komma und negative
364 // f"ur Stellen nach dem Komma.
365 // nPos==0 bedeutet erste Stelle vor dem Komma, also 10^0.
366 // liefert 0..9 f"ur g"ultige Ziffern und -1 f"ur nicht vorhanden,
367 // d.h. falls die "ubergebene Zahl zu klein ist
368 // (z.B. Stelle 5 bei dNumber=123).
369 // Weiter wird in dNextNumber die um die f"uhrenden Stellen
370 // (bis nPos) gek"urzte Zahl zur"uckgeliefert, z.B.
371 //   GetDigitAtPos( 3434.565 , 2 , dNewNumber ) --> dNewNumber = 434.565
372 // dies kann f"ur Schleifenabarbeitung g"unstiger sein, d.h.
373 // die Zahlen immer von der gr"ossten Stelle abarbeiten/scanen.
374 // In bFoundFirstDigit wird ggf. ein Flag gesetzt wenn eine Ziffer
375 // gefunden wurde, dies wird dazu verwendet um 'Fehler' beim Parsen 202
376 // zu vermeiden, die
377 //
378 // ACHTUNG: anscheinend gibt es manchmal noch Probleme mit Rundungs-Fehlern!
GetDigitAtPos(double dNumber,short nPos,double & dNextNumber,sal_Bool & bFoundFirstDigit)379 short SbxBasicFormater::GetDigitAtPos( double dNumber, short nPos,
380                                 double& dNextNumber, sal_Bool& bFoundFirstDigit )
381 // ACHTUNG: nPos kann auch negativ werden, f"ur Stellen nach dem Dezimal-Punkt
382 {
383     double dTemp = dNumber;
384     double dDigit,dPos;
385     short  nMaxDigit;
386 
387     // erst mal aus der Zahl eine positive Zahl machen:
388     dNumber = fabs( dNumber );
389     dPos = (double)nPos;
390 
391     // "uberpr"ufe ob Zahl zu klein f"ur angegebene Stelle ist
392     nMaxDigit = (short)get_number_of_digits( dNumber );
393     // f"uhrende Ziffern 'l"oschen'
394     // Bem.: Fehler nur bei Zahlen gr"osser 0, d.h. bei Ziffern vor dem
395     //       Dezimal-Punkt
396     if( nMaxDigit<nPos && !bFoundFirstDigit && nPos>=0 )
397         return _NO_DIGIT;
398     // Ziffer gefunden, setze Flag:
399     bFoundFirstDigit = sal_True;
400     for( short i=nMaxDigit; i>=nPos; i-- )
401     {
402         double dI = (double)i;
403         double dTemp1 = pow( 10.0,dI );
404         // pr"apariere nun die gesuchte Ziffer:
405         dDigit = floor( pow( 10.0,log10( fabs( dNumber ) )-dI ) );
406         dNumber -= dTemp1 * dDigit;
407     }
408         // Zuweisung f"ur optimierte Schleifen-Durchl"aufe
409     dNextNumber = dNumber;
410     // und zum Schluss noch die float-Rundungsungenauigkeiten heraus filtern
411     return RoundDigit( dDigit );
412 }
413 
414 // rundet eine double-Zahl zwischen 0 und 9 auf die genaue
415 // Integer-Zahl, z.B. 2.8 -> 3 und 2.2 -> 2
RoundDigit(double dNumber)416 short SbxBasicFormater::RoundDigit( double dNumber )
417 {
418     // ist der Wertebereich g"ultig ?
419     if( dNumber<0.0 || dNumber>10.0 )
420         return -1;
421     short nTempHigh = (short)(dNumber+0.5); // ggf. floor( )
422     return nTempHigh;
423 }
424 
425 #endif
426 
427 // kopiert den entsprechenden Teil des Format-Strings, falls vorhanden,
428 // und liefert diesen zur"uck.
429 // Somit wird ein neuer String erzeugt, der vom Aufrufer wieder freigegeben
430 // werden muss
GetPosFormatString(const String & sFormatStrg,sal_Bool & bFound)431 String SbxBasicFormater::GetPosFormatString( const String& sFormatStrg, sal_Bool & bFound )
432 {
433     bFound = sal_False;     // default...
434     sal_uInt16 nPos = sFormatStrg.Search( FORMAT_SEPARATOR );
435 
436     if( nPos!=STRING_NOTFOUND )
437     {
438         bFound = sal_True;
439         // der Format-String f"ur die positiven Zahlen ist alles
440         // vor dem ersten ';'
441         return sFormatStrg.Copy( 0,nPos );
442     }
443     // kein ; gefunden, liefere Leerstring
444     String aRetStr;
445     aRetStr.AssignAscii( EMPTYFORMATSTRING );
446     return aRetStr;
447 }
448 
449 // siehe auch GetPosFormatString()
GetNegFormatString(const String & sFormatStrg,sal_Bool & bFound)450 String SbxBasicFormater::GetNegFormatString( const String& sFormatStrg, sal_Bool & bFound )
451 {
452     bFound = sal_False;     // default...
453     sal_uInt16 nPos = sFormatStrg.Search( FORMAT_SEPARATOR );
454 
455     if( nPos!=STRING_NOTFOUND )
456     {
457         // der Format-String f"ur die negative Zahlen ist alles
458         // zwischen dem ersten und dem zweiten ';'.
459         // Daher: hole erst mal alles nach dem ersten ';'
460         String sTempStrg = sFormatStrg.Copy( nPos+1 );
461         // und suche darin ggf. ein weiteres ';'
462         nPos = sTempStrg.Search( FORMAT_SEPARATOR );
463         bFound = sal_True;
464         if( nPos==STRING_NOTFOUND )
465             // keins gefunden, liefere alles...
466             return sTempStrg;
467         else
468             // ansonsten den String zwischen den beiden ';' liefern
469             return sTempStrg.Copy( 0,nPos );
470     }
471     String aRetStr;
472     aRetStr.AssignAscii( EMPTYFORMATSTRING );
473     return aRetStr;
474 }
475 
476 // siehe auch GetPosFormatString()
Get0FormatString(const String & sFormatStrg,sal_Bool & bFound)477 String SbxBasicFormater::Get0FormatString( const String& sFormatStrg, sal_Bool & bFound )
478 {
479     bFound = sal_False;     // default...
480     sal_uInt16 nPos = sFormatStrg.Search( FORMAT_SEPARATOR );
481 
482     if( nPos!=STRING_NOTFOUND )
483     {
484         // der Format-String f"ur die Null ist alles
485         // was nach dem zweiten ';' kommt.
486         // Daher: hole erst mal alles nach dem ersten ';'
487         String sTempStrg = sFormatStrg.Copy( nPos+1 );
488         // und suche darin ggf. ein weiteres ';'
489         nPos = sTempStrg.Search( FORMAT_SEPARATOR );
490         if( nPos!=STRING_NOTFOUND )
491         {
492             bFound = sal_True;
493             sTempStrg = sTempStrg.Copy( nPos+1 );
494             nPos = sTempStrg.Search( FORMAT_SEPARATOR );
495             if( nPos==STRING_NOTFOUND )
496                 // keins gefunden, liefere alles...
497                 return sTempStrg;
498             else
499                 return sTempStrg.Copy( 0,nPos );
500         }
501     }
502     // kein ; gefunden, liefere Leerstring
503     String aRetStr;
504     aRetStr.AssignAscii( EMPTYFORMATSTRING );
505     return aRetStr;
506 }
507 
508 // siehe auch GetPosFormatString()
GetNullFormatString(const String & sFormatStrg,sal_Bool & bFound)509 String SbxBasicFormater::GetNullFormatString( const String& sFormatStrg, sal_Bool & bFound )
510 {
511     bFound = sal_False;     // default...
512     sal_uInt16 nPos = sFormatStrg.Search( FORMAT_SEPARATOR );
513 
514     if( nPos!=STRING_NOTFOUND )
515     {
516         // der Format-String f"ur die Null ist alles
517         // was nach dem dritten ';' kommt.
518         // Daher: hole erst mal alles nach dem ersten ';'
519         String sTempStrg = sFormatStrg.Copy( nPos+1 );
520         // und suche darin ggf. ein weiteres ';'
521         nPos = sTempStrg.Search( FORMAT_SEPARATOR );
522         if( nPos!=STRING_NOTFOUND )
523         {
524             // und suche nun nach dem dritten ';'
525             sTempStrg = sTempStrg.Copy( nPos+1 );
526             nPos = sTempStrg.Search( FORMAT_SEPARATOR );
527             if( nPos!=STRING_NOTFOUND )
528             {
529                 bFound = sal_True;
530                 return sTempStrg.Copy( nPos+1 );
531             }
532         }
533     }
534     // kein ; gefunden, liefere Leerstring
535     String aRetStr;
536     aRetStr.AssignAscii( EMPTYFORMATSTRING );
537     return aRetStr;
538 }
539 
540 // analysiert den Format-String, liefert Wert <> 0 falls ein Fehler
541 // aufgetreten ist
AnalyseFormatString(const String & sFormatStrg,short & nNoOfDigitsLeft,short & nNoOfDigitsRight,short & nNoOfOptionalDigitsLeft,short & nNoOfExponentDigits,short & nNoOfOptionalExponentDigits,sal_Bool & bPercent,sal_Bool & bCurrency,sal_Bool & bScientific,sal_Bool & bGenerateThousandSeparator,short & nMultipleThousandSeparators)542 short SbxBasicFormater::AnalyseFormatString( const String& sFormatStrg,
543                 short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
544                 short& nNoOfOptionalDigitsLeft,
545                 short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits,
546                 sal_Bool& bPercent, sal_Bool& bCurrency, sal_Bool& bScientific,
547                 sal_Bool& bGenerateThousandSeparator,
548                 short& nMultipleThousandSeparators )
549 {
550     sal_uInt16 nLen;
551     short nState = 0;
552 
553     nLen = sFormatStrg.Len();
554     // initialisiere alle Z"ahler und Flags
555     nNoOfDigitsLeft = 0;
556     nNoOfDigitsRight = 0;
557     nNoOfOptionalDigitsLeft = 0;
558     nNoOfExponentDigits = 0;
559     nNoOfOptionalExponentDigits = 0;
560     bPercent = sal_False;
561     bCurrency = sal_False;
562     bScientific = sal_False;
563     // ab 11.7.97: sobald ein Komma in dem Format String gefunden wird,
564     // werden alle 3 Zehnerpotenzen markiert (d.h. tausender, milionen, ...)
565     // bisher wurde nur an den gesetzten Position ein Tausender-Separator
566     // ausgegeben oder wenn ein @ im Format-String stand.
567     // Dies war ein Missverstaendnis der VB Kompatiblitaet.
568     bGenerateThousandSeparator = sFormatStrg.Search( ',' ) != STRING_NOTFOUND;
569     nMultipleThousandSeparators = 0;
570     // und untersuche den Format-String nach den gew"unschten Informationen
571     for( sal_uInt16 i=0; i<nLen; i++ )
572     {
573         sal_Unicode c = sFormatStrg.GetChar( i );
574         switch( c ) {
575             case '#':
576             case '0':
577                 if( nState==0 )
578                 {
579                     nNoOfDigitsLeft++;
580 // TODO  hier ggf. bessere Fehler-"Uberpr"ufung der Mantisse auf g"ultige Syntax (siehe Grammatik)
581                     // ACHTUNG: 'undefiniertes' Verhalten falls # und 0
582                     //   gemischt werden !!!
583                     // BEMERKUNG: eigentlich sind #-Platzhalter bei Scientific
584                     //   Darstellung vor dem Dezimal-Punkt sinnlos !
585                     if( c=='#' )
586                         nNoOfOptionalDigitsLeft++;
587                 }
588                 else if( nState==1 )
589                     nNoOfDigitsRight++;
590                 else if( nState==-1 )   // suche 0 im Exponent
591                 {
592                     if( c=='#' )    // # schaltet den Zustand weiter
593                     {
594                         nNoOfOptionalExponentDigits++;
595                         nState = -2;
596                     }
597                     nNoOfExponentDigits++;
598                 }
599                 else if( nState==-2 )   // suche # im Exponent
600                 {
601                     if( c=='0' )
602                         // ERROR: 0 nach # im Exponent ist NICHT erlaubt !!
603                         return -4;
604                     nNoOfOptionalExponentDigits++;
605                     nNoOfExponentDigits++;
606                 }
607                 break;
608             case '.':
609                 nState++;
610                 if( nState>1 )
611                     return -1;  // ERROR: zu viele Dezimal-Punkte
612                 break;
613             case '%':
614                 bPercent = sal_True;
615                 /* old:
616                 bPercent++;
617                 if( bPercent>1 )
618                     return -2;  // ERROR: zu viele Prozent-Zeichen
619                 */
620                 break;
621             case '(':
622                 bCurrency = sal_True;
623                 break;
624             case ',':
625             {
626                 sal_Unicode ch = sFormatStrg.GetChar( i+1 );
627                 // vorl"aufig wird NUR auf zwei aufeinanderfolgede
628                 // Zeichen gepr"uft
629                 if( ch!=0 && (ch==',' || ch=='.') )
630                     nMultipleThousandSeparators++;
631             }   break;
632             case 'e':
633             case 'E':
634                 // #i13821 not when no digits before
635                 if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 )
636                 {
637                     nState = -1;    // breche jetzt das Z"ahlen der Stellen ab
638                     bScientific = sal_True;
639                 }
640                 /* old:
641                 bScientific++;
642                 if( bScientific>1 )
643                     return -3;  // ERROR: zu viele Exponent-Zeichen
644                 */
645                 break;
646             // EIGENES Kommando-Zeichen, das die Erzeugung der
647             // Tausender-Trennzeichen einschaltet
648             case '\\':
649                 // Ignore next char
650                 i++;
651                 break;
652             case CREATE_1000SEP_CHAR:
653                 bGenerateThousandSeparator = sal_True;
654                 break;
655         }
656     }
657     return 0;
658 }
659 
660 // das Flag bCreateSign zeigt an, dass bei der Mantisse ein Vorzeichen
661 // erzeugt werden soll
ScanFormatString(double dNumber,const String & sFormatStrg,String & sReturnStrg,sal_Bool bCreateSign)662 void SbxBasicFormater::ScanFormatString( double dNumber,
663                                 const String& sFormatStrg, String& sReturnStrg,
664                                 sal_Bool bCreateSign )
665 {
666     short   /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft,
667             nNoOfExponentDigits,nNoOfOptionalExponentDigits,
668             nMultipleThousandSeparators;
669     sal_Bool    bPercent,bCurrency,bScientific,bGenerateThousandSeparator;
670 
671     // Initialisiere den Return-String
672     sReturnStrg = String();
673 
674     // analysiere den Format-String, d.h. bestimme folgende Werte:
675     /*
676             - Anzahl der Ziffern vor dem Komma
677             - Anzahl der Ziffern nach dem Komma
678             - optionale Ziffern vor dem Komma
679             - Anzahl der Ziffern im Exponent
680             - optionale Ziffern im Exponent
681             - Prozent-Zeichen gefunden ?
682             - () f"ur negatives Vorzeichen ?
683             - Exponetial-Schreibweise ?
684             - sollen Tausender-Separatoren erzeugt werden ?
685             - wird ein Prozent-Zeichen gefunden ? --> dNumber *= 100.0;
686             - gibt es aufeinanderfolgende Tausender-Trennzeichen ?
687                 ,, oder ,. --> dNumber /= 1000.0;
688             - sonstige Fehler ? mehrfache Dezimalpunkte, E's, etc.
689         --> Fehler werden zur Zeit einfach ignoriert
690     */
691     /*nErr =*/ AnalyseFormatString( sFormatStrg,nNoOfDigitsLeft,nNoOfDigitsRight,
692                     nNoOfOptionalDigitsLeft,nNoOfExponentDigits,
693                     nNoOfOptionalExponentDigits,
694                     bPercent,bCurrency,bScientific,bGenerateThousandSeparator,
695                     nMultipleThousandSeparators );
696     /* es werden alle Fehler ignoriert, wie in Visual-Basic
697     if( nErr!=0 )
698     {
699         char sBuffer[512];
700 
701         //sprintf( sBuffer,"bad format-string >%s< err=%i",sFormatStrg,nErr );
702         strcpy( sBuffer,"bad format-string" );
703         ShowError( sBuffer );
704     }
705     else
706     */
707     {
708         // Spezialbehandlung f"ur Spezialzeichen
709         if( bPercent )
710             dNumber *= 100.0;
711 // TODO: diese Vorgabe (,, oder ,.) ist NICHT Visual-Basic kompatibel !
712         // Frage: soll das hier stehen bleiben (Anforderungen) ?
713         if( nMultipleThousandSeparators )
714             dNumber /= 1000.0;
715 
716         // einige Arbeits-Variablen
717         double dExponent;
718         short i,nLen;
719         short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit;
720         sal_Bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit,
721              bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative;
722 
723         // Initialisierung der Arbeits-Variablen
724         bSignHappend = sal_False;
725         bFoundFirstDigit = sal_False;
726         bIsNegative = dNumber<0.0;
727         nLen = sFormatStrg.Len();
728         dExponent = get_number_of_digits( dNumber );
729         nExponentPos = 0;
730         nMaxExponentDigit = 0;
731         nMaxDigit = (short)dExponent;
732         bDigitPosNegative = false;
733         if( bScientific )
734         {
735             //if( nNoOfOptionalDigitsLeft>0 )
736             //  ShowError( "# in scientific-format in front of the decimal-point has no effect" );
737             // beim Exponent ggf. "uberz"ahlige Stellen vor dem Komma abziehen
738             dExponent = dExponent - (double)(nNoOfDigitsLeft-1);
739             nDigitPos = nMaxDigit;
740             nMaxExponentDigit = (short)get_number_of_digits( dExponent );
741             nExponentPos = nNoOfExponentDigits-1 - nNoOfOptionalExponentDigits;
742         }
743         else
744         {
745             nDigitPos = nNoOfDigitsLeft-1; // Z"ahlweise f"angt bei 0 an, 10^0
746             // hier ben"otigt man keine Exponent-Daten !
747             bDigitPosNegative = (nDigitPos < 0);
748         }
749         bFirstDigit = sal_True;
750         bFirstExponentDigit = sal_True;
751         nState = 0; // 0 --> Mantisse; 1 --> Exponent
752         bZeroSpaceOn = 0;
753 
754 
755 #ifdef _with_sprintf
756         InitScan( dNumber );
757 #endif
758         // scanne jetzt den Format-String:
759         sal_Unicode cForce = 0;
760         for( i=0; i<nLen; i++ )
761         {
762             sal_Unicode c;
763             if( cForce )
764             {
765                 c = cForce;
766                 cForce = 0;
767             }
768             else
769             {
770                 c = sFormatStrg.GetChar( i );
771             }
772             switch( c ) {
773                 case '0':
774                 case '#':
775                     if( nState==0 )
776                     {
777                     // Behandlung der Mantisse
778                         if( bFirstDigit )
779                         {
780                             //org:bFirstDigit = sal_False;
781                             // ggf. Vorzeichen erzeugen
782                             // Bem.: bei bCurrency soll das negative
783                             //       Vorzeichen durch () angezeigt werden
784                             if( bIsNegative && !bCreateSign/*!bCurrency*/ && !bSignHappend )
785                             {
786                                 // nur einmal ein Vorzeichen ausgeben
787                                 bSignHappend = sal_True;
788                                 StrAppendChar( sReturnStrg,'-' );
789                             }
790                             // hier jetzt "uberz"ahlige Stellen ausgeben,
791                             // d.h. vom Format-String nicht erfasste Stellen
792                             if( nMaxDigit>nDigitPos )
793                             {
794                                 for( short j=nMaxDigit; j>nDigitPos; j-- )
795                                 {
796                                     short nTempDigit;
797 #ifdef _with_sprintf
798                                     AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( j,bFoundFirstDigit ) );
799 #else
800                                     AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,j,dNumber,bFoundFirstDigit ) );
801 #endif
802                                     // wurde wirklich eine Ziffer eingefuegt ?
803                                     if( nTempDigit!=_NO_DIGIT )
804                                         // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen
805                                         bFirstDigit = sal_False;
806                                     // muss ggf. ein Tausender-Trennzeichen erzeugt werden?
807                                     if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && j>0 && (j % 3 == 0) )
808                                         StrAppendChar( sReturnStrg,cThousandSep );
809                                 }
810                             }
811                         }
812                         // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ?
813                         if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) )
814                         {
815                             AppendDigit( sReturnStrg,0 );       // Ja
816                             // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen
817                             bFirstDigit = sal_False;
818                             bZeroSpaceOn = 1;
819                             // BEM.: bei Visual-Basic schaltet die erste 0 f"ur alle
820                             //       nachfolgenden # (bis zum Dezimal-Punkt) die 0 ein,
821                             //       dieses Verhalten wird hier mit dem Flag simmuliert.
822                             // muss ggf. ein Tausender-Trennzeichen erzeugt werden?
823                             if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
824                                 StrAppendChar( sReturnStrg,cThousandSep );
825                         }
826                         else
827                         {
828                             short nTempDigit;
829 #ifdef _with_sprintf
830                             AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ) );
831 #else
832                             AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ) );
833 #endif
834                             // wurde wirklich eine Ziffer eingefuegt ?
835                             if( nTempDigit!=_NO_DIGIT )
836                                 // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen
837                                 bFirstDigit = sal_False;
838                             // muss ggf. ein Tausender-Trennzeichen erzeugt werden?
839                             if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
840                                 StrAppendChar( sReturnStrg,cThousandSep );
841                         }
842                         // und Position aktualisieren
843                         nDigitPos--;
844                     }
845                     else
846                     {
847                     // Behandlung des Exponenten
848                         if( bFirstExponentDigit )
849                         {
850                             // Vorzeichen wurde schon bei e/E ausgegeben
851                             bFirstExponentDigit = sal_False;
852                             if( nMaxExponentDigit>nExponentPos )
853                             // hier jetzt "uberz"ahlige Stellen ausgeben,
854                             // d.h. vom Format-String nicht erfasste Stellen
855                             {
856                                 for( short j=nMaxExponentDigit; j>nExponentPos; j-- )
857                                 {
858 #ifdef _with_sprintf
859                                     AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,j,bFoundFirstDigit ) );
860 #else
861                                     AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,j,dExponent,bFoundFirstDigit ) );
862 #endif
863                                 }
864                             }
865                         }
866                         // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ?
867                         if( nMaxExponentDigit<nExponentPos && c=='0' )
868                             AppendDigit( sReturnStrg,0 );       // Ja
869                         else
870 #ifdef _with_sprintf
871                             AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,nExponentPos,bFoundFirstDigit ) );
872 #else
873                             AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,nExponentPos,dExponent,bFoundFirstDigit ) );
874 #endif
875                         nExponentPos--;
876                     }
877                     break;
878                 case '.':
879                     if( bDigitPosNegative ) // #i13821: If no digits before .
880                     {
881                         bDigitPosNegative = false;
882                         nDigitPos = 0;
883                         cForce = '#';
884                         i-=2;
885                         break;
886                     }
887                     // gebe Komma aus
888                     StrAppendChar( sReturnStrg,cDecPoint );
889                     break;
890                 case '%':
891                     // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00
892                     ParseBack( sReturnStrg,sFormatStrg,i-1 );
893                     // gebe Prozent-Zeichen aus
894                     sReturnStrg.Insert('%');
895                     break;
896                 case 'e':
897                 case 'E':
898                     // muss Mantisse noch gerundet werden, bevor der Exponent angezeigt wird ?
899                     {
900                         // gibt es ueberhaupt eine Mantisse ?
901                         if( bFirstDigit )
902                         {
903                             // anscheinend nicht, d.h. ungueltiger Format String, z.B. E000.00
904                             // d.h. ignoriere diese e bzw. E Zeichen
905                             // ggf. einen Fehler (wie Visual Basic) ausgeben ?
906 
907                             // #i13821: VB 6 behaviour
908                             StrAppendChar( sReturnStrg,c );
909                             break;
910                         }
911 
912                         sal_Bool bOverflow = sal_False;
913 #ifdef _with_sprintf
914                         short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit );
915 #else
916                         short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit );
917 #endif
918                         if( nNextDigit>=5 )
919                             StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1,bOverflow );
920                         if( bOverflow )
921                         {
922                             // es wurde eine f"uhrende 9 gerundet, d.h.
923                             // verschiebe den Dezimal-Punkt um eine Stelle nach links
924                             LeftShiftDecimalPoint( sReturnStrg );
925                             // und l"osche die letzte Ziffer, diese wird
926                             // duch die f"uhrende 1 ersetzt:
927                             sReturnStrg.SetChar( sReturnStrg.Len()-1 , 0 );
928                             // der Exponent muss um 1 erh"oht werden,
929                             // da der Dezimalpunkt verschoben wurde
930                             dExponent += 1.0;
931                         }
932                         // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00
933                         ParseBack( sReturnStrg,sFormatStrg,i-1 );
934                     }
935                     // "andere Zustand des Scanners
936                     nState++;
937                     // gebe Exponent-Zeichen aus
938                     StrAppendChar( sReturnStrg,c );
939                     // i++; // MANIPULATION der Schleifen-Variable !
940                     c = sFormatStrg.GetChar( ++i );
941                     // und gebe Vorzeichen / Exponent aus
942                     if( c!=0 )
943                     {
944                         if( c=='-' )
945                         {
946                             // falls Exponent < 0 gebe - aus
947                             if( dExponent<0.0 )
948                                 StrAppendChar( sReturnStrg,'-' );
949                         }
950                         else if( c=='+' )
951                         {
952                             // gebe auf jeden Fall das Vorzeichen des Exponenten aus !
953                             if( dExponent<0.0 )
954                                 StrAppendChar( sReturnStrg,'-' );
955                             else
956                                 StrAppendChar( sReturnStrg,'+' );
957                         }
958                         //else
959                         //  ShowError( "operator e/E did not find + or -" );
960                     }
961                     //else
962                     //  ShowError( "operator e/E ended with 0" );
963                     break;
964                 case ',':
965                     // ACHTUNG: nur falls Zahl bisher ausgegeben wurde
966                     //          das Zeichen ausgeben
967                     ////--> Siehe Kommentar vom 11.7. in AnalyseFormatString()
968                     ////if( !bFirstDigit )
969                     ////    // gebe Tausender-Trennzeichen aus
970                     ////    StrAppendChar( sReturnStrg,cThousandSep );
971                     break;
972                 case ';':
973                     break;
974                 case '(':
975                 case ')':
976                     // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00
977                     ParseBack( sReturnStrg,sFormatStrg,i-1 );
978                     if( bIsNegative )
979                         StrAppendChar( sReturnStrg,c );
980                     break;
981                 case '$':
982                     // den String fuer die Waehrung dranhengen:
983                     sReturnStrg += sCurrencyStrg;
984                     break;
985                 case ' ':
986                 case '-':
987                 case '+':
988                     // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00
989                     ParseBack( sReturnStrg,sFormatStrg,i-1 );
990                     // gebe das jeweilige Zeichen direkt aus
991                     StrAppendChar( sReturnStrg,c );
992                     break;
993                 case '\\':
994                     // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00
995                     // falls Sonderzeichen am Ende oder mitten in
996                     // Format-String vorkommen
997                     ParseBack( sReturnStrg,sFormatStrg,i-1 );
998                     // Sonderzeichen gefunden, gebe N"ACHSTES
999                     // Zeichen direkt aus (falls es existiert)
1000                     // i++;
1001                     c = sFormatStrg.GetChar( ++i );
1002                     if( c!=0 )
1003                         StrAppendChar( sReturnStrg,c );
1004                     //else
1005                     //  ShowError( "operator \\ ended with 0" );
1006                     break;
1007                 case CREATE_1000SEP_CHAR:
1008                     // hier ignorieren, Aktion wurde schon in
1009                     // AnalyseFormatString durchgef"uhrt
1010                     break;
1011                 default:
1012                     // auch die Zeichen und Ziffern ausgeben (wie in Visual-Basic)
1013                     if( ( c>='a' && c<='z' ) ||
1014                         ( c>='A' && c<='Z' ) ||
1015                         ( c>='1' && c<='9' ) )
1016                         StrAppendChar( sReturnStrg,c );
1017                     // else
1018                         // ignorieren !
1019                     // ehemals: ShowError( "bad character in format-string" );
1020             }
1021         }
1022         // Format-String wurde vollst"andig gescanned,
1023         // muss die letzte Stelle nun gerundet werden ?
1024         // Dies hier ist jedoch NUR notwendig, falls das
1025         // Zahlenformat NICHT Scientific-Format ist !
1026         if( !bScientific )
1027         {
1028 #ifdef _with_sprintf
1029             short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit );
1030 #else
1031             short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit );
1032 #endif
1033             if( nNextDigit>=5 )
1034                 StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1 );
1035         }
1036         // und ganz zum Schluss:
1037         // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00#,
1038         // ABER nur Stellen nach dem Dezimal-Punkt k"onnen gel"oscht werden
1039         if( nNoOfDigitsRight>0 )
1040             ParseBack( sReturnStrg,sFormatStrg,sFormatStrg.Len()-1 );
1041     }
1042 }
1043 
BasicFormatNull(String sFormatStrg)1044 String SbxBasicFormater::BasicFormatNull( String sFormatStrg )
1045 {
1046     sal_Bool bNullFormatFound;
1047     String sNullFormatStrg = GetNullFormatString( sFormatStrg,bNullFormatFound );
1048 
1049     if( bNullFormatFound )
1050         return sNullFormatStrg;
1051     String aRetStr;
1052     aRetStr.AssignAscii( "null" );
1053     return aRetStr;
1054 }
1055 
BasicFormat(double dNumber,String sFormatStrg)1056 String SbxBasicFormater::BasicFormat( double dNumber, String sFormatStrg )
1057 {
1058     sal_Bool bPosFormatFound,bNegFormatFound,b0FormatFound;
1059 
1060     // analysiere Format-String auf vordefinierte Formate:
1061     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) )
1062         sFormatStrg.AssignAscii( GENERALNUMBER_FORMAT );
1063     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) )
1064         sFormatStrg = sCurrencyFormatStrg; // old: CURRENCY_FORMAT;
1065     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) )
1066         sFormatStrg.AssignAscii( FIXED_FORMAT );
1067     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) )
1068         sFormatStrg.AssignAscii( STANDARD_FORMAT );
1069     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) )
1070         sFormatStrg.AssignAscii( PERCENT_FORMAT );
1071     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) )
1072         sFormatStrg.AssignAscii( SCIENTIFIC_FORMAT );
1073     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) )
1074         return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ;
1075     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) )
1076         return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ;
1077     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) )
1078         return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ;
1079 
1080     // analysiere Format-String auf ';', d.h. Format-Strings f"ur
1081     // positive-, negative- und 0-Werte
1082     String sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound );
1083     String sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound );
1084     String s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound );
1085     //String sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound );
1086 
1087     String sReturnStrg;
1088     String sTempStrg;
1089 
1090     if( dNumber==0.0 )
1091     {
1092         sTempStrg = sFormatStrg;
1093         if( b0FormatFound )
1094         {
1095             // wurde ggf. Leer-String uebergeben ?
1096             if( s0FormatStrg.Len() == 0 && bPosFormatFound )
1097                 // --> Ja, dann verwende String fuer positive Werte
1098                 sTempStrg = sPosFormatStrg;
1099             else
1100                 sTempStrg = s0FormatStrg;
1101         }
1102         else if( bPosFormatFound )
1103         {
1104             // verwende String fuer positive Werte
1105             sTempStrg = sPosFormatStrg;
1106         }
1107         ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/sal_False );
1108     }
1109     else
1110     {
1111         if( dNumber<0.0 )
1112         {
1113             if( bNegFormatFound )
1114             {
1115                 // wurde ggf. Leer-String uebergeben ?
1116                 if( sNegFormatStrg.Len() == 0 && bPosFormatFound )
1117                 {
1118                     // --> Ja, dann verwende String fuer positive Werte
1119                     // und setzte Minus-Zeichen davor !
1120                     sTempStrg = String::CreateFromAscii("-");
1121                     sTempStrg += sPosFormatStrg;
1122                 }
1123                 else
1124                     sTempStrg = sNegFormatStrg;
1125            }
1126             else
1127                 sTempStrg = sFormatStrg;
1128             // falls KEIN Format-String speziell f"ur negative Werte angegeben
1129             // wurde, so soll das Vorzeichen ausgegeben werden
1130             ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ );
1131         }
1132         else // if( dNumber>0.0 )
1133         {
1134             ScanFormatString( dNumber,
1135                     (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg),
1136                     sReturnStrg,/*bCreateSign=*/sal_False );
1137         }
1138     }
1139     return sReturnStrg;
1140 }
1141 
isBasicFormat(String sFormatStrg)1142 sal_Bool SbxBasicFormater::isBasicFormat( String sFormatStrg )
1143 {
1144     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) )
1145         return sal_True;
1146     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) )
1147         return sal_True;
1148     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) )
1149         return sal_True;
1150     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) )
1151         return sal_True;
1152     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) )
1153         return sal_True;
1154     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) )
1155         return sal_True;
1156     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) )
1157         return sal_True;
1158     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) )
1159         return sal_True;
1160     if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) )
1161         return sal_True;
1162     return sal_False;
1163 }
1164 
1165