merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / numbers / zforscan.cxx
blobab780cd050dd3c24a8b82e6d8c234f5bfcda1ae8
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;
495 Color* pResult = NULL;
496 if (i >= NF_MAX_DEFAULT_COLORS)
498 const String& rColorWord = pKeyword[NF_KEY_COLOR];
499 xub_StrLen nPos = sString.Match(rColorWord);
500 if (nPos > 0)
502 sStr.Erase(0, nPos);
503 sStr.EraseLeadingChars();
504 sStr.EraseTrailingChars();
505 if (bConvertMode)
507 pFormatter->ChangeIntl(eNewLnge);
508 sStr.Insert( GetKeywords()[NF_KEY_COLOR], 0 ); // Color -> FARBE
509 pFormatter->ChangeIntl(eTmpLnge);
511 else
512 sStr.Insert(rColorWord,0);
513 sString.Erase(0, nPos);
514 sString.EraseLeadingChars();
515 sString.EraseTrailingChars();
517 if ( CharClass::isAsciiNumeric( sString ) )
519 long nIndex = sString.ToInt32();
520 if (nIndex > 0 && nIndex <= 64)
521 pResult = pFormatter->GetUserDefColor((USHORT)nIndex-1);
525 else
527 sStr.Erase();
528 if (bConvertMode)
530 pFormatter->ChangeIntl(eNewLnge);
531 sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot
532 pFormatter->ChangeIntl(eTmpLnge);
534 else
535 sStr = pKeyword[NF_KEY_FIRSTCOLOR+i];
537 pResult = &(StandardColor[i]);
539 return pResult;
543 short ImpSvNumberformatScan::GetKeyWord( const String& sSymbol, xub_StrLen nPos )
545 String sString = pFormatter->GetCharClass()->toUpper( sSymbol, nPos, sSymbol.Len() - nPos );
546 const String* pKeyword = GetKeywords();
547 // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
548 if ( sString.Search( pKeyword[NF_KEY_GENERAL] ) == 0 )
549 return NF_KEY_GENERAL;
550 //! MUST be a reverse search to find longer strings first
551 short i = NF_KEYWORD_ENTRIES_COUNT-1;
552 BOOL bFound = FALSE;
553 for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
555 bFound = sString.Search(pKeyword[i]) == 0;
556 if ( bFound )
558 break;
561 // new keywords take precedence over old keywords
562 if ( !bFound )
563 { // skip the gap of colors et al between new and old keywords and search on
564 i = NF_KEY_LASTKEYWORD;
565 while ( i > 0 && sString.Search(pKeyword[i]) != 0 )
566 i--;
567 if ( i > NF_KEY_LASTOLDKEYWORD && sString != pKeyword[i] )
568 { // found something, but maybe it's something else?
569 // e.g. new NNN is found in NNNN, for NNNN we must search on
570 short j = i - 1;
571 while ( j > 0 && sString.Search(pKeyword[j]) != 0 )
572 j--;
573 if ( j && pKeyword[j].Len() > pKeyword[i].Len() )
574 return j;
577 // The Thai T NatNum modifier during Xcl import.
578 if (i == 0 && bConvertMode && sString.GetChar(0) == 'T' && eTmpLnge ==
579 LANGUAGE_ENGLISH_US && MsLangId::getRealLanguage( eNewLnge) ==
580 LANGUAGE_THAI)
581 i = NF_KEY_THAI_T;
582 return i; // 0 => not found
585 //---------------------------------------------------------------------------
586 // Next_Symbol
587 //---------------------------------------------------------------------------
588 // Zerlegt die Eingabe in Symbole fuer die weitere
589 // Verarbeitung (Turing-Maschine).
590 //---------------------------------------------------------------------------
591 // Ausgangs Zustand = SsStart
592 //---------------+-------------------+-----------------------+---------------
593 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
594 //---------------+-------------------+-----------------------+---------------
595 // SsStart | Buchstabe | Symbol=Zeichen | SsGetWord
596 // | " | Typ = String | SsGetString
597 // | \ | Typ = String | SsGetChar
598 // | * | Typ = Star | SsGetStar
599 // | _ | Typ = Blank | SsGetBlank
600 // | @ # 0 ? / . , % [ | Symbol = Zeichen; |
601 // | ] ' Blank | Typ = Steuerzeichen | SsStop
602 // | $ - + ( ) : | Typ = String; |
603 // | | | Typ = Comment | SsStop
604 // | Sonst | Symbol = Zeichen | SsStop
605 //---------------|-------------------+-----------------------+---------------
606 // SsGetChar | Sonst | Symbol=Zeichen | SsStop
607 //---------------+-------------------+-----------------------+---------------
608 // GetString | " | | SsStop
609 // | Sonst | Symbol+=Zeichen | GetString
610 //---------------+-------------------+-----------------------+---------------
611 // SsGetWord | Buchstabe | Symbol += Zeichen |
612 // | + - (E+ E-)| Symbol += Zeichen | SsStop
613 // | / (AM/PM)| Symbol += Zeichen |
614 // | Sonst | Pos--, if Key Typ=Word| SsStop
615 //---------------+-------------------+-----------------------+---------------
616 // SsGetStar | Sonst | Symbol+=Zeichen | SsStop
617 // | | markiere Sonderfall * |
618 //---------------+-------------------+-----------------------+---------------
619 // SsGetBlank | Sonst | Symbol+=Zeichen | SsStop
620 // | | markiere Sonderfall _ |
621 //---------------+-------------------+-----------------------+---------------
622 // Wurde im State SsGetWord ein Schluesselwort erkannt (auch als
623 // Anfangsteilwort des Symbols)
624 // so werden die restlichen Buchstaben zurueckgeschrieben !!
626 enum ScanState
628 SsStop = 0,
629 SsStart = 1,
630 SsGetChar = 2,
631 SsGetString = 3,
632 SsGetWord = 4,
633 SsGetStar = 5,
634 SsGetBlank = 6
637 short ImpSvNumberformatScan::Next_Symbol( const String& rStr,
638 xub_StrLen& nPos, String& sSymbol )
640 if ( bKeywordsNeedInit )
641 InitKeywords();
642 const CharClass* pChrCls = pFormatter->GetCharClass();
643 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
644 const xub_StrLen nStart = nPos;
645 short eType = 0;
646 ScanState eState = SsStart;
647 sSymbol.Erase();
648 while ( nPos < rStr.Len() && eState != SsStop )
650 sal_Unicode cToken = rStr.GetChar( nPos++ );
651 switch (eState)
653 case SsStart:
655 // Fetch any currency longer than one character and don't get
656 // confused later on by "E/" or other combinations of letters
657 // and meaningful symbols. Necessary for old automatic currency.
658 // #96158# But don't do it if we're starting a "[...]" section,
659 // for example a "[$...]" new currency symbol to not parse away
660 // "$U" (symbol) of "[$UYU]" (abbreviation).
661 if ( nCurrPos != STRING_NOTFOUND && sCurString.Len() > 1 &&
662 nPos-1 + sCurString.Len() <= rStr.Len() &&
663 !(nPos > 1 && rStr.GetChar( nPos-2 ) == '[') )
665 String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
666 pChrCls->toUpper( aTest );
667 if ( aTest == sCurString )
669 sSymbol = rStr.Copy( --nPos, sCurString.Len() );
670 nPos = nPos + sSymbol.Len();
671 eState = SsStop;
672 eType = NF_SYMBOLTYPE_STRING;
673 return eType;
676 switch (cToken)
678 case '#':
679 case '0':
680 case '?':
681 case '%':
682 case '@':
683 case '[':
684 case ']':
685 case ',':
686 case '.':
687 case '/':
688 case '\'':
689 case ' ':
690 case ':':
691 case '-':
693 eType = NF_SYMBOLTYPE_DEL;
694 sSymbol += cToken;
695 eState = SsStop;
697 break;
698 case '*':
700 eType = NF_SYMBOLTYPE_STAR;
701 sSymbol += cToken;
702 eState = SsGetStar;
704 break;
705 case '_':
707 eType = NF_SYMBOLTYPE_BLANK;
708 sSymbol += cToken;
709 eState = SsGetBlank;
711 break;
712 #if NF_COMMENT_IN_FORMATSTRING
713 case '{':
714 eType = NF_SYMBOLTYPE_COMMENT;
715 eState = SsStop;
716 sSymbol.Append( rStr.GetBuffer() + (nPos-1), rStr.Len() - (nPos-1) );
717 nPos = rStr.Len();
718 break;
719 #endif
720 case '"':
721 eType = NF_SYMBOLTYPE_STRING;
722 eState = SsGetString;
723 sSymbol += cToken;
724 break;
725 case '\\':
726 eType = NF_SYMBOLTYPE_STRING;
727 eState = SsGetChar;
728 sSymbol += cToken;
729 break;
730 case '$':
731 case '+':
732 case '(':
733 case ')':
734 eType = NF_SYMBOLTYPE_STRING;
735 eState = SsStop;
736 sSymbol += cToken;
737 break;
738 default :
740 if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
741 StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
742 StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
743 StringEqualsChar( pLoc->getTimeSep(), cToken) ||
744 StringEqualsChar( pLoc->getTime100SecSep(), cToken))
746 // Another separator than pre-known ASCII
747 eType = NF_SYMBOLTYPE_DEL;
748 sSymbol += cToken;
749 eState = SsStop;
751 else if ( pChrCls->isLetter( rStr, nPos-1 ) )
753 short nTmpType = GetKeyWord( rStr, nPos-1 );
754 if ( nTmpType )
756 BOOL bCurrency = FALSE;
757 // "Automatic" currency may start with keyword,
758 // like "R" (Rand) and 'R' (era)
759 if ( nCurrPos != STRING_NOTFOUND &&
760 nPos-1 + sCurString.Len() <= rStr.Len() &&
761 sCurString.Search( sKeyword[nTmpType] ) == 0 )
763 String aTest( rStr.Copy( nPos-1, sCurString.Len() ) );
764 pChrCls->toUpper( aTest );
765 if ( aTest == sCurString )
766 bCurrency = TRUE;
768 if ( bCurrency )
770 eState = SsGetWord;
771 sSymbol += cToken;
773 else
775 eType = nTmpType;
776 xub_StrLen nLen = sKeyword[eType].Len();
777 sSymbol = rStr.Copy( nPos-1, nLen );
778 if ( eType == NF_KEY_E || IsAmbiguousE( eType ) )
780 sal_Unicode cNext = rStr.GetChar(nPos);
781 switch ( cNext )
783 case '+' :
784 case '-' : // E+ E- combine to one symbol
785 sSymbol += cNext;
786 eType = NF_KEY_E;
787 nPos++;
788 break;
789 case '0' :
790 case '#' : // scientific E without sign
791 eType = NF_KEY_E;
792 break;
795 nPos--;
796 nPos = nPos + nLen;
797 eState = SsStop;
800 else
802 eState = SsGetWord;
803 sSymbol += cToken;
806 else
808 eType = NF_SYMBOLTYPE_STRING;
809 eState = SsStop;
810 sSymbol += cToken;
813 break;
816 break;
817 case SsGetChar:
819 sSymbol += cToken;
820 eState = SsStop;
822 break;
823 case SsGetString:
825 if (cToken == '"')
826 eState = SsStop;
827 sSymbol += cToken;
829 break;
830 case SsGetWord:
832 if ( pChrCls->isLetter( rStr, nPos-1 ) )
834 short nTmpType = GetKeyWord( rStr, nPos-1 );
835 if ( nTmpType )
836 { // beginning of keyword, stop scan and put back
837 eType = NF_SYMBOLTYPE_STRING;
838 eState = SsStop;
839 nPos--;
841 else
842 sSymbol += cToken;
844 else
846 BOOL bDontStop = FALSE;
847 switch (cToken)
849 case '/': // AM/PM, A/P
851 sal_Unicode cNext = rStr.GetChar(nPos);
852 if ( cNext == 'P' || cNext == 'p' )
854 xub_StrLen nLen = sSymbol.Len();
855 if ( 1 <= nLen
856 && (sSymbol.GetChar(0) == 'A' || sSymbol.GetChar(0) == 'a')
857 && (nLen == 1 || (nLen == 2
858 && (sSymbol.GetChar(1) == 'M' || sSymbol.GetChar(1) == 'm')
859 && (rStr.GetChar(nPos+1) == 'M' || rStr.GetChar(nPos+1) == 'm'))) )
861 sSymbol += cToken;
862 bDontStop = TRUE;
866 break;
868 // anything not recognized will stop the scan
869 if ( eState != SsStop && !bDontStop )
871 eState = SsStop;
872 nPos--;
873 eType = NF_SYMBOLTYPE_STRING;
877 break;
878 case SsGetStar:
880 eState = SsStop;
881 sSymbol += cToken;
882 nRepPos = (nPos - nStart) - 1; // everytime > 0!!
884 break;
885 case SsGetBlank:
887 eState = SsStop;
888 sSymbol += cToken;
890 break;
891 default:
892 break;
893 } // of switch
894 } // of while
895 if (eState == SsGetWord)
896 eType = NF_SYMBOLTYPE_STRING;
897 return eType;
900 xub_StrLen ImpSvNumberformatScan::Symbol_Division(const String& rString)
902 nCurrPos = STRING_NOTFOUND;
903 // Ist Waehrung im Spiel?
904 String sString = pFormatter->GetCharClass()->upper(rString);
905 xub_StrLen nCPos = 0;
906 while (nCPos != STRING_NOTFOUND)
908 nCPos = sString.Search(GetCurString(),nCPos);
909 if (nCPos != STRING_NOTFOUND)
911 // in Quotes?
912 xub_StrLen nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
913 if ( nQ == STRING_NOTFOUND )
915 sal_Unicode c;
916 if ( nCPos == 0 ||
917 ((c = sString.GetChar(xub_StrLen(nCPos-1))) != '"'
918 && c != '\\') ) // dm kann durch "dm
919 { // \d geschuetzt werden
920 nCurrPos = nCPos;
921 nCPos = STRING_NOTFOUND; // Abbruch
923 else
924 nCPos++; // weitersuchen
926 else
927 nCPos = nQ + 1; // weitersuchen
930 nAnzStrings = 0;
931 BOOL bStar = FALSE; // wird bei '*'Detektion gesetzt
932 Reset();
934 xub_StrLen nPos = 0;
935 const xub_StrLen nLen = rString.Len();
936 while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
938 nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
939 if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
940 { // Ueberwachung des '*'
941 if (bStar)
942 return nPos; // Fehler: doppelter '*'
943 else
944 bStar = TRUE;
946 nAnzStrings++;
949 return 0; // 0 => ok
952 void ImpSvNumberformatScan::SkipStrings(USHORT& i, xub_StrLen& nPos)
954 while (i < nAnzStrings && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING
955 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK
956 || nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
958 nPos = nPos + sStrArray[i].Len();
959 i++;
964 USHORT ImpSvNumberformatScan::PreviousKeyword(USHORT i)
966 short res = 0;
967 if (i > 0 && i < nAnzStrings)
969 i--;
970 while (i > 0 && nTypeArray[i] <= 0)
971 i--;
972 if (nTypeArray[i] > 0)
973 res = nTypeArray[i];
975 return res;
978 USHORT ImpSvNumberformatScan::NextKeyword(USHORT i)
980 short res = 0;
981 if (i < nAnzStrings-1)
983 i++;
984 while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
985 i++;
986 if (nTypeArray[i] > 0)
987 res = nTypeArray[i];
989 return res;
992 short ImpSvNumberformatScan::PreviousType( USHORT i )
994 if ( i > 0 && i < nAnzStrings )
998 i--;
999 } while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
1000 return nTypeArray[i];
1002 return 0;
1005 sal_Unicode ImpSvNumberformatScan::PreviousChar(USHORT i)
1007 sal_Unicode res = ' ';
1008 if (i > 0 && i < nAnzStrings)
1010 i--;
1011 while (i > 0 && ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1012 || nTypeArray[i] == NF_SYMBOLTYPE_STRING
1013 || nTypeArray[i] == NF_SYMBOLTYPE_STAR
1014 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK ) )
1015 i--;
1016 if (sStrArray[i].Len() > 0)
1017 res = sStrArray[i].GetChar(xub_StrLen(sStrArray[i].Len()-1));
1019 return res;
1022 sal_Unicode ImpSvNumberformatScan::NextChar(USHORT i)
1024 sal_Unicode res = ' ';
1025 if (i < nAnzStrings-1)
1027 i++;
1028 while (i < nAnzStrings-1 &&
1029 ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY
1030 || nTypeArray[i] == NF_SYMBOLTYPE_STRING
1031 || nTypeArray[i] == NF_SYMBOLTYPE_STAR
1032 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
1033 i++;
1034 if (sStrArray[i].Len() > 0)
1035 res = sStrArray[i].GetChar(0);
1037 return res;
1040 BOOL ImpSvNumberformatScan::IsLastBlankBeforeFrac(USHORT i)
1042 BOOL res = TRUE;
1043 if (i < nAnzStrings-1)
1045 BOOL bStop = FALSE;
1046 i++;
1047 while (i < nAnzStrings-1 && !bStop)
1049 i++;
1050 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1051 sStrArray[i].GetChar(0) == '/')
1052 bStop = TRUE;
1053 else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1054 sStrArray[i].GetChar(0) == ' ')
1055 res = FALSE;
1057 if (!bStop) // kein '/'
1058 res = FALSE;
1060 else
1061 res = FALSE; // kein '/' mehr
1063 return res;
1066 void ImpSvNumberformatScan::Reset()
1068 nAnzStrings = 0;
1069 nAnzResStrings = 0;
1070 #if 0
1071 // ER 20.06.97 14:05 nicht noetig, wenn nAnzStrings beachtet wird
1072 for (size_t i = 0; i < NF_MAX_FORMAT_SYMBOLS; i++)
1074 sStrArray[i].Erase();
1075 nTypeArray[i] = 0;
1077 #endif
1078 eScannedType = NUMBERFORMAT_UNDEFINED;
1079 nRepPos = 0;
1080 bExp = FALSE;
1081 bThousand = FALSE;
1082 nThousand = 0;
1083 bDecSep = FALSE;
1084 nDecPos = -1;
1085 nExpPos = (USHORT) -1;
1086 nBlankPos = (USHORT) -1;
1087 nCntPre = 0;
1088 nCntPost = 0;
1089 nCntExp = 0;
1090 bFrac = FALSE;
1091 bBlank = FALSE;
1092 nNatNumModifier = 0;
1096 BOOL ImpSvNumberformatScan::Is100SecZero( USHORT i, BOOL bHadDecSep )
1098 USHORT nIndexPre = PreviousKeyword( i );
1099 return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS)
1100 && (bHadDecSep // S, SS ','
1101 || (i>0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
1102 // SS"any"00 take "any" as a valid decimal separator
1106 xub_StrLen ImpSvNumberformatScan::ScanType(const String&)
1108 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1110 xub_StrLen nPos = 0;
1111 USHORT i = 0;
1112 short eNewType;
1113 BOOL bMatchBracket = FALSE;
1114 bool bHaveGeneral = false; // if General/Standard encountered
1116 SkipStrings(i, nPos);
1117 while (i < nAnzStrings)
1119 if (nTypeArray[i] > 0)
1120 { // keyword
1121 switch (nTypeArray[i])
1123 case NF_KEY_E: // E
1124 eNewType = NUMBERFORMAT_SCIENTIFIC;
1125 break;
1126 case NF_KEY_AMPM: // AM,A,PM,P
1127 case NF_KEY_AP:
1128 case NF_KEY_H: // H
1129 case NF_KEY_HH: // HH
1130 case NF_KEY_S: // S
1131 case NF_KEY_SS: // SS
1132 eNewType = NUMBERFORMAT_TIME;
1133 break;
1134 case NF_KEY_M: // M
1135 case NF_KEY_MM: // MM
1136 { // minute or month
1137 USHORT nIndexPre = PreviousKeyword(i);
1138 USHORT nIndexNex = NextKeyword(i);
1139 sal_Unicode cChar = PreviousChar(i);
1140 if (nIndexPre == NF_KEY_H || // H
1141 nIndexPre == NF_KEY_HH || // HH
1142 nIndexNex == NF_KEY_S || // S
1143 nIndexNex == NF_KEY_SS || // SS
1144 cChar == '[' ) // [M
1146 eNewType = NUMBERFORMAT_TIME;
1147 nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5
1149 else
1150 eNewType = NUMBERFORMAT_DATE;
1152 break;
1153 case NF_KEY_MMM: // MMM
1154 case NF_KEY_MMMM: // MMMM
1155 case NF_KEY_MMMMM: // MMMMM
1156 case NF_KEY_Q: // Q
1157 case NF_KEY_QQ: // QQ
1158 case NF_KEY_D: // D
1159 case NF_KEY_DD: // DD
1160 case NF_KEY_DDD: // DDD
1161 case NF_KEY_DDDD: // DDDD
1162 case NF_KEY_YY: // YY
1163 case NF_KEY_YYYY: // YYYY
1164 case NF_KEY_NN: // NN
1165 case NF_KEY_NNN: // NNN
1166 case NF_KEY_NNNN: // NNNN
1167 case NF_KEY_WW : // WW
1168 case NF_KEY_AAA : // AAA
1169 case NF_KEY_AAAA : // AAAA
1170 case NF_KEY_EC : // E
1171 case NF_KEY_EEC : // EE
1172 case NF_KEY_G : // G
1173 case NF_KEY_GG : // GG
1174 case NF_KEY_GGG : // GGG
1175 case NF_KEY_R : // R
1176 case NF_KEY_RR : // RR
1177 eNewType = NUMBERFORMAT_DATE;
1178 break;
1179 case NF_KEY_CCC: // CCC
1180 eNewType = NUMBERFORMAT_CURRENCY;
1181 break;
1182 case NF_KEY_GENERAL: // Standard
1183 eNewType = NUMBERFORMAT_NUMBER;
1184 bHaveGeneral = true;
1185 break;
1186 default:
1187 eNewType = NUMBERFORMAT_UNDEFINED;
1188 break;
1191 else
1192 { // control character
1193 switch ( sStrArray[i].GetChar(0) )
1195 case '#':
1196 case '?':
1197 eNewType = NUMBERFORMAT_NUMBER;
1198 break;
1199 case '0':
1201 if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
1203 if ( Is100SecZero( i, bDecSep ) )
1205 bDecSep = TRUE; // subsequent 0's
1206 eNewType = NUMBERFORMAT_TIME;
1208 else
1209 return nPos; // Error
1211 else
1212 eNewType = NUMBERFORMAT_NUMBER;
1214 break;
1215 case '%':
1216 eNewType = NUMBERFORMAT_PERCENT;
1217 break;
1218 case '/':
1219 eNewType = NUMBERFORMAT_FRACTION;
1220 break;
1221 case '[':
1223 if ( i < nAnzStrings-1 &&
1224 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1225 sStrArray[i+1].GetChar(0) == '$' )
1226 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1227 eNewType = NUMBERFORMAT_CURRENCY;
1228 bMatchBracket = TRUE;
1230 else if ( i < nAnzStrings-1 &&
1231 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1232 sStrArray[i+1].GetChar(0) == '~' )
1233 { // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1234 eNewType = NUMBERFORMAT_DATE;
1235 bMatchBracket = TRUE;
1237 else
1239 USHORT nIndexNex = NextKeyword(i);
1240 if (nIndexNex == NF_KEY_H || // H
1241 nIndexNex == NF_KEY_HH || // HH
1242 nIndexNex == NF_KEY_M || // M
1243 nIndexNex == NF_KEY_MM || // MM
1244 nIndexNex == NF_KEY_S || // S
1245 nIndexNex == NF_KEY_SS ) // SS
1246 eNewType = NUMBERFORMAT_TIME;
1247 else
1248 return nPos; // Error
1251 break;
1252 case '@':
1253 eNewType = NUMBERFORMAT_TEXT;
1254 break;
1255 default:
1256 if ( sStrArray[i] == pLoc->getTime100SecSep() )
1257 bDecSep = TRUE; // for SS,0
1258 eNewType = NUMBERFORMAT_UNDEFINED;
1259 break;
1262 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1263 eScannedType = eNewType;
1264 else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
1265 eScannedType = NUMBERFORMAT_TEXT; // Text bleibt immer Text
1266 else if (eNewType == NUMBERFORMAT_UNDEFINED)
1267 { // bleibt wie bisher
1269 else if (eScannedType != eNewType)
1271 switch (eScannedType)
1273 case NUMBERFORMAT_DATE:
1275 switch (eNewType)
1277 case NUMBERFORMAT_TIME:
1278 eScannedType = NUMBERFORMAT_DATETIME;
1279 break;
1280 case NUMBERFORMAT_FRACTION: // DD/MM
1281 break;
1282 default:
1284 if (nCurrPos != STRING_NOTFOUND)
1285 eScannedType = NUMBERFORMAT_UNDEFINED;
1286 else if ( sStrArray[i] != pFormatter->GetDateSep() )
1287 return nPos;
1291 break;
1292 case NUMBERFORMAT_TIME:
1294 switch (eNewType)
1296 case NUMBERFORMAT_DATE:
1297 eScannedType = NUMBERFORMAT_DATETIME;
1298 break;
1299 case NUMBERFORMAT_FRACTION: // MM/SS
1300 break;
1301 default:
1303 if (nCurrPos != STRING_NOTFOUND)
1304 eScannedType = NUMBERFORMAT_UNDEFINED;
1305 else if ( sStrArray[i] != pLoc->getTimeSep() )
1306 return nPos;
1310 break;
1311 case NUMBERFORMAT_DATETIME:
1313 switch (eNewType)
1315 case NUMBERFORMAT_TIME:
1316 case NUMBERFORMAT_DATE:
1317 break;
1318 case NUMBERFORMAT_FRACTION: // DD/MM
1319 break;
1320 default:
1322 if (nCurrPos != STRING_NOTFOUND)
1323 eScannedType = NUMBERFORMAT_UNDEFINED;
1324 else if ( sStrArray[i] != pFormatter->GetDateSep()
1325 && sStrArray[i] != pLoc->getTimeSep() )
1326 return nPos;
1330 break;
1331 case NUMBERFORMAT_PERCENT:
1333 switch (eNewType)
1335 case NUMBERFORMAT_NUMBER: // nur Zahl nach Prozent
1336 break;
1337 default:
1338 return nPos;
1341 break;
1342 case NUMBERFORMAT_SCIENTIFIC:
1344 switch (eNewType)
1346 case NUMBERFORMAT_NUMBER: // nur Zahl nach E
1347 break;
1348 default:
1349 return nPos;
1352 break;
1353 case NUMBERFORMAT_NUMBER:
1355 switch (eNewType)
1357 case NUMBERFORMAT_SCIENTIFIC:
1358 case NUMBERFORMAT_PERCENT:
1359 case NUMBERFORMAT_FRACTION:
1360 case NUMBERFORMAT_CURRENCY:
1361 eScannedType = eNewType;
1362 break;
1363 default:
1364 if (nCurrPos != STRING_NOTFOUND)
1365 eScannedType = NUMBERFORMAT_UNDEFINED;
1366 else
1367 return nPos;
1370 break;
1371 case NUMBERFORMAT_FRACTION:
1373 switch (eNewType)
1375 case NUMBERFORMAT_NUMBER: // nur Zahl nach Bruch
1376 break;
1377 default:
1378 return nPos;
1381 break;
1382 default:
1383 break;
1386 nPos = nPos + sStrArray[i].Len(); // Korrekturposition
1387 i++;
1388 if ( bMatchBracket )
1389 { // no type detection inside of matching brackets if [$...], [~...]
1390 while ( bMatchBracket && i < nAnzStrings )
1392 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
1393 && sStrArray[i].GetChar(0) == ']' )
1394 bMatchBracket = FALSE;
1395 else
1396 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1397 nPos = nPos + sStrArray[i].Len();
1398 i++;
1400 if ( bMatchBracket )
1401 return nPos; // missing closing bracket at end of code
1403 SkipStrings(i, nPos);
1406 if ((eScannedType == NUMBERFORMAT_NUMBER || eScannedType == NUMBERFORMAT_UNDEFINED)
1407 && nCurrPos != STRING_NOTFOUND && !bHaveGeneral)
1408 eScannedType = NUMBERFORMAT_CURRENCY; // old "automatic" currency
1409 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1410 eScannedType = NUMBERFORMAT_DEFINED;
1411 return 0; // Alles ok
1415 bool ImpSvNumberformatScan::InsertSymbol( USHORT & nPos, svt::NfSymbolType eType, const String& rStr )
1417 if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
1418 return false;
1419 ++nAnzResStrings;
1420 if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
1421 --nPos; // reuse position
1422 else
1424 ++nAnzStrings;
1425 for (size_t i = nAnzStrings; i > nPos; --i)
1427 nTypeArray[i] = nTypeArray[i-1];
1428 sStrArray[i] = sStrArray[i-1];
1431 nTypeArray[nPos] = static_cast<short>(eType);
1432 sStrArray[nPos] = rStr;
1433 return true;
1437 int ImpSvNumberformatScan::FinalScanGetCalendar( xub_StrLen& nPos, USHORT& i,
1438 USHORT& rAnzResStrings )
1440 if ( sStrArray[i].GetChar(0) == '[' &&
1441 i < nAnzStrings-1 &&
1442 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1443 sStrArray[i+1].GetChar(0) == '~' )
1444 { // [~calendarID]
1445 // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1446 nPos = nPos + sStrArray[i].Len(); // [
1447 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1448 nPos = nPos + sStrArray[++i].Len(); // ~
1449 sStrArray[i-1] += sStrArray[i]; // [~
1450 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1451 rAnzResStrings--;
1452 if ( ++i >= nAnzStrings )
1453 return -1; // error
1454 nPos = nPos + sStrArray[i].Len(); // calendarID
1455 String& rStr = sStrArray[i];
1456 nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert
1457 i++;
1458 while ( i < nAnzStrings &&
1459 sStrArray[i].GetChar(0) != ']' )
1461 nPos = nPos + sStrArray[i].Len();
1462 rStr += sStrArray[i];
1463 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1464 rAnzResStrings--;
1465 i++;
1467 if ( rStr.Len() && i < nAnzStrings &&
1468 sStrArray[i].GetChar(0) == ']' )
1470 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1471 nPos = nPos + sStrArray[i].Len();
1472 i++;
1474 else
1475 return -1; // error
1476 return 1;
1478 return 0;
1481 xub_StrLen ImpSvNumberformatScan::FinalScan( String& rString, String& rComment )
1483 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1485 // save values for convert mode
1486 String sOldDecSep = pFormatter->GetNumDecimalSep();
1487 String sOldThousandSep = pFormatter->GetNumThousandSep();
1488 String sOldDateSep = pFormatter->GetDateSep();
1489 String sOldTimeSep = pLoc->getTimeSep();
1490 String sOldTime100SecSep= pLoc->getTime100SecSep();
1491 String sOldCurSymbol = GetCurSymbol();
1492 String sOldCurString = GetCurString();
1493 sal_Unicode cOldKeyH = sKeyword[NF_KEY_H].GetChar(0);
1494 sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI].GetChar(0);
1495 sal_Unicode cOldKeyS = sKeyword[NF_KEY_S].GetChar(0);
1497 // If the group separator is a Non-Breaking Space (French) continue with a
1498 // normal space instead so queries on space work correctly.
1499 // The format string is adjusted to allow both.
1500 // For output of the format code string the LocaleData characters are used.
1501 if ( sOldThousandSep.GetChar(0) == cNonBreakingSpace && sOldThousandSep.Len() == 1 )
1502 sOldThousandSep = ' ';
1504 // change locale data et al
1505 if (bConvertMode)
1507 pFormatter->ChangeIntl(eNewLnge);
1508 //! pointer may have changed
1509 pLoc = pFormatter->GetLocaleData();
1510 //! init new keywords
1511 InitKeywords();
1513 const CharClass* pChrCls = pFormatter->GetCharClass();
1515 xub_StrLen nPos = 0; // error correction position
1516 USHORT i = 0; // symbol loop counter
1517 USHORT nCounter = 0; // counts digits
1518 nAnzResStrings = nAnzStrings; // counts remaining symbols
1519 bDecSep = FALSE; // reset in case already used in TypeCheck
1520 bool bThaiT = false; // Thai T NatNum modifier present
1522 switch (eScannedType)
1524 case NUMBERFORMAT_TEXT:
1525 case NUMBERFORMAT_DEFINED:
1527 while (i < nAnzStrings)
1529 switch (nTypeArray[i])
1531 case NF_SYMBOLTYPE_BLANK:
1532 case NF_SYMBOLTYPE_STAR:
1533 break;
1534 case NF_SYMBOLTYPE_COMMENT:
1536 String& rStr = sStrArray[i];
1537 nPos = nPos + rStr.Len();
1538 SvNumberformat::EraseCommentBraces( rStr );
1539 rComment += rStr;
1540 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1541 nAnzResStrings--;
1543 break;
1544 case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
1545 break;
1546 default:
1548 if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
1549 sStrArray[i].GetChar(0) != '@' )
1550 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1552 break;
1554 nPos = nPos + sStrArray[i].Len();
1555 i++;
1556 } // of while
1558 break;
1559 case NUMBERFORMAT_NUMBER:
1560 case NUMBERFORMAT_PERCENT:
1561 case NUMBERFORMAT_CURRENCY:
1562 case NUMBERFORMAT_SCIENTIFIC:
1563 case NUMBERFORMAT_FRACTION:
1565 sal_Unicode cThousandFill = ' ';
1566 while (i < nAnzStrings)
1568 if (eScannedType == NUMBERFORMAT_FRACTION && // special case
1569 nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/#
1570 StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
1571 StringEqualsChar( sStrArray[i], ' ' ) &&
1572 !bFrac &&
1573 IsLastBlankBeforeFrac(i) )
1575 nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string
1576 } // kein Taus.p.
1579 if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK ||
1580 nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
1581 nTypeArray[i] == NF_KEY_CCC || // CCC
1582 nTypeArray[i] == NF_KEY_GENERAL ) // Standard
1584 if (nTypeArray[i] == NF_KEY_GENERAL)
1586 nThousand = FLAG_STANDARD_IN_FORMAT;
1587 if ( bConvertMode )
1588 sStrArray[i] = sNameStandardFormat;
1590 nPos = nPos + sStrArray[i].Len();
1591 i++;
1593 else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // Strings oder
1594 nTypeArray[i] > 0) // Keywords
1596 if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
1597 nTypeArray[i] == NF_KEY_E) // E+
1599 if (bExp) // doppelt
1600 return nPos;
1601 bExp = TRUE;
1602 nExpPos = i;
1603 if (bDecSep)
1604 nCntPost = nCounter;
1605 else
1606 nCntPre = nCounter;
1607 nCounter = 0;
1608 nTypeArray[i] = NF_SYMBOLTYPE_EXP;
1610 else if (eScannedType == NUMBERFORMAT_FRACTION &&
1611 sStrArray[i].GetChar(0) == ' ')
1613 if (!bBlank && !bFrac) // nicht doppelt oder hinter /
1615 if (bDecSep && nCounter > 0) // Nachkommastellen
1616 return nPos; // Fehler
1617 bBlank = TRUE;
1618 nBlankPos = i;
1619 nCntPre = nCounter;
1620 nCounter = 0;
1622 nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
1624 else if (nTypeArray[i] == NF_KEY_THAI_T)
1626 bThaiT = true;
1627 sStrArray[i] = sKeyword[nTypeArray[i]];
1629 else
1630 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1631 nPos = nPos + sStrArray[i].Len();
1632 i++;
1634 else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
1636 sal_Unicode cHere = sStrArray[i].GetChar(0);
1637 // Handle not pre-known separators in switch.
1638 sal_Unicode cSimplified;
1639 if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
1640 cSimplified = ',';
1641 else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
1642 cSimplified = '.';
1643 else
1644 cSimplified = cHere;
1645 switch ( cSimplified )
1647 case '#':
1648 case '0':
1649 case '?':
1651 if (nThousand > 0) // #... #
1652 return nPos; // Fehler
1653 else if (bFrac && cHere == '0')
1654 return nPos; // 0 im Nenner
1655 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1656 String& rStr = sStrArray[i];
1657 nPos = nPos + rStr.Len();
1658 i++;
1659 nCounter++;
1660 while (i < nAnzStrings &&
1661 (sStrArray[i].GetChar(0) == '#' ||
1662 sStrArray[i].GetChar(0) == '0' ||
1663 sStrArray[i].GetChar(0) == '?')
1666 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1667 nPos = nPos + sStrArray[i].Len();
1668 nCounter++;
1669 i++;
1672 break;
1673 case '-':
1675 if ( bDecSep && nDecPos+1 == i &&
1676 nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
1677 { // "0.--"
1678 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1679 String& rStr = sStrArray[i];
1680 nPos = nPos + rStr.Len();
1681 i++;
1682 nCounter++;
1683 while (i < nAnzStrings &&
1684 (sStrArray[i].GetChar(0) == '-') )
1686 // If more than two dashes are present in
1687 // currency formats the last dash will be
1688 // interpreted literally as a minus sign.
1689 // Has to be this ugly. Period.
1690 if ( eScannedType == NUMBERFORMAT_CURRENCY
1691 && rStr.Len() >= 2 &&
1692 (i == nAnzStrings-1 ||
1693 sStrArray[i+1].GetChar(0) != '-') )
1694 break;
1695 rStr += sStrArray[i];
1696 nPos = nPos + sStrArray[i].Len();
1697 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1698 nAnzResStrings--;
1699 nCounter++;
1700 i++;
1703 else
1705 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1706 nPos = nPos + sStrArray[i].Len();
1707 i++;
1710 break;
1711 case '.':
1712 case ',':
1713 case '\'':
1714 case ' ':
1716 sal_Unicode cSep = cHere; // remember
1717 if ( StringEqualsChar( sOldThousandSep, cSep ) )
1719 // previous char with skip empty
1720 sal_Unicode cPre = PreviousChar(i);
1721 sal_Unicode cNext;
1722 if (bExp || bBlank || bFrac)
1723 { // after E, / or ' '
1724 if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
1726 nPos = nPos + sStrArray[i].Len();
1727 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1728 nAnzResStrings--;
1729 i++; // eat it
1731 else
1732 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1734 else if (i > 0 && i < nAnzStrings-1 &&
1735 (cPre == '#' || cPre == '0') &&
1736 ((cNext = NextChar(i)) == '#' || cNext == '0')
1737 ) // #,#
1739 nPos = nPos + sStrArray[i].Len();
1740 if (!bThousand) // only once
1742 bThousand = TRUE;
1743 cThousandFill = sStrArray[i+1].GetChar(0);
1745 // Eat it, will be reinserted at proper
1746 // grouping positions further down.
1747 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1748 nAnzResStrings--;
1749 i++;
1751 else if (i > 0 && (cPre == '#' || cPre == '0')
1752 && PreviousType(i) == NF_SYMBOLTYPE_DIGIT
1753 && nThousand < FLAG_STANDARD_IN_FORMAT )
1754 { // #,,,,
1755 if ( StringEqualsChar( sOldThousandSep, ' ' ) )
1756 { // strange, those French..
1757 BOOL bFirst = TRUE;
1758 String& rStr = sStrArray[i];
1759 // set a hard Non-Breaking Space or ConvertMode
1760 const String& rSepF = pFormatter->GetNumThousandSep();
1761 while ( i < nAnzStrings
1762 && sStrArray[i] == sOldThousandSep
1763 && StringEqualsChar( sOldThousandSep, NextChar(i) ) )
1764 { // last was a space or another space
1765 // is following => separator
1766 nPos = nPos + sStrArray[i].Len();
1767 if ( bFirst )
1769 bFirst = FALSE;
1770 rStr = rSepF;
1771 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1773 else
1775 rStr += rSepF;
1776 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1777 nAnzResStrings--;
1779 nThousand++;
1780 i++;
1782 if ( i < nAnzStrings-1
1783 && sStrArray[i] == sOldThousandSep )
1784 { // something following last space
1785 // => space if currency contained,
1786 // else separator
1787 nPos = nPos + sStrArray[i].Len();
1788 if ( (nPos <= nCurrPos &&
1789 nCurrPos < nPos + sStrArray[i+1].Len())
1790 || nTypeArray[i+1] == NF_KEY_CCC
1791 || (i < nAnzStrings-2 &&
1792 sStrArray[i+1].GetChar(0) == '[' &&
1793 sStrArray[i+2].GetChar(0) == '$') )
1795 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1797 else
1799 if ( bFirst )
1801 bFirst = FALSE;
1802 rStr = rSepF;
1803 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1805 else
1807 rStr += rSepF;
1808 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1809 nAnzResStrings--;
1811 nThousand++;
1813 i++;
1816 else
1820 nThousand++;
1821 nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1822 nPos = nPos + sStrArray[i].Len();
1823 sStrArray[i] = pFormatter->GetNumThousandSep();
1824 i++;
1825 } while (i < nAnzStrings &&
1826 sStrArray[i] == sOldThousandSep);
1829 else // any grsep
1831 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1832 String& rStr = sStrArray[i];
1833 nPos = nPos + rStr.Len();
1834 i++;
1835 while ( i < nAnzStrings &&
1836 sStrArray[i] == sOldThousandSep )
1838 rStr += sStrArray[i];
1839 nPos = nPos + sStrArray[i].Len();
1840 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1841 nAnzResStrings--;
1842 i++;
1846 else if ( StringEqualsChar( sOldDecSep, cSep ) )
1848 if (bBlank || bFrac) // . behind / or ' '
1849 return nPos; // error
1850 else if (bExp) // behind E
1852 nPos = nPos + sStrArray[i].Len();
1853 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1854 nAnzResStrings--;
1855 i++; // eat it
1857 else if (bDecSep) // any .
1859 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1860 String& rStr = sStrArray[i];
1861 nPos = nPos + rStr.Len();
1862 i++;
1863 while ( i < nAnzStrings &&
1864 sStrArray[i] == sOldDecSep )
1866 rStr += sStrArray[i];
1867 nPos = nPos + sStrArray[i].Len();
1868 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1869 nAnzResStrings--;
1870 i++;
1873 else
1875 nPos = nPos + sStrArray[i].Len();
1876 nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
1877 sStrArray[i] = pFormatter->GetNumDecimalSep();
1878 bDecSep = TRUE;
1879 nDecPos = i;
1880 nCntPre = nCounter;
1881 nCounter = 0;
1883 i++;
1885 } // of else = DecSep
1886 else // . without meaning
1888 if (cSep == ' ' &&
1889 eScannedType == NUMBERFORMAT_FRACTION &&
1890 StringEqualsChar( sStrArray[i], ' ' ) )
1892 if (!bBlank && !bFrac) // no dups
1893 { // or behind /
1894 if (bDecSep && nCounter > 0)// dec.
1895 return nPos; // error
1896 bBlank = TRUE;
1897 nBlankPos = i;
1898 nCntPre = nCounter;
1899 nCounter = 0;
1901 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1902 nPos = nPos + sStrArray[i].Len();
1904 else
1906 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1907 String& rStr = sStrArray[i];
1908 nPos = nPos + rStr.Len();
1909 i++;
1910 while (i < nAnzStrings &&
1911 StringEqualsChar( sStrArray[i], cSep ) )
1913 rStr += sStrArray[i];
1914 nPos = nPos + sStrArray[i].Len();
1915 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1916 nAnzResStrings--;
1917 i++;
1922 break;
1923 case '/':
1925 if (eScannedType == NUMBERFORMAT_FRACTION)
1927 if ( i == 0 ||
1928 (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
1929 nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
1930 return nPos ? nPos : 1; // /? not allowed
1931 else if (!bFrac || (bDecSep && nCounter > 0))
1933 bFrac = TRUE;
1934 nCntPost = nCounter;
1935 nCounter = 0;
1936 nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
1937 nPos = nPos + sStrArray[i].Len();
1938 i++;
1940 else // / doppelt od. , imZaehl
1941 return nPos; // Fehler
1943 else
1945 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1946 nPos = nPos + sStrArray[i].Len();
1947 i++;
1950 break;
1951 case '[' :
1953 if ( eScannedType == NUMBERFORMAT_CURRENCY &&
1954 i < nAnzStrings-1 &&
1955 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1956 sStrArray[i+1].GetChar(0) == '$' )
1957 { // [$DM-xxx]
1958 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR
1959 nPos = nPos + sStrArray[i].Len(); // [
1960 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
1961 nPos = nPos + sStrArray[++i].Len(); // $
1962 sStrArray[i-1] += sStrArray[i]; // [$
1963 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1964 nAnzResStrings--;
1965 if ( ++i >= nAnzStrings )
1966 return nPos; // Fehler
1967 nPos = nPos + sStrArray[i].Len(); // DM
1968 String& rStr = sStrArray[i];
1969 String* pStr = &sStrArray[i];
1970 nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // wandeln
1971 BOOL bHadDash = FALSE;
1972 i++;
1973 while ( i < nAnzStrings &&
1974 sStrArray[i].GetChar(0) != ']' )
1976 nPos = nPos + sStrArray[i].Len();
1977 if ( bHadDash )
1979 *pStr += sStrArray[i];
1980 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1981 nAnzResStrings--;
1983 else
1985 if ( sStrArray[i].GetChar(0) == '-' )
1987 bHadDash = TRUE;
1988 pStr = &sStrArray[i];
1989 nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
1991 else
1993 *pStr += sStrArray[i];
1994 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1995 nAnzResStrings--;
1998 i++;
2000 if ( rStr.Len() && i < nAnzStrings &&
2001 sStrArray[i].GetChar(0) == ']' )
2003 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
2004 nPos = nPos + sStrArray[i].Len();
2005 i++;
2007 else
2008 return nPos; // Fehler
2010 else
2012 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2013 nPos = nPos + sStrArray[i].Len();
2014 i++;
2017 break;
2018 default: // andere Dels
2020 if (eScannedType == NUMBERFORMAT_PERCENT &&
2021 cHere == '%')
2022 nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
2023 else
2024 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2025 nPos = nPos + sStrArray[i].Len();
2026 i++;
2028 break;
2029 } // of switch (Del)
2030 } // of else Del
2031 else if ( nTypeArray[i] == NF_SYMBOLTYPE_COMMENT )
2033 String& rStr = sStrArray[i];
2034 nPos = nPos + rStr.Len();
2035 SvNumberformat::EraseCommentBraces( rStr );
2036 rComment += rStr;
2037 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2038 nAnzResStrings--;
2039 i++;
2041 else
2043 DBG_ERRORFILE( "unknown NF_SYMBOLTYPE_..." );
2044 nPos = nPos + sStrArray[i].Len();
2045 i++;
2047 } // of while
2048 if (eScannedType == NUMBERFORMAT_FRACTION)
2050 if (bFrac)
2051 nCntExp = nCounter;
2052 else if (bBlank)
2053 nCntPost = nCounter;
2054 else
2055 nCntPre = nCounter;
2057 else
2059 if (bExp)
2060 nCntExp = nCounter;
2061 else if (bDecSep)
2062 nCntPost = nCounter;
2063 else
2064 nCntPre = nCounter;
2066 if (bThousand) // Expansion of grouping separators
2068 USHORT nMaxPos;
2069 if (bFrac)
2071 if (bBlank)
2072 nMaxPos = nBlankPos;
2073 else
2074 nMaxPos = 0; // no grouping
2076 else if (bDecSep) // decimal separator present
2077 nMaxPos = nDecPos;
2078 else if (bExp) // 'E' exponent present
2079 nMaxPos = nExpPos;
2080 else // up to end
2081 nMaxPos = i;
2082 // Insert separators at proper positions.
2083 xub_StrLen nCount = 0;
2084 utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
2085 size_t nFirstDigitSymbol = nMaxPos;
2086 size_t nFirstGroupingSymbol = nMaxPos;
2087 i = nMaxPos;
2088 while (i-- > 0)
2090 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2092 nFirstDigitSymbol = i;
2093 nCount = nCount + sStrArray[i].Len(); // MSC converts += to int and then warns, so ...
2094 // Insert separator only if not leftmost symbol.
2095 if (i > 0 && nCount >= aGrouping.getPos())
2097 DBG_ASSERT( sStrArray[i].Len() == 1,
2098 "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
2099 if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP,
2100 pFormatter->GetNumThousandSep()))
2101 // nPos isn't correct here, but signals error
2102 return nPos;
2103 // i may have been decremented by 1
2104 nFirstDigitSymbol = i + 1;
2105 nFirstGroupingSymbol = i;
2106 aGrouping.advance();
2110 // Generated something like "string",000; remove separator again.
2111 if (nFirstGroupingSymbol < nFirstDigitSymbol)
2113 nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
2114 nAnzResStrings--;
2117 // Combine digits into groups to save memory (Info will be copied
2118 // later, taking only non-empty symbols).
2119 for (i = 0; i < nAnzStrings; ++i)
2121 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2123 String& rStr = sStrArray[i];
2124 while (++i < nAnzStrings &&
2125 nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2127 rStr += sStrArray[i];
2128 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2129 nAnzResStrings--;
2134 break; // of NUMBERFORMAT_NUMBER
2135 case NUMBERFORMAT_DATE:
2137 while (i < nAnzStrings)
2139 switch (nTypeArray[i])
2141 case NF_SYMBOLTYPE_BLANK:
2142 case NF_SYMBOLTYPE_STAR:
2143 case NF_SYMBOLTYPE_STRING:
2144 nPos = nPos + sStrArray[i].Len();
2145 i++;
2146 break;
2147 case NF_SYMBOLTYPE_COMMENT:
2149 String& rStr = sStrArray[i];
2150 nPos = nPos + rStr.Len();
2151 SvNumberformat::EraseCommentBraces( rStr );
2152 rComment += rStr;
2153 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2154 nAnzResStrings--;
2155 i++;
2157 break;
2158 case NF_SYMBOLTYPE_DEL:
2160 int nCalRet;
2161 if (sStrArray[i] == sOldDateSep)
2163 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2164 nPos = nPos + sStrArray[i].Len();
2165 if (bConvertMode)
2166 sStrArray[i] = pFormatter->GetDateSep();
2167 i++;
2169 else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2171 if ( nCalRet < 0 )
2172 return nPos; // error
2174 else
2176 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2177 nPos = nPos + sStrArray[i].Len();
2178 i++;
2181 break;
2182 case NF_KEY_THAI_T :
2183 bThaiT = true;
2184 // fall thru
2185 case NF_KEY_M: // M
2186 case NF_KEY_MM: // MM
2187 case NF_KEY_MMM: // MMM
2188 case NF_KEY_MMMM: // MMMM
2189 case NF_KEY_MMMMM: // MMMMM
2190 case NF_KEY_Q: // Q
2191 case NF_KEY_QQ: // QQ
2192 case NF_KEY_D: // D
2193 case NF_KEY_DD: // DD
2194 case NF_KEY_DDD: // DDD
2195 case NF_KEY_DDDD: // DDDD
2196 case NF_KEY_YY: // YY
2197 case NF_KEY_YYYY: // YYYY
2198 case NF_KEY_NN: // NN
2199 case NF_KEY_NNN: // NNN
2200 case NF_KEY_NNNN: // NNNN
2201 case NF_KEY_WW : // WW
2202 case NF_KEY_AAA : // AAA
2203 case NF_KEY_AAAA : // AAAA
2204 case NF_KEY_EC : // E
2205 case NF_KEY_EEC : // EE
2206 case NF_KEY_G : // G
2207 case NF_KEY_GG : // GG
2208 case NF_KEY_GGG : // GGG
2209 case NF_KEY_R : // R
2210 case NF_KEY_RR : // RR
2211 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2212 nPos = nPos + sStrArray[i].Len();
2213 i++;
2214 break;
2215 default: // andere Keywords
2216 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2217 nPos = nPos + sStrArray[i].Len();
2218 i++;
2219 break;
2221 } // of while
2223 break; // of NUMBERFORMAT_DATE
2224 case NUMBERFORMAT_TIME:
2226 while (i < nAnzStrings)
2228 switch (nTypeArray[i])
2230 case NF_SYMBOLTYPE_BLANK:
2231 case NF_SYMBOLTYPE_STAR:
2233 nPos = nPos + sStrArray[i].Len();
2234 i++;
2236 break;
2237 case NF_SYMBOLTYPE_DEL:
2239 switch( sStrArray[i].GetChar(0) )
2241 case '0':
2243 if ( Is100SecZero( i, bDecSep ) )
2245 bDecSep = TRUE;
2246 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2247 String& rStr = sStrArray[i];
2248 i++;
2249 nPos = nPos + sStrArray[i].Len();
2250 nCounter++;
2251 while (i < nAnzStrings &&
2252 sStrArray[i].GetChar(0) == '0')
2254 rStr += sStrArray[i];
2255 nPos = nPos + sStrArray[i].Len();
2256 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2257 nAnzResStrings--;
2258 nCounter++;
2259 i++;
2262 else
2263 return nPos;
2265 break;
2266 case '#':
2267 case '?':
2268 return nPos;
2269 case '[':
2271 if (bThousand) // doppelt
2272 return nPos;
2273 bThousand = TRUE; // bei Time frei
2274 sal_Unicode cChar = pChrCls->upper( NextChar(i) ).GetChar(0);
2275 if ( cChar == cOldKeyH )
2276 nThousand = 1; // H
2277 else if ( cChar == cOldKeyMI )
2278 nThousand = 2; // M
2279 else if ( cChar == cOldKeyS )
2280 nThousand = 3; // S
2281 else
2282 return nPos;
2283 nPos = nPos + sStrArray[i].Len();
2284 i++;
2286 break;
2287 case ']':
2289 if (!bThousand) // kein [ vorher
2290 return nPos;
2291 nPos = nPos + sStrArray[i].Len();
2292 i++;
2294 break;
2295 default:
2297 nPos = nPos + sStrArray[i].Len();
2298 if ( sStrArray[i] == sOldTimeSep )
2300 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2301 if ( bConvertMode )
2302 sStrArray[i] = pLoc->getTimeSep();
2304 else if ( sStrArray[i] == sOldTime100SecSep )
2306 bDecSep = TRUE;
2307 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2308 if ( bConvertMode )
2309 sStrArray[i] = pLoc->getTime100SecSep();
2311 else
2312 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2313 i++;
2315 break;
2318 break;
2319 case NF_SYMBOLTYPE_STRING:
2321 nPos = nPos + sStrArray[i].Len();
2322 i++;
2324 break;
2325 case NF_SYMBOLTYPE_COMMENT:
2327 String& rStr = sStrArray[i];
2328 nPos = nPos + rStr.Len();
2329 SvNumberformat::EraseCommentBraces( rStr );
2330 rComment += rStr;
2331 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2332 nAnzResStrings--;
2333 i++;
2335 break;
2336 case NF_KEY_AMPM: // AM/PM
2337 case NF_KEY_AP: // A/P
2339 bExp = TRUE; // missbraucht fuer A/P
2340 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2341 nPos = nPos + sStrArray[i].Len();
2342 i++;
2344 break;
2345 case NF_KEY_THAI_T :
2346 bThaiT = true;
2347 // fall thru
2348 case NF_KEY_MI: // M
2349 case NF_KEY_MMI: // MM
2350 case NF_KEY_H: // H
2351 case NF_KEY_HH: // HH
2352 case NF_KEY_S: // S
2353 case NF_KEY_SS: // SS
2355 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2356 nPos = nPos + sStrArray[i].Len();
2357 i++;
2359 break;
2360 default: // andere Keywords
2362 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2363 nPos = nPos + sStrArray[i].Len();
2364 i++;
2366 break;
2368 } // of while
2369 nCntPost = nCounter; // Zaehler der Nullen
2370 if (bExp)
2371 nCntExp = 1; // merkt AM/PM
2373 break; // of NUMBERFORMAT_TIME
2374 case NUMBERFORMAT_DATETIME:
2376 BOOL bTimePart = FALSE;
2377 while (i < nAnzStrings)
2379 switch (nTypeArray[i])
2381 case NF_SYMBOLTYPE_BLANK:
2382 case NF_SYMBOLTYPE_STAR:
2383 case NF_SYMBOLTYPE_STRING:
2384 nPos = nPos + sStrArray[i].Len();
2385 i++;
2386 break;
2387 case NF_SYMBOLTYPE_COMMENT:
2389 String& rStr = sStrArray[i];
2390 nPos = nPos + rStr.Len();
2391 SvNumberformat::EraseCommentBraces( rStr );
2392 rComment += rStr;
2393 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2394 nAnzResStrings--;
2395 i++;
2397 break;
2398 case NF_SYMBOLTYPE_DEL:
2400 int nCalRet;
2401 if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2403 if ( nCalRet < 0 )
2404 return nPos; // error
2406 else
2408 switch( sStrArray[i].GetChar(0) )
2410 case '0':
2412 if ( bTimePart && Is100SecZero( i, bDecSep ) )
2414 bDecSep = TRUE;
2415 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2416 String& rStr = sStrArray[i];
2417 i++;
2418 nPos = nPos + sStrArray[i].Len();
2419 nCounter++;
2420 while (i < nAnzStrings &&
2421 sStrArray[i].GetChar(0) == '0')
2423 rStr += sStrArray[i];
2424 nPos = nPos + sStrArray[i].Len();
2425 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2426 nAnzResStrings--;
2427 nCounter++;
2428 i++;
2431 else
2432 return nPos;
2434 break;
2435 case '#':
2436 case '?':
2437 return nPos;
2438 default:
2440 nPos = nPos + sStrArray[i].Len();
2441 if (bTimePart)
2443 if ( sStrArray[i] == sOldTimeSep )
2445 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2446 if ( bConvertMode )
2447 sStrArray[i] = pLoc->getTimeSep();
2449 else if ( sStrArray[i] == sOldTime100SecSep )
2451 bDecSep = TRUE;
2452 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2453 if ( bConvertMode )
2454 sStrArray[i] = pLoc->getTime100SecSep();
2456 else
2457 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2459 else
2461 if ( sStrArray[i] == sOldDateSep )
2463 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2464 if (bConvertMode)
2465 sStrArray[i] = pFormatter->GetDateSep();
2467 else
2468 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2470 i++;
2475 break;
2476 case NF_KEY_AMPM: // AM/PM
2477 case NF_KEY_AP: // A/P
2479 bTimePart = TRUE;
2480 bExp = TRUE; // missbraucht fuer A/P
2481 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2482 nPos = nPos + sStrArray[i].Len();
2483 i++;
2485 break;
2486 case NF_KEY_MI: // M
2487 case NF_KEY_MMI: // MM
2488 case NF_KEY_H: // H
2489 case NF_KEY_HH: // HH
2490 case NF_KEY_S: // S
2491 case NF_KEY_SS: // SS
2492 bTimePart = TRUE;
2493 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2494 nPos = nPos + sStrArray[i].Len();
2495 i++;
2496 break;
2497 case NF_KEY_M: // M
2498 case NF_KEY_MM: // MM
2499 case NF_KEY_MMM: // MMM
2500 case NF_KEY_MMMM: // MMMM
2501 case NF_KEY_MMMMM: // MMMMM
2502 case NF_KEY_Q: // Q
2503 case NF_KEY_QQ: // QQ
2504 case NF_KEY_D: // D
2505 case NF_KEY_DD: // DD
2506 case NF_KEY_DDD: // DDD
2507 case NF_KEY_DDDD: // DDDD
2508 case NF_KEY_YY: // YY
2509 case NF_KEY_YYYY: // YYYY
2510 case NF_KEY_NN: // NN
2511 case NF_KEY_NNN: // NNN
2512 case NF_KEY_NNNN: // NNNN
2513 case NF_KEY_WW : // WW
2514 case NF_KEY_AAA : // AAA
2515 case NF_KEY_AAAA : // AAAA
2516 case NF_KEY_EC : // E
2517 case NF_KEY_EEC : // EE
2518 case NF_KEY_G : // G
2519 case NF_KEY_GG : // GG
2520 case NF_KEY_GGG : // GGG
2521 case NF_KEY_R : // R
2522 case NF_KEY_RR : // RR
2523 bTimePart = FALSE;
2524 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2525 nPos = nPos + sStrArray[i].Len();
2526 i++;
2527 break;
2528 case NF_KEY_THAI_T :
2529 bThaiT = true;
2530 sStrArray[i] = sKeyword[nTypeArray[i]];
2531 nPos = nPos + sStrArray[i].Len();
2532 i++;
2533 break;
2534 default: // andere Keywords
2535 nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2536 nPos = nPos + sStrArray[i].Len();
2537 i++;
2538 break;
2540 } // of while
2541 nCntPost = nCounter; // decimals (100th seconds)
2542 if (bExp)
2543 nCntExp = 1; // merkt AM/PM
2545 break; // of NUMBERFORMAT_DATETIME
2546 default:
2547 break;
2549 if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
2550 (nCntPre + nCntPost == 0 || nCntExp == 0))
2551 return nPos;
2552 else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
2553 return nPos;
2555 if (bThaiT && !GetNatNumModifier())
2556 SetNatNumModifier(1);
2558 if ( bConvertMode )
2559 { // strings containing keywords of the target locale must be quoted, so
2560 // the user sees the difference and is able to edit the format string
2561 for ( i=0; i < nAnzStrings; i++ )
2563 if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
2564 sStrArray[i].GetChar(0) != '\"' )
2566 if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
2567 { // don't stringize automatic currency, will be converted
2568 if ( sStrArray[i] == sOldCurSymbol )
2569 continue; // for
2570 // DM might be splitted into D and M
2571 if ( sStrArray[i].Len() < sOldCurSymbol.Len() &&
2572 pChrCls->toUpper( sStrArray[i], 0, 1 ).GetChar(0) ==
2573 sOldCurString.GetChar(0) )
2575 String aTmp( sStrArray[i] );
2576 USHORT j = i + 1;
2577 while ( aTmp.Len() < sOldCurSymbol.Len() &&
2578 j < nAnzStrings &&
2579 nTypeArray[j] == NF_SYMBOLTYPE_STRING )
2581 aTmp += sStrArray[j++];
2583 if ( pChrCls->upper( aTmp ) == sOldCurString )
2585 sStrArray[i++] = aTmp;
2586 for ( ; i<j; i++ )
2588 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2589 nAnzResStrings--;
2591 i = j - 1;
2592 continue; // for
2596 String& rStr = sStrArray[i];
2597 xub_StrLen nLen = rStr.Len();
2598 for ( xub_StrLen j=0; j<nLen; j++ )
2600 if ( (j == 0 || rStr.GetChar(j-1) != '\\') && GetKeyWord( rStr, j ) )
2602 rStr.Insert( '\"', 0 );
2603 rStr += '\"';
2604 break; // for
2610 // concatenate strings, remove quotes for output, and rebuild the format string
2611 rString.Erase();
2612 i = 0;
2613 while (i < nAnzStrings)
2615 switch ( nTypeArray[i] )
2617 case NF_SYMBOLTYPE_STRING :
2619 xub_StrLen nStringPos = rString.Len();
2620 xub_StrLen nArrPos = 0;
2621 USHORT iPos = i;
2624 if (sStrArray[i].Len() == 2 &&
2625 sStrArray[i].GetChar(0) == '\\')
2627 // Unescape some simple forms of symbols even in the UI
2628 // visible string to prevent duplicates that differ
2629 // only in notation, originating from import.
2630 // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
2631 // but 0\ 000 0 and 0 000 0 in a French locale are not.
2632 sal_Unicode c = sStrArray[i].GetChar(1);
2633 switch (c)
2635 case '+':
2636 case '-':
2637 rString += c;
2638 break;
2639 case ' ':
2640 case '.':
2641 case '/':
2642 if (((eScannedType & NUMBERFORMAT_DATE) == 0)
2643 && (StringEqualsChar(
2644 pFormatter->GetNumThousandSep(),
2645 c) || StringEqualsChar(
2646 pFormatter->GetNumDecimalSep(),
2647 c) || (c == ' ' &&
2648 StringEqualsChar(
2649 pFormatter->GetNumThousandSep(),
2650 cNonBreakingSpace))))
2651 rString += sStrArray[i];
2652 else if ((eScannedType & NUMBERFORMAT_DATE) &&
2653 StringEqualsChar(
2654 pFormatter->GetDateSep(), c))
2655 rString += sStrArray[i];
2656 else if ((eScannedType & NUMBERFORMAT_TIME) &&
2657 (StringEqualsChar( pLoc->getTimeSep(),
2658 c) ||
2659 StringEqualsChar(
2660 pLoc->getTime100SecSep(), c)))
2661 rString += sStrArray[i];
2662 else if (eScannedType & NUMBERFORMAT_FRACTION)
2663 rString += sStrArray[i];
2664 else
2665 rString += c;
2666 break;
2667 default:
2668 rString += sStrArray[i];
2671 else
2672 rString += sStrArray[i];
2673 if ( RemoveQuotes( sStrArray[i] ) > 0 )
2674 { // update currency up to quoted string
2675 if ( eScannedType == NUMBERFORMAT_CURRENCY )
2676 { // dM -> DM or DM -> $ in old automatic
2677 // currency formats, oh my ..., why did we ever
2678 // introduce them?
2679 String aTmp( pChrCls->toUpper(
2680 sStrArray[iPos], nArrPos,
2681 sStrArray[iPos].Len()-nArrPos ) );
2682 xub_StrLen nCPos = aTmp.Search( sOldCurString );
2683 if ( nCPos != STRING_NOTFOUND )
2685 const String& rCur =
2686 bConvertMode && bConvertSystemToSystem ?
2687 GetCurSymbol() : sOldCurSymbol;
2688 sStrArray[iPos].Replace( nArrPos+nCPos,
2689 sOldCurString.Len(), rCur );
2690 rString.Replace( nStringPos+nCPos,
2691 sOldCurString.Len(), rCur );
2693 nStringPos = rString.Len();
2694 if ( iPos == i )
2695 nArrPos = sStrArray[iPos].Len();
2696 else
2697 nArrPos = sStrArray[iPos].Len() + sStrArray[i].Len();
2700 if ( iPos != i )
2702 sStrArray[iPos] += sStrArray[i];
2703 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2704 nAnzResStrings--;
2706 i++;
2707 } while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
2708 if ( i < nAnzStrings )
2709 i--; // enter switch on next symbol again
2710 if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.Len() )
2711 { // same as above, since last RemoveQuotes
2712 String aTmp( pChrCls->toUpper(
2713 sStrArray[iPos], nArrPos,
2714 sStrArray[iPos].Len()-nArrPos ) );
2715 xub_StrLen nCPos = aTmp.Search( sOldCurString );
2716 if ( nCPos != STRING_NOTFOUND )
2718 const String& rCur =
2719 bConvertMode && bConvertSystemToSystem ?
2720 GetCurSymbol() : sOldCurSymbol;
2721 sStrArray[iPos].Replace( nArrPos+nCPos,
2722 sOldCurString.Len(), rCur );
2723 rString.Replace( nStringPos+nCPos,
2724 sOldCurString.Len(), rCur );
2728 break;
2729 case NF_SYMBOLTYPE_CURRENCY :
2731 rString += sStrArray[i];
2732 RemoveQuotes( sStrArray[i] );
2734 break;
2735 case NF_KEY_THAI_T:
2736 if (bThaiT && GetNatNumModifier() == 1)
2737 { // Remove T from format code, will be replaced with a [NatNum1] prefix.
2738 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2739 nAnzResStrings--;
2741 else
2742 rString += sStrArray[i];
2743 break;
2744 case NF_SYMBOLTYPE_EMPTY :
2745 // nothing
2746 break;
2747 default:
2748 rString += sStrArray[i];
2750 i++;
2752 return 0;
2756 xub_StrLen ImpSvNumberformatScan::RemoveQuotes( String& rStr )
2758 if ( rStr.Len() > 1 )
2760 sal_Unicode c = rStr.GetChar(0);
2761 xub_StrLen n;
2762 if ( c == '"' && rStr.GetChar( (n = xub_StrLen(rStr.Len()-1)) ) == '"' )
2764 rStr.Erase(n,1);
2765 rStr.Erase(0,1);
2766 return 2;
2768 else if ( c == '\\' )
2770 rStr.Erase(0,1);
2771 return 1;
2774 return 0;
2778 xub_StrLen ImpSvNumberformatScan::ScanFormat( String& rString, String& rComment )
2780 xub_StrLen res = Symbol_Division(rString); //lexikalische Analyse
2781 if (!res)
2782 res = ScanType(rString); // Erkennung des Formattyps
2783 if (!res)
2784 res = FinalScan( rString, rComment ); // Typabhaengige Endanalyse
2785 return res; // res = Kontrollposition
2786 // res = 0 => Format ok
2789 void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, USHORT nAnz)
2791 size_t i,j;
2792 j = 0;
2793 i = 0;
2794 while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
2796 if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
2798 pInfo->sStrArray[i] = sStrArray[j];
2799 pInfo->nTypeArray[i] = nTypeArray[j];
2800 i++;
2802 j++;
2804 pInfo->eScannedType = eScannedType;
2805 pInfo->bThousand = bThousand;
2806 pInfo->nThousand = nThousand;
2807 pInfo->nCntPre = nCntPre;
2808 pInfo->nCntPost = nCntPost;
2809 pInfo->nCntExp = nCntExp;