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