xref: /AOO41X/main/svl/source/numbers/zforfind.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svl.hxx"
30 
31 #include <ctype.h>
32 #include <stdlib.h>
33 #include <float.h>
34 #include <errno.h>
35 #include <tools/date.hxx>
36 #include <tools/debug.hxx>
37 #include <rtl/math.hxx>
38 #include <unotools/charclass.hxx>
39 #include <unotools/calendarwrapper.hxx>
40 #include <unotools/localedatawrapper.hxx>
41 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
42 #include <unotools/digitgroupingiterator.hxx>
43 
44 #include <svl/zforlist.hxx>         // NUMBERFORMAT_XXX
45 #include "zforscan.hxx"
46 #include <svl/zformat.hxx>
47 
48 #define _ZFORFIND_CXX
49 #include "zforfind.hxx"
50 #undef _ZFORFIND_CXX
51 
52 
53 #ifndef DBG_UTIL
54 #define NF_TEST_CALENDAR 0
55 #else
56 #define NF_TEST_CALENDAR 0
57 #endif
58 #if NF_TEST_CALENDAR
59 #include <comphelper/processfactory.hxx>
60 #include <com/sun/star/i18n/XExtendedCalendar.hpp>
61 #endif
62 
63 
64 const sal_uInt8 ImpSvNumberInputScan::nMatchedEndString    = 0x01;
65 const sal_uInt8 ImpSvNumberInputScan::nMatchedMidString    = 0x02;
66 const sal_uInt8 ImpSvNumberInputScan::nMatchedStartString  = 0x04;
67 const sal_uInt8 ImpSvNumberInputScan::nMatchedVirgin       = 0x08;
68 const sal_uInt8 ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
69 
70 /* It is not clear how we want timezones to be handled. Convert them to local
71  * time isn't wanted, as it isn't done in any other place and timezone
72  * information isn't stored anywhere. Ignoring them and pretending local time
73  * may be wrong too and might not be what the user expects. Keep the input as
74  * string so that no information is lost.
75  * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
76  * would work, together with the nTimezonePos handling in GetTimeRef(). */
77 #define NF_RECOGNIZE_ISO8601_TIMEZONES 0
78 
79 //---------------------------------------------------------------------------
80 //      Konstruktor
81 
82 ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
83         :
84         pUpperMonthText( NULL ),
85         pUpperAbbrevMonthText( NULL ),
86         pUpperDayText( NULL ),
87         pUpperAbbrevDayText( NULL )
88 {
89     pFormatter = pFormatterP;
90     pNullDate = new Date(30,12,1899);
91     nYear2000 = SvNumberFormatter::GetYear2000Default();
92     Reset();
93     ChangeIntl();
94 }
95 
96 
97 //---------------------------------------------------------------------------
98 //      Destruktor
99 
100 ImpSvNumberInputScan::~ImpSvNumberInputScan()
101 {
102     Reset();
103     delete pNullDate;
104     delete [] pUpperMonthText;
105     delete [] pUpperAbbrevMonthText;
106     delete [] pUpperDayText;
107     delete [] pUpperAbbrevDayText;
108 }
109 
110 
111 //---------------------------------------------------------------------------
112 //      Reset
113 
114 void ImpSvNumberInputScan::Reset()
115 {
116 #if 0
117 // ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision,
118 // wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht
119 // gebraucht wird..
120     for (sal_uInt16 i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
121     {
122         sStrArray[i].Erase();
123         nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1;
124         IsNum[i] = sal_False;
125     }
126 #endif
127     nMonth       = 0;
128     nMonthPos    = 0;
129     nTimePos     = 0;
130     nSign        = 0;
131     nESign       = 0;
132     nDecPos      = 0;
133     nNegCheck    = 0;
134     nAnzStrings  = 0;
135     nAnzNums     = 0;
136     nThousand    = 0;
137     eScannedType = NUMBERFORMAT_UNDEFINED;
138     nAmPm        = 0;
139     nPosThousandString = 0;
140     nLogical     = 0;
141     nStringScanNumFor = 0;
142     nStringScanSign = 0;
143     nMatchedAllStrings = nMatchedVirgin;
144     nMayBeIso8601 = 0;
145     nTimezonePos = 0;
146 }
147 
148 
149 //---------------------------------------------------------------------------
150 //
151 // static
152 inline sal_Bool ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
153 {
154     // If the input string wouldn't be converted using TransformInput() we'd
155     // to use something similar to the following and to adapt many places.
156 #if 0
157     // use faster isdigit() if possible
158     if ( c < 128 )
159         return isdigit( (unsigned char) c ) != 0;
160     if ( c < 256 )
161         return sal_False;
162     String aTmp( c );
163     return pFormatter->GetCharClass()->isDigit( aTmp, 0 );
164 #else
165     return c < 128 && isdigit( (unsigned char) c );
166 #endif
167 }
168 
169 
170 //---------------------------------------------------------------------------
171 //
172 void ImpSvNumberInputScan::TransformInput( String& rStr )
173 {
174     xub_StrLen nPos, nLen;
175     for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos )
176     {
177         if ( 256 <= rStr.GetChar( nPos ) &&
178                 pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
179             break;
180     }
181     if ( nPos < nLen )
182         rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
183                 pFormatter->GetLocale(), 0 );
184 }
185 
186 
187 //---------------------------------------------------------------------------
188 //      StringToDouble
189 //
190 // Only simple unsigned floating point values without any error detection,
191 // decimal separator has to be '.'
192 
193 double ImpSvNumberInputScan::StringToDouble( const String& rStr, sal_Bool bForceFraction )
194 {
195     double fNum = 0.0;
196     double fFrac = 0.0;
197     int nExp = 0;
198     xub_StrLen nPos = 0;
199     xub_StrLen nLen = rStr.Len();
200     sal_Bool bPreSep = !bForceFraction;
201 
202     while (nPos < nLen)
203     {
204         if (rStr.GetChar(nPos) == '.')
205             bPreSep = sal_False;
206         else if (bPreSep)
207             fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0');
208         else
209         {
210             fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0');
211             --nExp;
212         }
213         nPos++;
214     }
215     if ( fFrac )
216         return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
217     return fNum;
218 }
219 
220 
221 //---------------------------------------------------------------------------
222 //       NextNumberStringSymbol
223 //
224 // Zerlegt die Eingabe in Zahlen und Strings fuer die weitere
225 // Verarbeitung (Turing-Maschine).
226 //---------------------------------------------------------------------------
227 // Ausgangs Zustand = GetChar
228 //---------------+-------------------+-----------------------+---------------
229 // Alter Zustand | gelesenes Zeichen | Aktion                | Neuer Zustand
230 //---------------+-------------------+-----------------------+---------------
231 // GetChar       | Ziffer            | Symbol=Zeichen        | GetValue
232 //               | Sonst             | Symbol=Zeichen        | GetString
233 //---------------|-------------------+-----------------------+---------------
234 // GetValue      | Ziffer            | Symbol=Symbol+Zeichen | GetValue
235 //               | Sonst             | Dec(CharPos)          | Stop
236 //---------------+-------------------+-----------------------+---------------
237 // GetString     | Ziffer            | Dec(CharPos)          | Stop
238 //               | Sonst             | Symbol=Symbol+Zeichen | GetString
239 //---------------+-------------------+-----------------------+---------------
240 
241 enum ScanState              // States der Turing-Maschine
242 {
243     SsStop      = 0,
244     SsStart     = 1,
245     SsGetValue  = 2,
246     SsGetString = 3
247 };
248 
249 sal_Bool ImpSvNumberInputScan::NextNumberStringSymbol(
250         const sal_Unicode*& pStr,
251         String& rSymbol )
252 {
253     sal_Bool isNumber = sal_False;
254     sal_Unicode cToken;
255     ScanState eState = SsStart;
256     register const sal_Unicode* pHere = pStr;
257     register xub_StrLen nChars = 0;
258 
259     while ( ((cToken = *pHere) != 0) && eState != SsStop)
260     {
261         pHere++;
262         switch (eState)
263         {
264             case SsStart:
265                 if ( MyIsdigit( cToken ) )
266                 {
267                     eState = SsGetValue;
268                     isNumber = sal_True;
269                 }
270                 else
271                     eState = SsGetString;
272                 nChars++;
273                 break;
274             case SsGetValue:
275                 if ( MyIsdigit( cToken ) )
276                     nChars++;
277                 else
278                 {
279                     eState = SsStop;
280                     pHere--;
281                 }
282                 break;
283             case SsGetString:
284                 if ( !MyIsdigit( cToken ) )
285                     nChars++;
286                 else
287                 {
288                     eState = SsStop;
289                     pHere--;
290                 }
291                 break;
292             default:
293                 break;
294         }   // switch
295     }   // while
296 
297     if ( nChars )
298         rSymbol.Assign( pStr, nChars );
299     else
300         rSymbol.Erase();
301 
302     pStr = pHere;
303 
304     return isNumber;
305 }
306 
307 
308 //---------------------------------------------------------------------------
309 //      SkipThousands
310 
311 // FIXME: should be grouping; it is only used though in case nAnzStrings is
312 // near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision().
313 
314 sal_Bool ImpSvNumberInputScan::SkipThousands(
315         const sal_Unicode*& pStr,
316         String& rSymbol )
317 {
318     sal_Bool res = sal_False;
319     sal_Unicode cToken;
320     const String& rThSep = pFormatter->GetNumThousandSep();
321     register const sal_Unicode* pHere = pStr;
322     ScanState eState = SsStart;
323     xub_StrLen nCounter = 0;                                // counts 3 digits
324 
325     while ( ((cToken = *pHere) != 0) && eState != SsStop)
326     {
327         pHere++;
328         switch (eState)
329         {
330             case SsStart:
331                 if ( StringPtrContains( rThSep, pHere-1, 0 ) )
332                 {
333                     nCounter = 0;
334                     eState = SsGetValue;
335                     pHere += rThSep.Len()-1;
336                 }
337                 else
338                 {
339                     eState = SsStop;
340                     pHere--;
341                 }
342                 break;
343             case SsGetValue:
344                 if ( MyIsdigit( cToken ) )
345                 {
346                     rSymbol += cToken;
347                     nCounter++;
348                     if (nCounter == 3)
349                     {
350                         eState = SsStart;
351                         res = sal_True;                 // .000 combination found
352                     }
353                 }
354                 else
355                 {
356                     eState = SsStop;
357                     pHere--;
358                 }
359                 break;
360             default:
361                 break;
362         }   // switch
363     }   // while
364 
365     if (eState == SsGetValue)               // break witth less than 3 digits
366     {
367         if ( nCounter )
368             rSymbol.Erase( rSymbol.Len() - nCounter, nCounter );
369         pHere -= nCounter + rThSep.Len();       // put back ThSep also
370     }
371     pStr = pHere;
372 
373     return res;
374 }
375 
376 
377 //---------------------------------------------------------------------------
378 //      NumberStringDivision
379 
380 void ImpSvNumberInputScan::NumberStringDivision( const String& rString )
381 {
382     const sal_Unicode* pStr = rString.GetBuffer();
383     const sal_Unicode* const pEnd = pStr + rString.Len();
384     while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
385     {
386         if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
387         {                                               // Zahl
388             IsNum[nAnzStrings] = sal_True;
389             nNums[nAnzNums] = nAnzStrings;
390             nAnzNums++;
391             if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
392                 nPosThousandString == 0)                // nur einmal
393                 if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
394                     nPosThousandString = nAnzStrings;
395         }
396         else
397         {
398             IsNum[nAnzStrings] = sal_False;
399         }
400         nAnzStrings++;
401     }
402 }
403 
404 
405 //---------------------------------------------------------------------------
406 // Whether rString contains rWhat at nPos
407 
408 sal_Bool ImpSvNumberInputScan::StringContainsImpl( const String& rWhat,
409             const String& rString, xub_StrLen nPos )
410 {
411     if ( nPos + rWhat.Len() <= rString.Len() )
412         return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos );
413     return sal_False;
414 }
415 
416 
417 //---------------------------------------------------------------------------
418 // Whether pString contains rWhat at nPos
419 
420 sal_Bool ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat,
421             const sal_Unicode* pString, xub_StrLen nPos )
422 {
423     if ( rWhat.Len() == 0 )
424         return sal_False;
425     register const sal_Unicode* pWhat = rWhat.GetBuffer();
426     register const sal_Unicode* const pEnd = pWhat + rWhat.Len();
427     register const sal_Unicode* pStr = pString + nPos;
428     while ( pWhat < pEnd )
429     {
430         if ( *pWhat != *pStr )
431             return sal_False;
432         pWhat++;
433         pStr++;
434     }
435     return sal_True;
436 }
437 
438 
439 //---------------------------------------------------------------------------
440 //      SkipChar
441 //
442 // ueberspringt genau das angegebene Zeichen
443 
444 inline sal_Bool ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString,
445         xub_StrLen& nPos )
446 {
447     if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c))
448     {
449         nPos++;
450         return sal_True;
451     }
452     return sal_False;
453 }
454 
455 
456 //---------------------------------------------------------------------------
457 //      SkipBlanks
458 //
459 // Ueberspringt Leerzeichen
460 
461 inline void ImpSvNumberInputScan::SkipBlanks( const String& rString,
462         xub_StrLen& nPos )
463 {
464     if ( nPos < rString.Len() )
465     {
466         register const sal_Unicode* p = rString.GetBuffer() + nPos;
467         while ( *p == ' ' )
468         {
469             nPos++;
470             p++;
471         }
472     }
473 }
474 
475 
476 //---------------------------------------------------------------------------
477 //      SkipString
478 //
479 // jump over rWhat in rString at nPos
480 
481 inline sal_Bool ImpSvNumberInputScan::SkipString( const String& rWhat,
482         const String& rString, xub_StrLen& nPos )
483 {
484     if ( StringContains( rWhat, rString, nPos ) )
485     {
486         nPos = nPos + rWhat.Len();
487         return sal_True;
488     }
489     return sal_False;
490 }
491 
492 
493 //---------------------------------------------------------------------------
494 //      GetThousandSep
495 //
496 // recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping
497 
498 inline sal_Bool ImpSvNumberInputScan::GetThousandSep(
499         const String& rString,
500         xub_StrLen& nPos,
501         sal_uInt16 nStringPos )
502 {
503     const String& rSep = pFormatter->GetNumThousandSep();
504     // Is it an ordinary space instead of a non-breaking space?
505     bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 &&
506         rSep.Len() == 1 && rString.Len() == 1;
507     if (!( (rString == rSep || bSpaceBreak)             // nothing else
508                 && nStringPos < nAnzStrings - 1         // safety first!
509                 && IsNum[nStringPos+1] ))               // number follows
510         return sal_False;                                   // no? => out
511 
512     utl::DigitGroupingIterator aGrouping(
513             pFormatter->GetLocaleData()->getDigitGrouping());
514     // Match ,### in {3} or ,## in {3,2}
515     /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or
516      * ,##,### and to match ,### in {3,2} only if it's the last. However,
517      * currently there is no track kept where group separators occur. In {3,2}
518      * #,###,### and #,##,## would be valid input, which maybe isn't even bad
519      * for #,###,###. Other combinations such as #,###,## maybe not. */
520     xub_StrLen nLen = sStrArray[nStringPos+1].Len();
521     if (nLen == aGrouping.get()                         // with 3 (or so) digits
522             || nLen == aGrouping.advance().get()        // or with 2 (or 3 or so) digits
523             || nPosThousandString == nStringPos+1       // or concatenated
524        )
525     {
526         nPos = nPos + rSep.Len();
527         return sal_True;
528     }
529     return sal_False;
530 }
531 
532 
533 //---------------------------------------------------------------------------
534 //      GetLogical
535 //
536 // Conversion of text to logial value
537 // "sal_True" =>  1:
538 // "sal_False"=> -1:
539 // else   =>  0:
540 
541 short ImpSvNumberInputScan::GetLogical( const String& rString )
542 {
543     short res;
544 
545     const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
546     if ( rString == pFS->GetTrueString() )
547         res = 1;
548     else if ( rString == pFS->GetFalseString() )
549         res = -1;
550     else
551         res = 0;
552 
553     return res;
554 }
555 
556 
557 //---------------------------------------------------------------------------
558 //      GetMonth
559 //
560 // Converts a string containing a month name (JAN, January) at nPos into the
561 // month number (negative if abbreviated), returns 0 if nothing found
562 
563 short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos )
564 {
565     // #102136# The correct English form of month September abbreviated is
566     // SEPT, but almost every data contains SEP instead.
567     static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
568     static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
569 
570     short res = 0;      // no month found
571 
572     if (rString.Len() > nPos)                           // only if needed
573     {
574         if ( !bTextInitialized )
575             InitText();
576         sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
577         for ( sal_Int16 i = 0; i < nMonths; i++ )
578         {
579             if ( StringContains( pUpperMonthText[i], rString, nPos ) )
580             {                                           // full names first
581                 nPos = nPos + pUpperMonthText[i].Len();
582                 res = i+1;
583                 break;  // for
584             }
585             else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) )
586             {                                           // abbreviated
587                 nPos = nPos + pUpperAbbrevMonthText[i].Len();
588                 res = sal::static_int_cast< short >(-(i+1)); // negative
589                 break;  // for
590             }
591             else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
592                     StringContains( aSepShortened, rString, nPos ) )
593             {                                           // #102136# SEPT/SEP
594                 nPos = nPos + aSepShortened.Len();
595                 res = sal::static_int_cast< short >(-(i+1)); // negative
596                 break;  // for
597             }
598         }
599     }
600 
601     return res;
602 }
603 
604 
605 //---------------------------------------------------------------------------
606 //      GetDayOfWeek
607 //
608 // Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
609 // DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
610 
611 int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos )
612 {
613     int res = 0;      // no day found
614 
615     if (rString.Len() > nPos)                           // only if needed
616     {
617         if ( !bTextInitialized )
618             InitText();
619         sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
620         for ( sal_Int16 i = 0; i < nDays; i++ )
621         {
622             if ( StringContains( pUpperDayText[i], rString, nPos ) )
623             {                                           // full names first
624                 nPos = nPos + pUpperDayText[i].Len();
625                 res = i + 1;
626                 break;  // for
627             }
628             if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) )
629             {                                           // abbreviated
630                 nPos = nPos + pUpperAbbrevDayText[i].Len();
631                 res = -(i + 1);                         // negative
632                 break;  // for
633             }
634         }
635     }
636 
637     return res;
638 }
639 
640 
641 //---------------------------------------------------------------------------
642 //      GetCurrency
643 //
644 // Lesen eines Waehrungssysmbols
645 // '$'   => sal_True
646 // sonst => sal_False
647 
648 sal_Bool ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos,
649             const SvNumberformat* pFormat )
650 {
651     if ( rString.Len() > nPos )
652     {
653         if ( !aUpperCurrSymbol.Len() )
654         {   // if no format specified the currency of the initialized formatter
655             LanguageType eLang = (pFormat ? pFormat->GetLanguage() :
656                 pFormatter->GetLanguage());
657             aUpperCurrSymbol = pFormatter->GetCharClass()->upper(
658                 SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
659         }
660         if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
661         {
662             nPos = nPos + aUpperCurrSymbol.Len();
663             return sal_True;
664         }
665         if ( pFormat )
666         {
667             String aSymbol, aExtension;
668             if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
669             {
670                 if ( aSymbol.Len() <= rString.Len() - nPos )
671                 {
672                     pFormatter->GetCharClass()->toUpper( aSymbol );
673                     if ( StringContains( aSymbol, rString, nPos ) )
674                     {
675                         nPos = nPos + aSymbol.Len();
676                         return sal_True;
677                     }
678                 }
679             }
680         }
681     }
682 
683     return sal_False;
684 }
685 
686 
687 //---------------------------------------------------------------------------
688 //      GetTimeAmPm
689 //
690 // Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe
691 //
692 // Rueckgabe:
693 //  "AM" od. "PM" => sal_True
694 //  sonst         => sal_False
695 //
696 // nAmPos:
697 //  "AM"  =>  1
698 //  "PM"  => -1
699 //  sonst =>  0
700 
701 sal_Bool ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos )
702 {
703 
704     if ( rString.Len() > nPos )
705     {
706         const CharClass* pChr = pFormatter->GetCharClass();
707         const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
708         if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) )
709         {
710             nAmPm = 1;
711             nPos = nPos + pLoc->getTimeAM().Len();
712             return sal_True;
713         }
714         else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) )
715         {
716             nAmPm = -1;
717             nPos = nPos + pLoc->getTimePM().Len();
718             return sal_True;
719         }
720     }
721 
722     return sal_False;
723 }
724 
725 
726 //---------------------------------------------------------------------------
727 //      GetDecSep
728 //
729 // Lesen eines Dezimaltrenners (',')
730 // ','   => sal_True
731 // sonst => sal_False
732 
733 inline sal_Bool ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos )
734 {
735     if ( rString.Len() > nPos )
736     {
737         const String& rSep = pFormatter->GetNumDecimalSep();
738         if ( rString.Equals( rSep, nPos, rSep.Len() ) )
739         {
740             nPos = nPos + rSep.Len();
741             return sal_True;
742         }
743     }
744     return sal_False;
745 }
746 
747 
748 //---------------------------------------------------------------------------
749 // read a hundredth seconds separator
750 
751 inline sal_Bool ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos )
752 {
753     if ( rString.Len() > nPos )
754     {
755         const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
756         if ( rString.Equals( rSep, nPos, rSep.Len() ) )
757         {
758             nPos = nPos + rSep.Len();
759             return sal_True;
760         }
761     }
762     return sal_False;
763 }
764 
765 
766 //---------------------------------------------------------------------------
767 //      GetSign
768 //
769 // Lesen eines Vorzeichens, auch Klammer !?!
770 // '+'   =>  1
771 // '-'   => -1
772 // '('   => -1, nNegCheck = 1
773 // sonst =>  0
774 
775 int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos )
776 {
777     if (rString.Len() > nPos)
778         switch (rString.GetChar(nPos))
779         {
780             case '+':
781                 nPos++;
782                 return 1;
783             case '(':               // '(' aehnlich wie '-' ?!?
784                 nNegCheck = 1;
785                 //! fallthru
786             case '-':
787                 nPos++;
788                 return -1;
789             default:
790                 break;
791         }
792 
793     return 0;
794 }
795 
796 
797 //---------------------------------------------------------------------------
798 //      GetESign
799 //
800 // Lesen eines Vorzeichens, gedacht fuer Exponent ?!?
801 // '+'   =>  1
802 // '-'   => -1
803 // sonst =>  0
804 
805 short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos )
806 {
807     if (rString.Len() > nPos)
808         switch (rString.GetChar(nPos))
809         {
810             case '+':
811                 nPos++;
812                 return 1;
813             case '-':
814                 nPos++;
815                 return -1;
816             default:
817                 break;
818         }
819 
820     return 0;
821 }
822 
823 
824 //---------------------------------------------------------------------------
825 //      GetNextNumber
826 //
827 // i counts string portions, j counts numbers thereof.
828 // It should had been called SkipNumber instead.
829 
830 inline sal_Bool ImpSvNumberInputScan::GetNextNumber( sal_uInt16& i, sal_uInt16& j )
831 {
832     if ( i < nAnzStrings && IsNum[i] )
833     {
834         j++;
835         i++;
836         return sal_True;
837     }
838     return sal_False;
839 }
840 
841 
842 //---------------------------------------------------------------------------
843 //      GetTimeRef
844 
845 void ImpSvNumberInputScan::GetTimeRef(
846         double& fOutNumber,
847         sal_uInt16 nIndex,          // j-value of the first numeric time part of input, default 0
848         sal_uInt16 nAnz )           // count of numeric time parts
849 {
850     sal_uInt16 nHour;
851     sal_uInt16 nMinute = 0;
852     sal_uInt16 nSecond = 0;
853     double fSecond100 = 0.0;
854     sal_uInt16 nStartIndex = nIndex;
855 
856     if (nTimezonePos)
857     {
858         // find first timezone number index and adjust count
859         for (sal_uInt16 j=0; j<nAnzNums; ++j)
860         {
861             if (nNums[j] == nTimezonePos)
862             {
863                 // nAnz is not total count, but count of time relevant strings.
864                 if (nStartIndex < j && j - nStartIndex < nAnz)
865                     nAnz = j - nStartIndex;
866                 break;  // for
867             }
868         }
869     }
870 
871     if (nDecPos == 2 && (nAnz == 3 || nAnz == 2))   // 20:45.5 or 45.5
872         nHour = 0;
873     else if (nIndex - nStartIndex < nAnz)
874         nHour   = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
875     else
876     {
877         nHour = 0;
878         DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index");
879     }
880     if (nDecPos == 2 && nAnz == 2)                  // 45.5
881         nMinute = 0;
882     else if (nIndex - nStartIndex < nAnz)
883         nMinute = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
884     if (nIndex - nStartIndex < nAnz)
885         nSecond = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
886     if (nIndex - nStartIndex < nAnz)
887         fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], sal_True );
888     if (nAmPm == -1 && nHour != 12)             // PM
889         nHour += 12;
890     else if (nAmPm == 1 && nHour == 12)         // 12 AM
891         nHour = 0;
892 
893     fOutNumber = ((double)nHour*3600 +
894                   (double)nMinute*60 +
895                   (double)nSecond +
896                   fSecond100)/86400.0;
897 }
898 
899 
900 //---------------------------------------------------------------------------
901 //      ImplGetDay
902 
903 sal_uInt16 ImpSvNumberInputScan::ImplGetDay( sal_uInt16 nIndex )
904 {
905     sal_uInt16 nRes = 0;
906 
907     if (sStrArray[nNums[nIndex]].Len() <= 2)
908     {
909         sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
910         if (nNum <= 31)
911             nRes = nNum;
912     }
913 
914     return nRes;
915 }
916 
917 
918 //---------------------------------------------------------------------------
919 //      ImplGetMonth
920 
921 sal_uInt16 ImpSvNumberInputScan::ImplGetMonth( sal_uInt16 nIndex )
922 {
923     // preset invalid month number
924     sal_uInt16 nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
925 
926     if (sStrArray[nNums[nIndex]].Len() <= 2)
927     {
928         sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
929         if ( 0 < nNum && nNum <= nRes )
930             nRes = nNum - 1;        // zero based for CalendarFieldIndex::MONTH
931     }
932 
933     return nRes;
934 }
935 
936 
937 //---------------------------------------------------------------------------
938 //      ImplGetYear
939 //
940 // 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ...
941 
942 sal_uInt16 ImpSvNumberInputScan::ImplGetYear( sal_uInt16 nIndex )
943 {
944     sal_uInt16 nYear = 0;
945 
946     if (sStrArray[nNums[nIndex]].Len() <= 4)
947     {
948         nYear = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
949         nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
950     }
951 
952     return nYear;
953 }
954 
955 //---------------------------------------------------------------------------
956 
957 bool ImpSvNumberInputScan::MayBeIso8601()
958 {
959     if (nMayBeIso8601 == 0)
960     {
961         if (nAnzNums >= 3 && nNums[0] < nAnzStrings &&
962                 sStrArray[nNums[0]].ToInt32() > 31)
963             nMayBeIso8601 = 1;
964         else
965             nMayBeIso8601 = 2;
966     }
967     return nMayBeIso8601 == 1;
968 }
969 
970 //---------------------------------------------------------------------------
971 //      GetDateRef
972 
973 sal_Bool ImpSvNumberInputScan::GetDateRef( double& fDays, sal_uInt16& nCounter,
974         const SvNumberformat* pFormat )
975 {
976     using namespace ::com::sun::star::i18n;
977     NfEvalDateFormat eEDF;
978     int nFormatOrder;
979     if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) )
980     {
981         eEDF = pFormatter->GetEvalDateFormat();
982         switch ( eEDF )
983         {
984             case NF_EVALDATEFORMAT_INTL :
985             case NF_EVALDATEFORMAT_FORMAT :
986                 nFormatOrder = 1;       // only one loop
987             break;
988             default:
989                 nFormatOrder = 2;
990                 if ( nMatchedAllStrings )
991                     eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
992                     // we have a complete match, use it
993         }
994     }
995     else
996     {
997         eEDF = NF_EVALDATEFORMAT_INTL;
998         nFormatOrder = 1;
999     }
1000     sal_Bool res = sal_True;
1001 
1002     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1003     CalendarWrapper* pCal = pFormatter->GetCalendar();
1004     for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
1005     {
1006         pCal->setGregorianDateTime( Date() );       // today
1007         String aOrgCalendar;        // empty => not changed yet
1008         DateFormat DateFmt;
1009         sal_Bool bFormatTurn;
1010         switch ( eEDF )
1011         {
1012             case NF_EVALDATEFORMAT_INTL :
1013                 bFormatTurn = sal_False;
1014                 DateFmt = pLoc->getDateFormat();
1015             break;
1016             case NF_EVALDATEFORMAT_FORMAT :
1017                 bFormatTurn = sal_True;
1018                 DateFmt = pFormat->GetDateOrder();
1019             break;
1020             case NF_EVALDATEFORMAT_INTL_FORMAT :
1021                 if ( nTryOrder == 1 )
1022                 {
1023                     bFormatTurn = sal_False;
1024                     DateFmt = pLoc->getDateFormat();
1025                 }
1026                 else
1027                 {
1028                     bFormatTurn = sal_True;
1029                     DateFmt = pFormat->GetDateOrder();
1030                 }
1031             break;
1032             case NF_EVALDATEFORMAT_FORMAT_INTL :
1033                 if ( nTryOrder == 2 )
1034                 {
1035                     bFormatTurn = sal_False;
1036                     DateFmt = pLoc->getDateFormat();
1037                 }
1038                 else
1039                 {
1040                     bFormatTurn = sal_True;
1041                     DateFmt = pFormat->GetDateOrder();
1042                 }
1043             break;
1044             default:
1045                 DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
1046 				DateFmt = YMD;
1047 				bFormatTurn = sal_False;
1048         }
1049         if ( bFormatTurn )
1050         {
1051 #if 0
1052 /* TODO:
1053 We are currently not able to fully support a switch to another calendar during
1054 input for the following reasons:
1055 1. We do have a problem if both (locale's default and format's) calendars
1056    define the same YMD order and use the same date separator, there is no way
1057    to distinguish between them if the input results in valid calendar input for
1058    both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
1059    it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
1060    calendar be preferred? This could be confusing if a Calc cell was formatted
1061    different to the locale's default and has no content yet, then the user has
1062    no clue about the format or calendar being set.
1063 2. In Calc cell edit mode a date is always displayed and edited using the
1064    default edit format of the default calendar (normally being Gregorian). If
1065    input was ambiguous due to issue #1 we'd need a mechanism to tell that a
1066    date was edited and not newly entered. Not feasible. Otherwise we'd need a
1067    mechanism to use a specific edit format with a specific calendar according
1068    to the format set.
1069 3. For some calendars like Japanese Gengou we'd need era input, which isn't
1070    implemented at all. Though this is a rare and special case, forcing a
1071    calendar dependent edit format as suggested in item #2 might require era
1072    input, if it shouldn't result in a fallback to Gregorian calendar.
1073 4. Last and least: the GetMonth() method currently only matches month names of
1074    the default calendar. Alternating month names of the actual format's
1075    calendar would have to be implemented. No problem.
1076 
1077 */
1078             if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
1079                 pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
1080             else
1081                 pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
1082                         nStringScanNumFor );
1083 #endif
1084         }
1085 
1086         res = sal_True;
1087         nCounter = 0;
1088         // For incomplete dates, always assume first day of month if not specified.
1089         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1090 
1091         switch (nAnzNums)       // count of numbers in string
1092         {
1093             case 0:                 // none
1094                 if (nMonthPos)          // only month (Jan)
1095                     pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1096                 else
1097                     res = sal_False;
1098                 break;
1099 
1100             case 1:                 // only one number
1101                 nCounter = 1;
1102                 switch (nMonthPos)  // where is the month
1103                 {
1104                     case 0:             // not found => only day entered
1105                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1106                         break;
1107                     case 1:             // month at the beginning (Jan 01)
1108                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1109                         switch (DateFmt)
1110                         {
1111                             case MDY:
1112                             case YMD:
1113                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1114                                 break;
1115                             case DMY:
1116                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1117                                 break;
1118                             default:
1119                                 res = sal_False;
1120                                 break;
1121                         }
1122                         break;
1123                     case 3:             // month at the end (10 Jan)
1124                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1125                         switch (DateFmt)
1126                         {
1127                             case DMY:
1128                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1129                                 break;
1130                             case YMD:
1131                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1132                                 break;
1133                             default:
1134                                 res = sal_False;
1135                                 break;
1136                         }
1137                         break;
1138                     default:
1139                         res = sal_False;
1140                         break;
1141                 }   // switch (nMonthPos)
1142                 break;
1143 
1144             case 2:                 // 2 numbers
1145                 nCounter = 2;
1146                 switch (nMonthPos)  // where is the month
1147                 {
1148                     case 0:             // not found
1149                     {
1150                         bool bHadExact;
1151                         sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1152                         if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff )
1153                         {   // formatted as date and exactly 2 parts
1154                             bHadExact = true;
1155                             switch ( (nExactDateOrder >> 8) & 0xff )
1156                             {
1157                                 case 'Y':
1158                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1159                                 break;
1160                                 case 'M':
1161                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1162                                 break;
1163                                 case 'D':
1164                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1165                                 break;
1166                                 default:
1167                                     bHadExact = false;
1168                             }
1169                             switch ( nExactDateOrder & 0xff )
1170                             {
1171                                 case 'Y':
1172                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1173                                 break;
1174                                 case 'M':
1175                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1176                                 break;
1177                                 case 'D':
1178                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1179                                 break;
1180                                 default:
1181                                     bHadExact = false;
1182                             }
1183                         }
1184                         else
1185                             bHadExact = false;
1186                         if ( !bHadExact || !pCal->isValid() )
1187                         {
1188                             if ( !bHadExact && nExactDateOrder )
1189                                 pCal->setGregorianDateTime( Date() );   // reset today
1190                             switch (DateFmt)
1191                             {
1192                                 case MDY:
1193                                     // M D
1194                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1195                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1196                                     if ( !pCal->isValid() )             // 2nd try
1197                                     {                                   // M Y
1198                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1199                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1200                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1201                                     }
1202                                     break;
1203                                 case DMY:
1204                                     // D M
1205                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1206                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1207                                     if ( !pCal->isValid() )             // 2nd try
1208                                     {                                   // M Y
1209                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1210                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1211                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1212                                     }
1213                                     break;
1214                                 case YMD:
1215                                     // M D
1216                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1217                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1218                                     if ( !pCal->isValid() )             // 2nd try
1219                                     {                                   // Y M
1220                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1221                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1222                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1223                                     }
1224                                     break;
1225                                 default:
1226                                     res = sal_False;
1227                                     break;
1228                             }
1229                         }
1230                     }
1231                     break;
1232                     case 1:             // month at the beginning (Jan 01 01)
1233                     {
1234                         // The input is valid as MDY in almost any
1235                         // constellation, there is no date order (M)YD except if
1236                         // set in a format applied.
1237                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1238                         sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1239                         if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
1240                         {
1241                             pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1242                             pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1243                         }
1244                         else
1245                         {
1246                             pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1247                             pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1248                         }
1249                     }
1250                     break;
1251                     case 2:             // month in the middle (10 Jan 94)
1252                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1253                         switch (DateFmt)
1254                         {
1255                             case MDY:   // yes, "10-Jan-94" is valid
1256                             case DMY:
1257                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1258                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1259                                 break;
1260                             case YMD:
1261                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1262                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1263                                 break;
1264                             default:
1265                                 res = sal_False;
1266                                 break;
1267                         }
1268                         break;
1269                     default:            // else, e.g. month at the end (94 10 Jan)
1270                         res = sal_False;
1271                         break;
1272                 }   // switch (nMonthPos)
1273                 break;
1274 
1275             default:                // more than two numbers (31.12.94 8:23) (31.12. 8:23)
1276                 switch (nMonthPos)  // where is the month
1277                 {
1278                     case 0:             // not found
1279                     {
1280                         nCounter = 3;
1281                         if ( nTimePos > 1 )
1282                         {   // find first time number index (should only be 3 or 2 anyway)
1283                             for ( sal_uInt16 j = 0; j < nAnzNums; j++ )
1284                             {
1285                                 if ( nNums[j] == nTimePos - 2 )
1286                                 {
1287                                     nCounter = j;
1288                                     break;  // for
1289                                 }
1290                             }
1291                         }
1292                         // ISO 8601 yyyy-mm-dd forced recognition
1293                         DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt);
1294                         switch (eDF)
1295                         {
1296                             case MDY:
1297                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1298                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1299                                 if ( nCounter > 2 )
1300                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1301                                 break;
1302                             case DMY:
1303                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1304                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1305                                 if ( nCounter > 2 )
1306                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1307                                 break;
1308                             case YMD:
1309                                 if ( nCounter > 2 )
1310                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
1311                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1312                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1313                                 break;
1314                             default:
1315                                 res = sal_False;
1316                                 break;
1317                         }
1318                     }
1319                         break;
1320                     case 1:             // month at the beginning (Jan 01 01 8:23)
1321                         nCounter = 2;
1322                         switch (DateFmt)
1323                         {
1324                             case MDY:
1325                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1326                                 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1327                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1328                                 break;
1329                             default:
1330                                 res = sal_False;
1331                                 break;
1332                         }
1333                         break;
1334                     case 2:             // month in the middle (10 Jan 94 8:23)
1335                         nCounter = 2;
1336                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1337                         switch (DateFmt)
1338                         {
1339                             case DMY:
1340                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1341                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1342                                 break;
1343                             case YMD:
1344                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1345                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1346                                 break;
1347                             default:
1348                                 res = sal_False;
1349                                 break;
1350                         }
1351                         break;
1352                     default:            // else, e.g. month at the end (94 10 Jan 8:23)
1353                         nCounter = 2;
1354                         res = sal_False;
1355                         break;
1356                 }   // switch (nMonthPos)
1357                 break;
1358         }   // switch (nAnzNums)
1359 
1360         if ( res && pCal->isValid() )
1361         {
1362             double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
1363             fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
1364             fDays -= fDiff;
1365             nTryOrder = nFormatOrder;   // break for
1366         }
1367         else
1368             res = sal_False;
1369 
1370         if ( aOrgCalendar.Len() )
1371             pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() );  // restore calendar
1372 
1373 #if NF_TEST_CALENDAR
1374 {
1375     using namespace ::com::sun::star;
1376     struct entry { const char* lan; const char* cou; const char* cal; };
1377     const entry cals[] = {
1378         { "en", "US",  "gregorian" },
1379         { "ar", "TN",      "hijri" },
1380         { "he", "IL",     "jewish" },
1381         { "ja", "JP",     "gengou" },
1382         { "ko", "KR", "hanja_yoil" },
1383         { "th", "TH",   "buddhist" },
1384         { "zh", "TW",        "ROC" },
1385         {0,0,0}
1386     };
1387     lang::Locale aLocale;
1388     sal_Bool bValid;
1389     sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond;
1390     sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
1391     sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis;
1392     sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis;
1393     uno::Reference< lang::XMultiServiceFactory > xSMgr =
1394         ::comphelper::getProcessServiceFactory();
1395     uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal(
1396             xSMgr->createInstance( ::rtl::OUString(
1397                     RTL_CONSTASCII_USTRINGPARAM(
1398                         "com.sun.star.i18n.LocaleCalendar" ) ) ),
1399             uno::UNO_QUERY );
1400     for ( const entry* p = cals; p->lan; ++p )
1401     {
1402         aLocale.Language = ::rtl::OUString::createFromAscii( p->lan );
1403         aLocale.Country  = ::rtl::OUString::createFromAscii( p->cou );
1404         xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ),
1405                 aLocale );
1406         double nDateTime = 0.0;     // 1-Jan-1970 00:00:00
1407         nZO           = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1408         nZOmillis     = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1409         nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 +
1410             (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis);
1411         nDST1         = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1412         nDST1millis   = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1413         nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 +
1414             (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis);
1415         nDateTime    -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1416         xCal->setDateTime( nDateTime );
1417         nDST2         = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1418         nDST2millis   = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1419         nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 +
1420             (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis);
1421         if ( nDST1InMillis != nDST2InMillis )
1422         {
1423             nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1424             xCal->setDateTime( nDateTime );
1425         }
1426         nDaySet    = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1427         nMonthSet  = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1428         nYearSet   = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1429         nHourSet   = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1430         nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1431         nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1432         nZO        = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1433         nZOmillis  = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1434         nDST       = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1435         nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1436         xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet );
1437         xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet );
1438         xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet );
1439         xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet );
1440         xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet );
1441         xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet );
1442         bValid  = xCal->isValid();
1443         nDay    = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1444         nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1445         nYear   = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1446         nHour   = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1447         nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1448         nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1449         bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear ==
1450             nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond
1451             == nSecondSet;
1452     }
1453 }
1454 #endif  // NF_TEST_CALENDAR
1455 
1456     }
1457 
1458     return res;
1459 }
1460 
1461 
1462 //---------------------------------------------------------------------------
1463 //      ScanStartString
1464 //
1465 // ersten String analysieren
1466 // Alles weg => sal_True
1467 // sonst     => sal_False
1468 
1469 sal_Bool ImpSvNumberInputScan::ScanStartString( const String& rString,
1470         const SvNumberformat* pFormat )
1471 {
1472     xub_StrLen nPos = 0;
1473     int nDayOfWeek;
1474 
1475     // First of all, eat leading blanks
1476     SkipBlanks(rString, nPos);
1477 
1478     // Yes, nMatchedAllStrings should know about the sign position
1479     nSign = GetSign(rString, nPos);
1480     if ( nSign )           // sign?
1481         SkipBlanks(rString, nPos);
1482 
1483     // #102371# match against format string only if start string is not a sign character
1484     if ( nMatchedAllStrings && !(nSign && rString.Len() == 1) )
1485     {   // Match against format in any case, so later on for a "x1-2-3" input
1486         // we may distinguish between a xy-m-d (or similar) date and a x0-0-0
1487         // format. No sign detection here!
1488         if ( ScanStringNumFor( rString, nPos, pFormat, 0, sal_True ) )
1489             nMatchedAllStrings |= nMatchedStartString;
1490         else
1491             nMatchedAllStrings = 0;
1492     }
1493 
1494     if ( GetDecSep(rString, nPos) )                 // decimal separator in start string
1495     {
1496         nDecPos = 1;
1497         SkipBlanks(rString, nPos);
1498     }
1499     else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)?
1500     {
1501         eScannedType = NUMBERFORMAT_CURRENCY;       // !!! it IS currency !!!
1502         SkipBlanks(rString, nPos);
1503         if (nSign == 0)                             // no sign yet
1504         {
1505             nSign = GetSign(rString, nPos);
1506             if ( nSign )   // DM -1
1507                 SkipBlanks(rString, nPos);
1508         }
1509     }
1510     else
1511     {
1512         nMonth = GetMonth(rString, nPos);
1513         if ( nMonth )    // month (Jan 1)?
1514         {
1515             eScannedType = NUMBERFORMAT_DATE;       // !!! it IS a date !!!
1516             nMonthPos = 1;                          // month at the beginning
1517             if ( nMonth < 0 )
1518                 SkipChar( '.', rString, nPos );     // abbreviated
1519             SkipBlanks(rString, nPos);
1520         }
1521         else
1522         {
1523             nDayOfWeek = GetDayOfWeek( rString, nPos );
1524             if ( nDayOfWeek )
1525             {   // day of week is just parsed away
1526                 eScannedType = NUMBERFORMAT_DATE;       // !!! it IS a date !!!
1527                 if ( nPos < rString.Len() )
1528                 {
1529                     if ( nDayOfWeek < 0 )
1530                     {   // abbreviated
1531                         if ( rString.GetChar( nPos ) == '.' )
1532                             ++nPos;
1533                     }
1534                     else
1535                     {   // full long name
1536                         SkipBlanks(rString, nPos);
1537                         SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
1538                     }
1539                     SkipBlanks(rString, nPos);
1540                     nMonth = GetMonth(rString, nPos);
1541                     if ( nMonth ) // month (Jan 1)?
1542                     {
1543                         nMonthPos = 1;                  // month a the beginning
1544                         if ( nMonth < 0 )
1545                             SkipChar( '.', rString, nPos ); // abbreviated
1546                         SkipBlanks(rString, nPos);
1547                     }
1548                 }
1549             }
1550         }
1551     }
1552 
1553     if (nPos < rString.Len())                       // not everything consumed
1554     {
1555         // Does input StartString equal StartString of format?
1556         // This time with sign detection!
1557         if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
1558             return MatchedReturn();
1559     }
1560 
1561     return sal_True;
1562 }
1563 
1564 
1565 //---------------------------------------------------------------------------
1566 //      ScanMidString
1567 //
1568 // String in der Mitte analysieren
1569 // Alles weg => sal_True
1570 // sonst     => sal_False
1571 
1572 sal_Bool ImpSvNumberInputScan::ScanMidString( const String& rString,
1573         sal_uInt16 nStringPos, const SvNumberformat* pFormat )
1574 {
1575     xub_StrLen nPos = 0;
1576     short eOldScannedType = eScannedType;
1577 
1578     if ( nMatchedAllStrings )
1579     {   // Match against format in any case, so later on for a "1-2-3-4" input
1580         // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1581         // format.
1582         if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
1583             nMatchedAllStrings |= nMatchedMidString;
1584         else
1585             nMatchedAllStrings = 0;
1586     }
1587 
1588     SkipBlanks(rString, nPos);
1589     if (GetDecSep(rString, nPos))                   // decimal separator?
1590     {
1591         if (nDecPos == 1 || nDecPos == 3)           // .12.4 or 1.E2.1
1592             return MatchedReturn();
1593         else if (nDecPos == 2)                      // . dup: 12.4.
1594         {
1595             if (bDecSepInDateSeps)                  // . also date separator
1596             {
1597                 if (    eScannedType != NUMBERFORMAT_UNDEFINED &&
1598                         eScannedType != NUMBERFORMAT_DATE &&
1599                         eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1600                     return MatchedReturn();
1601                 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1602                     eScannedType = NUMBERFORMAT_DATE;   // !!! it IS a date
1603                 SkipBlanks(rString, nPos);
1604             }
1605             else
1606                 return MatchedReturn();
1607         }
1608         else
1609         {
1610             nDecPos = 2;                            // . in mid string
1611             SkipBlanks(rString, nPos);
1612         }
1613     }
1614     else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME)
1615             && GetTime100SecSep( rString, nPos ) )
1616     {                                               // hundredth seconds separator
1617         if ( nDecPos )
1618             return MatchedReturn();
1619         nDecPos = 2;                                // . in mid string
1620         SkipBlanks(rString, nPos);
1621     }
1622 
1623     if (SkipChar('/', rString, nPos))               // fraction?
1624     {
1625         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1626             && eScannedType != NUMBERFORMAT_DATE)       // except date
1627             return MatchedReturn();                               // => jan/31/1994
1628         else if (    eScannedType != NUMBERFORMAT_DATE      // analyzed date until now
1629                  && (    eSetType == NUMBERFORMAT_FRACTION  // and preset was fraction
1630                      || (nAnzNums == 3                      // or 3 numbers
1631                          && nStringPos > 2) ) )             // and what ???
1632         {
1633             SkipBlanks(rString, nPos);
1634             eScannedType = NUMBERFORMAT_FRACTION;   // !!! it IS a fraction
1635         }
1636         else
1637             nPos--;                                 // put '/' back
1638     }
1639 
1640     if (GetThousandSep(rString, nPos, nStringPos))  // 1,000
1641     {
1642         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1643             && eScannedType != NUMBERFORMAT_CURRENCY)   // except currency
1644             return MatchedReturn();
1645         nThousand++;
1646     }
1647 
1648     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1649     const String& rDate = pFormatter->GetDateSep();
1650     const String& rTime = pLoc->getTimeSep();
1651     sal_Unicode cTime = rTime.GetChar(0);
1652     SkipBlanks(rString, nPos);
1653     if (                      SkipString(rDate, rString, nPos)  // 10., 10-, 10/
1654         || ((cTime != '.') && SkipChar('.',   rString, nPos))   // TRICKY:
1655         || ((cTime != '/') && SkipChar('/',   rString, nPos))   // short boolean
1656         || ((cTime != '-') && SkipChar('-',   rString, nPos)) ) // evaluation!
1657     {
1658         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1659             && eScannedType != NUMBERFORMAT_DATE)       // except date
1660             return MatchedReturn();
1661         SkipBlanks(rString, nPos);
1662         eScannedType = NUMBERFORMAT_DATE;           // !!! it IS a date
1663         short nTmpMonth = GetMonth(rString, nPos);  // 10. Jan 94
1664         if (nMonth && nTmpMonth)                    // month dup
1665             return MatchedReturn();
1666         if (nTmpMonth)
1667         {
1668             nMonth = nTmpMonth;
1669             nMonthPos = 2;                          // month in the middle
1670             if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
1671                 ;   // short month may be abbreviated Jan.
1672             else if ( SkipChar( '-', rString, nPos ) )
1673                 ;   // #79632# recognize 17-Jan-2001 to be a date
1674                     // #99065# short and long month name
1675             else
1676                 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1677             SkipBlanks(rString, nPos);
1678         }
1679     }
1680 
1681     short nTempMonth = GetMonth(rString, nPos);     // month in the middle (10 Jan 94)
1682     if (nTempMonth)
1683     {
1684         if (nMonth != 0)                            // month dup
1685             return MatchedReturn();
1686         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1687             && eScannedType != NUMBERFORMAT_DATE)       // except date
1688             return MatchedReturn();
1689         eScannedType = NUMBERFORMAT_DATE;           // !!! it IS a date
1690         nMonth = nTempMonth;
1691         nMonthPos = 2;                              // month in the middle
1692         if ( nMonth < 0 )
1693             SkipChar( '.', rString, nPos );         // abbreviated
1694         SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1695         SkipBlanks(rString, nPos);
1696     }
1697 
1698     if (    SkipChar('E', rString, nPos)            // 10E, 10e, 10,Ee
1699          || SkipChar('e', rString, nPos) )
1700     {
1701         if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1702             return MatchedReturn();
1703         else
1704         {
1705             SkipBlanks(rString, nPos);
1706             eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific
1707             if (    nThousand+2 == nAnzNums         // special case 1.E2
1708                  && nDecPos == 2 )
1709                 nDecPos = 3;                        // 1,100.E2 1,100,100.E3
1710         }
1711         nESign = GetESign(rString, nPos);           // signed exponent?
1712         SkipBlanks(rString, nPos);
1713     }
1714 
1715     if ( SkipString(rTime, rString, nPos) )         // time separator?
1716     {
1717         if (nDecPos)                                // already . => maybe error
1718         {
1719             if (bDecSepInDateSeps)                  // . also date sep
1720             {
1721                 if (    eScannedType != NUMBERFORMAT_DATE &&    // already another type than date
1722                         eScannedType != NUMBERFORMAT_DATETIME)  // or date time
1723                     return MatchedReturn();
1724                 if (eScannedType == NUMBERFORMAT_DATE)
1725                     nDecPos = 0;                    // reset for time transition
1726             }
1727             else
1728                 return MatchedReturn();
1729         }
1730         if (   (   eScannedType == NUMBERFORMAT_DATE        // already date type
1731                 || eScannedType == NUMBERFORMAT_DATETIME)   // or date time
1732             && nAnzNums > 3)                                // and more than 3 numbers? (31.Dez.94 8:23)
1733         {
1734             SkipBlanks(rString, nPos);
1735             eScannedType = NUMBERFORMAT_DATETIME;   // !!! it IS date with time
1736         }
1737         else if (   eScannedType != NUMBERFORMAT_UNDEFINED  // already another type
1738                  && eScannedType != NUMBERFORMAT_TIME)      // except time
1739             return MatchedReturn();
1740         else
1741         {
1742             SkipBlanks(rString, nPos);
1743             eScannedType = NUMBERFORMAT_TIME;       // !!! it IS a time
1744         }
1745         if ( !nTimePos )
1746             nTimePos = nStringPos + 1;
1747     }
1748 
1749     if (nPos < rString.Len())
1750     {
1751         switch (eScannedType)
1752         {
1753             case NUMBERFORMAT_DATE:
1754                 if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
1755                 {
1756                     // #68232# recognize long date separators like ", " in "September 5, 1999"
1757                     if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
1758                         SkipBlanks( rString, nPos );
1759                 }
1760                 else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 &&
1761                         rString.GetChar(0) == 'T' && MayBeIso8601())
1762                 {
1763                     // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
1764                     ++nPos;
1765                 }
1766                 break;
1767 #if NF_RECOGNIZE_ISO8601_TIMEZONES
1768             case NUMBERFORMAT_DATETIME:
1769                 if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 &&
1770                         MayBeIso8601())
1771                 {
1772                     // ISO 8601 timezone offset
1773                     switch (rString.GetChar(0))
1774                     {
1775                         case '+':
1776                         case '-':
1777                             if (nStringPos == nAnzStrings-2 ||
1778                                     nStringPos == nAnzStrings-4)
1779                             {
1780                                 ++nPos;     // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
1781                                 // nTimezonePos needed for GetTimeRef()
1782                                 if (!nTimezonePos)
1783                                     nTimezonePos = nStringPos + 1;
1784                             }
1785                             break;
1786                         case ':':
1787                             if (nTimezonePos && nStringPos >= 11 &&
1788                                     nStringPos == nAnzStrings-2)
1789                                 ++nPos;     // yyyy-mm-ddThh:mm[:ss]+xx:yy
1790                             break;
1791                     }
1792                 }
1793                 break;
1794 #endif
1795         }
1796     }
1797 
1798     if (nPos < rString.Len())                       // not everything consumed?
1799     {
1800         if ( nMatchedAllStrings & ~nMatchedVirgin )
1801             eScannedType = eOldScannedType;
1802         else
1803             return sal_False;
1804     }
1805 
1806     return sal_True;
1807 }
1808 
1809 
1810 //---------------------------------------------------------------------------
1811 //      ScanEndString
1812 //
1813 // Schlussteil analysieren
1814 // Alles weg => sal_True
1815 // sonst     => sal_False
1816 
1817 sal_Bool ImpSvNumberInputScan::ScanEndString( const String& rString,
1818         const SvNumberformat* pFormat )
1819 {
1820     xub_StrLen nPos = 0;
1821 
1822     if ( nMatchedAllStrings )
1823     {   // Match against format in any case, so later on for a "1-2-3-4" input
1824         // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1825         // format.
1826         if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
1827             nMatchedAllStrings |= nMatchedEndString;
1828         else
1829             nMatchedAllStrings = 0;
1830     }
1831 
1832     SkipBlanks(rString, nPos);
1833     if (GetDecSep(rString, nPos))                   // decimal separator?
1834     {
1835         if (nDecPos == 1 || nDecPos == 3)           // .12.4 or 12.E4.
1836             return MatchedReturn();
1837         else if (nDecPos == 2)                      // . dup: 12.4.
1838         {
1839             if (bDecSepInDateSeps)                  // . also date sep
1840             {
1841                 if (    eScannedType != NUMBERFORMAT_UNDEFINED &&
1842                         eScannedType != NUMBERFORMAT_DATE &&
1843                         eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1844                     return MatchedReturn();
1845                 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1846                     eScannedType = NUMBERFORMAT_DATE;   // !!! it IS a date
1847                 SkipBlanks(rString, nPos);
1848             }
1849             else
1850                 return MatchedReturn();
1851         }
1852         else
1853         {
1854             nDecPos = 3;                            // . in end string
1855             SkipBlanks(rString, nPos);
1856         }
1857     }
1858 
1859     if (   nSign == 0                               // conflict - not signed
1860         && eScannedType != NUMBERFORMAT_DATE)       // and not date
1861 //!? catch time too?
1862     {                                               // not signed yet
1863         nSign = GetSign(rString, nPos);             // 1- DM
1864         if (nNegCheck)                              // '(' as sign
1865             return MatchedReturn();
1866     }
1867 
1868     SkipBlanks(rString, nPos);
1869     if (nNegCheck && SkipChar(')', rString, nPos))  // skip ')' if appropriate
1870     {
1871         nNegCheck = 0;
1872         SkipBlanks(rString, nPos);
1873     }
1874 
1875     if ( GetCurrency(rString, nPos, pFormat) )      // currency symbol?
1876     {
1877         if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup
1878             return MatchedReturn();
1879         else
1880         {
1881             SkipBlanks(rString, nPos);
1882             eScannedType = NUMBERFORMAT_CURRENCY;
1883         }                                           // behind currency a '-' is allowed
1884         if (nSign == 0)                             // not signed yet
1885         {
1886             nSign = GetSign(rString, nPos);         // DM -
1887             SkipBlanks(rString, nPos);
1888             if (nNegCheck)                          // 3 DM (
1889                 return MatchedReturn();
1890         }
1891         if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY
1892                        && SkipChar(')', rString, nPos) )
1893         {
1894             nNegCheck = 0;                          // ')' skipped
1895             SkipBlanks(rString, nPos);              // only if currency
1896         }
1897     }
1898 
1899     if ( SkipChar('%', rString, nPos) )             // 1 %
1900     {
1901         if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1902             return MatchedReturn();
1903         SkipBlanks(rString, nPos);
1904         eScannedType = NUMBERFORMAT_PERCENT;
1905     }
1906 
1907     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1908     const String& rDate = pFormatter->GetDateSep();
1909     const String& rTime = pLoc->getTimeSep();
1910     if ( SkipString(rTime, rString, nPos) )         // 10:
1911     {
1912         if (nDecPos)                                // already , => error
1913             return MatchedReturn();
1914         if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8:
1915         {
1916             SkipBlanks(rString, nPos);
1917             eScannedType = NUMBERFORMAT_DATETIME;
1918         }
1919         else if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1920                  eScannedType != NUMBERFORMAT_TIME) // already another type
1921             return MatchedReturn();
1922         else
1923         {
1924             SkipBlanks(rString, nPos);
1925             eScannedType = NUMBERFORMAT_TIME;
1926         }
1927         if ( !nTimePos )
1928             nTimePos = nAnzStrings;
1929     }
1930 
1931     sal_Unicode cTime = rTime.GetChar(0);
1932     if (                      SkipString(rDate, rString, nPos)  // 10., 10-, 10/
1933         || ((cTime != '.') && SkipChar('.',   rString, nPos))   // TRICKY:
1934         || ((cTime != '/') && SkipChar('/',   rString, nPos))   // short boolean
1935         || ((cTime != '-') && SkipChar('-',   rString, nPos)) ) // evaluation!
1936     {
1937         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1938             eScannedType != NUMBERFORMAT_DATE)          // already another type
1939             return MatchedReturn();
1940         else
1941         {
1942             SkipBlanks(rString, nPos);
1943             eScannedType = NUMBERFORMAT_DATE;
1944         }
1945         short nTmpMonth = GetMonth(rString, nPos);  // 10. Jan
1946         if (nMonth && nTmpMonth)                    // month dup
1947             return MatchedReturn();
1948         if (nTmpMonth)
1949         {
1950             nMonth = nTmpMonth;
1951             nMonthPos = 3;                          // month at end
1952             if ( nMonth < 0 )
1953                 SkipChar( '.', rString, nPos );     // abbreviated
1954             SkipBlanks(rString, nPos);
1955         }
1956     }
1957 
1958     short nTempMonth = GetMonth(rString, nPos);     // 10 Jan
1959     if (nTempMonth)
1960     {
1961         if (nMonth)                                 // month dup
1962             return MatchedReturn();
1963         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1964             eScannedType != NUMBERFORMAT_DATE)      // already another type
1965             return MatchedReturn();
1966         eScannedType = NUMBERFORMAT_DATE;
1967         nMonth = nTempMonth;
1968         nMonthPos = 3;                              // month at end
1969         if ( nMonth < 0 )
1970             SkipChar( '.', rString, nPos );         // abbreviated
1971         SkipBlanks(rString, nPos);
1972     }
1973 
1974     xub_StrLen nOrigPos = nPos;
1975     if (GetTimeAmPm(rString, nPos))
1976     {
1977         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1978             eScannedType != NUMBERFORMAT_TIME &&
1979             eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1980             return MatchedReturn();
1981         else
1982         {
1983             // If not already scanned as time, 6.78am does not result in 6
1984             // seconds and 78 hundredths in the morning. Keep as suffix.
1985             if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2)
1986                 nPos = nOrigPos;     // rewind am/pm
1987             else
1988             {
1989                 SkipBlanks(rString, nPos);
1990                 if ( eScannedType != NUMBERFORMAT_DATETIME )
1991                     eScannedType = NUMBERFORMAT_TIME;
1992             }
1993         }
1994     }
1995 
1996     if ( nNegCheck && SkipChar(')', rString, nPos) )
1997     {
1998         if (eScannedType == NUMBERFORMAT_CURRENCY)  // only if currency
1999         {
2000             nNegCheck = 0;                          // skip ')'
2001             SkipBlanks(rString, nPos);
2002         }
2003         else
2004             return MatchedReturn();
2005     }
2006 
2007     if ( nPos < rString.Len() &&
2008             (eScannedType == NUMBERFORMAT_DATE
2009             || eScannedType == NUMBERFORMAT_DATETIME) )
2010     {   // day of week is just parsed away
2011         xub_StrLen nOldPos = nPos;
2012         const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
2013         if ( StringContains( rSep, rString, nPos ) )
2014         {
2015             nPos = nPos + rSep.Len();
2016             SkipBlanks(rString, nPos);
2017         }
2018         int nDayOfWeek = GetDayOfWeek( rString, nPos );
2019         if ( nDayOfWeek )
2020         {
2021             if ( nPos < rString.Len() )
2022             {
2023                 if ( nDayOfWeek < 0 )
2024                 {   // short
2025                     if ( rString.GetChar( nPos ) == '.' )
2026                         ++nPos;
2027                 }
2028                 SkipBlanks(rString, nPos);
2029             }
2030         }
2031         else
2032             nPos = nOldPos;
2033     }
2034 
2035 #if NF_RECOGNIZE_ISO8601_TIMEZONES
2036     if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME &&
2037             rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601())
2038     {
2039         // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
2040         ++nPos;
2041     }
2042 #endif
2043 
2044     if (nPos < rString.Len())                       // everything consumed?
2045     {
2046         // does input EndString equal EndString in Format?
2047         if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
2048             return sal_False;
2049     }
2050 
2051     return sal_True;
2052 }
2053 
2054 
2055 sal_Bool ImpSvNumberInputScan::ScanStringNumFor(
2056         const String& rString,          // String to scan
2057         xub_StrLen nPos,                // Position until which was consumed
2058         const SvNumberformat* pFormat,  // The format to match
2059         sal_uInt16 nString,                 // Substring of format, 0xFFFF => last
2060         sal_Bool bDontDetectNegation        // Suppress sign detection
2061         )
2062 {
2063     if ( !pFormat )
2064         return sal_False;
2065     const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
2066     const String* pStr;
2067     String aString( rString );
2068     sal_Bool bFound = sal_False;
2069     sal_Bool bFirst = sal_True;
2070     sal_Bool bContinue = sal_True;
2071     sal_uInt16 nSub;
2072     do
2073     {
2074         // Don't try "lower" subformats ff the very first match was the second
2075         // or third subformat.
2076         nSub = nStringScanNumFor;
2077         do
2078         {   // Step through subformats, first positive, then negative, then
2079             // other, but not the last (text) subformat.
2080             pStr = pFormat->GetNumForString( nSub, nString, sal_True );
2081             if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
2082             {
2083                 bFound = sal_True;
2084                 bContinue = sal_False;
2085             }
2086             else if ( nSub < 2 )
2087                 ++nSub;
2088             else
2089                 bContinue = sal_False;
2090         } while ( bContinue );
2091         if ( !bFound && bFirst && nPos )
2092         {   // try remaining substring
2093             bFirst = sal_False;
2094             aString.Erase( 0, nPos );
2095             bContinue = sal_True;
2096         }
2097     } while ( bContinue );
2098 
2099     if ( !bFound )
2100     {
2101         if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0)
2102                 && pFormat->IsNegativeRealNegative() )
2103         {   // simply negated twice? --1
2104             aString.EraseAllChars( ' ' );
2105             if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') )
2106             {
2107                 bFound = sal_True;
2108                 nStringScanSign = -1;
2109                 nSub = 0;       //! not 1
2110             }
2111         }
2112         if ( !bFound )
2113             return sal_False;
2114     }
2115     else if ( !bDontDetectNegation && (nSub == 1) &&
2116             pFormat->IsNegativeRealNegative() )
2117     {   // negative
2118         if ( nStringScanSign < 0 )
2119         {
2120             if ( (nSign < 0) && (nStringScanNumFor != 1) )
2121                 nStringScanSign = 1;        // triple negated --1 yyy
2122         }
2123         else if ( nStringScanSign == 0 )
2124         {
2125             if ( nSign < 0 )
2126             {   // nSign and nStringScanSign will be combined later,
2127                 // flip sign if doubly negated
2128                 if ( (nString == 0) && !bFirst
2129                         && SvNumberformat::HasStringNegativeSign( aString ) )
2130                     nStringScanSign = -1;   // direct double negation
2131                 else if ( pFormat->IsNegativeWithoutSign() )
2132                     nStringScanSign = -1;   // indirect double negation
2133             }
2134             else
2135                 nStringScanSign = -1;
2136         }
2137         else    // > 0
2138             nStringScanSign = -1;
2139     }
2140     nStringScanNumFor = nSub;
2141     return sal_True;
2142 }
2143 
2144 
2145 //---------------------------------------------------------------------------
2146 //      IsNumberFormatMain
2147 //
2148 // Recognizes types of number, exponential, fraction, percent, currency, date, time.
2149 // Else text => return sal_False
2150 
2151 sal_Bool ImpSvNumberInputScan::IsNumberFormatMain(
2152         const String& rString,                  // string to be analyzed
2153         double& ,                               // OUT: result as number, if possible
2154         const SvNumberformat* pFormat )         // maybe number format set to match against
2155 {
2156     Reset();
2157     NumberStringDivision( rString );            // breakdown into strings and numbers
2158     if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
2159         return sal_False;                           // Njet, Nope, ...
2160 
2161     if (nAnzNums == 0)                          // no number in input
2162     {
2163         if ( nAnzStrings > 0 )
2164         {
2165             // Here we may change the original, we don't need it anymore.
2166             // This saves copies and ToUpper() in GetLogical() and is faster.
2167             String& rStrArray = sStrArray[0];
2168             rStrArray.EraseTrailingChars( ' ' );
2169             rStrArray.EraseLeadingChars( ' ' );
2170             nLogical = GetLogical( rStrArray );
2171             if ( nLogical )
2172             {
2173                 eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN
2174                 nMatchedAllStrings &= ~nMatchedVirgin;
2175                 return sal_True;
2176             }
2177             else
2178                 return sal_False;                   // simple text
2179         }
2180         else
2181             return sal_False;                       // simple text
2182     }
2183 
2184     sal_uInt16 i = 0;                               // mark any symbol
2185     sal_uInt16 j = 0;                               // mark only numbers
2186 
2187     switch ( nAnzNums )
2188     {
2189         case 1 :                                // Exactly 1 number in input
2190         {                                       // nAnzStrings >= 1
2191             if (GetNextNumber(i,j))             // i=1,0
2192             {                                   // Number at start
2193                 if (eSetType == NUMBERFORMAT_FRACTION)  // Fraction 1 = 1/1
2194                 {
2195                     if (i >= nAnzStrings ||     // no end string nor decimal separator
2196                         sStrArray[i] == pFormatter->GetNumDecimalSep())
2197                     {
2198                         eScannedType = NUMBERFORMAT_FRACTION;
2199                         nMatchedAllStrings &= ~nMatchedVirgin;
2200                         return sal_True;
2201                     }
2202                 }
2203             }
2204             else
2205             {                                   // Analyze start string
2206                 if (!ScanStartString( sStrArray[i], pFormat ))  // i=0
2207                     return sal_False;               // already an error
2208                 i++;                            // next symbol, i=1
2209             }
2210             GetNextNumber(i,j);                 // i=1,2
2211             if (eSetType == NUMBERFORMAT_FRACTION)  // Fraction -1 = -1/1
2212             {
2213                 if (nSign && !nNegCheck &&      // Sign +, -
2214                     eScannedType == NUMBERFORMAT_UNDEFINED &&   // not date or currency
2215                     nDecPos == 0 &&             // no previous decimal separator
2216                     (i >= nAnzStrings ||        // no end string nor decimal separator
2217                         sStrArray[i] == pFormatter->GetNumDecimalSep())
2218                 )
2219                 {
2220                     eScannedType = NUMBERFORMAT_FRACTION;
2221                     nMatchedAllStrings &= ~nMatchedVirgin;
2222                     return sal_True;
2223                 }
2224             }
2225             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2226                     return sal_False;
2227         }
2228         break;
2229         case 2 :                                // Exactly 2 numbers in input
2230         {                                       // nAnzStrings >= 3
2231             if (!GetNextNumber(i,j))            // i=1,0
2232             {                                   // Analyze start string
2233                 if (!ScanStartString( sStrArray[i], pFormat ))
2234                     return sal_False;               // already an error
2235                 i++;                            // i=1
2236             }
2237             GetNextNumber(i,j);                 // i=1,2
2238             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2239                 return sal_False;
2240             i++;                                // next symbol, i=2,3
2241             GetNextNumber(i,j);                 // i=3,4
2242             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2243                 return sal_False;
2244             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200. as fraction
2245             {
2246                 if (!nNegCheck  &&                  // no sign '('
2247                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2248                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2249                     )
2250                 {
2251                     eScannedType = NUMBERFORMAT_FRACTION;
2252                     nMatchedAllStrings &= ~nMatchedVirgin;
2253                     return sal_True;
2254                 }
2255             }
2256         }
2257         break;
2258         case 3 :                                // Exactly 3 numbers in input
2259         {                                       // nAnzStrings >= 5
2260             if (!GetNextNumber(i,j))            // i=1,0
2261             {                                   // Analyze start string
2262                 if (!ScanStartString( sStrArray[i], pFormat ))
2263                     return sal_False;               // already an error
2264                 i++;                            // i=1
2265                 if (nDecPos == 1)               // decimal separator at start => error
2266                     return sal_False;
2267             }
2268             GetNextNumber(i,j);                 // i=1,2
2269             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2270                 return sal_False;
2271             i++;                                // i=2,3
2272             if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at end
2273                 return sal_False;
2274             GetNextNumber(i,j);                 // i=3,4
2275             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2276                 return sal_False;
2277             i++;                                // i=4,5
2278             GetNextNumber(i,j);                 // i=5,6
2279             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2280                 return sal_False;
2281             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200,100. as fraction
2282             {
2283                 if (!nNegCheck  &&                  // no sign '('
2284                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2285                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2286                 )
2287                 {
2288                     eScannedType = NUMBERFORMAT_FRACTION;
2289                     nMatchedAllStrings &= ~nMatchedVirgin;
2290                     return sal_True;
2291                 }
2292             }
2293             if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2294                 return sal_False;                   // #36857# not a real fraction
2295         }
2296         break;
2297         default:                                // More than 3 numbers in input
2298         {                                       // nAnzStrings >= 7
2299             if (!GetNextNumber(i,j))            // i=1,0
2300             {                                   // Analyze startstring
2301                 if (!ScanStartString( sStrArray[i], pFormat ))
2302                     return sal_False;               // already an error
2303                 i++;                            // i=1
2304                 if (nDecPos == 1)               // decimal separator at start => error
2305                     return sal_False;
2306             }
2307             GetNextNumber(i,j);                 // i=1,2
2308             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2309                 return sal_False;
2310             i++;                                // i=2,3
2311             sal_uInt16 nThOld = 10;                 // just not 0 or 1
2312             while (nThOld != nThousand && j < nAnzNums-1)
2313                                                 // Execute at least one time
2314                                                 // but leave one number.
2315             {                                   // Loop over group separators
2316                 nThOld = nThousand;
2317                 if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at end
2318                     return sal_False;
2319                 GetNextNumber(i,j);
2320                 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2321                     return sal_False;
2322                 i++;
2323             }
2324             if (eScannedType == NUMBERFORMAT_DATE ||    // long date or
2325                 eScannedType == NUMBERFORMAT_TIME ||    // long time or
2326                 eScannedType == NUMBERFORMAT_UNDEFINED) // long number
2327             {
2328                 for (sal_uInt16 k = j; k < nAnzNums-1; k++)
2329                 {
2330                     if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at endd
2331                         return sal_False;
2332                     GetNextNumber(i,j);
2333                     if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2334                         return sal_False;
2335                     i++;
2336                 }
2337             }
2338             GetNextNumber(i,j);
2339             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2340                 return sal_False;
2341             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200,100. as fraction
2342             {
2343                 if (!nNegCheck  &&                  // no sign '('
2344                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2345                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2346                 )
2347                 {
2348                     eScannedType = NUMBERFORMAT_FRACTION;
2349                     nMatchedAllStrings &= ~nMatchedVirgin;
2350                     return sal_True;
2351                 }
2352             }
2353             if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2354                 return sal_False;                       // #36857# not a real fraction
2355         }
2356     }
2357 
2358     if (eScannedType == NUMBERFORMAT_UNDEFINED)
2359     {
2360         nMatchedAllStrings &= ~nMatchedVirgin;
2361         // did match including nMatchedUsedAsReturn
2362         sal_Bool bDidMatch = (nMatchedAllStrings != 0);
2363         if ( nMatchedAllStrings )
2364         {
2365             sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2366                         nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2367             if ( !bMatch )
2368                 nMatchedAllStrings = 0;
2369         }
2370         if ( nMatchedAllStrings )
2371             eScannedType = eSetType;
2372         else if ( bDidMatch )
2373             return sal_False;
2374         else
2375             eScannedType = NUMBERFORMAT_NUMBER;
2376             // everything else should have been recognized by now
2377     }
2378     else if ( eScannedType == NUMBERFORMAT_DATE )
2379     {   // the very relaxed date input checks may interfere with a preset format
2380         nMatchedAllStrings &= ~nMatchedVirgin;
2381         sal_Bool bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
2382         if ( nMatchedAllStrings )
2383         {
2384             sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2385                         nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2386             if ( !bMatch )
2387                 nMatchedAllStrings = 0;
2388         }
2389         if ( nMatchedAllStrings )
2390             eScannedType = eSetType;
2391         else if ( bWasReturn )
2392             return sal_False;
2393     }
2394     else
2395         nMatchedAllStrings = 0;  // reset flag to no substrings matched
2396 
2397     return sal_True;
2398 }
2399 
2400 
2401 //---------------------------------------------------------------------------
2402 // return sal_True or sal_False depending on the nMatched... state and remember usage
2403 sal_Bool ImpSvNumberInputScan::MatchedReturn()
2404 {
2405     if ( nMatchedAllStrings & ~nMatchedVirgin )
2406     {
2407         nMatchedAllStrings |= nMatchedUsedAsReturn;
2408         return sal_True;
2409     }
2410     return sal_False;
2411 }
2412 
2413 
2414 //---------------------------------------------------------------------------
2415 // Initialize uppercase months and weekdays
2416 
2417 void ImpSvNumberInputScan::InitText()
2418 {
2419     sal_Int32 j, nElems;
2420     const CharClass* pChrCls = pFormatter->GetCharClass();
2421     const CalendarWrapper* pCal = pFormatter->GetCalendar();
2422     delete [] pUpperMonthText;
2423     delete [] pUpperAbbrevMonthText;
2424     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems
2425         = pCal->getMonths();
2426     nElems = xElems.getLength();
2427     pUpperMonthText = new String[nElems];
2428     pUpperAbbrevMonthText = new String[nElems];
2429     for ( j=0; j<nElems; j++ )
2430     {
2431         pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName );
2432         pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName );
2433     }
2434     delete [] pUpperDayText;
2435     delete [] pUpperAbbrevDayText;
2436     xElems = pCal->getDays();
2437     nElems = xElems.getLength();
2438     pUpperDayText = new String[nElems];
2439     pUpperAbbrevDayText = new String[nElems];
2440     for ( j=0; j<nElems; j++ )
2441     {
2442         pUpperDayText[j] = pChrCls->upper( xElems[j].FullName );
2443         pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName );
2444     }
2445     bTextInitialized = sal_True;
2446 }
2447 
2448 
2449 //===========================================================================
2450 //          P U B L I C
2451 
2452 //---------------------------------------------------------------------------
2453 //      ChangeIntl
2454 //
2455 // MUST be called if International/Locale is changed
2456 
2457 void ImpSvNumberInputScan::ChangeIntl()
2458 {
2459     sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0);
2460     bDecSepInDateSeps = ( cDecSep == '-' ||
2461                           cDecSep == '/' ||
2462                           cDecSep == '.' ||
2463                           cDecSep == pFormatter->GetDateSep().GetChar(0) );
2464     bTextInitialized = sal_False;
2465     aUpperCurrSymbol.Erase();
2466 }
2467 
2468 
2469 //---------------------------------------------------------------------------
2470 //      ChangeNullDate
2471 
2472 void ImpSvNumberInputScan::ChangeNullDate(
2473         const sal_uInt16 Day,
2474         const sal_uInt16 Month,
2475         const sal_uInt16 Year )
2476 {
2477     if ( pNullDate )
2478         *pNullDate = Date(Day, Month, Year);
2479     else
2480         pNullDate = new Date(Day, Month, Year);
2481 }
2482 
2483 
2484 //---------------------------------------------------------------------------
2485 //      IsNumberFormat
2486 //
2487 // => does rString represent a number (also date, time et al)
2488 
2489 sal_Bool ImpSvNumberInputScan::IsNumberFormat(
2490         const String& rString,                  // string to be analyzed
2491         short& F_Type,                          // IN: old type, OUT: new type
2492         double& fOutNumber,                     // OUT: number if convertable
2493         const SvNumberformat* pFormat )         // maybe a number format to match against
2494 {
2495     String sResString;
2496     String aString;
2497     sal_Bool res;                                   // return value
2498     eSetType = F_Type;                          // old type set
2499 
2500     if ( !rString.Len() )
2501         res = sal_False;
2502     else if (rString.Len() > 308)               // arbitrary
2503         res = sal_False;
2504     else
2505     {
2506         // NoMoreUpperNeeded, all comparisons on UpperCase
2507         aString = pFormatter->GetCharClass()->upper( rString );
2508         // convert native number to ASCII if necessary
2509         TransformInput( aString );
2510         res = IsNumberFormatMain( aString, fOutNumber, pFormat );
2511     }
2512 
2513     if (res)
2514     {
2515         if ( nNegCheck                              // ')' not found for '('
2516                 || (nSign && (eScannedType == NUMBERFORMAT_DATE
2517                     || eScannedType == NUMBERFORMAT_DATETIME))
2518             )                                       // signed date/datetime
2519             res = sal_False;
2520         else
2521         {                                           // check count of partial number strings
2522             switch (eScannedType)
2523             {
2524                 case NUMBERFORMAT_PERCENT:
2525                 case NUMBERFORMAT_CURRENCY:
2526                 case NUMBERFORMAT_NUMBER:
2527                     if (nDecPos == 1)               // .05
2528                     {
2529                         // matched MidStrings function like group separators
2530                         if ( nMatchedAllStrings )
2531                             nThousand = nAnzNums - 1;
2532                         else if ( nAnzNums != 1 )
2533                             res = sal_False;
2534                     }
2535                     else if (nDecPos == 2)          // 1.05
2536                     {
2537                         // matched MidStrings function like group separators
2538                         if ( nMatchedAllStrings )
2539                             nThousand = nAnzNums - 1;
2540                         else if ( nAnzNums != nThousand+2 )
2541                             res = sal_False;
2542                     }
2543                     else                            // 1,100 or 1,100.
2544                     {
2545                         // matched MidStrings function like group separators
2546                         if ( nMatchedAllStrings )
2547                             nThousand = nAnzNums - 1;
2548                         else if ( nAnzNums != nThousand+1 )
2549                             res = sal_False;
2550                     }
2551                     break;
2552 
2553                 case NUMBERFORMAT_SCIENTIFIC:       // 1.0e-2
2554                     if (nDecPos == 1)               // .05
2555                     {
2556                         if (nAnzNums != 2)
2557                             res = sal_False;
2558                     }
2559                     else if (nDecPos == 2)          // 1.05
2560                     {
2561                         if (nAnzNums != nThousand+3)
2562                             res = sal_False;
2563                     }
2564                     else                            // 1,100 or 1,100.
2565                     {
2566                         if (nAnzNums != nThousand+2)
2567                             res = sal_False;
2568                     }
2569                     break;
2570 
2571                 case NUMBERFORMAT_DATE:
2572                     if (nMonth)
2573                     {                               // month name and numbers
2574                         if (nAnzNums > 2)
2575                             res = sal_False;
2576                     }
2577                     else
2578                     {
2579                         if (nAnzNums > 3)
2580                             res = sal_False;
2581                     }
2582                     break;
2583 
2584                 case NUMBERFORMAT_TIME:
2585                     if (nDecPos)
2586                     {                               // hundredth seconds included
2587                         if (nAnzNums > 4)
2588                             res = sal_False;
2589                     }
2590                     else
2591                     {
2592                         if (nAnzNums > 3)
2593                             res = sal_False;
2594                     }
2595                     break;
2596 
2597                 case NUMBERFORMAT_DATETIME:
2598                     if (nMonth)
2599                     {                               // month name and numbers
2600                         if (nDecPos)
2601                         {                           // hundredth seconds included
2602                             if (nAnzNums > 6)
2603                                 res = sal_False;
2604                         }
2605                         else
2606                         {
2607                             if (nAnzNums > 5)
2608                                 res = sal_False;
2609                         }
2610                     }
2611                     else
2612                     {
2613                         if (nDecPos)
2614                         {                           // hundredth seconds included
2615                             if (nAnzNums > 7)
2616                                 res = sal_False;
2617                         }
2618                         else
2619                         {
2620                             if (nAnzNums > 6)
2621                                 res = sal_False;
2622                         }
2623                     }
2624                     break;
2625 
2626                 default:
2627                     break;
2628             }   // switch
2629         }   // else
2630     }   // if (res)
2631 
2632     if (res)
2633     {                                           // we finally have a number
2634         switch (eScannedType)
2635         {
2636             case NUMBERFORMAT_LOGICAL:
2637                 if      (nLogical ==  1)
2638                     fOutNumber = 1.0;           // True
2639                 else if (nLogical == -1)
2640                     fOutNumber = 0.0;           // False
2641                 else
2642                     res = sal_False;                // Oops
2643                 break;
2644 
2645             case NUMBERFORMAT_PERCENT:
2646             case NUMBERFORMAT_CURRENCY:
2647             case NUMBERFORMAT_NUMBER:
2648             case NUMBERFORMAT_SCIENTIFIC:
2649             case NUMBERFORMAT_DEFINED:          // if no category detected handle as number
2650             {
2651                 if ( nDecPos == 1 )                         // . at start
2652                     sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) );
2653                 else
2654                     sResString.Erase();
2655                 sal_uInt16 k;
2656                 for ( k = 0; k <= nThousand; k++)
2657                     sResString += sStrArray[nNums[k]];  // integer part
2658                 if ( nDecPos == 2 && k < nAnzNums )     // . somewhere
2659                 {
2660                     sResString += '.';
2661                     sal_uInt16 nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ?
2662                             nAnzNums-1 : nAnzNums);
2663                     for ( ; k < nStop; k++)
2664                         sResString += sStrArray[nNums[k]];  // fractional part
2665                 }
2666 
2667                 if (eScannedType != NUMBERFORMAT_SCIENTIFIC)
2668                     fOutNumber = StringToDouble(sResString);
2669                 else
2670                 {                                           // append exponent
2671                     sResString += 'E';
2672                     if ( nESign == -1 )
2673                         sResString += '-';
2674                     sResString += sStrArray[nNums[nAnzNums-1]];
2675                     rtl_math_ConversionStatus eStatus;
2676                     fOutNumber = ::rtl::math::stringToDouble(
2677                         sResString, '.', ',', &eStatus, NULL );
2678                     if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
2679                     {
2680                         F_Type = NUMBERFORMAT_TEXT;         // overflow/underflow -> Text
2681                         if (nESign == -1)
2682                             fOutNumber = 0.0;
2683                         else
2684                             fOutNumber = DBL_MAX;
2685 /*!*/                   return sal_True;
2686                     }
2687                 }
2688 
2689                 if ( nStringScanSign )
2690                 {
2691                     if ( nSign )
2692                         nSign *= nStringScanSign;
2693                     else
2694                         nSign = nStringScanSign;
2695                 }
2696                 if ( nSign < 0 )
2697                     fOutNumber = -fOutNumber;
2698 
2699                 if (eScannedType == NUMBERFORMAT_PERCENT)
2700                     fOutNumber/= 100.0;
2701             }
2702             break;
2703 
2704             case NUMBERFORMAT_FRACTION:
2705                 if (nAnzNums == 1)
2706                     fOutNumber = StringToDouble(sStrArray[nNums[0]]);
2707                 else if (nAnzNums == 2)
2708                 {
2709                     if (nThousand == 1)
2710                     {
2711                         sResString = sStrArray[nNums[0]];
2712                         sResString += sStrArray[nNums[1]];  // integer part
2713                         fOutNumber = StringToDouble(sResString);
2714                     }
2715                     else
2716                     {
2717                         double fZaehler = StringToDouble(sStrArray[nNums[0]]);
2718                         double fNenner = StringToDouble(sStrArray[nNums[1]]);
2719                         if (fNenner != 0.0)
2720                             fOutNumber = fZaehler/fNenner;
2721                         else
2722                             res = sal_False;
2723                     }
2724                 }
2725                 else                                        // nAnzNums > 2
2726                 {
2727                     sal_uInt16 k = 1;
2728                     sResString = sStrArray[nNums[0]];
2729                     if (nThousand > 0)
2730                         for (k = 1; k <= nThousand; k++)
2731                             sResString += sStrArray[nNums[k]];
2732                     fOutNumber = StringToDouble(sResString);
2733 
2734                     if (k == nAnzNums-2)
2735                     {
2736                         double fZaehler = StringToDouble(sStrArray[nNums[k]]);
2737                         double fNenner = StringToDouble(sStrArray[nNums[k+1]]);
2738                         if (fNenner != 0.0)
2739                             fOutNumber += fZaehler/fNenner;
2740                         else
2741                             res = sal_False;
2742                     }
2743                 }
2744 
2745                 if ( nStringScanSign )
2746                 {
2747                     if ( nSign )
2748                         nSign *= nStringScanSign;
2749                     else
2750                         nSign = nStringScanSign;
2751                 }
2752                 if ( nSign < 0 )
2753                     fOutNumber = -fOutNumber;
2754                 break;
2755 
2756             case NUMBERFORMAT_TIME:
2757                 GetTimeRef(fOutNumber, 0, nAnzNums);
2758                 if ( nSign < 0 )
2759                     fOutNumber = -fOutNumber;
2760                 break;
2761 
2762             case NUMBERFORMAT_DATE:
2763             {
2764                 sal_uInt16 nCounter = 0;                        // dummy here
2765                 res = GetDateRef( fOutNumber, nCounter, pFormat );
2766             }
2767             break;
2768 
2769             case NUMBERFORMAT_DATETIME:
2770             {
2771                 sal_uInt16 nCounter = 0;                        // needed here
2772                 res = GetDateRef( fOutNumber, nCounter, pFormat );
2773                 if ( res )
2774                 {
2775                     double fTime;
2776                     GetTimeRef( fTime, nCounter, nAnzNums - nCounter );
2777                     fOutNumber += fTime;
2778                 }
2779             }
2780             break;
2781 
2782             default:
2783                 DBG_ERRORFILE( "Some number recognized but what's it?" );
2784                 fOutNumber = 0.0;
2785                 break;
2786         }
2787     }
2788 
2789     if (res)        // overflow/underflow -> Text
2790     {
2791         if      (fOutNumber < -DBL_MAX) // -1.7E308
2792         {
2793             F_Type = NUMBERFORMAT_TEXT;
2794             fOutNumber = -DBL_MAX;
2795             return sal_True;
2796         }
2797         else if (fOutNumber >  DBL_MAX) // 1.7E308
2798         {
2799             F_Type = NUMBERFORMAT_TEXT;
2800             fOutNumber = DBL_MAX;
2801             return sal_True;
2802         }
2803     }
2804 
2805     if (res == sal_False)
2806     {
2807         eScannedType = NUMBERFORMAT_TEXT;
2808         fOutNumber = 0.0;
2809     }
2810 
2811     F_Type = eScannedType;
2812     return res;
2813 }
2814 
2815 
2816 
2817