merge the formfield patch from ooo-build
[ooovba.git] / svtools / source / numbers / zforfind.cxx
blob9fba39ee856b20517dfbfacc0aacffc634fb5d59
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: zforfind.cxx,v $
10 * $Revision: 1.51.96.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svtools.hxx"
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <float.h>
37 #include <errno.h>
38 #include <tools/date.hxx>
39 #include <tools/debug.hxx>
40 #include <rtl/math.hxx>
41 #include <unotools/charclass.hxx>
42 #include <unotools/calendarwrapper.hxx>
43 #include <unotools/localedatawrapper.hxx>
44 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
45 #include <unotools/digitgroupingiterator.hxx>
47 #include <svtools/zforlist.hxx> // NUMBERFORMAT_XXX
48 #include "zforscan.hxx"
49 #include <svtools/zformat.hxx>
51 #define _ZFORFIND_CXX
52 #include "zforfind.hxx"
53 #undef _ZFORFIND_CXX
56 #ifdef PRODUCT
57 #define NF_TEST_CALENDAR 0
58 #else
59 #define NF_TEST_CALENDAR 0
60 #endif
61 #if NF_TEST_CALENDAR
62 #include <comphelper/processfactory.hxx>
63 #include <com/sun/star/i18n/XExtendedCalendar.hpp>
64 #endif
67 const BYTE ImpSvNumberInputScan::nMatchedEndString = 0x01;
68 const BYTE ImpSvNumberInputScan::nMatchedMidString = 0x02;
69 const BYTE ImpSvNumberInputScan::nMatchedStartString = 0x04;
70 const BYTE ImpSvNumberInputScan::nMatchedVirgin = 0x08;
71 const BYTE ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
73 /* It is not clear how we want timezones to be handled. Convert them to local
74 * time isn't wanted, as it isn't done in any other place and timezone
75 * information isn't stored anywhere. Ignoring them and pretending local time
76 * may be wrong too and might not be what the user expects. Keep the input as
77 * string so that no information is lost.
78 * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
79 * would work, together with the nTimezonePos handling in GetTimeRef(). */
80 #define NF_RECOGNIZE_ISO8601_TIMEZONES 0
82 //---------------------------------------------------------------------------
83 // Konstruktor
85 ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
87 pUpperMonthText( NULL ),
88 pUpperAbbrevMonthText( NULL ),
89 pUpperDayText( NULL ),
90 pUpperAbbrevDayText( NULL )
92 pFormatter = pFormatterP;
93 pNullDate = new Date(30,12,1899);
94 nYear2000 = SvNumberFormatter::GetYear2000Default();
95 Reset();
96 ChangeIntl();
100 //---------------------------------------------------------------------------
101 // Destruktor
103 ImpSvNumberInputScan::~ImpSvNumberInputScan()
105 Reset();
106 delete pNullDate;
107 delete [] pUpperMonthText;
108 delete [] pUpperAbbrevMonthText;
109 delete [] pUpperDayText;
110 delete [] pUpperAbbrevDayText;
114 //---------------------------------------------------------------------------
115 // Reset
117 void ImpSvNumberInputScan::Reset()
119 #if 0
120 // ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision,
121 // wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht
122 // gebraucht wird..
123 for (USHORT i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
125 sStrArray[i].Erase();
126 nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1;
127 IsNum[i] = FALSE;
129 #endif
130 nMonth = 0;
131 nMonthPos = 0;
132 nTimePos = 0;
133 nSign = 0;
134 nESign = 0;
135 nDecPos = 0;
136 nNegCheck = 0;
137 nAnzStrings = 0;
138 nAnzNums = 0;
139 nThousand = 0;
140 eScannedType = NUMBERFORMAT_UNDEFINED;
141 nAmPm = 0;
142 nPosThousandString = 0;
143 nLogical = 0;
144 nStringScanNumFor = 0;
145 nStringScanSign = 0;
146 nMatchedAllStrings = nMatchedVirgin;
147 nMayBeIso8601 = 0;
148 nTimezonePos = 0;
152 //---------------------------------------------------------------------------
154 // static
155 inline BOOL ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
157 // If the input string wouldn't be converted using TransformInput() we'd
158 // to use something similar to the following and to adapt many places.
159 #if 0
160 // use faster isdigit() if possible
161 if ( c < 128 )
162 return isdigit( (unsigned char) c ) != 0;
163 if ( c < 256 )
164 return FALSE;
165 String aTmp( c );
166 return pFormatter->GetCharClass()->isDigit( aTmp, 0 );
167 #else
168 return c < 128 && isdigit( (unsigned char) c );
169 #endif
173 //---------------------------------------------------------------------------
175 void ImpSvNumberInputScan::TransformInput( String& rStr )
177 xub_StrLen nPos, nLen;
178 for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos )
180 if ( 256 <= rStr.GetChar( nPos ) &&
181 pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
182 break;
184 if ( nPos < nLen )
185 rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
186 pFormatter->GetLocale(), 0 );
190 //---------------------------------------------------------------------------
191 // StringToDouble
193 // Only simple unsigned floating point values without any error detection,
194 // decimal separator has to be '.'
196 double ImpSvNumberInputScan::StringToDouble( const String& rStr, BOOL bForceFraction )
198 double fNum = 0.0;
199 double fFrac = 0.0;
200 int nExp = 0;
201 xub_StrLen nPos = 0;
202 xub_StrLen nLen = rStr.Len();
203 BOOL bPreSep = !bForceFraction;
205 while (nPos < nLen)
207 if (rStr.GetChar(nPos) == '.')
208 bPreSep = FALSE;
209 else if (bPreSep)
210 fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0');
211 else
213 fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0');
214 --nExp;
216 nPos++;
218 if ( fFrac )
219 return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
220 return fNum;
224 //---------------------------------------------------------------------------
225 // NextNumberStringSymbol
227 // Zerlegt die Eingabe in Zahlen und Strings fuer die weitere
228 // Verarbeitung (Turing-Maschine).
229 //---------------------------------------------------------------------------
230 // Ausgangs Zustand = GetChar
231 //---------------+-------------------+-----------------------+---------------
232 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand
233 //---------------+-------------------+-----------------------+---------------
234 // GetChar | Ziffer | Symbol=Zeichen | GetValue
235 // | Sonst | Symbol=Zeichen | GetString
236 //---------------|-------------------+-----------------------+---------------
237 // GetValue | Ziffer | Symbol=Symbol+Zeichen | GetValue
238 // | Sonst | Dec(CharPos) | Stop
239 //---------------+-------------------+-----------------------+---------------
240 // GetString | Ziffer | Dec(CharPos) | Stop
241 // | Sonst | Symbol=Symbol+Zeichen | GetString
242 //---------------+-------------------+-----------------------+---------------
244 enum ScanState // States der Turing-Maschine
246 SsStop = 0,
247 SsStart = 1,
248 SsGetValue = 2,
249 SsGetString = 3
252 BOOL ImpSvNumberInputScan::NextNumberStringSymbol(
253 const sal_Unicode*& pStr,
254 String& rSymbol )
256 BOOL isNumber = FALSE;
257 sal_Unicode cToken;
258 ScanState eState = SsStart;
259 register const sal_Unicode* pHere = pStr;
260 register xub_StrLen nChars = 0;
262 while ( ((cToken = *pHere) != 0) && eState != SsStop)
264 pHere++;
265 switch (eState)
267 case SsStart:
268 if ( MyIsdigit( cToken ) )
270 eState = SsGetValue;
271 isNumber = TRUE;
273 else
274 eState = SsGetString;
275 nChars++;
276 break;
277 case SsGetValue:
278 if ( MyIsdigit( cToken ) )
279 nChars++;
280 else
282 eState = SsStop;
283 pHere--;
285 break;
286 case SsGetString:
287 if ( !MyIsdigit( cToken ) )
288 nChars++;
289 else
291 eState = SsStop;
292 pHere--;
294 break;
295 default:
296 break;
297 } // switch
298 } // while
300 if ( nChars )
301 rSymbol.Assign( pStr, nChars );
302 else
303 rSymbol.Erase();
305 pStr = pHere;
307 return isNumber;
311 //---------------------------------------------------------------------------
312 // SkipThousands
314 // FIXME: should be grouping; it is only used though in case nAnzStrings is
315 // near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision().
317 BOOL ImpSvNumberInputScan::SkipThousands(
318 const sal_Unicode*& pStr,
319 String& rSymbol )
321 BOOL res = FALSE;
322 sal_Unicode cToken;
323 const String& rThSep = pFormatter->GetNumThousandSep();
324 register const sal_Unicode* pHere = pStr;
325 ScanState eState = SsStart;
326 xub_StrLen nCounter = 0; // counts 3 digits
328 while ( ((cToken = *pHere) != 0) && eState != SsStop)
330 pHere++;
331 switch (eState)
333 case SsStart:
334 if ( StringPtrContains( rThSep, pHere-1, 0 ) )
336 nCounter = 0;
337 eState = SsGetValue;
338 pHere += rThSep.Len()-1;
340 else
342 eState = SsStop;
343 pHere--;
345 break;
346 case SsGetValue:
347 if ( MyIsdigit( cToken ) )
349 rSymbol += cToken;
350 nCounter++;
351 if (nCounter == 3)
353 eState = SsStart;
354 res = TRUE; // .000 combination found
357 else
359 eState = SsStop;
360 pHere--;
362 break;
363 default:
364 break;
365 } // switch
366 } // while
368 if (eState == SsGetValue) // break witth less than 3 digits
370 if ( nCounter )
371 rSymbol.Erase( rSymbol.Len() - nCounter, nCounter );
372 pHere -= nCounter + rThSep.Len(); // put back ThSep also
374 pStr = pHere;
376 return res;
380 //---------------------------------------------------------------------------
381 // NumberStringDivision
383 void ImpSvNumberInputScan::NumberStringDivision( const String& rString )
385 const sal_Unicode* pStr = rString.GetBuffer();
386 const sal_Unicode* const pEnd = pStr + rString.Len();
387 while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
389 if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
390 { // Zahl
391 IsNum[nAnzStrings] = TRUE;
392 nNums[nAnzNums] = nAnzStrings;
393 nAnzNums++;
394 if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
395 nPosThousandString == 0) // nur einmal
396 if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
397 nPosThousandString = nAnzStrings;
399 else
401 IsNum[nAnzStrings] = FALSE;
403 nAnzStrings++;
408 //---------------------------------------------------------------------------
409 // Whether rString contains rWhat at nPos
411 BOOL ImpSvNumberInputScan::StringContainsImpl( const String& rWhat,
412 const String& rString, xub_StrLen nPos )
414 if ( nPos + rWhat.Len() <= rString.Len() )
415 return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos );
416 return FALSE;
420 //---------------------------------------------------------------------------
421 // Whether pString contains rWhat at nPos
423 BOOL ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat,
424 const sal_Unicode* pString, xub_StrLen nPos )
426 if ( rWhat.Len() == 0 )
427 return FALSE;
428 register const sal_Unicode* pWhat = rWhat.GetBuffer();
429 register const sal_Unicode* const pEnd = pWhat + rWhat.Len();
430 register const sal_Unicode* pStr = pString + nPos;
431 while ( pWhat < pEnd )
433 if ( *pWhat != *pStr )
434 return FALSE;
435 pWhat++;
436 pStr++;
438 return TRUE;
442 //---------------------------------------------------------------------------
443 // SkipChar
445 // ueberspringt genau das angegebene Zeichen
447 inline BOOL ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString,
448 xub_StrLen& nPos )
450 if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c))
452 nPos++;
453 return TRUE;
455 return FALSE;
459 //---------------------------------------------------------------------------
460 // SkipBlanks
462 // Ueberspringt Leerzeichen
464 inline void ImpSvNumberInputScan::SkipBlanks( const String& rString,
465 xub_StrLen& nPos )
467 if ( nPos < rString.Len() )
469 register const sal_Unicode* p = rString.GetBuffer() + nPos;
470 while ( *p == ' ' )
472 nPos++;
473 p++;
479 //---------------------------------------------------------------------------
480 // SkipString
482 // jump over rWhat in rString at nPos
484 inline BOOL ImpSvNumberInputScan::SkipString( const String& rWhat,
485 const String& rString, xub_StrLen& nPos )
487 if ( StringContains( rWhat, rString, nPos ) )
489 nPos = nPos + rWhat.Len();
490 return TRUE;
492 return FALSE;
496 //---------------------------------------------------------------------------
497 // GetThousandSep
499 // recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping
501 inline BOOL ImpSvNumberInputScan::GetThousandSep(
502 const String& rString,
503 xub_StrLen& nPos,
504 USHORT nStringPos )
506 const String& rSep = pFormatter->GetNumThousandSep();
507 // Is it an ordinary space instead of a non-breaking space?
508 bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 &&
509 rSep.Len() == 1 && rString.Len() == 1;
510 if (!( (rString == rSep || bSpaceBreak) // nothing else
511 && nStringPos < nAnzStrings - 1 // safety first!
512 && IsNum[nStringPos+1] )) // number follows
513 return FALSE; // no? => out
515 utl::DigitGroupingIterator aGrouping(
516 pFormatter->GetLocaleData()->getDigitGrouping());
517 // Match ,### in {3} or ,## in {3,2}
518 /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or
519 * ,##,### and to match ,### in {3,2} only if it's the last. However,
520 * currently there is no track kept where group separators occur. In {3,2}
521 * #,###,### and #,##,## would be valid input, which maybe isn't even bad
522 * for #,###,###. Other combinations such as #,###,## maybe not. */
523 xub_StrLen nLen = sStrArray[nStringPos+1].Len();
524 if (nLen == aGrouping.get() // with 3 (or so) digits
525 || nLen == aGrouping.advance().get() // or with 2 (or 3 or so) digits
526 || nPosThousandString == nStringPos+1 // or concatenated
529 nPos = nPos + rSep.Len();
530 return TRUE;
532 return FALSE;
536 //---------------------------------------------------------------------------
537 // GetLogical
539 // Conversion of text to logial value
540 // "TRUE" => 1:
541 // "FALSE"=> -1:
542 // else => 0:
544 short ImpSvNumberInputScan::GetLogical( const String& rString )
546 short res;
548 const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
549 if ( rString == pFS->GetTrueString() )
550 res = 1;
551 else if ( rString == pFS->GetFalseString() )
552 res = -1;
553 else
554 res = 0;
556 return res;
560 //---------------------------------------------------------------------------
561 // GetMonth
563 // Converts a string containing a month name (JAN, January) at nPos into the
564 // month number (negative if abbreviated), returns 0 if nothing found
566 short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos )
568 // #102136# The correct English form of month September abbreviated is
569 // SEPT, but almost every data contains SEP instead.
570 static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
571 static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
573 short res = 0; // no month found
575 if (rString.Len() > nPos) // only if needed
577 if ( !bTextInitialized )
578 InitText();
579 sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
580 for ( sal_Int16 i = 0; i < nMonths; i++ )
582 if ( StringContains( pUpperMonthText[i], rString, nPos ) )
583 { // full names first
584 nPos = nPos + pUpperMonthText[i].Len();
585 res = i+1;
586 break; // for
588 else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) )
589 { // abbreviated
590 nPos = nPos + pUpperAbbrevMonthText[i].Len();
591 res = sal::static_int_cast< short >(-(i+1)); // negative
592 break; // for
594 else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
595 StringContains( aSepShortened, rString, nPos ) )
596 { // #102136# SEPT/SEP
597 nPos = nPos + aSepShortened.Len();
598 res = sal::static_int_cast< short >(-(i+1)); // negative
599 break; // for
604 return res;
608 //---------------------------------------------------------------------------
609 // GetDayOfWeek
611 // Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
612 // DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
614 int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos )
616 int res = 0; // no day found
618 if (rString.Len() > nPos) // only if needed
620 if ( !bTextInitialized )
621 InitText();
622 sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
623 for ( sal_Int16 i = 0; i < nDays; i++ )
625 if ( StringContains( pUpperDayText[i], rString, nPos ) )
626 { // full names first
627 nPos = nPos + pUpperDayText[i].Len();
628 res = i + 1;
629 break; // for
631 if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) )
632 { // abbreviated
633 nPos = nPos + pUpperAbbrevDayText[i].Len();
634 res = -(i + 1); // negative
635 break; // for
640 return res;
644 //---------------------------------------------------------------------------
645 // GetCurrency
647 // Lesen eines Waehrungssysmbols
648 // '$' => TRUE
649 // sonst => FALSE
651 BOOL ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos,
652 const SvNumberformat* pFormat )
654 if ( rString.Len() > nPos )
656 if ( !aUpperCurrSymbol.Len() )
657 { // if no format specified the currency of the initialized formatter
658 LanguageType eLang = (pFormat ? pFormat->GetLanguage() :
659 pFormatter->GetLanguage());
660 aUpperCurrSymbol = pFormatter->GetCharClass()->upper(
661 SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
663 if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
665 nPos = nPos + aUpperCurrSymbol.Len();
666 return TRUE;
668 if ( pFormat )
670 String aSymbol, aExtension;
671 if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
673 if ( aSymbol.Len() <= rString.Len() - nPos )
675 pFormatter->GetCharClass()->toUpper( aSymbol );
676 if ( StringContains( aSymbol, rString, nPos ) )
678 nPos = nPos + aSymbol.Len();
679 return TRUE;
686 return FALSE;
690 //---------------------------------------------------------------------------
691 // GetTimeAmPm
693 // Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe
695 // Rueckgabe:
696 // "AM" od. "PM" => TRUE
697 // sonst => FALSE
699 // nAmPos:
700 // "AM" => 1
701 // "PM" => -1
702 // sonst => 0
704 BOOL ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos )
707 if ( rString.Len() > nPos )
709 const CharClass* pChr = pFormatter->GetCharClass();
710 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
711 if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) )
713 nAmPm = 1;
714 nPos = nPos + pLoc->getTimeAM().Len();
715 return TRUE;
717 else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) )
719 nAmPm = -1;
720 nPos = nPos + pLoc->getTimePM().Len();
721 return TRUE;
725 return FALSE;
729 //---------------------------------------------------------------------------
730 // GetDecSep
732 // Lesen eines Dezimaltrenners (',')
733 // ',' => TRUE
734 // sonst => FALSE
736 inline BOOL ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos )
738 if ( rString.Len() > nPos )
740 const String& rSep = pFormatter->GetNumDecimalSep();
741 if ( rString.Equals( rSep, nPos, rSep.Len() ) )
743 nPos = nPos + rSep.Len();
744 return TRUE;
747 return FALSE;
751 //---------------------------------------------------------------------------
752 // read a hundredth seconds separator
754 inline BOOL ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos )
756 if ( rString.Len() > nPos )
758 const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
759 if ( rString.Equals( rSep, nPos, rSep.Len() ) )
761 nPos = nPos + rSep.Len();
762 return TRUE;
765 return FALSE;
769 //---------------------------------------------------------------------------
770 // GetSign
772 // Lesen eines Vorzeichens, auch Klammer !?!
773 // '+' => 1
774 // '-' => -1
775 // '(' => -1, nNegCheck = 1
776 // sonst => 0
778 int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos )
780 if (rString.Len() > nPos)
781 switch (rString.GetChar(nPos))
783 case '+':
784 nPos++;
785 return 1;
786 case '(': // '(' aehnlich wie '-' ?!?
787 nNegCheck = 1;
788 //! fallthru
789 case '-':
790 nPos++;
791 return -1;
792 default:
793 break;
796 return 0;
800 //---------------------------------------------------------------------------
801 // GetESign
803 // Lesen eines Vorzeichens, gedacht fuer Exponent ?!?
804 // '+' => 1
805 // '-' => -1
806 // sonst => 0
808 short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos )
810 if (rString.Len() > nPos)
811 switch (rString.GetChar(nPos))
813 case '+':
814 nPos++;
815 return 1;
816 case '-':
817 nPos++;
818 return -1;
819 default:
820 break;
823 return 0;
827 //---------------------------------------------------------------------------
828 // GetNextNumber
830 // i counts string portions, j counts numbers thereof.
831 // It should had been called SkipNumber instead.
833 inline BOOL ImpSvNumberInputScan::GetNextNumber( USHORT& i, USHORT& j )
835 if ( i < nAnzStrings && IsNum[i] )
837 j++;
838 i++;
839 return TRUE;
841 return FALSE;
845 //---------------------------------------------------------------------------
846 // GetTimeRef
848 void ImpSvNumberInputScan::GetTimeRef(
849 double& fOutNumber,
850 USHORT nIndex, // j-value of the first numeric time part of input, default 0
851 USHORT nAnz ) // count of numeric time parts
853 USHORT nHour;
854 USHORT nMinute = 0;
855 USHORT nSecond = 0;
856 double fSecond100 = 0.0;
857 USHORT nStartIndex = nIndex;
859 if (nTimezonePos)
861 // find first timezone number index and adjust count
862 for (USHORT j=0; j<nAnzNums; ++j)
864 if (nNums[j] == nTimezonePos)
866 // nAnz is not total count, but count of time relevant strings.
867 if (nStartIndex < j && j - nStartIndex < nAnz)
868 nAnz = j - nStartIndex;
869 break; // for
874 if (nDecPos == 2 && (nAnz == 3 || nAnz == 2)) // 20:45.5 or 45.5
875 nHour = 0;
876 else if (nIndex - nStartIndex < nAnz)
877 nHour = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
878 else
880 nHour = 0;
881 DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index");
883 if (nDecPos == 2 && nAnz == 2) // 45.5
884 nMinute = 0;
885 else if (nIndex - nStartIndex < nAnz)
886 nMinute = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
887 if (nIndex - nStartIndex < nAnz)
888 nSecond = (USHORT) sStrArray[nNums[nIndex++]].ToInt32();
889 if (nIndex - nStartIndex < nAnz)
890 fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], TRUE );
891 if (nAmPm == -1 && nHour != 12) // PM
892 nHour += 12;
893 else if (nAmPm == 1 && nHour == 12) // 12 AM
894 nHour = 0;
896 fOutNumber = ((double)nHour*3600 +
897 (double)nMinute*60 +
898 (double)nSecond +
899 fSecond100)/86400.0;
903 //---------------------------------------------------------------------------
904 // ImplGetDay
906 USHORT ImpSvNumberInputScan::ImplGetDay( USHORT nIndex )
908 USHORT nRes = 0;
910 if (sStrArray[nNums[nIndex]].Len() <= 2)
912 USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
913 if (nNum <= 31)
914 nRes = nNum;
917 return nRes;
921 //---------------------------------------------------------------------------
922 // ImplGetMonth
924 USHORT ImpSvNumberInputScan::ImplGetMonth( USHORT nIndex )
926 // preset invalid month number
927 USHORT nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
929 if (sStrArray[nNums[nIndex]].Len() <= 2)
931 USHORT nNum = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
932 if ( 0 < nNum && nNum <= nRes )
933 nRes = nNum - 1; // zero based for CalendarFieldIndex::MONTH
936 return nRes;
940 //---------------------------------------------------------------------------
941 // ImplGetYear
943 // 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ...
945 USHORT ImpSvNumberInputScan::ImplGetYear( USHORT nIndex )
947 USHORT nYear = 0;
949 if (sStrArray[nNums[nIndex]].Len() <= 4)
951 nYear = (USHORT) sStrArray[nNums[nIndex]].ToInt32();
952 nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
955 return nYear;
958 //---------------------------------------------------------------------------
960 bool ImpSvNumberInputScan::MayBeIso8601()
962 if (nMayBeIso8601 == 0)
964 if (nAnzNums >= 3 && nNums[0] < nAnzStrings &&
965 sStrArray[nNums[0]].ToInt32() > 31)
966 nMayBeIso8601 = 1;
967 else
968 nMayBeIso8601 = 2;
970 return nMayBeIso8601 == 1;
973 //---------------------------------------------------------------------------
974 // GetDateRef
976 BOOL ImpSvNumberInputScan::GetDateRef( double& fDays, USHORT& nCounter,
977 const SvNumberformat* pFormat )
979 using namespace ::com::sun::star::i18n;
980 NfEvalDateFormat eEDF;
981 int nFormatOrder;
982 if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) )
984 eEDF = pFormatter->GetEvalDateFormat();
985 switch ( eEDF )
987 case NF_EVALDATEFORMAT_INTL :
988 case NF_EVALDATEFORMAT_FORMAT :
989 nFormatOrder = 1; // only one loop
990 break;
991 default:
992 nFormatOrder = 2;
993 if ( nMatchedAllStrings )
994 eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
995 // we have a complete match, use it
998 else
1000 eEDF = NF_EVALDATEFORMAT_INTL;
1001 nFormatOrder = 1;
1003 BOOL res = TRUE;
1005 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1006 CalendarWrapper* pCal = pFormatter->GetCalendar();
1007 for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
1009 pCal->setGregorianDateTime( Date() ); // today
1010 String aOrgCalendar; // empty => not changed yet
1011 DateFormat DateFmt;
1012 BOOL bFormatTurn;
1013 switch ( eEDF )
1015 case NF_EVALDATEFORMAT_INTL :
1016 bFormatTurn = FALSE;
1017 DateFmt = pLoc->getDateFormat();
1018 break;
1019 case NF_EVALDATEFORMAT_FORMAT :
1020 bFormatTurn = TRUE;
1021 DateFmt = pFormat->GetDateOrder();
1022 break;
1023 case NF_EVALDATEFORMAT_INTL_FORMAT :
1024 if ( nTryOrder == 1 )
1026 bFormatTurn = FALSE;
1027 DateFmt = pLoc->getDateFormat();
1029 else
1031 bFormatTurn = TRUE;
1032 DateFmt = pFormat->GetDateOrder();
1034 break;
1035 case NF_EVALDATEFORMAT_FORMAT_INTL :
1036 if ( nTryOrder == 2 )
1038 bFormatTurn = FALSE;
1039 DateFmt = pLoc->getDateFormat();
1041 else
1043 bFormatTurn = TRUE;
1044 DateFmt = pFormat->GetDateOrder();
1046 break;
1047 default:
1048 DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
1049 DateFmt = YMD;
1050 bFormatTurn = FALSE;
1052 if ( bFormatTurn )
1054 #if 0
1055 /* TODO:
1056 We are currently not able to fully support a switch to another calendar during
1057 input for the following reasons:
1058 1. We do have a problem if both (locale's default and format's) calendars
1059 define the same YMD order and use the same date separator, there is no way
1060 to distinguish between them if the input results in valid calendar input for
1061 both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
1062 it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
1063 calendar be preferred? This could be confusing if a Calc cell was formatted
1064 different to the locale's default and has no content yet, then the user has
1065 no clue about the format or calendar being set.
1066 2. In Calc cell edit mode a date is always displayed and edited using the
1067 default edit format of the default calendar (normally being Gregorian). If
1068 input was ambiguous due to issue #1 we'd need a mechanism to tell that a
1069 date was edited and not newly entered. Not feasible. Otherwise we'd need a
1070 mechanism to use a specific edit format with a specific calendar according
1071 to the format set.
1072 3. For some calendars like Japanese Gengou we'd need era input, which isn't
1073 implemented at all. Though this is a rare and special case, forcing a
1074 calendar dependent edit format as suggested in item #2 might require era
1075 input, if it shouldn't result in a fallback to Gregorian calendar.
1076 4. Last and least: the GetMonth() method currently only matches month names of
1077 the default calendar. Alternating month names of the actual format's
1078 calendar would have to be implemented. No problem.
1081 if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
1082 pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
1083 else
1084 pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
1085 nStringScanNumFor );
1086 #endif
1089 res = TRUE;
1090 nCounter = 0;
1091 // For incomplete dates, always assume first day of month if not specified.
1092 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1094 switch (nAnzNums) // count of numbers in string
1096 case 0: // none
1097 if (nMonthPos) // only month (Jan)
1098 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1099 else
1100 res = FALSE;
1101 break;
1103 case 1: // only one number
1104 nCounter = 1;
1105 switch (nMonthPos) // where is the month
1107 case 0: // not found => only day entered
1108 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1109 break;
1110 case 1: // month at the beginning (Jan 01)
1111 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1112 switch (DateFmt)
1114 case MDY:
1115 case YMD: {
1116 USHORT nDay = ImplGetDay(0);
1117 USHORT nYear = ImplGetYear(0);
1118 if (nDay == 0 || nDay > 32) {
1119 pCal->setValue( CalendarFieldIndex::YEAR, nYear);
1121 else
1122 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1123 break;
1125 case DMY:
1126 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1127 break;
1128 default:
1129 res = FALSE;
1130 break;
1132 break;
1133 case 3: // month at the end (10 Jan)
1134 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1135 switch (DateFmt)
1137 case DMY:
1138 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1139 break;
1140 case YMD:
1141 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1142 break;
1143 default:
1144 res = FALSE;
1145 break;
1147 break;
1148 default:
1149 res = FALSE;
1150 break;
1151 } // switch (nMonthPos)
1152 break;
1154 case 2: // 2 numbers
1155 nCounter = 2;
1156 switch (nMonthPos) // where is the month
1158 case 0: // not found
1160 bool bHadExact;
1161 sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1162 if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff )
1163 { // formatted as date and exactly 2 parts
1164 bHadExact = true;
1165 switch ( (nExactDateOrder >> 8) & 0xff )
1167 case 'Y':
1168 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1169 break;
1170 case 'M':
1171 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1172 break;
1173 case 'D':
1174 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1175 break;
1176 default:
1177 bHadExact = false;
1179 switch ( nExactDateOrder & 0xff )
1181 case 'Y':
1182 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1183 break;
1184 case 'M':
1185 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1186 break;
1187 case 'D':
1188 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1189 break;
1190 default:
1191 bHadExact = false;
1194 else
1195 bHadExact = false;
1196 if ( !bHadExact || !pCal->isValid() )
1198 if ( !bHadExact && nExactDateOrder )
1199 pCal->setGregorianDateTime( Date() ); // reset today
1200 switch (DateFmt)
1202 case MDY:
1203 // M D
1204 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1205 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1206 if ( !pCal->isValid() ) // 2nd try
1207 { // M Y
1208 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1209 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1210 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1212 break;
1213 case DMY:
1214 // D M
1215 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1216 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1217 if ( !pCal->isValid() ) // 2nd try
1218 { // M Y
1219 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1220 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1221 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1223 break;
1224 case YMD:
1225 // M D
1226 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1227 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1228 if ( !pCal->isValid() ) // 2nd try
1229 { // Y M
1230 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1231 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1232 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1234 break;
1235 default:
1236 res = FALSE;
1237 break;
1241 break;
1242 case 1: // month at the beginning (Jan 01 01)
1244 // The input is valid as MDY in almost any
1245 // constellation, there is no date order (M)YD except if
1246 // set in a format applied.
1247 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1248 sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1249 if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
1251 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1252 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1254 else
1256 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1257 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1260 break;
1261 case 2: // month in the middle (10 Jan 94)
1262 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1263 switch (DateFmt)
1265 case MDY: // yes, "10-Jan-94" is valid
1266 case DMY:
1267 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1268 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1269 break;
1270 case YMD:
1271 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1272 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1273 break;
1274 default:
1275 res = FALSE;
1276 break;
1278 break;
1279 default: // else, e.g. month at the end (94 10 Jan)
1280 res = FALSE;
1281 break;
1282 } // switch (nMonthPos)
1283 break;
1285 default: // more than two numbers (31.12.94 8:23) (31.12. 8:23)
1286 switch (nMonthPos) // where is the month
1288 case 0: // not found
1290 nCounter = 3;
1291 if ( nTimePos > 1 )
1292 { // find first time number index (should only be 3 or 2 anyway)
1293 for ( USHORT j = 0; j < nAnzNums; j++ )
1295 if ( nNums[j] == nTimePos - 2 )
1297 nCounter = j;
1298 break; // for
1302 // ISO 8601 yyyy-mm-dd forced recognition
1303 DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt);
1304 switch (eDF)
1306 case MDY:
1307 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1308 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1309 if ( nCounter > 2 )
1310 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1311 break;
1312 case DMY:
1313 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1314 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1315 if ( nCounter > 2 )
1316 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1317 break;
1318 case YMD:
1319 if ( nCounter > 2 )
1320 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
1321 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1322 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1323 break;
1324 default:
1325 res = FALSE;
1326 break;
1329 break;
1330 case 1: // month at the beginning (Jan 01 01 8:23)
1331 nCounter = 2;
1332 switch (DateFmt)
1334 case MDY:
1335 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1336 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1337 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1338 break;
1339 default:
1340 res = FALSE;
1341 break;
1343 break;
1344 case 2: // month in the middle (10 Jan 94 8:23)
1345 nCounter = 2;
1346 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1347 switch (DateFmt)
1349 case DMY:
1350 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1351 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1352 break;
1353 case YMD:
1354 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1355 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1356 break;
1357 default:
1358 res = FALSE;
1359 break;
1361 break;
1362 default: // else, e.g. month at the end (94 10 Jan 8:23)
1363 nCounter = 2;
1364 res = FALSE;
1365 break;
1366 } // switch (nMonthPos)
1367 break;
1368 } // switch (nAnzNums)
1370 if ( res && pCal->isValid() )
1372 double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
1373 fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
1374 fDays -= fDiff;
1375 nTryOrder = nFormatOrder; // break for
1377 else
1378 res = FALSE;
1380 if ( aOrgCalendar.Len() )
1381 pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() ); // restore calendar
1383 #if NF_TEST_CALENDAR
1385 using namespace ::com::sun::star;
1386 struct entry { const char* lan; const char* cou; const char* cal; };
1387 const entry cals[] = {
1388 { "en", "US", "gregorian" },
1389 { "ar", "TN", "hijri" },
1390 { "he", "IL", "jewish" },
1391 { "ja", "JP", "gengou" },
1392 { "ko", "KR", "hanja_yoil" },
1393 { "th", "TH", "buddhist" },
1394 { "zh", "TW", "ROC" },
1395 {0,0,0}
1397 lang::Locale aLocale;
1398 sal_Bool bValid;
1399 sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond;
1400 sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
1401 sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis;
1402 sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis;
1403 uno::Reference< lang::XMultiServiceFactory > xSMgr =
1404 ::comphelper::getProcessServiceFactory();
1405 uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal(
1406 xSMgr->createInstance( ::rtl::OUString(
1407 RTL_CONSTASCII_USTRINGPARAM(
1408 "com.sun.star.i18n.LocaleCalendar" ) ) ),
1409 uno::UNO_QUERY );
1410 for ( const entry* p = cals; p->lan; ++p )
1412 aLocale.Language = ::rtl::OUString::createFromAscii( p->lan );
1413 aLocale.Country = ::rtl::OUString::createFromAscii( p->cou );
1414 xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ),
1415 aLocale );
1416 double nDateTime = 0.0; // 1-Jan-1970 00:00:00
1417 nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1418 nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1419 nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 +
1420 (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis);
1421 nDST1 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1422 nDST1millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1423 nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 +
1424 (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis);
1425 nDateTime -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1426 xCal->setDateTime( nDateTime );
1427 nDST2 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1428 nDST2millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1429 nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 +
1430 (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis);
1431 if ( nDST1InMillis != nDST2InMillis )
1433 nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1434 xCal->setDateTime( nDateTime );
1436 nDaySet = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1437 nMonthSet = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1438 nYearSet = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1439 nHourSet = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1440 nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1441 nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1442 nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1443 nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1444 nDST = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1445 nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1446 xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet );
1447 xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet );
1448 xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet );
1449 xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet );
1450 xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet );
1451 xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet );
1452 bValid = xCal->isValid();
1453 nDay = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1454 nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1455 nYear = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1456 nHour = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1457 nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1458 nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1459 bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear ==
1460 nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond
1461 == nSecondSet;
1464 #endif // NF_TEST_CALENDAR
1468 return res;
1472 //---------------------------------------------------------------------------
1473 // ScanStartString
1475 // ersten String analysieren
1476 // Alles weg => TRUE
1477 // sonst => FALSE
1479 BOOL ImpSvNumberInputScan::ScanStartString( const String& rString,
1480 const SvNumberformat* pFormat )
1482 xub_StrLen nPos = 0;
1483 int nDayOfWeek;
1485 // First of all, eat leading blanks
1486 SkipBlanks(rString, nPos);
1488 // Yes, nMatchedAllStrings should know about the sign position
1489 nSign = GetSign(rString, nPos);
1490 if ( nSign ) // sign?
1491 SkipBlanks(rString, nPos);
1493 // #102371# match against format string only if start string is not a sign character
1494 if ( nMatchedAllStrings && !(nSign && rString.Len() == 1) )
1495 { // Match against format in any case, so later on for a "x1-2-3" input
1496 // we may distinguish between a xy-m-d (or similar) date and a x0-0-0
1497 // format. No sign detection here!
1498 if ( ScanStringNumFor( rString, nPos, pFormat, 0, TRUE ) )
1499 nMatchedAllStrings |= nMatchedStartString;
1500 else
1501 nMatchedAllStrings = 0;
1504 if ( GetDecSep(rString, nPos) ) // decimal separator in start string
1506 nDecPos = 1;
1507 SkipBlanks(rString, nPos);
1509 else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)?
1511 eScannedType = NUMBERFORMAT_CURRENCY; // !!! it IS currency !!!
1512 SkipBlanks(rString, nPos);
1513 if (nSign == 0) // no sign yet
1515 nSign = GetSign(rString, nPos);
1516 if ( nSign ) // DM -1
1517 SkipBlanks(rString, nPos);
1520 else
1522 nMonth = GetMonth(rString, nPos);
1523 if ( nMonth ) // month (Jan 1)?
1525 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
1526 nMonthPos = 1; // month at the beginning
1527 if ( nMonth < 0 )
1528 SkipChar( '.', rString, nPos ); // abbreviated
1529 SkipBlanks(rString, nPos);
1531 else
1533 nDayOfWeek = GetDayOfWeek( rString, nPos );
1534 if ( nDayOfWeek )
1535 { // day of week is just parsed away
1536 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
1537 if ( nPos < rString.Len() )
1539 if ( nDayOfWeek < 0 )
1540 { // abbreviated
1541 if ( rString.GetChar( nPos ) == '.' )
1542 ++nPos;
1544 else
1545 { // full long name
1546 SkipBlanks(rString, nPos);
1547 SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
1549 SkipBlanks(rString, nPos);
1550 nMonth = GetMonth(rString, nPos);
1551 if ( nMonth ) // month (Jan 1)?
1553 nMonthPos = 1; // month a the beginning
1554 if ( nMonth < 0 )
1555 SkipChar( '.', rString, nPos ); // abbreviated
1556 SkipBlanks(rString, nPos);
1563 // skip any trailing '-' or '/' chars
1564 if (nPos < rString.Len())
1566 while (SkipChar ('-', rString, nPos) || SkipChar ('/', rString, nPos)) {
1567 // do nothing
1570 if (nPos < rString.Len()) // not everything consumed
1572 // Does input StartString equal StartString of format?
1573 // This time with sign detection!
1574 if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
1575 return MatchedReturn();
1578 return TRUE;
1582 //---------------------------------------------------------------------------
1583 // ScanMidString
1585 // String in der Mitte analysieren
1586 // Alles weg => TRUE
1587 // sonst => FALSE
1589 BOOL ImpSvNumberInputScan::ScanMidString( const String& rString,
1590 USHORT nStringPos, const SvNumberformat* pFormat )
1592 xub_StrLen nPos = 0;
1593 short eOldScannedType = eScannedType;
1595 if ( nMatchedAllStrings )
1596 { // Match against format in any case, so later on for a "1-2-3-4" input
1597 // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1598 // format.
1599 if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
1600 nMatchedAllStrings |= nMatchedMidString;
1601 else
1602 nMatchedAllStrings = 0;
1605 SkipBlanks(rString, nPos);
1606 if (GetDecSep(rString, nPos)) // decimal separator?
1608 if (nDecPos == 1 || nDecPos == 3) // .12.4 or 1.E2.1
1609 return MatchedReturn();
1610 else if (nDecPos == 2) // . dup: 12.4.
1612 if (bDecSepInDateSeps) // . also date separator
1614 if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
1615 eScannedType != NUMBERFORMAT_DATE &&
1616 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1617 return MatchedReturn();
1618 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1619 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1620 SkipBlanks(rString, nPos);
1622 else
1623 return MatchedReturn();
1625 else
1627 nDecPos = 2; // . in mid string
1628 SkipBlanks(rString, nPos);
1631 else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME)
1632 && GetTime100SecSep( rString, nPos ) )
1633 { // hundredth seconds separator
1634 if ( nDecPos )
1635 return MatchedReturn();
1636 nDecPos = 2; // . in mid string
1637 SkipBlanks(rString, nPos);
1640 if (SkipChar('/', rString, nPos)) // fraction?
1642 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1643 && eScannedType != NUMBERFORMAT_DATE) // except date
1644 return MatchedReturn(); // => jan/31/1994
1645 else if ( eScannedType != NUMBERFORMAT_DATE // analyzed date until now
1646 && ( eSetType == NUMBERFORMAT_FRACTION // and preset was fraction
1647 || (nAnzNums == 3 // or 3 numbers
1648 && nStringPos > 2) ) ) // and what ???
1650 SkipBlanks(rString, nPos);
1651 eScannedType = NUMBERFORMAT_FRACTION; // !!! it IS a fraction
1653 else
1654 nPos--; // put '/' back
1657 if (GetThousandSep(rString, nPos, nStringPos)) // 1,000
1659 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1660 && eScannedType != NUMBERFORMAT_CURRENCY) // except currency
1661 return MatchedReturn();
1662 nThousand++;
1665 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1666 const String& rDate = pFormatter->GetDateSep();
1667 const String& rTime = pLoc->getTimeSep();
1668 sal_Unicode cTime = rTime.GetChar(0);
1669 SkipBlanks(rString, nPos);
1670 if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
1671 || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
1672 || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
1673 || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
1675 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1676 && eScannedType != NUMBERFORMAT_DATE) // except date
1677 return MatchedReturn();
1678 SkipBlanks(rString, nPos);
1679 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1680 short nTmpMonth = GetMonth(rString, nPos); // 10. Jan 94
1681 if (nMonth && nTmpMonth) // month dup
1682 return MatchedReturn();
1683 if (nTmpMonth)
1685 nMonth = nTmpMonth;
1686 nMonthPos = 2; // month in the middle
1687 if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
1688 ; // short month may be abbreviated Jan.
1689 else if ( SkipChar( '-', rString, nPos ) )
1690 ; // #79632# recognize 17-Jan-2001 to be a date
1691 // #99065# short and long month name
1692 else
1693 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1694 SkipBlanks(rString, nPos);
1698 short nTempMonth = GetMonth(rString, nPos); // month in the middle (10 Jan 94)
1699 if (nTempMonth)
1701 if (nMonth != 0) // month dup
1702 return MatchedReturn();
1703 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1704 && eScannedType != NUMBERFORMAT_DATE) // except date
1705 return MatchedReturn();
1706 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1707 nMonth = nTempMonth;
1708 nMonthPos = 2; // month in the middle
1709 if ( nMonth < 0 )
1710 SkipChar( '.', rString, nPos ); // abbreviated
1711 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1712 SkipBlanks(rString, nPos);
1715 if ( SkipChar('E', rString, nPos) // 10E, 10e, 10,Ee
1716 || SkipChar('e', rString, nPos) )
1718 if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1719 return MatchedReturn();
1720 else
1722 SkipBlanks(rString, nPos);
1723 eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific
1724 if ( nThousand+2 == nAnzNums // special case 1.E2
1725 && nDecPos == 2 )
1726 nDecPos = 3; // 1,100.E2 1,100,100.E3
1728 nESign = GetESign(rString, nPos); // signed exponent?
1729 SkipBlanks(rString, nPos);
1732 if ( SkipString(rTime, rString, nPos) ) // time separator?
1734 if (nDecPos) // already . => maybe error
1736 if (bDecSepInDateSeps) // . also date sep
1738 if ( eScannedType != NUMBERFORMAT_DATE && // already another type than date
1739 eScannedType != NUMBERFORMAT_DATETIME) // or date time
1740 return MatchedReturn();
1741 if (eScannedType == NUMBERFORMAT_DATE)
1742 nDecPos = 0; // reset for time transition
1744 else
1745 return MatchedReturn();
1747 if ( ( eScannedType == NUMBERFORMAT_DATE // already date type
1748 || eScannedType == NUMBERFORMAT_DATETIME) // or date time
1749 && nAnzNums > 3) // and more than 3 numbers? (31.Dez.94 8:23)
1751 SkipBlanks(rString, nPos);
1752 eScannedType = NUMBERFORMAT_DATETIME; // !!! it IS date with time
1754 else if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1755 && eScannedType != NUMBERFORMAT_TIME) // except time
1756 return MatchedReturn();
1757 else
1759 SkipBlanks(rString, nPos);
1760 eScannedType = NUMBERFORMAT_TIME; // !!! it IS a time
1762 if ( !nTimePos )
1763 nTimePos = nStringPos + 1;
1766 if (nPos < rString.Len())
1768 switch (eScannedType)
1770 case NUMBERFORMAT_DATE:
1771 if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
1773 // #68232# recognize long date separators like ", " in "September 5, 1999"
1774 if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
1775 SkipBlanks( rString, nPos );
1777 else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 &&
1778 rString.GetChar(0) == 'T' && MayBeIso8601())
1780 // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
1781 ++nPos;
1783 break;
1784 #if NF_RECOGNIZE_ISO8601_TIMEZONES
1785 case NUMBERFORMAT_DATETIME:
1786 if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 &&
1787 MayBeIso8601())
1789 // ISO 8601 timezone offset
1790 switch (rString.GetChar(0))
1792 case '+':
1793 case '-':
1794 if (nStringPos == nAnzStrings-2 ||
1795 nStringPos == nAnzStrings-4)
1797 ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
1798 // nTimezonePos needed for GetTimeRef()
1799 if (!nTimezonePos)
1800 nTimezonePos = nStringPos + 1;
1802 break;
1803 case ':':
1804 if (nTimezonePos && nStringPos >= 11 &&
1805 nStringPos == nAnzStrings-2)
1806 ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx:yy
1807 break;
1810 break;
1811 #endif
1815 if (nPos < rString.Len()) // not everything consumed?
1817 if ( nMatchedAllStrings & ~nMatchedVirgin )
1818 eScannedType = eOldScannedType;
1819 else
1820 return FALSE;
1823 return TRUE;
1827 //---------------------------------------------------------------------------
1828 // ScanEndString
1830 // Schlussteil analysieren
1831 // Alles weg => TRUE
1832 // sonst => FALSE
1834 BOOL ImpSvNumberInputScan::ScanEndString( const String& rString,
1835 const SvNumberformat* pFormat )
1837 xub_StrLen nPos = 0;
1839 if ( nMatchedAllStrings )
1840 { // Match against format in any case, so later on for a "1-2-3-4" input
1841 // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1842 // format.
1843 if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
1844 nMatchedAllStrings |= nMatchedEndString;
1845 else
1846 nMatchedAllStrings = 0;
1849 SkipBlanks(rString, nPos);
1850 if (GetDecSep(rString, nPos)) // decimal separator?
1852 if (nDecPos == 1 || nDecPos == 3) // .12.4 or 12.E4.
1853 return MatchedReturn();
1854 else if (nDecPos == 2) // . dup: 12.4.
1856 if (bDecSepInDateSeps) // . also date sep
1858 if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
1859 eScannedType != NUMBERFORMAT_DATE &&
1860 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1861 return MatchedReturn();
1862 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1863 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1864 SkipBlanks(rString, nPos);
1866 else
1867 return MatchedReturn();
1869 else
1871 nDecPos = 3; // . in end string
1872 SkipBlanks(rString, nPos);
1876 if ( nSign == 0 // conflict - not signed
1877 && eScannedType != NUMBERFORMAT_DATE) // and not date
1878 //!? catch time too?
1879 { // not signed yet
1880 nSign = GetSign(rString, nPos); // 1- DM
1881 if (nNegCheck) // '(' as sign
1882 return MatchedReturn();
1885 SkipBlanks(rString, nPos);
1886 if (nNegCheck && SkipChar(')', rString, nPos)) // skip ')' if appropriate
1888 nNegCheck = 0;
1889 SkipBlanks(rString, nPos);
1892 if ( GetCurrency(rString, nPos, pFormat) ) // currency symbol?
1894 if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup
1895 return MatchedReturn();
1896 else
1898 SkipBlanks(rString, nPos);
1899 eScannedType = NUMBERFORMAT_CURRENCY;
1900 } // behind currency a '-' is allowed
1901 if (nSign == 0) // not signed yet
1903 nSign = GetSign(rString, nPos); // DM -
1904 SkipBlanks(rString, nPos);
1905 if (nNegCheck) // 3 DM (
1906 return MatchedReturn();
1908 if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY
1909 && SkipChar(')', rString, nPos) )
1911 nNegCheck = 0; // ')' skipped
1912 SkipBlanks(rString, nPos); // only if currency
1916 if ( SkipChar('%', rString, nPos) ) // 1 %
1918 if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1919 return MatchedReturn();
1920 SkipBlanks(rString, nPos);
1921 eScannedType = NUMBERFORMAT_PERCENT;
1924 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1925 const String& rDate = pFormatter->GetDateSep();
1926 const String& rTime = pLoc->getTimeSep();
1927 if ( SkipString(rTime, rString, nPos) ) // 10:
1929 if (nDecPos) // already , => error
1930 return MatchedReturn();
1931 if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8:
1933 SkipBlanks(rString, nPos);
1934 eScannedType = NUMBERFORMAT_DATETIME;
1936 else if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1937 eScannedType != NUMBERFORMAT_TIME) // already another type
1938 return MatchedReturn();
1939 else
1941 SkipBlanks(rString, nPos);
1942 eScannedType = NUMBERFORMAT_TIME;
1944 if ( !nTimePos )
1945 nTimePos = nAnzStrings;
1948 sal_Unicode cTime = rTime.GetChar(0);
1949 if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
1950 || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
1951 || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
1952 || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
1954 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1955 eScannedType != NUMBERFORMAT_DATE) // already another type
1956 return MatchedReturn();
1957 else
1959 SkipBlanks(rString, nPos);
1960 eScannedType = NUMBERFORMAT_DATE;
1962 short nTmpMonth = GetMonth(rString, nPos); // 10. Jan
1963 if (nMonth && nTmpMonth) // month dup
1964 return MatchedReturn();
1965 if (nTmpMonth)
1967 nMonth = nTmpMonth;
1968 nMonthPos = 3; // month at end
1969 if ( nMonth < 0 )
1970 SkipChar( '.', rString, nPos ); // abbreviated
1971 SkipBlanks(rString, nPos);
1975 short nTempMonth = GetMonth(rString, nPos); // 10 Jan
1976 if (nTempMonth)
1978 if (nMonth) // month dup
1979 return MatchedReturn();
1980 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1981 eScannedType != NUMBERFORMAT_DATE) // already another type
1982 return MatchedReturn();
1983 eScannedType = NUMBERFORMAT_DATE;
1984 nMonth = nTempMonth;
1985 nMonthPos = 3; // month at end
1986 if ( nMonth < 0 )
1987 SkipChar( '.', rString, nPos ); // abbreviated
1988 SkipBlanks(rString, nPos);
1991 xub_StrLen nOrigPos = nPos;
1992 if (GetTimeAmPm(rString, nPos))
1994 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1995 eScannedType != NUMBERFORMAT_TIME &&
1996 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1997 return MatchedReturn();
1998 else
2000 // If not already scanned as time, 6.78am does not result in 6
2001 // seconds and 78 hundredths in the morning. Keep as suffix.
2002 if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2)
2003 nPos = nOrigPos; // rewind am/pm
2004 else
2006 SkipBlanks(rString, nPos);
2007 if ( eScannedType != NUMBERFORMAT_DATETIME )
2008 eScannedType = NUMBERFORMAT_TIME;
2013 if ( nNegCheck && SkipChar(')', rString, nPos) )
2015 if (eScannedType == NUMBERFORMAT_CURRENCY) // only if currency
2017 nNegCheck = 0; // skip ')'
2018 SkipBlanks(rString, nPos);
2020 else
2021 return MatchedReturn();
2024 if ( nPos < rString.Len() &&
2025 (eScannedType == NUMBERFORMAT_DATE
2026 || eScannedType == NUMBERFORMAT_DATETIME) )
2027 { // day of week is just parsed away
2028 xub_StrLen nOldPos = nPos;
2029 const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
2030 if ( StringContains( rSep, rString, nPos ) )
2032 nPos = nPos + rSep.Len();
2033 SkipBlanks(rString, nPos);
2035 int nDayOfWeek = GetDayOfWeek( rString, nPos );
2036 if ( nDayOfWeek )
2038 if ( nPos < rString.Len() )
2040 if ( nDayOfWeek < 0 )
2041 { // short
2042 if ( rString.GetChar( nPos ) == '.' )
2043 ++nPos;
2045 SkipBlanks(rString, nPos);
2048 else
2049 nPos = nOldPos;
2052 #if NF_RECOGNIZE_ISO8601_TIMEZONES
2053 if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME &&
2054 rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601())
2056 // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
2057 ++nPos;
2059 #endif
2061 if (nPos < rString.Len()) // everything consumed?
2063 // does input EndString equal EndString in Format?
2064 if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
2065 return FALSE;
2068 return TRUE;
2072 BOOL ImpSvNumberInputScan::ScanStringNumFor(
2073 const String& rString, // String to scan
2074 xub_StrLen nPos, // Position until which was consumed
2075 const SvNumberformat* pFormat, // The format to match
2076 USHORT nString, // Substring of format, 0xFFFF => last
2077 BOOL bDontDetectNegation // Suppress sign detection
2080 if ( !pFormat )
2081 return FALSE;
2082 const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
2083 const String* pStr;
2084 String aString( rString );
2085 BOOL bFound = FALSE;
2086 BOOL bFirst = TRUE;
2087 BOOL bContinue = TRUE;
2088 USHORT nSub;
2091 // Don't try "lower" subformats ff the very first match was the second
2092 // or third subformat.
2093 nSub = nStringScanNumFor;
2095 { // Step through subformats, first positive, then negative, then
2096 // other, but not the last (text) subformat.
2097 pStr = pFormat->GetNumForString( nSub, nString, TRUE );
2098 if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
2100 bFound = TRUE;
2101 bContinue = FALSE;
2103 else if ( nSub < 2 )
2104 ++nSub;
2105 else
2106 bContinue = FALSE;
2107 } while ( bContinue );
2108 if ( !bFound && bFirst && nPos )
2109 { // try remaining substring
2110 bFirst = FALSE;
2111 aString.Erase( 0, nPos );
2112 bContinue = TRUE;
2114 } while ( bContinue );
2116 if ( !bFound )
2118 if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0)
2119 && pFormat->IsNegativeRealNegative() )
2120 { // simply negated twice? --1
2121 aString.EraseAllChars( ' ' );
2122 if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') )
2124 bFound = TRUE;
2125 nStringScanSign = -1;
2126 nSub = 0; //! not 1
2129 if ( !bFound )
2130 return FALSE;
2132 else if ( !bDontDetectNegation && (nSub == 1) &&
2133 pFormat->IsNegativeRealNegative() )
2134 { // negative
2135 if ( nStringScanSign < 0 )
2137 if ( (nSign < 0) && (nStringScanNumFor != 1) )
2138 nStringScanSign = 1; // triple negated --1 yyy
2140 else if ( nStringScanSign == 0 )
2142 if ( nSign < 0 )
2143 { // nSign and nStringScanSign will be combined later,
2144 // flip sign if doubly negated
2145 if ( (nString == 0) && !bFirst
2146 && SvNumberformat::HasStringNegativeSign( aString ) )
2147 nStringScanSign = -1; // direct double negation
2148 else if ( pFormat->IsNegativeWithoutSign() )
2149 nStringScanSign = -1; // indirect double negation
2151 else
2152 nStringScanSign = -1;
2154 else // > 0
2155 nStringScanSign = -1;
2157 nStringScanNumFor = nSub;
2158 return TRUE;
2162 //---------------------------------------------------------------------------
2163 // IsNumberFormatMain
2165 // Recognizes types of number, exponential, fraction, percent, currency, date, time.
2166 // Else text => return FALSE
2168 BOOL ImpSvNumberInputScan::IsNumberFormatMain(
2169 const String& rString, // string to be analyzed
2170 double& , // OUT: result as number, if possible
2171 const SvNumberformat* pFormat ) // maybe number format set to match against
2173 Reset();
2174 NumberStringDivision( rString ); // breakdown into strings and numbers
2175 if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
2176 return FALSE; // Njet, Nope, ...
2178 if (nAnzNums == 0) // no number in input
2180 if ( nAnzStrings > 0 )
2182 // Here we may change the original, we don't need it anymore.
2183 // This saves copies and ToUpper() in GetLogical() and is faster.
2184 String& rStrArray = sStrArray[0];
2185 rStrArray.EraseTrailingChars( ' ' );
2186 rStrArray.EraseLeadingChars( ' ' );
2187 nLogical = GetLogical( rStrArray );
2188 if ( nLogical )
2190 eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN
2191 nMatchedAllStrings &= ~nMatchedVirgin;
2192 return TRUE;
2194 else
2195 return FALSE; // simple text
2197 else
2198 return FALSE; // simple text
2201 USHORT i = 0; // mark any symbol
2202 USHORT j = 0; // mark only numbers
2204 switch ( nAnzNums )
2206 case 1 : // Exactly 1 number in input
2207 { // nAnzStrings >= 1
2208 if (GetNextNumber(i,j)) // i=1,0
2209 { // Number at start
2210 if (eSetType == NUMBERFORMAT_FRACTION) // Fraction 1 = 1/1
2212 if (i >= nAnzStrings || // no end string nor decimal separator
2213 sStrArray[i] == pFormatter->GetNumDecimalSep())
2215 eScannedType = NUMBERFORMAT_FRACTION;
2216 nMatchedAllStrings &= ~nMatchedVirgin;
2217 return TRUE;
2221 else
2222 { // Analyze start string
2223 if (!ScanStartString( sStrArray[i], pFormat )) // i=0
2224 return FALSE; // already an error
2225 i++; // next symbol, i=1
2227 GetNextNumber(i,j); // i=1,2
2228 if (eSetType == NUMBERFORMAT_FRACTION) // Fraction -1 = -1/1
2230 if (nSign && !nNegCheck && // Sign +, -
2231 eScannedType == NUMBERFORMAT_UNDEFINED && // not date or currency
2232 nDecPos == 0 && // no previous decimal separator
2233 (i >= nAnzStrings || // no end string nor decimal separator
2234 sStrArray[i] == pFormatter->GetNumDecimalSep())
2237 eScannedType = NUMBERFORMAT_FRACTION;
2238 nMatchedAllStrings &= ~nMatchedVirgin;
2239 return TRUE;
2242 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2243 return FALSE;
2245 break;
2246 case 2 : // Exactly 2 numbers in input
2247 { // nAnzStrings >= 3
2248 if (!GetNextNumber(i,j)) // i=1,0
2249 { // Analyze start string
2250 if (!ScanStartString( sStrArray[i], pFormat ))
2251 return FALSE; // already an error
2252 i++; // i=1
2254 GetNextNumber(i,j); // i=1,2
2255 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2256 return FALSE;
2257 i++; // next symbol, i=2,3
2258 GetNextNumber(i,j); // i=3,4
2259 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2260 return FALSE;
2261 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200. as fraction
2263 if (!nNegCheck && // no sign '('
2264 eScannedType == NUMBERFORMAT_UNDEFINED &&
2265 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2268 eScannedType = NUMBERFORMAT_FRACTION;
2269 nMatchedAllStrings &= ~nMatchedVirgin;
2270 return TRUE;
2274 break;
2275 case 3 : // Exactly 3 numbers in input
2276 { // nAnzStrings >= 5
2277 if (!GetNextNumber(i,j)) // i=1,0
2278 { // Analyze start string
2279 if (!ScanStartString( sStrArray[i], pFormat ))
2280 return FALSE; // already an error
2281 i++; // i=1
2282 if (nDecPos == 1) // decimal separator at start => error
2283 return FALSE;
2285 GetNextNumber(i,j); // i=1,2
2286 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2287 return FALSE;
2288 i++; // i=2,3
2289 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
2290 return FALSE;
2291 GetNextNumber(i,j); // i=3,4
2292 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2293 return FALSE;
2294 i++; // i=4,5
2295 GetNextNumber(i,j); // i=5,6
2296 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2297 return FALSE;
2298 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
2300 if (!nNegCheck && // no sign '('
2301 eScannedType == NUMBERFORMAT_UNDEFINED &&
2302 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2305 eScannedType = NUMBERFORMAT_FRACTION;
2306 nMatchedAllStrings &= ~nMatchedVirgin;
2307 return TRUE;
2310 if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2311 return FALSE; // #36857# not a real fraction
2313 break;
2314 default: // More than 3 numbers in input
2315 { // nAnzStrings >= 7
2316 if (!GetNextNumber(i,j)) // i=1,0
2317 { // Analyze startstring
2318 if (!ScanStartString( sStrArray[i], pFormat ))
2319 return FALSE; // already an error
2320 i++; // i=1
2321 if (nDecPos == 1) // decimal separator at start => error
2322 return FALSE;
2324 GetNextNumber(i,j); // i=1,2
2325 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2326 return FALSE;
2327 i++; // i=2,3
2328 USHORT nThOld = 10; // just not 0 or 1
2329 while (nThOld != nThousand && j < nAnzNums-1)
2330 // Execute at least one time
2331 // but leave one number.
2332 { // Loop over group separators
2333 nThOld = nThousand;
2334 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
2335 return FALSE;
2336 GetNextNumber(i,j);
2337 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2338 return FALSE;
2339 i++;
2341 if (eScannedType == NUMBERFORMAT_DATE || // long date or
2342 eScannedType == NUMBERFORMAT_TIME || // long time or
2343 eScannedType == NUMBERFORMAT_UNDEFINED) // long number
2345 for (USHORT k = j; k < nAnzNums-1; k++)
2347 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at endd
2348 return FALSE;
2349 GetNextNumber(i,j);
2350 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2351 return FALSE;
2352 i++;
2355 GetNextNumber(i,j);
2356 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2357 return FALSE;
2358 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
2360 if (!nNegCheck && // no sign '('
2361 eScannedType == NUMBERFORMAT_UNDEFINED &&
2362 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2365 eScannedType = NUMBERFORMAT_FRACTION;
2366 nMatchedAllStrings &= ~nMatchedVirgin;
2367 return TRUE;
2370 if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2371 return FALSE; // #36857# not a real fraction
2375 if (eScannedType == NUMBERFORMAT_UNDEFINED)
2377 nMatchedAllStrings &= ~nMatchedVirgin;
2378 // did match including nMatchedUsedAsReturn
2379 BOOL bDidMatch = (nMatchedAllStrings != 0);
2380 if ( nMatchedAllStrings )
2382 BOOL bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2383 nStringScanNumFor, nAnzStrings, nAnzNums ) : FALSE);
2384 if ( !bMatch )
2385 nMatchedAllStrings = 0;
2387 if ( nMatchedAllStrings )
2388 eScannedType = eSetType;
2389 else if ( bDidMatch )
2390 return FALSE;
2391 else
2392 eScannedType = NUMBERFORMAT_NUMBER;
2393 // everything else should have been recognized by now
2395 else if ( eScannedType == NUMBERFORMAT_DATE )
2396 { // the very relaxed date input checks may interfere with a preset format
2397 nMatchedAllStrings &= ~nMatchedVirgin;
2398 BOOL bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
2399 if ( nMatchedAllStrings )
2401 BOOL bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2402 nStringScanNumFor, nAnzStrings, nAnzNums ) : FALSE);
2403 if ( !bMatch )
2404 nMatchedAllStrings = 0;
2406 if ( nMatchedAllStrings )
2407 eScannedType = eSetType;
2408 else if ( bWasReturn )
2409 return FALSE;
2411 else
2412 nMatchedAllStrings = 0; // reset flag to no substrings matched
2414 return TRUE;
2418 //---------------------------------------------------------------------------
2419 // return TRUE or FALSE depending on the nMatched... state and remember usage
2420 BOOL ImpSvNumberInputScan::MatchedReturn()
2422 if ( nMatchedAllStrings & ~nMatchedVirgin )
2424 nMatchedAllStrings |= nMatchedUsedAsReturn;
2425 return TRUE;
2427 return FALSE;
2431 //---------------------------------------------------------------------------
2432 // Initialize uppercase months and weekdays
2434 void ImpSvNumberInputScan::InitText()
2436 sal_Int32 j, nElems;
2437 const CharClass* pChrCls = pFormatter->GetCharClass();
2438 const CalendarWrapper* pCal = pFormatter->GetCalendar();
2439 delete [] pUpperMonthText;
2440 delete [] pUpperAbbrevMonthText;
2441 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems
2442 = pCal->getMonths();
2443 nElems = xElems.getLength();
2444 pUpperMonthText = new String[nElems];
2445 pUpperAbbrevMonthText = new String[nElems];
2446 for ( j=0; j<nElems; j++ )
2448 pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName );
2449 pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName );
2451 delete [] pUpperDayText;
2452 delete [] pUpperAbbrevDayText;
2453 xElems = pCal->getDays();
2454 nElems = xElems.getLength();
2455 pUpperDayText = new String[nElems];
2456 pUpperAbbrevDayText = new String[nElems];
2457 for ( j=0; j<nElems; j++ )
2459 pUpperDayText[j] = pChrCls->upper( xElems[j].FullName );
2460 pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName );
2462 bTextInitialized = TRUE;
2466 //===========================================================================
2467 // P U B L I C
2469 //---------------------------------------------------------------------------
2470 // ChangeIntl
2472 // MUST be called if International/Locale is changed
2474 void ImpSvNumberInputScan::ChangeIntl()
2476 sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0);
2477 bDecSepInDateSeps = ( cDecSep == '-' ||
2478 cDecSep == '/' ||
2479 cDecSep == '.' ||
2480 cDecSep == pFormatter->GetDateSep().GetChar(0) );
2481 bTextInitialized = FALSE;
2482 aUpperCurrSymbol.Erase();
2486 //---------------------------------------------------------------------------
2487 // ChangeNullDate
2489 void ImpSvNumberInputScan::ChangeNullDate(
2490 const USHORT Day,
2491 const USHORT Month,
2492 const USHORT Year )
2494 if ( pNullDate )
2495 *pNullDate = Date(Day, Month, Year);
2496 else
2497 pNullDate = new Date(Day, Month, Year);
2501 //---------------------------------------------------------------------------
2502 // IsNumberFormat
2504 // => does rString represent a number (also date, time et al)
2506 BOOL ImpSvNumberInputScan::IsNumberFormat(
2507 const String& rString, // string to be analyzed
2508 short& F_Type, // IN: old type, OUT: new type
2509 double& fOutNumber, // OUT: number if convertable
2510 const SvNumberformat* pFormat ) // maybe a number format to match against
2512 String sResString;
2513 String aString;
2514 BOOL res; // return value
2515 eSetType = F_Type; // old type set
2517 if ( !rString.Len() )
2518 res = FALSE;
2519 else if (rString.Len() > 308) // arbitrary
2520 res = FALSE;
2521 else
2523 // NoMoreUpperNeeded, all comparisons on UpperCase
2524 aString = pFormatter->GetCharClass()->upper( rString );
2525 // convert native number to ASCII if necessary
2526 TransformInput( aString );
2527 res = IsNumberFormatMain( aString, fOutNumber, pFormat );
2530 if (res)
2532 if ( nNegCheck // ')' not found for '('
2533 || (nSign && (eScannedType == NUMBERFORMAT_DATE
2534 || eScannedType == NUMBERFORMAT_DATETIME))
2535 ) // signed date/datetime
2536 res = FALSE;
2537 else
2538 { // check count of partial number strings
2539 switch (eScannedType)
2541 case NUMBERFORMAT_PERCENT:
2542 case NUMBERFORMAT_CURRENCY:
2543 case NUMBERFORMAT_NUMBER:
2544 if (nDecPos == 1) // .05
2546 // matched MidStrings function like group separators
2547 if ( nMatchedAllStrings )
2548 nThousand = nAnzNums - 1;
2549 else if ( nAnzNums != 1 )
2550 res = FALSE;
2552 else if (nDecPos == 2) // 1.05
2554 // matched MidStrings function like group separators
2555 if ( nMatchedAllStrings )
2556 nThousand = nAnzNums - 1;
2557 else if ( nAnzNums != nThousand+2 )
2558 res = FALSE;
2560 else // 1,100 or 1,100.
2562 // matched MidStrings function like group separators
2563 if ( nMatchedAllStrings )
2564 nThousand = nAnzNums - 1;
2565 else if ( nAnzNums != nThousand+1 )
2566 res = FALSE;
2568 break;
2570 case NUMBERFORMAT_SCIENTIFIC: // 1.0e-2
2571 if (nDecPos == 1) // .05
2573 if (nAnzNums != 2)
2574 res = FALSE;
2576 else if (nDecPos == 2) // 1.05
2578 if (nAnzNums != nThousand+3)
2579 res = FALSE;
2581 else // 1,100 or 1,100.
2583 if (nAnzNums != nThousand+2)
2584 res = FALSE;
2586 break;
2588 case NUMBERFORMAT_DATE:
2589 if (nMonth)
2590 { // month name and numbers
2591 if (nAnzNums > 2)
2592 res = FALSE;
2594 else
2596 if (nAnzNums > 3)
2597 res = FALSE;
2599 break;
2601 case NUMBERFORMAT_TIME:
2602 if (nDecPos)
2603 { // hundredth seconds included
2604 if (nAnzNums > 4)
2605 res = FALSE;
2607 else
2609 if (nAnzNums > 3)
2610 res = FALSE;
2612 break;
2614 case NUMBERFORMAT_DATETIME:
2615 if (nMonth)
2616 { // month name and numbers
2617 if (nDecPos)
2618 { // hundredth seconds included
2619 if (nAnzNums > 6)
2620 res = FALSE;
2622 else
2624 if (nAnzNums > 5)
2625 res = FALSE;
2628 else
2630 if (nDecPos)
2631 { // hundredth seconds included
2632 if (nAnzNums > 7)
2633 res = FALSE;
2635 else
2637 if (nAnzNums > 6)
2638 res = FALSE;
2641 break;
2643 default:
2644 break;
2645 } // switch
2646 } // else
2647 } // if (res)
2649 if (res)
2650 { // we finally have a number
2651 switch (eScannedType)
2653 case NUMBERFORMAT_LOGICAL:
2654 if (nLogical == 1)
2655 fOutNumber = 1.0; // True
2656 else if (nLogical == -1)
2657 fOutNumber = 0.0; // False
2658 else
2659 res = FALSE; // Oops
2660 break;
2662 case NUMBERFORMAT_PERCENT:
2663 case NUMBERFORMAT_CURRENCY:
2664 case NUMBERFORMAT_NUMBER:
2665 case NUMBERFORMAT_SCIENTIFIC:
2666 case NUMBERFORMAT_DEFINED: // if no category detected handle as number
2668 if ( nDecPos == 1 ) // . at start
2669 sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) );
2670 else
2671 sResString.Erase();
2672 USHORT k;
2673 for ( k = 0; k <= nThousand; k++)
2674 sResString += sStrArray[nNums[k]]; // integer part
2675 if ( nDecPos == 2 && k < nAnzNums ) // . somewhere
2677 sResString += '.';
2678 USHORT nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ?
2679 nAnzNums-1 : nAnzNums);
2680 for ( ; k < nStop; k++)
2681 sResString += sStrArray[nNums[k]]; // fractional part
2684 if (eScannedType != NUMBERFORMAT_SCIENTIFIC)
2685 fOutNumber = StringToDouble(sResString);
2686 else
2687 { // append exponent
2688 sResString += 'E';
2689 if ( nESign == -1 )
2690 sResString += '-';
2691 sResString += sStrArray[nNums[nAnzNums-1]];
2692 rtl_math_ConversionStatus eStatus;
2693 fOutNumber = ::rtl::math::stringToDouble(
2694 sResString, '.', ',', &eStatus, NULL );
2695 if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
2697 F_Type = NUMBERFORMAT_TEXT; // overflow/underflow -> Text
2698 if (nESign == -1)
2699 fOutNumber = 0.0;
2700 else
2701 fOutNumber = DBL_MAX;
2702 /*!*/ return TRUE;
2706 if ( nStringScanSign )
2708 if ( nSign )
2709 nSign *= nStringScanSign;
2710 else
2711 nSign = nStringScanSign;
2713 if ( nSign < 0 )
2714 fOutNumber = -fOutNumber;
2716 if (eScannedType == NUMBERFORMAT_PERCENT)
2717 fOutNumber/= 100.0;
2719 break;
2721 case NUMBERFORMAT_FRACTION:
2722 if (nAnzNums == 1)
2723 fOutNumber = StringToDouble(sStrArray[nNums[0]]);
2724 else if (nAnzNums == 2)
2726 if (nThousand == 1)
2728 sResString = sStrArray[nNums[0]];
2729 sResString += sStrArray[nNums[1]]; // integer part
2730 fOutNumber = StringToDouble(sResString);
2732 else
2734 double fZaehler = StringToDouble(sStrArray[nNums[0]]);
2735 double fNenner = StringToDouble(sStrArray[nNums[1]]);
2736 if (fNenner != 0.0)
2737 fOutNumber = fZaehler/fNenner;
2738 else
2739 res = FALSE;
2742 else // nAnzNums > 2
2744 USHORT k = 1;
2745 sResString = sStrArray[nNums[0]];
2746 if (nThousand > 0)
2747 for (k = 1; k <= nThousand; k++)
2748 sResString += sStrArray[nNums[k]];
2749 fOutNumber = StringToDouble(sResString);
2751 if (k == nAnzNums-2)
2753 double fZaehler = StringToDouble(sStrArray[nNums[k]]);
2754 double fNenner = StringToDouble(sStrArray[nNums[k+1]]);
2755 if (fNenner != 0.0)
2756 fOutNumber += fZaehler/fNenner;
2757 else
2758 res = FALSE;
2762 if ( nStringScanSign )
2764 if ( nSign )
2765 nSign *= nStringScanSign;
2766 else
2767 nSign = nStringScanSign;
2769 if ( nSign < 0 )
2770 fOutNumber = -fOutNumber;
2771 break;
2773 case NUMBERFORMAT_TIME:
2774 GetTimeRef(fOutNumber, 0, nAnzNums);
2775 if ( nSign < 0 )
2776 fOutNumber = -fOutNumber;
2777 break;
2779 case NUMBERFORMAT_DATE:
2781 USHORT nCounter = 0; // dummy here
2782 res = GetDateRef( fOutNumber, nCounter, pFormat );
2784 break;
2786 case NUMBERFORMAT_DATETIME:
2788 USHORT nCounter = 0; // needed here
2789 res = GetDateRef( fOutNumber, nCounter, pFormat );
2790 if ( res )
2792 double fTime;
2793 GetTimeRef( fTime, nCounter, nAnzNums - nCounter );
2794 fOutNumber += fTime;
2797 break;
2799 default:
2800 DBG_ERRORFILE( "Some number recognized but what's it?" );
2801 fOutNumber = 0.0;
2802 break;
2806 if (res) // overflow/underflow -> Text
2808 if (fOutNumber < -DBL_MAX) // -1.7E308
2810 F_Type = NUMBERFORMAT_TEXT;
2811 fOutNumber = -DBL_MAX;
2812 return TRUE;
2814 else if (fOutNumber > DBL_MAX) // 1.7E308
2816 F_Type = NUMBERFORMAT_TEXT;
2817 fOutNumber = DBL_MAX;
2818 return TRUE;
2822 if (res == FALSE)
2824 eScannedType = NUMBERFORMAT_TEXT;
2825 fOutNumber = 0.0;
2828 F_Type = eScannedType;
2829 return res;