xref: /aoo42x/main/basic/source/sbx/sbxform.cxx (revision e1f63238)
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