update dev300-m57
[ooovba.git] / svtools / source / numbers / zforscan.cxx
blob44fe8a08a51065d349a83220dae5b315a2d673be
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: zforscan.cxx,v $
10 * $Revision: 1.49.140.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
33 #ifndef GCC
34 #endif
36 #include <stdlib.h>
37 #include <tools/debug.hxx>
38 #include <i18npool/mslangid.hxx>
39 #include <unotools/charclass.hxx>
40 #include <unotools/localedatawrapper.hxx>
41 #include <unotools/numberformatcodewrapper.hxx>
42 #include <rtl/instance.hxx>
44 #include <svtools/zforlist.hxx>
45 #include <svtools/zformat.hxx>
46 #include <unotools/digitgroupingiterator.hxx>
48 #define _ZFORSCAN_CXX
49 #include "zforscan.hxx"
50 #undef _ZFORSCAN_CXX
51 #include "nfsymbol.hxx"
52 using namespace svt;
54 const sal_Unicode cNonBreakingSpace = 0xA0;
56 namespace
58 struct ImplEnglishColors
60 const String* operator()()
62 static const String aEnglishColors[NF_MAX_DEFAULT_COLORS] =
64 String( RTL_CONSTASCII_USTRINGPARAM( "BLACK" ) ),
65 String( RTL_CONSTASCII_USTRINGPARAM( "BLUE" ) ),
66 String( RTL_CONSTASCII_USTRINGPARAM( "GREEN" ) ),
67 String( RTL_CONSTASCII_USTRINGPARAM( "CYAN" ) ),
68 String( RTL_CONSTASCII_USTRINGPARAM( "RED" ) ),
69 String( RTL_CONSTASCII_USTRINGPARAM( "MAGENTA" ) ),
70 String( RTL_CONSTASCII_USTRINGPARAM( "BROWN" ) ),
71 String( RTL_CONSTASCII_USTRINGPARAM( "GREY" ) ),
72 String( RTL_CONSTASCII_USTRINGPARAM( "YELLOW" ) ),
73 String( RTL_CONSTASCII_USTRINGPARAM( "WHITE" ) )
75 return &aEnglishColors[0];
79 struct theEnglishColors
80 : public rtl::StaticAggregate< const String, ImplEnglishColors> {};
84 ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP )
86 pFormatter = pFormatterP;
87 bConvertMode = FALSE;
88 //! All keywords MUST be UPPERCASE!
89 sKeyword[NF_KEY_E].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) ); // Exponent
90 sKeyword[NF_KEY_AMPM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AM/PM" ) ); // AM/PM
91 sKeyword[NF_KEY_AP].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "A/P" ) ); // AM/PM short
92 sKeyword[NF_KEY_MI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // Minute
93 sKeyword[NF_KEY_MMI].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // Minute 02
94 sKeyword[NF_KEY_S].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "S" ) ); // Second
95 sKeyword[NF_KEY_SS].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SS" ) ); // Second 02
96 sKeyword[NF_KEY_Q].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Q" ) ); // Quarter short 'Q'
97 sKeyword[NF_KEY_QQ].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "QQ" ) ); // Quarter long
98 sKeyword[NF_KEY_NN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NN" ) ); // Day of week short
99 sKeyword[NF_KEY_NNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNN" ) ); // Day of week long
100 sKeyword[NF_KEY_NNNN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NNNN" ) ); // Day of week long incl. separator
101 sKeyword[NF_KEY_WW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WW" ) ); // Week of year
102 sKeyword[NF_KEY_CCC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CCC" ) ); // Currency abbreviation
103 bKeywordsNeedInit = TRUE; // locale dependent keywords
104 bCompatCurNeedInit = TRUE; // locale dependent compatibility currency strings
106 StandardColor[0] = Color(COL_BLACK);
107 StandardColor[1] = Color(COL_LIGHTBLUE);
108 StandardColor[2] = Color(COL_LIGHTGREEN);
109 StandardColor[3] = Color(COL_LIGHTCYAN);
110 StandardColor[4] = Color(COL_LIGHTRED);
111 StandardColor[5] = Color(COL_LIGHTMAGENTA);
112 StandardColor[6] = Color(COL_BROWN);
113 StandardColor[7] = Color(COL_GRAY);
114 StandardColor[8] = Color(COL_YELLOW);
115 StandardColor[9] = Color(COL_WHITE);
117 pNullDate = new Date(30,12,1899);
118 nStandardPrec = 2;
120 sErrStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "###" ) );
121 Reset();
124 ImpSvNumberformatScan::~ImpSvNumberformatScan()
126 delete pNullDate;
127 Reset();
131 void ImpSvNumberformatScan::ChangeIntl()
133 bKeywordsNeedInit = TRUE;
134 bCompatCurNeedInit = TRUE;
135 // may be initialized by InitSpecialKeyword()
136 sKeyword[NF_KEY_TRUE].Erase();
137 sKeyword[NF_KEY_FALSE].Erase();
141 void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const
143 switch ( eIdx )
145 case NF_KEY_TRUE :
146 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] =
147 pFormatter->GetCharClass()->upper(
148 pFormatter->GetLocaleData()->getTrueWord() );
149 if ( !sKeyword[NF_KEY_TRUE].Len() )
151 DBG_ERRORFILE( "InitSpecialKeyword: TRUE_WORD?" );
152 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TRUE" ) );
154 break;
155 case NF_KEY_FALSE :
156 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] =
157 pFormatter->GetCharClass()->upper(
158 pFormatter->GetLocaleData()->getFalseWord() );
159 if ( !sKeyword[NF_KEY_FALSE].Len() )
161 DBG_ERRORFILE( "InitSpecialKeyword: FALSE_WORD?" );
162 ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "FALSE" ) );
164 break;
165 default:
166 DBG_ERRORFILE( "InitSpecialKeyword: unknown request" );
171 void ImpSvNumberformatScan::InitCompatCur() const
173 ImpSvNumberformatScan* pThis = (ImpSvNumberformatScan*)this;
174 // currency symbol for old style ("automatic") compatibility format codes
175 pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev );
176 // currency symbol upper case
177 pThis->sCurString = pFormatter->GetCharClass()->upper( sCurSymbol );
178 bCompatCurNeedInit = FALSE;
182 void ImpSvNumberformatScan::InitKeywords() const
184 if ( !bKeywordsNeedInit )
185 return ;
186 ((ImpSvNumberformatScan*)this)->SetDependentKeywords();
187 bKeywordsNeedInit = FALSE;
191 /** Extract the name of General, Standard, Whatever, ignoring leading modifiers
192 such as [NatNum1]. */
193 static String lcl_extractStandardGeneralName( const ::rtl::OUString & rCode )
195 String aStr;
196 const sal_Unicode* p = rCode.getStr();
197 const sal_Unicode* const pStop = p + rCode.getLength();
198 const sal_Unicode* pBeg = p; // name begins here
199 bool bMod = false;
200 bool bDone = false;
201 while (p < pStop && !bDone)
203 switch (*p)
205 case '[':
206 bMod = true;
207 break;
208 case ']':
209 if (bMod)
211 bMod = false;
212 pBeg = p+1;
214 // else: would be a locale data error, easily to be spotted in
215 // UI dialog
216 break;
217 case ';':
218 if (!bMod)
220 bDone = true;
221 --p; // put back, increment by one follows
223 break;
225 ++p;
226 if (bMod)
227 pBeg = p;
229 if (pBeg < p)
230 aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg);
231 return aStr;
235 void ImpSvNumberformatScan::SetDependentKeywords()
237 using namespace ::com::sun::star;
238 using namespace ::com::sun::star::uno;
240 const CharClass* pCharClass = pFormatter->GetCharClass();
241 const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData();
242 // #80023# be sure to generate keywords for the loaded Locale, not for the
243 // requested Locale, otherwise number format codes might not match
244 lang::Locale aLoadedLocale = pLocaleData->getLoadedLocale();
245 LanguageType eLang = MsLangId::convertLocaleToLanguage( aLoadedLocale );
246 NumberFormatCodeWrapper aNumberFormatCode( pFormatter->GetServiceManager(), aLoadedLocale );
248 i18n::NumberFormatCode aFormat = aNumberFormatCode.getFormatCode( NF_NUMBER_STANDARD );
249 sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code);
250 sKeyword[NF_KEY_GENERAL] = pCharClass->upper( sNameStandardFormat );
252 // preset new calendar keywords
253 sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAA" ) );
254 sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
255 sKeyword[NF_KEY_EC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "E" ) );
256 sKeyword[NF_KEY_EEC].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "EE" ) );
257 sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
258 sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
259 sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
260 sKeyword[NF_KEY_R].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "R" ) );
261 sKeyword[NF_KEY_RR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RR" ) );
263 // Thai T NatNum special. Other locale's small letter 't' results in upper
264 // case comparison not matching but length does in conversion mode. Ugly.
265 if (eLang == LANGUAGE_THAI)
266 sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T"));
267 else
268 sKeyword[NF_KEY_THAI_T].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "t"));
270 switch ( eLang )
272 case LANGUAGE_GERMAN:
273 case LANGUAGE_GERMAN_SWISS:
274 case LANGUAGE_GERMAN_AUSTRIAN:
275 case LANGUAGE_GERMAN_LUXEMBOURG:
276 case LANGUAGE_GERMAN_LIECHTENSTEIN:
278 //! all capital letters
279 sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) ); // month 1
280 sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) ); // month 01
281 sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) ); // month Jan
282 sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) ); // month Januar
283 sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );// month J
284 sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) ); // hour 2
285 sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) ); // hour 02
286 sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
287 sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
288 sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTT" ) );
289 sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TTTT" ) );
290 sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
291 sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
292 sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "LOGISCH" ) );
293 sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "FARBE" ) );
294 sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SCHWARZ" ) );
295 sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLAU" ) );
296 sKeyword[NF_KEY_GREEN] = UniString( "GR" "\xDC" "N", RTL_TEXTENCODING_ISO_8859_1 );
297 sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
298 sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "ROT" ) );
299 sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
300 sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BRAUN" ) );
301 sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GRAU" ) );
302 sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GELB" ) );
303 sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WEISS" ) );
305 break;
306 default:
308 // day
309 switch ( eLang )
311 case LANGUAGE_ITALIAN :
312 case LANGUAGE_ITALIAN_SWISS :
313 sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "G" ) );
314 sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GG" ) );
315 sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGG" ) );
316 sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GGGG" ) );
317 // must exchange the era code, same as Xcl
318 sKeyword[NF_KEY_G].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "X" ) );
319 sKeyword[NF_KEY_GG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XX" ) );
320 sKeyword[NF_KEY_GGG].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "XXX" ) );
321 break;
322 case LANGUAGE_FRENCH :
323 case LANGUAGE_FRENCH_BELGIAN :
324 case LANGUAGE_FRENCH_CANADIAN :
325 case LANGUAGE_FRENCH_SWISS :
326 case LANGUAGE_FRENCH_LUXEMBOURG :
327 case LANGUAGE_FRENCH_MONACO :
328 sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "J" ) );
329 sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
330 sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJ" ) );
331 sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
332 break;
333 case LANGUAGE_FINNISH :
334 sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "P" ) );
335 sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PP" ) );
336 sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPP" ) );
337 sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "PPPP" ) );
338 break;
339 default:
340 sKeyword[NF_KEY_D].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D" ) );
341 sKeyword[NF_KEY_DD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DD" ) );
342 sKeyword[NF_KEY_DDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDD" ) );
343 sKeyword[NF_KEY_DDDD].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DDDD" ) );
345 // month
346 switch ( eLang )
348 case LANGUAGE_FINNISH :
349 sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "K" ) );
350 sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KK" ) );
351 sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKK" ) );
352 sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKK" ) );
353 sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "KKKKK" ) );
354 break;
355 default:
356 sKeyword[NF_KEY_M].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "M" ) );
357 sKeyword[NF_KEY_MM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MM" ) );
358 sKeyword[NF_KEY_MMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMM" ) );
359 sKeyword[NF_KEY_MMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMM" ) );
360 sKeyword[NF_KEY_MMMMM].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MMMMM" ) );
362 // year
363 switch ( eLang )
365 case LANGUAGE_ITALIAN :
366 case LANGUAGE_ITALIAN_SWISS :
367 case LANGUAGE_FRENCH :
368 case LANGUAGE_FRENCH_BELGIAN :
369 case LANGUAGE_FRENCH_CANADIAN :
370 case LANGUAGE_FRENCH_SWISS :
371 case LANGUAGE_FRENCH_LUXEMBOURG :
372 case LANGUAGE_FRENCH_MONACO :
373 case LANGUAGE_PORTUGUESE :
374 case LANGUAGE_PORTUGUESE_BRAZILIAN :
375 case LANGUAGE_SPANISH_MODERN :
376 case LANGUAGE_SPANISH_DATED :
377 case LANGUAGE_SPANISH_MEXICAN :
378 case LANGUAGE_SPANISH_GUATEMALA :
379 case LANGUAGE_SPANISH_COSTARICA :
380 case LANGUAGE_SPANISH_PANAMA :
381 case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC :
382 case LANGUAGE_SPANISH_VENEZUELA :
383 case LANGUAGE_SPANISH_COLOMBIA :
384 case LANGUAGE_SPANISH_PERU :
385 case LANGUAGE_SPANISH_ARGENTINA :
386 case LANGUAGE_SPANISH_ECUADOR :
387 case LANGUAGE_SPANISH_CHILE :
388 case LANGUAGE_SPANISH_URUGUAY :
389 case LANGUAGE_SPANISH_PARAGUAY :
390 case LANGUAGE_SPANISH_BOLIVIA :
391 case LANGUAGE_SPANISH_EL_SALVADOR :
392 case LANGUAGE_SPANISH_HONDURAS :
393 case LANGUAGE_SPANISH_NICARAGUA :
394 case LANGUAGE_SPANISH_PUERTO_RICO :
395 sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AA" ) );
396 sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "AAAA" ) );
397 // must exchange the day of week name code, same as Xcl
398 sKeyword[NF_KEY_AAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOO" ) );
399 sKeyword[NF_KEY_AAAA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OOOO" ) );
400 break;
401 case LANGUAGE_DUTCH :
402 case LANGUAGE_DUTCH_BELGIAN :
403 sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJ" ) );
404 sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "JJJJ" ) );
405 break;
406 case LANGUAGE_FINNISH :
407 sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VV" ) );
408 sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "VVVV" ) );
409 break;
410 default:
411 sKeyword[NF_KEY_YY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YY" ) );
412 sKeyword[NF_KEY_YYYY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YYYY" ) );
414 // hour
415 switch ( eLang )
417 case LANGUAGE_DUTCH :
418 case LANGUAGE_DUTCH_BELGIAN :
419 sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "U" ) );
420 sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "UU" ) );
421 break;
422 case LANGUAGE_FINNISH :
423 case LANGUAGE_SWEDISH :
424 case LANGUAGE_SWEDISH_FINLAND :
425 case LANGUAGE_DANISH :
426 case LANGUAGE_NORWEGIAN :
427 case LANGUAGE_NORWEGIAN_BOKMAL :
428 case LANGUAGE_NORWEGIAN_NYNORSK :
429 sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "T" ) );
430 sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "TT" ) );
431 break;
432 default:
433 sKeyword[NF_KEY_H].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "H" ) );
434 sKeyword[NF_KEY_HH].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "HH" ) );
436 // boolean
437 sKeyword[NF_KEY_BOOLEAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BOOLEAN" ) );
438 // colours
439 sKeyword[NF_KEY_COLOR].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "COLOR" ) );
440 sKeyword[NF_KEY_BLACK].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLACK" ) );
441 sKeyword[NF_KEY_BLUE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BLUE" ) );
442 sKeyword[NF_KEY_GREEN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREEN" ) );
443 sKeyword[NF_KEY_CYAN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "CYAN" ) );
444 sKeyword[NF_KEY_RED].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "RED" ) );
445 sKeyword[NF_KEY_MAGENTA].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "MAGENTA" ) );
446 sKeyword[NF_KEY_BROWN].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "BROWN" ) );
447 sKeyword[NF_KEY_GREY].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "GREY" ) );
448 sKeyword[NF_KEY_YELLOW].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "YELLOW" ) );
449 sKeyword[NF_KEY_WHITE].AssignAscii( RTL_CONSTASCII_STRINGPARAM( "WHITE" ) );
451 break;
454 // boolean keyords
455 InitSpecialKeyword( NF_KEY_TRUE );
456 InitSpecialKeyword( NF_KEY_FALSE );
458 // compatibility currency strings
459 InitCompatCur();
463 void ImpSvNumberformatScan::ChangeNullDate(USHORT nDay, USHORT nMonth, USHORT nYear)
465 if ( pNullDate )
466 *pNullDate = Date(nDay, nMonth, nYear);
467 else
468 pNullDate = new Date(nDay, nMonth, nYear);
471 void ImpSvNumberformatScan::ChangeStandardPrec(short nPrec)
473 nStandardPrec = nPrec;
476 Color* ImpSvNumberformatScan::GetColor(String& sStr)
478 String sString = pFormatter->GetCharClass()->upper(sStr);
479 const String* pKeyword = GetKeywords();
480 size_t i = 0;
481 while (i < NF_MAX_DEFAULT_COLORS &&
482 sString != pKeyword[NF_KEY_FIRSTCOLOR+i] )
483 i++;
484 if ( i >= NF_MAX_DEFAULT_COLORS )
486 const String* pEnglishColors = theEnglishColors::get();
487 size_t j = 0;
488 while ( j < NF_MAX_DEFAULT_COLORS &&
489 sString != pEnglishColors[j] )
490 ++j;
491 if ( j < NF_MAX_DEFAULT_COLORS )
492 i = j;
494 if (i >= NF_MAX_DEFAULT_COLORS)
496 const String& rColorWord = pKeyword[NF_KEY_COLOR];
497 xub_StrLen nPos = sString.Match(rColorWord);
498 if (nPos > 0)
500 sStr.Erase(0, nPos);
501 sStr.EraseLeadingChars();
502 sStr.EraseTrailingChars();
503 if (bConvertMode)
505 pFormatter->ChangeIntl(eNewLnge);
506 sStr.Insert( GetKeywords()[NF_KEY_COLOR], 0 ); // Color -> FARBE
507 pFormatter->ChangeIntl(eTmpLnge);
509 else
510 sStr.Insert(rColorWord,0);
511 sString.Erase(0, nPos);
512 sString.EraseLeadingChars();
513 sString.EraseTrailingChars();
515 if ( CharClass::isAsciiNumeric( sString ) )
517 long nIndex = sString.ToInt32();
518 if (nIndex > 0 && nIndex <= 64)
519 return pFormatter->GetUserDefColor((USHORT)nIndex-1);
520 else
521 return NULL;
523 else
524 return NULL;
526 else
527 return NULL;
529 else
531 sStr.Erase();
532 if (bConvertMode)
534 pFormatter->ChangeIntl(eNewLnge);
535 sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot
536 pFormatter->ChangeIntl(eTmpLnge);
538 else
539 sStr = pKeyword[NF_KEY_FIRSTCOLOR+i];
541 return &(StandardColor[i]);
546 short ImpSvNumberformatScan::GetKeyWord( const String& sSymbol, xub_StrLen nPos )
548 String sString = pFormatter->GetCharClass()->toUpper( sSymbol, nPos, sSymbol.Len() - nPos );
549 const String* pKeyword = GetKeywords();
550 // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
551 if ( sString.Search( pKeyword[NF_KEY_GENERAL] ) == 0 )
552 return NF_KEY_GENERAL;
553 //! MUST be a reverse search to find longer strings first
554 short i = NF_KEYWORD_ENTRIES_COUNT-1;
555 BOOL bFound = FALSE;
556 for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
558 bFound = sString.Search(pKeyword[i]) == 0;
559 if ( bFound )
561 break;
564 // new keywords take precedence over old keywords
565 if ( !bFound )
566 { // skip the gap of colors et al between new and old keywords and search on
567 i = NF_KEY_LASTKEYWORD;
568 while ( i > 0 && sString.Search(pKeyword[i]) != 0 )
569 i--;
570 if ( i > NF_KEY_LASTOLDKEYWORD && sString != pKeyword[i] )
571 { // found something, but maybe it's something else?
572 // e.g. new NNN is found in NNNN, for NNNN we must search on
573 short j = i - 1;
574 while ( j > 0 && sString.Search(pKeyword[j]) != 0 )
575 j--;
576 if ( j && pKeyword[j].Len() > pKeyword[i].Len() )
577 return j;
580 // The Thai T NatNum modifier during Xcl import.
581 if (i == 0 && bConvertMode && sString.GetChar(0) == 'T' && eTmpLnge ==
582 LANGUAGE_ENGLISH_US && MsLangId::getRealLanguage( eNewLnge) ==
583 LANGUAGE_THAI)
584 i = NF_KEY_THAI_T;
585 return i; // 0 => not found
588 //---------------------------------------------------------------------------
589 // Next_Symbol
590 //---------------------------------------------------------------------------
591 // Zerlegt die Eingabe in Symbole fuer die weitere
592 // Verarbeitung (Turing-Maschine).
593 //---------------------------------------------------------------------------
594 // Ausgangs Zustand = SsStart
595 //---------------+-------------------+-----------------------+---------------
596 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
597 //---------------+-------------------+-----------------------+---------------
598 // SsStart | Buchstabe | Symbol=Zeichen | SsGetWord
599 // | " | Typ = String | SsGetString
600 // | \ | Typ = String | SsGetChar
601 // | * | Typ = Star | SsGetStar
602 // | _ | Typ = Blank | SsGetBlank
603 // | @ # 0 ? / . , % [ | Symbol = Zeichen; |
604 // | ] ' Blank | Typ = Steuerzeichen | SsStop
605 // | $ - + ( ) : | Typ = String; |
606 // | | | Typ = Comment | SsStop
607 // | Sonst | Symbol = Zeichen | SsStop
608 //---------------|-------------------+-----------------------+---------------
609 // SsGetChar | Sonst | Symbol=Zeichen | SsStop
610 //---------------+-------------------+-----------------------+---------------
611 // GetString | " | | SsStop
612 // | Sonst | Symbol+=Zeichen | GetString
613 //---------------+-------------------+-----------------------+---------------
614 // SsGetWord | Buchstabe | Symbol += Zeichen |
615 // | + - (E+ E-)| Symbol += Zeichen | SsStop
616 // | / (AM/PM)| Symbol += Zeichen |
617 // | Sonst | Pos--, if Key Typ=Word| SsStop
618 //---------------+-------------------+-----------------------+---------------
619 // SsGetStar | Sonst | Symbol+=Zeichen | SsStop
620 // | | markiere Sonderfall * |
621 //---------------+-------------------+-----------------------+---------------
622 // SsGetBlank | Sonst | Symbol+=Zeichen | SsStop
623 // | | markiere Sonderfall _ |
624 //---------------+-------------------+-----------------------+---------------
625 // Wurde im State SsGetWord ein Schluesselwort erkannt (auch als
626 // Anfangsteilwort des Symbols)
627 // so werden die restlichen Buchstaben zurueckgeschrieben !!
629 enum ScanState
631 SsStop = 0,
632 SsStart = 1,
633 SsGetChar = 2,
634 SsGetString = 3,
635 SsGetWord = 4,
636 SsGetStar = 5,
637 SsGetBlank = 6
640 short ImpSvNumberformatScan::Next_Symbol( const String& rStr,
641 xub_StrLen& nPos, String& sSymbol )
643 if ( bKeywordsNeedInit )
644 InitKeywords();
645 const CharClass* pChrCls = pFormatter->GetCharClass();
646 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
647 const xub_StrLen nStart = nPos;
648 short eType = 0;
649 ScanState eState = SsStart;
650 sSymbol.Erase();
651 while ( nPos < rStr.Len() && eState != SsStop )
653 sal_Unicode cToken = rStr.GetChar( nPos++ );
654 switch (eState)
656 case SsStart:
658 // Fetch any currency longer than one character and don't get
659 // confused later on by "E/" or other combinations of letters
660 // and meaningful symbols. Necessary for old automatic currency.
661 // #96158# But don't do it if we're starting a "[...]" section,
662 // for example a "[$...]" new currency symbol to not parse away
663 // "$U" (symbol) of "[$UYU]" (abbreviation).
664 if ( nCurrPos != STRING_NOTFOUND && sCurString.Len() > 1 &&
665 nPos-1 + sCurString.Len() <= rStr.Len() &&
666 !(nPos > 1 && rStr.GetChar( nPos-2 ) == '[') )
668 String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
669 pChrCls->toUpper( aTest );
670 if ( aTest == sCurString )
672 sSymbol = rStr.Copy( --nPos, sCurString.Len() );
673 nPos = nPos + sSymbol.Len();
674 eState = SsStop;
675 eType = NF_SYMBOLTYPE_STRING;
676 return eType;
679 switch (cToken)
681 case '#':
682 case '0':
683 case '?':
684 case '%':
685 case '@':
686 case '[':
687 case ']':
688 case ',':
689 case '.':
690 case '/':
691 case '\'':
692 case ' ':
693 case ':':
694 case '-':
696 eType = NF_SYMBOLTYPE_DEL;
697 sSymbol += cToken;
698 eState = SsStop;
700 break;
701 case '*':
703 eType = NF_SYMBOLTYPE_STAR;
704 sSymbol += cToken;
705 eState = SsGetStar;
707 break;
708 case '_':
710 eType = NF_SYMBOLTYPE_BLANK;
711 sSymbol += cToken;
712 eState = SsGetBlank;
714 break;
715 #if NF_COMMENT_IN_FORMATSTRING
716 case '{':
717 eType = NF_SYMBOLTYPE_COMMENT;
718 eState = SsStop;
719 sSymbol.Append( rStr.GetBuffer() + (nPos-1), rStr.Len() - (nPos-1) );
720 nPos = rStr.Len();
721 break;
722 #endif
723 case '"':
724 eType = NF_SYMBOLTYPE_STRING;
725 eState = SsGetString;
726 sSymbol += cToken;
727 break;
728 case '\\':
729 eType = NF_SYMBOLTYPE_STRING;
730 eState = SsGetChar;
731 sSymbol += cToken;
732 break;
733 case '$':
734 case '+':
735 case '(':
736 case ')':
737 eType = NF_SYMBOLTYPE_STRING;
738 eState = SsStop;
739 sSymbol += cToken;
740 break;
741 default :
743 if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
744 StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
745 StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
746 StringEqualsChar( pLoc->getTimeSep(), cToken) ||
747 StringEqualsChar( pLoc->getTime100SecSep(), cToken))
749 // Another separator than pre-known ASCII
750 eType = NF_SYMBOLTYPE_DEL;
751 sSymbol += cToken;
752 eState = SsStop;
754 else if ( pChrCls->isLetter( rStr, nPos-1 ) )
756 short nTmpType = GetKeyWord( rStr, nPos-1 );
757 if ( nTmpType )
759 BOOL bCurrency = FALSE;
760 // "Automatic" currency may start with keyword,
761 // like "R" (Rand) and 'R' (era)
762 if ( nCurrPos != STRING_NOTFOUND &&
763 nPos-1 + sCurString.Len() <= rStr.Len() &&
764 sCurString.Search( sKeyword[nTmpType] ) == 0 )
766 String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
767 pChrCls->toUpper( aTest );
768 if ( aTest == sCurString )
769 bCurrency = TRUE;
771 if ( bCurrency )
773 eState = SsGetWord;
774 sSymbol += cToken;
776 else
778 eType = nTmpType;
779 xub_StrLen nLen = sKeyword[eType].Len();
780 sSymbol = rStr.Copy( nPos-1, nLen );
781 if ( eType == NF_KEY_E || IsAmbiguousE( eType ) )
783 sal_Unicode cNext = rStr.GetChar(nPos);
784 switch ( cNext )
786 case '+' :
787 case '-' : // E+ E- combine to one symbol
788 sSymbol += cNext;
789 eType = NF_KEY_E;
790 nPos++;
791 break;
792 case '0' :
793 case '#' : // scientific E without sign
794 eType = NF_KEY_E;
795 break;
798 nPos--;
799 nPos = nPos + nLen;
800 eState = SsStop;
803 else
805 eState = SsGetWord;
806 sSymbol += cToken;
809 else
811 eType = NF_SYMBOLTYPE_STRING;
812 eState = SsStop;
813 sSymbol += cToken;
816 break;
819 break;
820 case SsGetChar:
822 sSymbol += cToken;
823 eState = SsStop;
825 break;
826 case SsGetString:
828 if (cToken == '"')
829 eState = SsStop;
830 sSymbol += cToken;
832 break;
833 case SsGetWord:
835 if ( pChrCls->isLetter( rStr, nPos-1 ) )
837 short nTmpType = GetKeyWord( rStr, nPos-1 );
838 if ( nTmpType )
839 { // beginning of keyword, stop scan and put back
840 eType = NF_SYMBOLTYPE_STRING;
841 eState = SsStop;
842 nPos--;
844 else
845 sSymbol += cToken;
847 else
849 BOOL bDontStop = FALSE;
850 switch (cToken)
852 case '/': // AM/PM, A/P
854 sal_Unicode cNext = rStr.GetChar(nPos);
855 if ( cNext == 'P' || cNext == 'p' )
857 xub_StrLen nLen = sSymbol.Len();
858 if ( 1 <= nLen
859 && (sSymbol.GetChar(0) == 'A' || sSymbol.GetChar(0) == 'a')
860 && (nLen == 1 || (nLen == 2
861 && (sSymbol.GetChar(1) == 'M' || sSymbol.GetChar(1) == 'm')
862 && (rStr.GetChar(nPos+1) == 'M' || rStr.GetChar(nPos+1) == 'm'))) )
864 sSymbol += cToken;
865 bDontStop = TRUE;
869 break;
871 // anything not recognized will stop the scan
872 if ( eState != SsStop && !bDontStop )
874 eState = SsStop;
875 nPos--;
876 eType = NF_SYMBOLTYPE_STRING;
880 break;
881 case SsGetStar:
883 eState = SsStop;
884 sSymbol += cToken;
885 nRepPos = (nPos - nStart) - 1; // everytime > 0!!
887 break;
888 case SsGetBlank:
890 eState = SsStop;
891 sSymbol += cToken;
893 break;
894 default:
895 break;
896 } // of switch
897 } // of while
898 if (eState == SsGetWord)
899 eType = NF_SYMBOLTYPE_STRING;
900 return eType;
903 xub_StrLen ImpSvNumberformatScan::Symbol_Division(const String& rString)
905 nCurrPos = STRING_NOTFOUND;
906 // Ist Waehrung im Spiel?
907 String sString = pFormatter->GetCharClass()->upper(rString);
908 xub_StrLen nCPos = 0;
909 while (nCPos != STRING_NOTFOUND)
911 nCPos = sString.Search(GetCurString(),nCPos);
912 if (nCPos != STRING_NOTFOUND)
914 // in Quotes?
915 xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
916 if ( nQ == STRING_NOTFOUND )
918 sal_Unicode c;
919 if ( nCPos == 0 ||
920 ((c = sString.GetChar(xub_StrLen(nCPos-1))) != '"'
921 && c != '\\') ) // dm kann durch "dm
922 { // \d geschuetzt werden
923 nCurrPos = nCPos;
924 nCPos = STRING_NOTFOUND; // Abbruch
926 else
927 nCPos++; // weitersuchen
929 else
930 nCPos = nQ + 1; // weitersuchen
933 nAnzStrings = 0;
934 BOOL bStar = FALSE; // wird bei '*'Detektion gesetzt
935 Reset();
937 xub_StrLen nPos = 0;
938 const xub_StrLen nLen = rString.Len();
939 while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
941 nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
942 if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
943 { // Ueberwachung des '*'
944 if (bStar)
945 return nPos; // Fehler: doppelter '*'
946 else
947 bStar = TRUE;
949 nAnzStrings++;
952 return 0; // 0 => ok
955 void ImpSvNumberformatScan::SkipStrings(USHORT& i, xub_StrLen& nPos)
957 while (i < nAnzStrings && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING
958 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK
959 || nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
961 nPos = nPos + sStrArray[i].Len();
962 i++;
967 USHORT ImpSvNumberformatScan::PreviousKeyword(USHORT i)
969 short res = 0;
970 if (i > 0 && i < nAnzStrings)
972 i--;
973 while (i > 0 && nTypeArray[i] <= 0)
974 i--;
975 if (nTypeArray[i] > 0)
976 res = nTypeArray[i];
978 return res;
981 USHORT ImpSvNumberformatScan::NextKeyword(USHORT i)
983 short res = 0;
984 if (i < nAnzStrings-1)
986 i++;
987 while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
988 i++;
989 if (nTypeArray[i] > 0)
990 res = nTypeArray[i];
992 return res;
995 short ImpSvNumberformatScan::PreviousType( USHORT i )
997 if ( i > 0 && i < nAnzStrings )
1001 i--;
1002 } while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
1003 return nTypeArray[i];
1005 return 0;
1008 sal_Unicode ImpSvNumberformatScan::PreviousChar(USHORT i)
1010 sal_Unicode res = ' ';
1011 if (i > 0 && i < nAnzStrings)
1013 i--;
1014 while (i > 0 && ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1015 || nTypeArray[i] == NF_SYMBOLTYPE_STRING
1016 || nTypeArray[i] == NF_SYMBOLTYPE_STAR
1017 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK ) )
1018 i--;
1019 if (sStrArray[i].Len() > 0)
1020 res = sStrArray[i].GetChar(xub_StrLen(sStrArray[i].Len()-1));
1022 return res;
1025 sal_Unicode ImpSvNumberformatScan::NextChar(USHORT i)
1027 sal_Unicode res = ' ';
1028 if (i < nAnzStrings-1)
1030 i++;
1031 while (i < nAnzStrings-1 &&
1032 ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1033 || nTypeArray[i] == NF_SYMBOLTYPE_STRING
1034 || nTypeArray[i] == NF_SYMBOLTYPE_STAR
1035 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
1036 i++;
1037 if (sStrArray[i].Len() > 0)
1038 res = sStrArray[i].GetChar(0);
1040 return res;
1043 BOOL ImpSvNumberformatScan::IsLastBlankBeforeFrac(USHORT i)
1045 BOOL res = TRUE;
1046 if (i < nAnzStrings-1)
1048 BOOL bStop = FALSE;
1049 i++;
1050 while (i < nAnzStrings-1 && !bStop)
1052 i++;
1053 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1054 sStrArray[i].GetChar(0) == '/')
1055 bStop = TRUE;
1056 else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1057 sStrArray[i].GetChar(0) == ' ')
1058 res = FALSE;
1060 if (!bStop) // kein '/'
1061 res = FALSE;
1063 else
1064 res = FALSE; // kein '/' mehr
1066 return res;
1069 void ImpSvNumberformatScan::Reset()
1071 nAnzStrings = 0;
1072 nAnzResStrings = 0;
1073 #if 0
1074 // ER 20.06.97 14:05 nicht noetig, wenn nAnzStrings beachtet wird
1075 for (size_t i = 0; i < NF_MAX_FORMAT_SYMBOLS; i++)
1077 sStrArray[i].Erase();
1078 nTypeArray[i] = 0;
1080 #endif
1081 eScannedType = NUMBERFORMAT_UNDEFINED;
1082 nRepPos = 0;
1083 bExp = FALSE;
1084 bThousand = FALSE;
1085 nThousand = 0;
1086 bDecSep = FALSE;
1087 nDecPos = -1;
1088 nExpPos = (USHORT) -1;
1089 nBlankPos = (USHORT) -1;
1090 nCntPre = 0;
1091 nCntPost = 0;
1092 nCntExp = 0;
1093 bFrac = FALSE;
1094 bBlank = FALSE;
1095 nNatNumModifier = 0;
1099 BOOL ImpSvNumberformatScan::Is100SecZero( USHORT i, BOOL bHadDecSep )
1101 USHORT nIndexPre = PreviousKeyword( i );
1102 return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS)
1103 && (bHadDecSep // S, SS ','
1104 || (i>0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
1105 // SS"any"00 take "any" as a valid decimal separator
1109 xub_StrLen ImpSvNumberformatScan::ScanType(const String&)
1111 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1113 xub_StrLen nPos = 0;
1114 USHORT i = 0;
1115 short eNewType;
1116 BOOL bMatchBracket = FALSE;
1117 bool bHaveGeneral = false; // if General/Standard encountered
1119 SkipStrings(i, nPos);
1120 while (i < nAnzStrings)
1122 if (nTypeArray[i] > 0)
1123 { // keyword
1124 switch (nTypeArray[i])
1126 case NF_KEY_E: // E
1127 eNewType = NUMBERFORMAT_SCIENTIFIC;
1128 break;
1129 case NF_KEY_AMPM: // AM,A,PM,P
1130 case NF_KEY_AP:
1131 case NF_KEY_H: // H
1132 case NF_KEY_HH: // HH
1133 case NF_KEY_S: // S
1134 case NF_KEY_SS: // SS
1135 eNewType = NUMBERFORMAT_TIME;
1136 break;
1137 case NF_KEY_M: // M
1138 case NF_KEY_MM: // MM
1139 { // minute or month
1140 USHORT nIndexPre = PreviousKeyword(i);
1141 USHORT nIndexNex = NextKeyword(i);
1142 sal_Unicode cChar = PreviousChar(i);
1143 if (nIndexPre == NF_KEY_H || // H
1144 nIndexPre == NF_KEY_HH || // HH
1145 nIndexNex == NF_KEY_S || // S
1146 nIndexNex == NF_KEY_SS || // SS
1147 cChar == '[' ) // [M
1149 eNewType = NUMBERFORMAT_TIME;
1150 nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5
1152 else
1153 eNewType = NUMBERFORMAT_DATE;
1155 break;
1156 case NF_KEY_MMM: // MMM
1157 case NF_KEY_MMMM: // MMMM
1158 case NF_KEY_MMMMM: // MMMMM
1159 case NF_KEY_Q: // Q
1160 case NF_KEY_QQ: // QQ
1161 case NF_KEY_D: // D
1162 case NF_KEY_DD: // DD
1163 case NF_KEY_DDD: // DDD
1164 case NF_KEY_DDDD: // DDDD
1165 case NF_KEY_YY: // YY
1166 case NF_KEY_YYYY: // YYYY
1167 case NF_KEY_NN: // NN
1168 case NF_KEY_NNN: // NNN
1169 case NF_KEY_NNNN: // NNNN
1170 case NF_KEY_WW : // WW
1171 case NF_KEY_AAA : // AAA
1172 case NF_KEY_AAAA : // AAAA
1173 case NF_KEY_EC : // E
1174 case NF_KEY_EEC : // EE
1175 case NF_KEY_G : // G
1176 case NF_KEY_GG : // GG
1177 case NF_KEY_GGG : // GGG
1178 case NF_KEY_R : // R
1179 case NF_KEY_RR : // RR
1180 eNewType = NUMBERFORMAT_DATE;
1181 break;
1182 case NF_KEY_CCC: // CCC
1183 eNewType = NUMBERFORMAT_CURRENCY;
1184 break;
1185 case NF_KEY_GENERAL: // Standard
1186 eNewType = NUMBERFORMAT_NUMBER;
1187 bHaveGeneral = true;
1188 break;
1189 default:
1190 eNewType = NUMBERFORMAT_UNDEFINED;
1191 break;
1194 else
1195 { // control character
1196 switch ( sStrArray[i].GetChar(0) )
1198 case '#':
1199 case '?':
1200 eNewType = NUMBERFORMAT_NUMBER;
1201 break;
1202 case '0':
1204 if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
1206 if ( Is100SecZero( i, bDecSep ) )
1208 bDecSep = TRUE; // subsequent 0's
1209 eNewType = NUMBERFORMAT_TIME;
1211 else
1212 return nPos; // Error
1214 else
1215 eNewType = NUMBERFORMAT_NUMBER;
1217 break;
1218 case '%':
1219 eNewType = NUMBERFORMAT_PERCENT;
1220 break;
1221 case '/':
1222 eNewType = NUMBERFORMAT_FRACTION;
1223 break;
1224 case '[':
1226 if ( i < nAnzStrings-1 &&
1227 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1228 sStrArray[i+1].GetChar(0) == '$' )
1229 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1230 eNewType = NUMBERFORMAT_CURRENCY;
1231 bMatchBracket = TRUE;
1233 else if ( i < nAnzStrings-1 &&
1234 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1235 sStrArray[i+1].GetChar(0) == '~' )
1236 { // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1237 eNewType = NUMBERFORMAT_DATE;
1238 bMatchBracket = TRUE;
1240 else
1242 USHORT nIndexNex = NextKeyword(i);
1243 if (nIndexNex == NF_KEY_H || // H
1244 nIndexNex == NF_KEY_HH || // HH
1245 nIndexNex == NF_KEY_M || // M
1246 nIndexNex == NF_KEY_MM || // MM
1247 nIndexNex == NF_KEY_S || // S
1248 nIndexNex == NF_KEY_SS ) // SS
1249 eNewType = NUMBERFORMAT_TIME;
1250 else
1251 return nPos; // Error
1254 break;
1255 case '@':
1256 eNewType = NUMBERFORMAT_TEXT;
1257 break;
1258 default:
1259 if ( sStrArray[i] == pLoc->getTime100SecSep() )
1260 bDecSep = TRUE; // for SS,0
1261 eNewType = NUMBERFORMAT_UNDEFINED;
1262 break;
1265 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1266 eScannedType = eNewType;
1267 else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
1268 eScannedType = NUMBERFORMAT_TEXT; // Text bleibt immer Text
1269 else if (eNewType == NUMBERFORMAT_UNDEFINED)
1270 { // bleibt wie bisher
1272 else if (eScannedType != eNewType)
1274 switch (eScannedType)
1276 case NUMBERFORMAT_DATE:
1278 switch (eNewType)
1280 case NUMBERFORMAT_TIME:
1281 eScannedType = NUMBERFORMAT_DATETIME;
1282 break;
1283 case NUMBERFORMAT_FRACTION: // DD/MM
1284 break;
1285 default:
1287 if (nCurrPos != STRING_NOTFOUND)
1288 eScannedType = NUMBERFORMAT_UNDEFINED;
1289 else if ( sStrArray[i] != pFormatter->GetDateSep() )
1290 return nPos;
1294 break;
1295 case NUMBERFORMAT_TIME:
1297 switch (eNewType)
1299 case NUMBERFORMAT_DATE:
1300 eScannedType = NUMBERFORMAT_DATETIME;
1301 break;
1302 case NUMBERFORMAT_FRACTION: // MM/SS
1303 break;
1304 default:
1306 if (nCurrPos != STRING_NOTFOUND)
1307 eScannedType = NUMBERFORMAT_UNDEFINED;
1308 else if ( sStrArray[i] != pLoc->getTimeSep() )
1309 return nPos;
1313 break;
1314 case NUMBERFORMAT_DATETIME:
1316 switch (eNewType)
1318 case NUMBERFORMAT_TIME:
1319 case NUMBERFORMAT_DATE:
1320 break;
1321 case NUMBERFORMAT_FRACTION: // DD/MM
1322 break;
1323 default:
1325 if (nCurrPos != STRING_NOTFOUND)
1326 eScannedType = NUMBERFORMAT_UNDEFINED;
1327 else if ( sStrArray[i] != pFormatter->GetDateSep()
1328 && sStrArray[i] != pLoc->getTimeSep() )
1329 return nPos;
1333 break;
1334 case NUMBERFORMAT_PERCENT:
1336 switch (eNewType)
1338 case NUMBERFORMAT_NUMBER: // nur Zahl nach Prozent
1339 break;
1340 default:
1341 return nPos;
1344 break;
1345 case NUMBERFORMAT_SCIENTIFIC:
1347 switch (eNewType)
1349 case NUMBERFORMAT_NUMBER: // nur Zahl nach E
1350 break;
1351 default:
1352 return nPos;
1355 break;
1356 case NUMBERFORMAT_NUMBER:
1358 switch (eNewType)
1360 case NUMBERFORMAT_SCIENTIFIC:
1361 case NUMBERFORMAT_PERCENT:
1362 case NUMBERFORMAT_FRACTION:
1363 case NUMBERFORMAT_CURRENCY:
1364 eScannedType = eNewType;
1365 break;
1366 default:
1367 if (nCurrPos != STRING_NOTFOUND)
1368 eScannedType = NUMBERFORMAT_UNDEFINED;
1369 else
1370 return nPos;
1373 break;
1374 case NUMBERFORMAT_FRACTION:
1376 switch (eNewType)
1378 case NUMBERFORMAT_NUMBER: // nur Zahl nach Bruch
1379 break;
1380 default:
1381 return nPos;
1384 break;
1385 default:
1386 break;
1389 nPos = nPos + sStrArray[i].Len(); // Korrekturposition
1390 i++;
1391 if ( bMatchBracket )
1392 { // no type detection inside of matching brackets if [$...], [~...]
1393 while ( bMatchBracket && i < nAnzStrings )
1395 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
1396 && sStrArray[i].GetChar(0) == ']' )
1397 bMatchBracket = FALSE;
1398 else
1399 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1400 nPos = nPos + sStrArray[i].Len();
1401 i++;
1403 if ( bMatchBracket )
1404 return nPos; // missing closing bracket at end of code
1406 SkipStrings(i, nPos);
1409 if ((eScannedType == NUMBERFORMAT_NUMBER || eScannedType == NUMBERFORMAT_UNDEFINED)
1410 && nCurrPos != STRING_NOTFOUND && !bHaveGeneral)
1411 eScannedType = NUMBERFORMAT_CURRENCY; // old "automatic" currency
1412 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1413 eScannedType = NUMBERFORMAT_DEFINED;
1414 return 0; // Alles ok
1418 bool ImpSvNumberformatScan::InsertSymbol( USHORT & nPos, svt::NfSymbolType eType, const String& rStr )
1420 if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
1421 return false;
1422 ++nAnzResStrings;
1423 if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
1424 --nPos; // reuse position
1425 else
1427 ++nAnzStrings;
1428 for (size_t i = nAnzStrings; i > nPos; --i)
1430 nTypeArray[i] = nTypeArray[i-1];
1431 sStrArray[i] = sStrArray[i-1];
1434 nTypeArray[nPos] = static_cast<short>(eType);
1435 sStrArray[nPos] = rStr;
1436 return true;
1440 int ImpSvNumberformatScan::FinalScanGetCalendar( xub_StrLen& nPos, USHORT& i,
1441 USHORT& rAnzResStrings )
1443 if ( sStrArray[i].GetChar(0) == '[' &&
1444 i < nAnzStrings-1 &&
1445 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1446 sStrArray[i+1].GetChar(0) == '~' )
1447 { // [~calendarID]
1448 // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1449 nPos = nPos + sStrArray[i].Len(); // [
1450 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1451 nPos = nPos + sStrArray[++i].Len(); // ~
1452 sStrArray[i-1] += sStrArray[i]; // [~
1453 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1454 rAnzResStrings--;
1455 if ( ++i >= nAnzStrings )
1456 return -1; // error
1457 nPos = nPos + sStrArray[i].Len(); // calendarID
1458 String& rStr = sStrArray[i];
1459 nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert
1460 i++;
1461 while ( i < nAnzStrings &&
1462 sStrArray[i].GetChar(0) != ']' )
1464 nPos = nPos + sStrArray[i].Len();
1465 rStr += sStrArray[i];
1466 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1467 rAnzResStrings--;
1468 i++;
1470 if ( rStr.Len() && i < nAnzStrings &&
1471 sStrArray[i].GetChar(0) == ']' )
1473 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1474 nPos = nPos + sStrArray[i].Len();
1475 i++;
1477 else
1478 return -1; // error
1479 return 1;
1481 return 0;
1484 xub_StrLen ImpSvNumberformatScan::FinalScan( String& rString, String& rComment )
1486 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1488 // save values for convert mode
1489 String sOldDecSep = pFormatter->GetNumDecimalSep();
1490 String sOldThousandSep = pFormatter->GetNumThousandSep();
1491 String sOldDateSep = pFormatter->GetDateSep();
1492 String sOldTimeSep = pLoc->getTimeSep();
1493 String sOldTime100SecSep= pLoc->getTime100SecSep();
1494 String sOldCurSymbol = GetCurSymbol();
1495 String sOldCurString = GetCurString();
1496 sal_Unicode cOldKeyH = sKeyword[NF_KEY_H].GetChar(0);
1497 sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI].GetChar(0);
1498 sal_Unicode cOldKeyS = sKeyword[NF_KEY_S].GetChar(0);
1500 // If the group separator is a Non-Breaking Space (French) continue with a
1501 // normal space instead so queries on space work correctly.
1502 // The format string is adjusted to allow both.
1503 // For output of the format code string the LocaleData characters are used.
1504 if ( sOldThousandSep.GetChar(0) == cNonBreakingSpace && sOldThousandSep.Len() == 1 )
1505 sOldThousandSep = ' ';
1507 // change locale data et al
1508 if (bConvertMode)
1510 pFormatter->ChangeIntl(eNewLnge);
1511 //! pointer may have changed
1512 pLoc = pFormatter->GetLocaleData();
1513 //! init new keywords
1514 InitKeywords();
1516 const CharClass* pChrCls = pFormatter->GetCharClass();
1518 xub_StrLen nPos = 0; // error correction position
1519 USHORT i = 0; // symbol loop counter
1520 USHORT nCounter = 0; // counts digits
1521 nAnzResStrings = nAnzStrings; // counts remaining symbols
1522 bDecSep = FALSE; // reset in case already used in TypeCheck
1523 bool bThaiT = false; // Thai T NatNum modifier present
1525 switch (eScannedType)
1527 case NUMBERFORMAT_TEXT:
1528 case NUMBERFORMAT_DEFINED:
1530 while (i < nAnzStrings)
1532 switch (nTypeArray[i])
1534 case NF_SYMBOLTYPE_BLANK:
1535 case NF_SYMBOLTYPE_STAR:
1536 break;
1537 case NF_SYMBOLTYPE_COMMENT:
1539 String& rStr = sStrArray[i];
1540 nPos = nPos + rStr.Len();
1541 SvNumberformat::EraseCommentBraces( rStr );
1542 rComment += rStr;
1543 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1544 nAnzResStrings--;
1546 break;
1547 case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
1548 break;
1549 default:
1551 if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
1552 sStrArray[i].GetChar(0) != '@' )
1553 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1555 break;
1557 nPos = nPos + sStrArray[i].Len();
1558 i++;
1559 } // of while
1561 break;
1562 case NUMBERFORMAT_NUMBER:
1563 case NUMBERFORMAT_PERCENT:
1564 case NUMBERFORMAT_CURRENCY:
1565 case NUMBERFORMAT_SCIENTIFIC:
1566 case NUMBERFORMAT_FRACTION:
1568 sal_Unicode cThousandFill = ' ';
1569 while (i < nAnzStrings)
1571 if (eScannedType == NUMBERFORMAT_FRACTION && // special case
1572 nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/#
1573 StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
1574 StringEqualsChar( sStrArray[i], ' ' ) &&
1575 !bFrac &&
1576 IsLastBlankBeforeFrac(i) )
1578 nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string
1579 } // kein Taus.p.
1582 if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK ||
1583 nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
1584 nTypeArray[i] == NF_KEY_CCC || // CCC
1585 nTypeArray[i] == NF_KEY_GENERAL ) // Standard
1587 if (nTypeArray[i] == NF_KEY_GENERAL)
1589 nThousand = FLAG_STANDARD_IN_FORMAT;
1590 if ( bConvertMode )
1591 sStrArray[i] = sNameStandardFormat;
1593 nPos = nPos + sStrArray[i].Len();
1594 i++;
1596 else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // Strings oder
1597 nTypeArray[i] > 0) // Keywords
1599 if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
1600 nTypeArray[i] == NF_KEY_E) // E+
1602 if (bExp) // doppelt
1603 return nPos;
1604 bExp = TRUE;
1605 nExpPos = i;
1606 if (bDecSep)
1607 nCntPost = nCounter;
1608 else
1609 nCntPre = nCounter;
1610 nCounter = 0;
1611 nTypeArray[i] = NF_SYMBOLTYPE_EXP;
1613 else if (eScannedType == NUMBERFORMAT_FRACTION &&
1614 sStrArray[i].GetChar(0) == ' ')
1616 if (!bBlank && !bFrac) // nicht doppelt oder hinter /
1618 if (bDecSep && nCounter > 0) // Nachkommastellen
1619 return nPos; // Fehler
1620 bBlank = TRUE;
1621 nBlankPos = i;
1622 nCntPre = nCounter;
1623 nCounter = 0;
1625 nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
1627 else if (nTypeArray[i] == NF_KEY_THAI_T)
1629 bThaiT = true;
1630 sStrArray[i] = sKeyword[nTypeArray[i]];
1632 else
1633 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1634 nPos = nPos + sStrArray[i].Len();
1635 i++;
1637 else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
1639 sal_Unicode cHere = sStrArray[i].GetChar(0);
1640 // Handle not pre-known separators in switch.
1641 sal_Unicode cSimplified;
1642 if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
1643 cSimplified = ',';
1644 else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
1645 cSimplified = '.';
1646 else
1647 cSimplified = cHere;
1648 switch ( cSimplified )
1650 case '#':
1651 case '0':
1652 case '?':
1654 if (nThousand > 0) // #... #
1655 return nPos; // Fehler
1656 else if (bFrac && cHere == '0')
1657 return nPos; // 0 im Nenner
1658 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1659 String& rStr = sStrArray[i];
1660 nPos = nPos + rStr.Len();
1661 i++;
1662 nCounter++;
1663 while (i < nAnzStrings &&
1664 (sStrArray[i].GetChar(0) == '#' ||
1665 sStrArray[i].GetChar(0) == '0' ||
1666 sStrArray[i].GetChar(0) == '?')
1669 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1670 nPos = nPos + sStrArray[i].Len();
1671 nCounter++;
1672 i++;
1675 break;
1676 case '-':
1678 if ( bDecSep && nDecPos+1 == i &&
1679 nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
1680 { // "0.--"
1681 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1682 String& rStr = sStrArray[i];
1683 nPos = nPos + rStr.Len();
1684 i++;
1685 nCounter++;
1686 while (i < nAnzStrings &&
1687 (sStrArray[i].GetChar(0) == '-') )
1689 // If more than two dashes are present in
1690 // currency formats the last dash will be
1691 // interpreted literally as a minus sign.
1692 // Has to be this ugly. Period.
1693 if ( eScannedType == NUMBERFORMAT_CURRENCY
1694 && rStr.Len() >= 2 &&
1695 (i == nAnzStrings-1 ||
1696 sStrArray[i+1].GetChar(0) != '-') )
1697 break;
1698 rStr += sStrArray[i];
1699 nPos = nPos + sStrArray[i].Len();
1700 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1701 nAnzResStrings--;
1702 nCounter++;
1703 i++;
1706 else
1708 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1709 nPos = nPos + sStrArray[i].Len();
1710 i++;
1713 break;
1714 case '.':
1715 case ',':
1716 case '\'':
1717 case ' ':
1719 sal_Unicode cSep = cHere; // remember
1720 if ( StringEqualsChar( sOldThousandSep, cSep ) )
1722 // previous char with skip empty
1723 sal_Unicode cPre = PreviousChar(i);
1724 sal_Unicode cNext;
1725 if (bExp || bBlank || bFrac)
1726 { // after E, / or ' '
1727 if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
1729 nPos = nPos + sStrArray[i].Len();
1730 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1731 nAnzResStrings--;
1732 i++; // eat it
1734 else
1735 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1737 else if (i > 0 && i < nAnzStrings-1 &&
1738 (cPre == '#' || cPre == '0') &&
1739 ((cNext = NextChar(i)) == '#' || cNext == '0')
1740 ) // #,#
1742 nPos = nPos + sStrArray[i].Len();
1743 if (!bThousand) // only once
1745 bThousand = TRUE;
1746 cThousandFill = sStrArray[i+1].GetChar(0);
1748 // Eat it, will be reinserted at proper
1749 // grouping positions further down.
1750 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1751 nAnzResStrings--;
1752 i++;
1754 else if (i > 0 && (cPre == '#' || cPre == '0')
1755 && PreviousType(i) == NF_SYMBOLTYPE_DIGIT
1756 && nThousand < FLAG_STANDARD_IN_FORMAT )
1757 { // #,,,,
1758 if ( StringEqualsChar( sOldThousandSep, ' ' ) )
1759 { // strange, those French..
1760 BOOL bFirst = TRUE;
1761 String& rStr = sStrArray[i];
1762 // set a hard Non-Breaking Space or ConvertMode
1763 const String& rSepF = pFormatter->GetNumThousandSep();
1764 while ( i < nAnzStrings
1765 && sStrArray[i] == sOldThousandSep
1766 && StringEqualsChar( sOldThousandSep, NextChar(i) ) )
1767 { // last was a space or another space
1768 // is following => separator
1769 nPos = nPos + sStrArray[i].Len();
1770 if ( bFirst )
1772 bFirst = FALSE;
1773 rStr = rSepF;
1774 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1776 else
1778 rStr += rSepF;
1779 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1780 nAnzResStrings--;
1782 nThousand++;
1783 i++;
1785 if ( i < nAnzStrings-1
1786 && sStrArray[i] == sOldThousandSep )
1787 { // something following last space
1788 // => space if currency contained,
1789 // else separator
1790 nPos = nPos + sStrArray[i].Len();
1791 if ( (nPos <= nCurrPos &&
1792 nCurrPos < nPos + sStrArray[i+1].Len())
1793 || nTypeArray[i+1] == NF_KEY_CCC
1794 || (i < nAnzStrings-2 &&
1795 sStrArray[i+1].GetChar(0) == '[' &&
1796 sStrArray[i+2].GetChar(0) == '$') )
1798 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1800 else
1802 if ( bFirst )
1804 bFirst = FALSE;
1805 rStr = rSepF;
1806 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1808 else
1810 rStr += rSepF;
1811 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1812 nAnzResStrings--;
1814 nThousand++;
1816 i++;
1819 else
1823 nThousand++;
1824 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1825 nPos = nPos + sStrArray[i].Len();
1826 sStrArray[i] = pFormatter->GetNumThousandSep();
1827 i++;
1828 } while (i < nAnzStrings &&
1829 sStrArray[i] == sOldThousandSep);
1832 else // any grsep
1834 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1835 String& rStr = sStrArray[i];
1836 nPos = nPos + rStr.Len();
1837 i++;
1838 while ( i < nAnzStrings &&
1839 sStrArray[i] == sOldThousandSep )
1841 rStr += sStrArray[i];
1842 nPos = nPos + sStrArray[i].Len();
1843 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1844 nAnzResStrings--;
1845 i++;
1849 else if ( StringEqualsChar( sOldDecSep, cSep ) )
1851 if (bBlank || bFrac) // . behind / or ' '
1852 return nPos; // error
1853 else if (bExp) // behind E
1855 nPos = nPos + sStrArray[i].Len();
1856 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1857 nAnzResStrings--;
1858 i++; // eat it
1860 else if (bDecSep) // any .
1862 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1863 String& rStr = sStrArray[i];
1864 nPos = nPos + rStr.Len();
1865 i++;
1866 while ( i < nAnzStrings &&
1867 sStrArray[i] == sOldDecSep )
1869 rStr += sStrArray[i];
1870 nPos = nPos + sStrArray[i].Len();
1871 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1872 nAnzResStrings--;
1873 i++;
1876 else
1878 nPos = nPos + sStrArray[i].Len();
1879 nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
1880 sStrArray[i] = pFormatter->GetNumDecimalSep();
1881 bDecSep = TRUE;
1882 nDecPos = i;
1883 nCntPre = nCounter;
1884 nCounter = 0;
1886 i++;
1888 } // of else = DecSep
1889 else // . without meaning
1891 if (cSep == ' ' &&
1892 eScannedType == NUMBERFORMAT_FRACTION &&
1893 StringEqualsChar( sStrArray[i], ' ' ) )
1895 if (!bBlank && !bFrac) // no dups
1896 { // or behind /
1897 if (bDecSep && nCounter > 0)// dec.
1898 return nPos; // error
1899 bBlank = TRUE;
1900 nBlankPos = i;
1901 nCntPre = nCounter;
1902 nCounter = 0;
1904 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1905 nPos = nPos + sStrArray[i].Len();
1907 else
1909 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1910 String& rStr = sStrArray[i];
1911 nPos = nPos + rStr.Len();
1912 i++;
1913 while (i < nAnzStrings &&
1914 StringEqualsChar( sStrArray[i], cSep ) )
1916 rStr += sStrArray[i];
1917 nPos = nPos + sStrArray[i].Len();
1918 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1919 nAnzResStrings--;
1920 i++;
1925 break;
1926 case '/':
1928 if (eScannedType == NUMBERFORMAT_FRACTION)
1930 if ( i == 0 ||
1931 (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
1932 nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
1933 return nPos ? nPos : 1; // /? not allowed
1934 else if (!bFrac || (bDecSep && nCounter > 0))
1936 bFrac = TRUE;
1937 nCntPost = nCounter;
1938 nCounter = 0;
1939 nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
1940 nPos = nPos + sStrArray[i].Len();
1941 i++;
1943 else // / doppelt od. , imZaehl
1944 return nPos; // Fehler
1946 else
1948 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1949 nPos = nPos + sStrArray[i].Len();
1950 i++;
1953 break;
1954 case '[' :
1956 if ( eScannedType == NUMBERFORMAT_CURRENCY &&
1957 i < nAnzStrings-1 &&
1958 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1959 sStrArray[i+1].GetChar(0) == '$' )
1960 { // [$DM-xxx]
1961 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1962 nPos = nPos + sStrArray[i].Len(); // [
1963 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
1964 nPos = nPos + sStrArray[++i].Len(); // $
1965 sStrArray[i-1] += sStrArray[i]; // [$
1966 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1967 nAnzResStrings--;
1968 if ( ++i >= nAnzStrings )
1969 return nPos; // Fehler
1970 nPos = nPos + sStrArray[i].Len(); // DM
1971 String& rStr = sStrArray[i];
1972 String* pStr = &sStrArray[i];
1973 nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // wandeln
1974 BOOL bHadDash = FALSE;
1975 i++;
1976 while ( i < nAnzStrings &&
1977 sStrArray[i].GetChar(0) != ']' )
1979 nPos = nPos + sStrArray[i].Len();
1980 if ( bHadDash )
1982 *pStr += sStrArray[i];
1983 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1984 nAnzResStrings--;
1986 else
1988 if ( sStrArray[i].GetChar(0) == '-' )
1990 bHadDash = TRUE;
1991 pStr = &sStrArray[i];
1992 nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
1994 else
1996 *pStr += sStrArray[i];
1997 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1998 nAnzResStrings--;
2001 i++;
2003 if ( rStr.Len() && i < nAnzStrings &&
2004 sStrArray[i].GetChar(0) == ']' )
2006 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
2007 nPos = nPos + sStrArray[i].Len();
2008 i++;
2010 else
2011 return nPos; // Fehler
2013 else
2015 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2016 nPos = nPos + sStrArray[i].Len();
2017 i++;
2020 break;
2021 default: // andere Dels
2023 if (eScannedType == NUMBERFORMAT_PERCENT &&
2024 cHere == '%')
2025 nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
2026 else
2027 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2028 nPos = nPos + sStrArray[i].Len();
2029 i++;
2031 break;
2032 } // of switch (Del)
2033 } // of else Del
2034 else if ( nTypeArray[i] == NF_SYMBOLTYPE_COMMENT )
2036 String& rStr = sStrArray[i];
2037 nPos = nPos + rStr.Len();
2038 SvNumberformat::EraseCommentBraces( rStr );
2039 rComment += rStr;
2040 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2041 nAnzResStrings--;
2042 i++;
2044 else
2046 DBG_ERRORFILE( "unknown NF_SYMBOLTYPE_..." );
2047 nPos = nPos + sStrArray[i].Len();
2048 i++;
2050 } // of while
2051 if (eScannedType == NUMBERFORMAT_FRACTION)
2053 if (bFrac)
2054 nCntExp = nCounter;
2055 else if (bBlank)
2056 nCntPost = nCounter;
2057 else
2058 nCntPre = nCounter;
2060 else
2062 if (bExp)
2063 nCntExp = nCounter;
2064 else if (bDecSep)
2065 nCntPost = nCounter;
2066 else
2067 nCntPre = nCounter;
2069 if (bThousand) // Expansion of grouping separators
2071 USHORT nMaxPos;
2072 if (bFrac)
2074 if (bBlank)
2075 nMaxPos = nBlankPos;
2076 else
2077 nMaxPos = 0; // no grouping
2079 else if (bDecSep) // decimal separator present
2080 nMaxPos = nDecPos;
2081 else if (bExp) // 'E' exponent present
2082 nMaxPos = nExpPos;
2083 else // up to end
2084 nMaxPos = i;
2085 // Insert separators at proper positions.
2086 xub_StrLen nCount = 0;
2087 utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
2088 size_t nFirstDigitSymbol = nMaxPos;
2089 size_t nFirstGroupingSymbol = nMaxPos;
2090 i = nMaxPos;
2091 while (i-- > 0)
2093 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2095 nFirstDigitSymbol = i;
2096 nCount = nCount + sStrArray[i].Len(); // MSC converts += to int and then warns, so ...
2097 // Insert separator only if not leftmost symbol.
2098 if (i > 0 && nCount >= aGrouping.getPos())
2100 DBG_ASSERT( sStrArray[i].Len() == 1,
2101 "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
2102 if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP,
2103 pFormatter->GetNumThousandSep()))
2104 // nPos isn't correct here, but signals error
2105 return nPos;
2106 // i may have been decremented by 1
2107 nFirstDigitSymbol = i + 1;
2108 nFirstGroupingSymbol = i;
2109 aGrouping.advance();
2113 // Generated something like "string",000; remove separator again.
2114 if (nFirstGroupingSymbol < nFirstDigitSymbol)
2116 nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
2117 nAnzResStrings--;
2120 // Combine digits into groups to save memory (Info will be copied
2121 // later, taking only non-empty symbols).
2122 for (i = 0; i < nAnzStrings; ++i)
2124 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2126 String& rStr = sStrArray[i];
2127 while (++i < nAnzStrings &&
2128 nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2130 rStr += sStrArray[i];
2131 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2132 nAnzResStrings--;
2137 break; // of NUMBERFORMAT_NUMBER
2138 case NUMBERFORMAT_DATE:
2140 while (i < nAnzStrings)
2142 switch (nTypeArray[i])
2144 case NF_SYMBOLTYPE_BLANK:
2145 case NF_SYMBOLTYPE_STAR:
2146 case NF_SYMBOLTYPE_STRING:
2147 nPos = nPos + sStrArray[i].Len();
2148 i++;
2149 break;
2150 case NF_SYMBOLTYPE_COMMENT:
2152 String& rStr = sStrArray[i];
2153 nPos = nPos + rStr.Len();
2154 SvNumberformat::EraseCommentBraces( rStr );
2155 rComment += rStr;
2156 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2157 nAnzResStrings--;
2158 i++;
2160 break;
2161 case NF_SYMBOLTYPE_DEL:
2163 int nCalRet;
2164 if (sStrArray[i] == sOldDateSep)
2166 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2167 nPos = nPos + sStrArray[i].Len();
2168 if (bConvertMode)
2169 sStrArray[i] = pFormatter->GetDateSep();
2170 i++;
2172 else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2174 if ( nCalRet < 0 )
2175 return nPos; // error
2177 else
2179 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2180 nPos = nPos + sStrArray[i].Len();
2181 i++;
2184 break;
2185 case NF_KEY_THAI_T :
2186 bThaiT = true;
2187 // fall thru
2188 case NF_KEY_M: // M
2189 case NF_KEY_MM: // MM
2190 case NF_KEY_MMM: // MMM
2191 case NF_KEY_MMMM: // MMMM
2192 case NF_KEY_MMMMM: // MMMMM
2193 case NF_KEY_Q: // Q
2194 case NF_KEY_QQ: // QQ
2195 case NF_KEY_D: // D
2196 case NF_KEY_DD: // DD
2197 case NF_KEY_DDD: // DDD
2198 case NF_KEY_DDDD: // DDDD
2199 case NF_KEY_YY: // YY
2200 case NF_KEY_YYYY: // YYYY
2201 case NF_KEY_NN: // NN
2202 case NF_KEY_NNN: // NNN
2203 case NF_KEY_NNNN: // NNNN
2204 case NF_KEY_WW : // WW
2205 case NF_KEY_AAA : // AAA
2206 case NF_KEY_AAAA : // AAAA
2207 case NF_KEY_EC : // E
2208 case NF_KEY_EEC : // EE
2209 case NF_KEY_G : // G
2210 case NF_KEY_GG : // GG
2211 case NF_KEY_GGG : // GGG
2212 case NF_KEY_R : // R
2213 case NF_KEY_RR : // RR
2214 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2215 nPos = nPos + sStrArray[i].Len();
2216 i++;
2217 break;
2218 default: // andere Keywords
2219 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2220 nPos = nPos + sStrArray[i].Len();
2221 i++;
2222 break;
2224 } // of while
2226 break; // of NUMBERFORMAT_DATE
2227 case NUMBERFORMAT_TIME:
2229 while (i < nAnzStrings)
2231 switch (nTypeArray[i])
2233 case NF_SYMBOLTYPE_BLANK:
2234 case NF_SYMBOLTYPE_STAR:
2236 nPos = nPos + sStrArray[i].Len();
2237 i++;
2239 break;
2240 case NF_SYMBOLTYPE_DEL:
2242 switch( sStrArray[i].GetChar(0) )
2244 case '0':
2246 if ( Is100SecZero( i, bDecSep ) )
2248 bDecSep = TRUE;
2249 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2250 String& rStr = sStrArray[i];
2251 i++;
2252 nPos = nPos + sStrArray[i].Len();
2253 nCounter++;
2254 while (i < nAnzStrings &&
2255 sStrArray[i].GetChar(0) == '0')
2257 rStr += sStrArray[i];
2258 nPos = nPos + sStrArray[i].Len();
2259 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2260 nAnzResStrings--;
2261 nCounter++;
2262 i++;
2265 else
2266 return nPos;
2268 break;
2269 case '#':
2270 case '?':
2271 return nPos;
2272 case '[':
2274 if (bThousand) // doppelt
2275 return nPos;
2276 bThousand = TRUE; // bei Time frei
2277 sal_Unicode cChar = pChrCls->upper( NextChar(i) ).GetChar(0);
2278 if ( cChar == cOldKeyH )
2279 nThousand = 1; // H
2280 else if ( cChar == cOldKeyMI )
2281 nThousand = 2; // M
2282 else if ( cChar == cOldKeyS )
2283 nThousand = 3; // S
2284 else
2285 return nPos;
2286 nPos = nPos + sStrArray[i].Len();
2287 i++;
2289 break;
2290 case ']':
2292 if (!bThousand) // kein [ vorher
2293 return nPos;
2294 nPos = nPos + sStrArray[i].Len();
2295 i++;
2297 break;
2298 default:
2300 nPos = nPos + sStrArray[i].Len();
2301 if ( sStrArray[i] == sOldTimeSep )
2303 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2304 if ( bConvertMode )
2305 sStrArray[i] = pLoc->getTimeSep();
2307 else if ( sStrArray[i] == sOldTime100SecSep )
2309 bDecSep = TRUE;
2310 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2311 if ( bConvertMode )
2312 sStrArray[i] = pLoc->getTime100SecSep();
2314 else
2315 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2316 i++;
2318 break;
2321 break;
2322 case NF_SYMBOLTYPE_STRING:
2324 nPos = nPos + sStrArray[i].Len();
2325 i++;
2327 break;
2328 case NF_SYMBOLTYPE_COMMENT:
2330 String& rStr = sStrArray[i];
2331 nPos = nPos + rStr.Len();
2332 SvNumberformat::EraseCommentBraces( rStr );
2333 rComment += rStr;
2334 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2335 nAnzResStrings--;
2336 i++;
2338 break;
2339 case NF_KEY_AMPM: // AM/PM
2340 case NF_KEY_AP: // A/P
2342 bExp = TRUE; // missbraucht fuer A/P
2343 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2344 nPos = nPos + sStrArray[i].Len();
2345 i++;
2347 break;
2348 case NF_KEY_THAI_T :
2349 bThaiT = true;
2350 // fall thru
2351 case NF_KEY_MI: // M
2352 case NF_KEY_MMI: // MM
2353 case NF_KEY_H: // H
2354 case NF_KEY_HH: // HH
2355 case NF_KEY_S: // S
2356 case NF_KEY_SS: // SS
2358 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2359 nPos = nPos + sStrArray[i].Len();
2360 i++;
2362 break;
2363 default: // andere Keywords
2365 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2366 nPos = nPos + sStrArray[i].Len();
2367 i++;
2369 break;
2371 } // of while
2372 nCntPost = nCounter; // Zaehler der Nullen
2373 if (bExp)
2374 nCntExp = 1; // merkt AM/PM
2376 break; // of NUMBERFORMAT_TIME
2377 case NUMBERFORMAT_DATETIME:
2379 BOOL bTimePart = FALSE;
2380 while (i < nAnzStrings)
2382 switch (nTypeArray[i])
2384 case NF_SYMBOLTYPE_BLANK:
2385 case NF_SYMBOLTYPE_STAR:
2386 case NF_SYMBOLTYPE_STRING:
2387 nPos = nPos + sStrArray[i].Len();
2388 i++;
2389 break;
2390 case NF_SYMBOLTYPE_COMMENT:
2392 String& rStr = sStrArray[i];
2393 nPos = nPos + rStr.Len();
2394 SvNumberformat::EraseCommentBraces( rStr );
2395 rComment += rStr;
2396 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2397 nAnzResStrings--;
2398 i++;
2400 break;
2401 case NF_SYMBOLTYPE_DEL:
2403 int nCalRet;
2404 if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2406 if ( nCalRet < 0 )
2407 return nPos; // error
2409 else
2411 switch( sStrArray[i].GetChar(0) )
2413 case '0':
2415 if ( bTimePart && Is100SecZero( i, bDecSep ) )
2417 bDecSep = TRUE;
2418 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2419 String& rStr = sStrArray[i];
2420 i++;
2421 nPos = nPos + sStrArray[i].Len();
2422 nCounter++;
2423 while (i < nAnzStrings &&
2424 sStrArray[i].GetChar(0) == '0')
2426 rStr += sStrArray[i];
2427 nPos = nPos + sStrArray[i].Len();
2428 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2429 nAnzResStrings--;
2430 nCounter++;
2431 i++;
2434 else
2435 return nPos;
2437 break;
2438 case '#':
2439 case '?':
2440 return nPos;
2441 default:
2443 nPos = nPos + sStrArray[i].Len();
2444 if (bTimePart)
2446 if ( sStrArray[i] == sOldTimeSep )
2448 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2449 if ( bConvertMode )
2450 sStrArray[i] = pLoc->getTimeSep();
2452 else if ( sStrArray[i] == sOldTime100SecSep )
2454 bDecSep = TRUE;
2455 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2456 if ( bConvertMode )
2457 sStrArray[i] = pLoc->getTime100SecSep();
2459 else
2460 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2462 else
2464 if ( sStrArray[i] == sOldDateSep )
2466 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2467 if (bConvertMode)
2468 sStrArray[i] = pFormatter->GetDateSep();
2470 else
2471 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2473 i++;
2478 break;
2479 case NF_KEY_AMPM: // AM/PM
2480 case NF_KEY_AP: // A/P
2482 bTimePart = TRUE;
2483 bExp = TRUE; // missbraucht fuer A/P
2484 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2485 nPos = nPos + sStrArray[i].Len();
2486 i++;
2488 break;
2489 case NF_KEY_MI: // M
2490 case NF_KEY_MMI: // MM
2491 case NF_KEY_H: // H
2492 case NF_KEY_HH: // HH
2493 case NF_KEY_S: // S
2494 case NF_KEY_SS: // SS
2495 bTimePart = TRUE;
2496 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2497 nPos = nPos + sStrArray[i].Len();
2498 i++;
2499 break;
2500 case NF_KEY_M: // M
2501 case NF_KEY_MM: // MM
2502 case NF_KEY_MMM: // MMM
2503 case NF_KEY_MMMM: // MMMM
2504 case NF_KEY_MMMMM: // MMMMM
2505 case NF_KEY_Q: // Q
2506 case NF_KEY_QQ: // QQ
2507 case NF_KEY_D: // D
2508 case NF_KEY_DD: // DD
2509 case NF_KEY_DDD: // DDD
2510 case NF_KEY_DDDD: // DDDD
2511 case NF_KEY_YY: // YY
2512 case NF_KEY_YYYY: // YYYY
2513 case NF_KEY_NN: // NN
2514 case NF_KEY_NNN: // NNN
2515 case NF_KEY_NNNN: // NNNN
2516 case NF_KEY_WW : // WW
2517 case NF_KEY_AAA : // AAA
2518 case NF_KEY_AAAA : // AAAA
2519 case NF_KEY_EC : // E
2520 case NF_KEY_EEC : // EE
2521 case NF_KEY_G : // G
2522 case NF_KEY_GG : // GG
2523 case NF_KEY_GGG : // GGG
2524 case NF_KEY_R : // R
2525 case NF_KEY_RR : // RR
2526 bTimePart = FALSE;
2527 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2528 nPos = nPos + sStrArray[i].Len();
2529 i++;
2530 break;
2531 case NF_KEY_THAI_T :
2532 bThaiT = true;
2533 sStrArray[i] = sKeyword[nTypeArray[i]];
2534 nPos = nPos + sStrArray[i].Len();
2535 i++;
2536 break;
2537 default: // andere Keywords
2538 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2539 nPos = nPos + sStrArray[i].Len();
2540 i++;
2541 break;
2543 } // of while
2544 nCntPost = nCounter; // decimals (100th seconds)
2545 if (bExp)
2546 nCntExp = 1; // merkt AM/PM
2548 break; // of NUMBERFORMAT_DATETIME
2549 default:
2550 break;
2552 if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
2553 (nCntPre + nCntPost == 0 || nCntExp == 0))
2554 return nPos;
2555 else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
2556 return nPos;
2558 if (bThaiT && !GetNatNumModifier())
2559 SetNatNumModifier(1);
2561 if ( bConvertMode )
2562 { // strings containing keywords of the target locale must be quoted, so
2563 // the user sees the difference and is able to edit the format string
2564 for ( i=0; i < nAnzStrings; i++ )
2566 if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
2567 sStrArray[i].GetChar(0) != '\"' )
2569 if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
2570 { // don't stringize automatic currency, will be converted
2571 if ( sStrArray[i] == sOldCurSymbol )
2572 continue; // for
2573 // DM might be splitted into D and M
2574 if ( sStrArray[i].Len() < sOldCurSymbol.Len() &&
2575 pChrCls->toUpper( sStrArray[i], 0, 1 ).GetChar(0) ==
2576 sOldCurString.GetChar(0) )
2578 String aTmp( sStrArray[i] );
2579 USHORT j = i + 1;
2580 while ( aTmp.Len() < sOldCurSymbol.Len() &&
2581 j < nAnzStrings &&
2582 nTypeArray[j] == NF_SYMBOLTYPE_STRING )
2584 aTmp += sStrArray[j++];
2586 if ( pChrCls->upper( aTmp ) == sOldCurString )
2588 sStrArray[i++] = aTmp;
2589 for ( ; i<j; i++ )
2591 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2592 nAnzResStrings--;
2594 i = j - 1;
2595 continue; // for
2599 String& rStr = sStrArray[i];
2600 xub_StrLen nLen = rStr.Len();
2601 for ( xub_StrLen j=0; j<nLen; j++ )
2603 if ( (j == 0 || rStr.GetChar(j-1) != '\\') && GetKeyWord( rStr, j ) )
2605 rStr.Insert( '\"', 0 );
2606 rStr += '\"';
2607 break; // for
2613 // concatenate strings, remove quotes for output, and rebuild the format string
2614 rString.Erase();
2615 i = 0;
2616 while (i < nAnzStrings)
2618 switch ( nTypeArray[i] )
2620 case NF_SYMBOLTYPE_STRING :
2622 xub_StrLen nStringPos = rString.Len();
2623 xub_StrLen nArrPos = 0;
2624 USHORT iPos = i;
2627 if (sStrArray[i].Len() == 2 &&
2628 sStrArray[i].GetChar(0) == '\\')
2630 // Unescape some simple forms of symbols even in the UI
2631 // visible string to prevent duplicates that differ
2632 // only in notation, originating from import.
2633 // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
2634 // but 0\ 000 0 and 0 000 0 in a French locale are not.
2635 sal_Unicode c = sStrArray[i].GetChar(1);
2636 switch (c)
2638 case '+':
2639 case '-':
2640 rString += c;
2641 break;
2642 case ' ':
2643 case '.':
2644 case '/':
2645 if (((eScannedType & NUMBERFORMAT_DATE) == 0)
2646 && (StringEqualsChar(
2647 pFormatter->GetNumThousandSep(),
2648 c) || StringEqualsChar(
2649 pFormatter->GetNumDecimalSep(),
2650 c) || (c == ' ' &&
2651 StringEqualsChar(
2652 pFormatter->GetNumThousandSep(),
2653 cNonBreakingSpace))))
2654 rString += sStrArray[i];
2655 else if ((eScannedType & NUMBERFORMAT_DATE) &&
2656 StringEqualsChar(
2657 pFormatter->GetDateSep(), c))
2658 rString += sStrArray[i];
2659 else if ((eScannedType & NUMBERFORMAT_TIME) &&
2660 (StringEqualsChar( pLoc->getTimeSep(),
2661 c) ||
2662 StringEqualsChar(
2663 pLoc->getTime100SecSep(), c)))
2664 rString += sStrArray[i];
2665 else if (eScannedType & NUMBERFORMAT_FRACTION)
2666 rString += sStrArray[i];
2667 else
2668 rString += c;
2669 break;
2670 default:
2671 rString += sStrArray[i];
2674 else
2675 rString += sStrArray[i];
2676 if ( RemoveQuotes( sStrArray[i] ) > 0 )
2677 { // update currency up to quoted string
2678 if ( eScannedType == NUMBERFORMAT_CURRENCY )
2679 { // dM -> DM or DM -> $ in old automatic
2680 // currency formats, oh my ..., why did we ever
2681 // introduce them?
2682 String aTmp( pChrCls->toUpper(
2683 sStrArray[iPos], nArrPos,
2684 sStrArray[iPos].Len()-nArrPos ) );
2685 xub_StrLen nCPos = aTmp.Search( sOldCurString );
2686 if ( nCPos != STRING_NOTFOUND )
2688 const String& rCur =
2689 bConvertMode && bConvertSystemToSystem ?
2690 GetCurSymbol() : sOldCurSymbol;
2691 sStrArray[iPos].Replace( nArrPos+nCPos,
2692 sOldCurString.Len(), rCur );
2693 rString.Replace( nStringPos+nCPos,
2694 sOldCurString.Len(), rCur );
2696 nStringPos = rString.Len();
2697 if ( iPos == i )
2698 nArrPos = sStrArray[iPos].Len();
2699 else
2700 nArrPos = sStrArray[iPos].Len() + sStrArray[i].Len();
2703 if ( iPos != i )
2705 sStrArray[iPos] += sStrArray[i];
2706 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2707 nAnzResStrings--;
2709 i++;
2710 } while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
2711 if ( i < nAnzStrings )
2712 i--; // enter switch on next symbol again
2713 if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.Len() )
2714 { // same as above, since last RemoveQuotes
2715 String aTmp( pChrCls->toUpper(
2716 sStrArray[iPos], nArrPos,
2717 sStrArray[iPos].Len()-nArrPos ) );
2718 xub_StrLen nCPos = aTmp.Search( sOldCurString );
2719 if ( nCPos != STRING_NOTFOUND )
2721 const String& rCur =
2722 bConvertMode && bConvertSystemToSystem ?
2723 GetCurSymbol() : sOldCurSymbol;
2724 sStrArray[iPos].Replace( nArrPos+nCPos,
2725 sOldCurString.Len(), rCur );
2726 rString.Replace( nStringPos+nCPos,
2727 sOldCurString.Len(), rCur );
2731 break;
2732 case NF_SYMBOLTYPE_CURRENCY :
2734 rString += sStrArray[i];
2735 RemoveQuotes( sStrArray[i] );
2737 break;
2738 case NF_KEY_THAI_T:
2739 if (bThaiT && GetNatNumModifier() == 1)
2740 { // Remove T from format code, will be replaced with a [NatNum1] prefix.
2741 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2742 nAnzResStrings--;
2744 else
2745 rString += sStrArray[i];
2746 break;
2747 case NF_SYMBOLTYPE_EMPTY :
2748 // nothing
2749 break;
2750 default:
2751 rString += sStrArray[i];
2753 i++;
2755 return 0;
2759 xub_StrLen ImpSvNumberformatScan::RemoveQuotes( String& rStr )
2761 if ( rStr.Len() > 1 )
2763 sal_Unicode c = rStr.GetChar(0);
2764 xub_StrLen n;
2765 if ( c == '"' && rStr.GetChar( (n = xub_StrLen(rStr.Len()-1)) ) == '"' )
2767 rStr.Erase(n,1);
2768 rStr.Erase(0,1);
2769 return 2;
2771 else if ( c == '\\' )
2773 rStr.Erase(0,1);
2774 return 1;
2777 return 0;
2781 xub_StrLen ImpSvNumberformatScan::ScanFormat( String& rString, String& rComment )
2783 xub_StrLen res = Symbol_Division(rString); //lexikalische Analyse
2784 if (!res)
2785 res = ScanType(rString); // Erkennung des Formattyps
2786 if (!res)
2787 res = FinalScan( rString, rComment ); // Typabhaengige Endanalyse
2788 return res; // res = Kontrollposition
2789 // res = 0 => Format ok
2792 void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, USHORT nAnz)
2794 size_t i,j;
2795 j = 0;
2796 i = 0;
2797 while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
2799 if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
2801 pInfo->sStrArray[i] = sStrArray[j];
2802 pInfo->nTypeArray[i] = nTypeArray[j];
2803 i++;
2805 j++;
2807 pInfo->eScannedType = eScannedType;
2808 pInfo->bThousand = bThousand;
2809 pInfo->nThousand = nThousand;
2810 pInfo->nCntPre = nCntPre;
2811 pInfo->nCntPost = nCntPost;
2812 pInfo->nCntExp = nCntExp;