| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svl.hxx" |
| |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <float.h> |
| #include <errno.h> |
| #include <tools/date.hxx> |
| #include <tools/debug.hxx> |
| #include <rtl/math.hxx> |
| #include <unotools/charclass.hxx> |
| #include <unotools/calendarwrapper.hxx> |
| #include <unotools/localedatawrapper.hxx> |
| #include <com/sun/star/i18n/CalendarFieldIndex.hpp> |
| #include <unotools/digitgroupingiterator.hxx> |
| |
| #include <svl/zforlist.hxx> // NUMBERFORMAT_XXX |
| #include "zforscan.hxx" |
| #include <svl/zformat.hxx> |
| |
| #define _ZFORFIND_CXX |
| #include "zforfind.hxx" |
| #undef _ZFORFIND_CXX |
| |
| |
| #ifndef DBG_UTIL |
| #define NF_TEST_CALENDAR 0 |
| #else |
| #define NF_TEST_CALENDAR 0 |
| #endif |
| #if NF_TEST_CALENDAR |
| #include <comphelper/processfactory.hxx> |
| #include <com/sun/star/i18n/XExtendedCalendar.hpp> |
| #endif |
| |
| |
| const sal_uInt8 ImpSvNumberInputScan::nMatchedEndString = 0x01; |
| const sal_uInt8 ImpSvNumberInputScan::nMatchedMidString = 0x02; |
| const sal_uInt8 ImpSvNumberInputScan::nMatchedStartString = 0x04; |
| const sal_uInt8 ImpSvNumberInputScan::nMatchedVirgin = 0x08; |
| const sal_uInt8 ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10; |
| |
| /* It is not clear how we want timezones to be handled. Convert them to local |
| * time isn't wanted, as it isn't done in any other place and timezone |
| * information isn't stored anywhere. Ignoring them and pretending local time |
| * may be wrong too and might not be what the user expects. Keep the input as |
| * string so that no information is lost. |
| * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it |
| * would work, together with the nTimezonePos handling in GetTimeRef(). */ |
| #define NF_RECOGNIZE_ISO8601_TIMEZONES 0 |
| |
| //--------------------------------------------------------------------------- |
| // Konstruktor |
| |
| ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP ) |
| : |
| pUpperMonthText( NULL ), |
| pUpperAbbrevMonthText( NULL ), |
| pUpperDayText( NULL ), |
| pUpperAbbrevDayText( NULL ) |
| { |
| pFormatter = pFormatterP; |
| pNullDate = new Date(30,12,1899); |
| nYear2000 = SvNumberFormatter::GetYear2000Default(); |
| Reset(); |
| ChangeIntl(); |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Destruktor |
| |
| ImpSvNumberInputScan::~ImpSvNumberInputScan() |
| { |
| Reset(); |
| delete pNullDate; |
| delete [] pUpperMonthText; |
| delete [] pUpperAbbrevMonthText; |
| delete [] pUpperDayText; |
| delete [] pUpperAbbrevDayText; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Reset |
| |
| void ImpSvNumberInputScan::Reset() |
| { |
| #if 0 |
| // ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision, |
| // wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht |
| // gebraucht wird.. |
| for (sal_uInt16 i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++) |
| { |
| sStrArray[i].Erase(); |
| nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1; |
| IsNum[i] = sal_False; |
| } |
| #endif |
| nMonth = 0; |
| nMonthPos = 0; |
| nTimePos = 0; |
| nSign = 0; |
| nESign = 0; |
| nDecPos = 0; |
| nNegCheck = 0; |
| nAnzStrings = 0; |
| nAnzNums = 0; |
| nThousand = 0; |
| eScannedType = NUMBERFORMAT_UNDEFINED; |
| nAmPm = 0; |
| nPosThousandString = 0; |
| nLogical = 0; |
| nStringScanNumFor = 0; |
| nStringScanSign = 0; |
| nMatchedAllStrings = nMatchedVirgin; |
| nMayBeIso8601 = 0; |
| nTimezonePos = 0; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // |
| // static |
| inline sal_Bool ImpSvNumberInputScan::MyIsdigit( sal_Unicode c ) |
| { |
| // If the input string wouldn't be converted using TransformInput() we'd |
| // to use something similar to the following and to adapt many places. |
| #if 0 |
| // use faster isdigit() if possible |
| if ( c < 128 ) |
| return isdigit( (unsigned char) c ) != 0; |
| if ( c < 256 ) |
| return sal_False; |
| String aTmp( c ); |
| return pFormatter->GetCharClass()->isDigit( aTmp, 0 ); |
| #else |
| return c < 128 && isdigit( (unsigned char) c ); |
| #endif |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // |
| void ImpSvNumberInputScan::TransformInput( String& rStr ) |
| { |
| xub_StrLen nPos, nLen; |
| for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos ) |
| { |
| if ( 256 <= rStr.GetChar( nPos ) && |
| pFormatter->GetCharClass()->isDigit( rStr, nPos ) ) |
| break; |
| } |
| if ( nPos < nLen ) |
| rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr, |
| pFormatter->GetLocale(), 0 ); |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // StringToDouble |
| // |
| // Only simple unsigned floating point values without any error detection, |
| // decimal separator has to be '.' |
| |
| double ImpSvNumberInputScan::StringToDouble( const String& rStr, sal_Bool bForceFraction ) |
| { |
| double fNum = 0.0; |
| double fFrac = 0.0; |
| int nExp = 0; |
| xub_StrLen nPos = 0; |
| xub_StrLen nLen = rStr.Len(); |
| sal_Bool bPreSep = !bForceFraction; |
| |
| while (nPos < nLen) |
| { |
| if (rStr.GetChar(nPos) == '.') |
| bPreSep = sal_False; |
| else if (bPreSep) |
| fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0'); |
| else |
| { |
| fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0'); |
| --nExp; |
| } |
| nPos++; |
| } |
| if ( fFrac ) |
| return fNum + ::rtl::math::pow10Exp( fFrac, nExp ); |
| return fNum; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // NextNumberStringSymbol |
| // |
| // Zerlegt die Eingabe in Zahlen und Strings fuer die weitere |
| // Verarbeitung (Turing-Maschine). |
| //--------------------------------------------------------------------------- |
| // Ausgangs Zustand = GetChar |
| //---------------+-------------------+-----------------------+--------------- |
| // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand |
| //---------------+-------------------+-----------------------+--------------- |
| // GetChar | Ziffer | Symbol=Zeichen | GetValue |
| // | Sonst | Symbol=Zeichen | GetString |
| //---------------|-------------------+-----------------------+--------------- |
| // GetValue | Ziffer | Symbol=Symbol+Zeichen | GetValue |
| // | Sonst | Dec(CharPos) | Stop |
| //---------------+-------------------+-----------------------+--------------- |
| // GetString | Ziffer | Dec(CharPos) | Stop |
| // | Sonst | Symbol=Symbol+Zeichen | GetString |
| //---------------+-------------------+-----------------------+--------------- |
| |
| enum ScanState // States der Turing-Maschine |
| { |
| SsStop = 0, |
| SsStart = 1, |
| SsGetValue = 2, |
| SsGetString = 3 |
| }; |
| |
| sal_Bool ImpSvNumberInputScan::NextNumberStringSymbol( |
| const sal_Unicode*& pStr, |
| String& rSymbol ) |
| { |
| sal_Bool isNumber = sal_False; |
| sal_Unicode cToken; |
| ScanState eState = SsStart; |
| register const sal_Unicode* pHere = pStr; |
| register xub_StrLen nChars = 0; |
| |
| while ( ((cToken = *pHere) != 0) && eState != SsStop) |
| { |
| pHere++; |
| switch (eState) |
| { |
| case SsStart: |
| if ( MyIsdigit( cToken ) ) |
| { |
| eState = SsGetValue; |
| isNumber = sal_True; |
| } |
| else |
| eState = SsGetString; |
| nChars++; |
| break; |
| case SsGetValue: |
| if ( MyIsdigit( cToken ) ) |
| nChars++; |
| else |
| { |
| eState = SsStop; |
| pHere--; |
| } |
| break; |
| case SsGetString: |
| if ( !MyIsdigit( cToken ) ) |
| nChars++; |
| else |
| { |
| eState = SsStop; |
| pHere--; |
| } |
| break; |
| default: |
| break; |
| } // switch |
| } // while |
| |
| if ( nChars ) |
| rSymbol.Assign( pStr, nChars ); |
| else |
| rSymbol.Erase(); |
| |
| pStr = pHere; |
| |
| return isNumber; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // SkipThousands |
| |
| // FIXME: should be grouping; it is only used though in case nAnzStrings is |
| // near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision(). |
| |
| sal_Bool ImpSvNumberInputScan::SkipThousands( |
| const sal_Unicode*& pStr, |
| String& rSymbol ) |
| { |
| sal_Bool res = sal_False; |
| sal_Unicode cToken; |
| const String& rThSep = pFormatter->GetNumThousandSep(); |
| register const sal_Unicode* pHere = pStr; |
| ScanState eState = SsStart; |
| xub_StrLen nCounter = 0; // counts 3 digits |
| |
| while ( ((cToken = *pHere) != 0) && eState != SsStop) |
| { |
| pHere++; |
| switch (eState) |
| { |
| case SsStart: |
| if ( StringPtrContains( rThSep, pHere-1, 0 ) ) |
| { |
| nCounter = 0; |
| eState = SsGetValue; |
| pHere += rThSep.Len()-1; |
| } |
| else |
| { |
| eState = SsStop; |
| pHere--; |
| } |
| break; |
| case SsGetValue: |
| if ( MyIsdigit( cToken ) ) |
| { |
| rSymbol += cToken; |
| nCounter++; |
| if (nCounter == 3) |
| { |
| eState = SsStart; |
| res = sal_True; // .000 combination found |
| } |
| } |
| else |
| { |
| eState = SsStop; |
| pHere--; |
| } |
| break; |
| default: |
| break; |
| } // switch |
| } // while |
| |
| if (eState == SsGetValue) // break witth less than 3 digits |
| { |
| if ( nCounter ) |
| rSymbol.Erase( rSymbol.Len() - nCounter, nCounter ); |
| pHere -= nCounter + rThSep.Len(); // put back ThSep also |
| } |
| pStr = pHere; |
| |
| return res; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // NumberStringDivision |
| |
| void ImpSvNumberInputScan::NumberStringDivision( const String& rString ) |
| { |
| const sal_Unicode* pStr = rString.GetBuffer(); |
| const sal_Unicode* const pEnd = pStr + rString.Len(); |
| while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS ) |
| { |
| if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) ) |
| { // Zahl |
| IsNum[nAnzStrings] = sal_True; |
| nNums[nAnzNums] = nAnzStrings; |
| nAnzNums++; |
| if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 && |
| nPosThousandString == 0) // nur einmal |
| if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) ) |
| nPosThousandString = nAnzStrings; |
| } |
| else |
| { |
| IsNum[nAnzStrings] = sal_False; |
| } |
| nAnzStrings++; |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Whether rString contains rWhat at nPos |
| |
| sal_Bool ImpSvNumberInputScan::StringContainsImpl( const String& rWhat, |
| const String& rString, xub_StrLen nPos ) |
| { |
| if ( nPos + rWhat.Len() <= rString.Len() ) |
| return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos ); |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Whether pString contains rWhat at nPos |
| |
| sal_Bool ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat, |
| const sal_Unicode* pString, xub_StrLen nPos ) |
| { |
| if ( rWhat.Len() == 0 ) |
| return sal_False; |
| register const sal_Unicode* pWhat = rWhat.GetBuffer(); |
| register const sal_Unicode* const pEnd = pWhat + rWhat.Len(); |
| register const sal_Unicode* pStr = pString + nPos; |
| while ( pWhat < pEnd ) |
| { |
| if ( *pWhat != *pStr ) |
| return sal_False; |
| pWhat++; |
| pStr++; |
| } |
| return sal_True; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // SkipChar |
| // |
| // ueberspringt genau das angegebene Zeichen |
| |
| inline sal_Bool ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString, |
| xub_StrLen& nPos ) |
| { |
| if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c)) |
| { |
| nPos++; |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // SkipBlanks |
| // |
| // Ueberspringt Leerzeichen |
| |
| inline void ImpSvNumberInputScan::SkipBlanks( const String& rString, |
| xub_StrLen& nPos ) |
| { |
| if ( nPos < rString.Len() ) |
| { |
| register const sal_Unicode* p = rString.GetBuffer() + nPos; |
| while ( *p == ' ' ) |
| { |
| nPos++; |
| p++; |
| } |
| } |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // SkipString |
| // |
| // jump over rWhat in rString at nPos |
| |
| inline sal_Bool ImpSvNumberInputScan::SkipString( const String& rWhat, |
| const String& rString, xub_StrLen& nPos ) |
| { |
| if ( StringContains( rWhat, rString, nPos ) ) |
| { |
| nPos = nPos + rWhat.Len(); |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetThousandSep |
| // |
| // recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping |
| |
| inline sal_Bool ImpSvNumberInputScan::GetThousandSep( |
| const String& rString, |
| xub_StrLen& nPos, |
| sal_uInt16 nStringPos ) |
| { |
| const String& rSep = pFormatter->GetNumThousandSep(); |
| // Is it an ordinary space instead of a non-breaking space? |
| bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 && |
| rSep.Len() == 1 && rString.Len() == 1; |
| if (!( (rString == rSep || bSpaceBreak) // nothing else |
| && nStringPos < nAnzStrings - 1 // safety first! |
| && IsNum[nStringPos+1] )) // number follows |
| return sal_False; // no? => out |
| |
| utl::DigitGroupingIterator aGrouping( |
| pFormatter->GetLocaleData()->getDigitGrouping()); |
| // Match ,### in {3} or ,## in {3,2} |
| /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or |
| * ,##,### and to match ,### in {3,2} only if it's the last. However, |
| * currently there is no track kept where group separators occur. In {3,2} |
| * #,###,### and #,##,## would be valid input, which maybe isn't even bad |
| * for #,###,###. Other combinations such as #,###,## maybe not. */ |
| xub_StrLen nLen = sStrArray[nStringPos+1].Len(); |
| if (nLen == aGrouping.get() // with 3 (or so) digits |
| || nLen == aGrouping.advance().get() // or with 2 (or 3 or so) digits |
| || nPosThousandString == nStringPos+1 // or concatenated |
| ) |
| { |
| nPos = nPos + rSep.Len(); |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetLogical |
| // |
| // Conversion of text to logial value |
| // "sal_True" => 1: |
| // "sal_False"=> -1: |
| // else => 0: |
| |
| short ImpSvNumberInputScan::GetLogical( const String& rString ) |
| { |
| short res; |
| |
| const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner(); |
| if ( rString == pFS->GetTrueString() ) |
| res = 1; |
| else if ( rString == pFS->GetFalseString() ) |
| res = -1; |
| else |
| res = 0; |
| |
| return res; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetMonth |
| // |
| // Converts a string containing a month name (JAN, January) at nPos into the |
| // month number (negative if abbreviated), returns 0 if nothing found |
| |
| short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos ) |
| { |
| // #102136# The correct English form of month September abbreviated is |
| // SEPT, but almost every data contains SEP instead. |
| static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) ); |
| static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) ); |
| |
| short res = 0; // no month found |
| |
| if (rString.Len() > nPos) // only if needed |
| { |
| if ( !bTextInitialized ) |
| InitText(); |
| sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear(); |
| for ( sal_Int16 i = 0; i < nMonths; i++ ) |
| { |
| if ( StringContains( pUpperMonthText[i], rString, nPos ) ) |
| { // full names first |
| nPos = nPos + pUpperMonthText[i].Len(); |
| res = i+1; |
| break; // for |
| } |
| else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) ) |
| { // abbreviated |
| nPos = nPos + pUpperAbbrevMonthText[i].Len(); |
| res = sal::static_int_cast< short >(-(i+1)); // negative |
| break; // for |
| } |
| else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect && |
| StringContains( aSepShortened, rString, nPos ) ) |
| { // #102136# SEPT/SEP |
| nPos = nPos + aSepShortened.Len(); |
| res = sal::static_int_cast< short >(-(i+1)); // negative |
| break; // for |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetDayOfWeek |
| // |
| // Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the |
| // DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found |
| |
| int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos ) |
| { |
| int res = 0; // no day found |
| |
| if (rString.Len() > nPos) // only if needed |
| { |
| if ( !bTextInitialized ) |
| InitText(); |
| sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek(); |
| for ( sal_Int16 i = 0; i < nDays; i++ ) |
| { |
| if ( StringContains( pUpperDayText[i], rString, nPos ) ) |
| { // full names first |
| nPos = nPos + pUpperDayText[i].Len(); |
| res = i + 1; |
| break; // for |
| } |
| if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) ) |
| { // abbreviated |
| nPos = nPos + pUpperAbbrevDayText[i].Len(); |
| res = -(i + 1); // negative |
| break; // for |
| } |
| } |
| } |
| |
| return res; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetCurrency |
| // |
| // Lesen eines Waehrungssysmbols |
| // '$' => sal_True |
| // sonst => sal_False |
| |
| sal_Bool ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos, |
| const SvNumberformat* pFormat ) |
| { |
| if ( rString.Len() > nPos ) |
| { |
| if ( !aUpperCurrSymbol.Len() ) |
| { // if no format specified the currency of the initialized formatter |
| LanguageType eLang = (pFormat ? pFormat->GetLanguage() : |
| pFormatter->GetLanguage()); |
| aUpperCurrSymbol = pFormatter->GetCharClass()->upper( |
| SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() ); |
| } |
| if ( StringContains( aUpperCurrSymbol, rString, nPos ) ) |
| { |
| nPos = nPos + aUpperCurrSymbol.Len(); |
| return sal_True; |
| } |
| if ( pFormat ) |
| { |
| String aSymbol, aExtension; |
| if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) ) |
| { |
| if ( aSymbol.Len() <= rString.Len() - nPos ) |
| { |
| pFormatter->GetCharClass()->toUpper( aSymbol ); |
| if ( StringContains( aSymbol, rString, nPos ) ) |
| { |
| nPos = nPos + aSymbol.Len(); |
| return sal_True; |
| } |
| } |
| } |
| } |
| } |
| |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetTimeAmPm |
| // |
| // Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe |
| // |
| // Rueckgabe: |
| // "AM" od. "PM" => sal_True |
| // sonst => sal_False |
| // |
| // nAmPos: |
| // "AM" => 1 |
| // "PM" => -1 |
| // sonst => 0 |
| |
| sal_Bool ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos ) |
| { |
| |
| if ( rString.Len() > nPos ) |
| { |
| const CharClass* pChr = pFormatter->GetCharClass(); |
| const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); |
| if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) ) |
| { |
| nAmPm = 1; |
| nPos = nPos + pLoc->getTimeAM().Len(); |
| return sal_True; |
| } |
| else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) ) |
| { |
| nAmPm = -1; |
| nPos = nPos + pLoc->getTimePM().Len(); |
| return sal_True; |
| } |
| } |
| |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetDecSep |
| // |
| // Lesen eines Dezimaltrenners (',') |
| // ',' => sal_True |
| // sonst => sal_False |
| |
| inline sal_Bool ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos ) |
| { |
| if ( rString.Len() > nPos ) |
| { |
| const String& rSep = pFormatter->GetNumDecimalSep(); |
| if ( rString.Equals( rSep, nPos, rSep.Len() ) ) |
| { |
| nPos = nPos + rSep.Len(); |
| return sal_True; |
| } |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // read a hundredth seconds separator |
| |
| inline sal_Bool ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos ) |
| { |
| if ( rString.Len() > nPos ) |
| { |
| const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep(); |
| if ( rString.Equals( rSep, nPos, rSep.Len() ) ) |
| { |
| nPos = nPos + rSep.Len(); |
| return sal_True; |
| } |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetSign |
| // |
| // Lesen eines Vorzeichens, auch Klammer !?! |
| // '+' => 1 |
| // '-' => -1 |
| // '(' => -1, nNegCheck = 1 |
| // sonst => 0 |
| |
| int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos ) |
| { |
| if (rString.Len() > nPos) |
| switch (rString.GetChar(nPos)) |
| { |
| case '+': |
| nPos++; |
| return 1; |
| case '(': // '(' aehnlich wie '-' ?!? |
| nNegCheck = 1; |
| //! fallthru |
| case '-': |
| nPos++; |
| return -1; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetESign |
| // |
| // Lesen eines Vorzeichens, gedacht fuer Exponent ?!? |
| // '+' => 1 |
| // '-' => -1 |
| // sonst => 0 |
| |
| short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos ) |
| { |
| if (rString.Len() > nPos) |
| switch (rString.GetChar(nPos)) |
| { |
| case '+': |
| nPos++; |
| return 1; |
| case '-': |
| nPos++; |
| return -1; |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetNextNumber |
| // |
| // i counts string portions, j counts numbers thereof. |
| // It should had been called SkipNumber instead. |
| |
| inline sal_Bool ImpSvNumberInputScan::GetNextNumber( sal_uInt16& i, sal_uInt16& j ) |
| { |
| if ( i < nAnzStrings && IsNum[i] ) |
| { |
| j++; |
| i++; |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // GetTimeRef |
| |
| void ImpSvNumberInputScan::GetTimeRef( |
| double& fOutNumber, |
| sal_uInt16 nIndex, // j-value of the first numeric time part of input, default 0 |
| sal_uInt16 nAnz ) // count of numeric time parts |
| { |
| sal_uInt16 nHour; |
| sal_uInt16 nMinute = 0; |
| sal_uInt16 nSecond = 0; |
| double fSecond100 = 0.0; |
| sal_uInt16 nStartIndex = nIndex; |
| |
| if (nTimezonePos) |
| { |
| // find first timezone number index and adjust count |
| for (sal_uInt16 j=0; j<nAnzNums; ++j) |
| { |
| if (nNums[j] == nTimezonePos) |
| { |
| // nAnz is not total count, but count of time relevant strings. |
| if (nStartIndex < j && j - nStartIndex < nAnz) |
| nAnz = j - nStartIndex; |
| break; // for |
| } |
| } |
| } |
| |
| if (nDecPos == 2 && (nAnz == 3 || nAnz == 2)) // 20:45.5 or 45.5 |
| nHour = 0; |
| else if (nIndex - nStartIndex < nAnz) |
| nHour = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32(); |
| else |
| { |
| nHour = 0; |
| DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index"); |
| } |
| if (nDecPos == 2 && nAnz == 2) // 45.5 |
| nMinute = 0; |
| else if (nIndex - nStartIndex < nAnz) |
| nMinute = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32(); |
| if (nIndex - nStartIndex < nAnz) |
| nSecond = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32(); |
| if (nIndex - nStartIndex < nAnz) |
| fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], sal_True ); |
| if (nAmPm == -1 && nHour != 12) // PM |
| nHour += 12; |
| else if (nAmPm == 1 && nHour == 12) // 12 AM |
| nHour = 0; |
| |
| fOutNumber = ((double)nHour*3600 + |
| (double)nMinute*60 + |
| (double)nSecond + |
| fSecond100)/86400.0; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ImplGetDay |
| |
| sal_uInt16 ImpSvNumberInputScan::ImplGetDay( sal_uInt16 nIndex ) |
| { |
| sal_uInt16 nRes = 0; |
| |
| if (sStrArray[nNums[nIndex]].Len() <= 2) |
| { |
| sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32(); |
| if (nNum <= 31) |
| nRes = nNum; |
| } |
| |
| return nRes; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ImplGetMonth |
| |
| sal_uInt16 ImpSvNumberInputScan::ImplGetMonth( sal_uInt16 nIndex ) |
| { |
| // preset invalid month number |
| sal_uInt16 nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear(); |
| |
| if (sStrArray[nNums[nIndex]].Len() <= 2) |
| { |
| sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32(); |
| if ( 0 < nNum && nNum <= nRes ) |
| nRes = nNum - 1; // zero based for CalendarFieldIndex::MONTH |
| } |
| |
| return nRes; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ImplGetYear |
| // |
| // 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ... |
| |
| sal_uInt16 ImpSvNumberInputScan::ImplGetYear( sal_uInt16 nIndex ) |
| { |
| sal_uInt16 nYear = 0; |
| |
| if (sStrArray[nNums[nIndex]].Len() <= 4) |
| { |
| nYear = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32(); |
| nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 ); |
| } |
| |
| return nYear; |
| } |
| |
| //--------------------------------------------------------------------------- |
| |
| bool ImpSvNumberInputScan::MayBeIso8601() |
| { |
| if (nMayBeIso8601 == 0) |
| { |
| if (nAnzNums >= 3 && nNums[0] < nAnzStrings && |
| sStrArray[nNums[0]].ToInt32() > 31) |
| nMayBeIso8601 = 1; |
| else |
| nMayBeIso8601 = 2; |
| } |
| return nMayBeIso8601 == 1; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // GetDateRef |
| |
| sal_Bool ImpSvNumberInputScan::GetDateRef( double& fDays, sal_uInt16& nCounter, |
| const SvNumberformat* pFormat ) |
| { |
| using namespace ::com::sun::star::i18n; |
| NfEvalDateFormat eEDF; |
| int nFormatOrder; |
| if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) ) |
| { |
| eEDF = pFormatter->GetEvalDateFormat(); |
| switch ( eEDF ) |
| { |
| case NF_EVALDATEFORMAT_INTL : |
| case NF_EVALDATEFORMAT_FORMAT : |
| nFormatOrder = 1; // only one loop |
| break; |
| default: |
| nFormatOrder = 2; |
| if ( nMatchedAllStrings ) |
| eEDF = NF_EVALDATEFORMAT_FORMAT_INTL; |
| // we have a complete match, use it |
| } |
| } |
| else |
| { |
| eEDF = NF_EVALDATEFORMAT_INTL; |
| nFormatOrder = 1; |
| } |
| sal_Bool res = sal_True; |
| |
| const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); |
| CalendarWrapper* pCal = pFormatter->GetCalendar(); |
| for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ ) |
| { |
| pCal->setGregorianDateTime( Date() ); // today |
| String aOrgCalendar; // empty => not changed yet |
| DateFormat DateFmt; |
| sal_Bool bFormatTurn; |
| switch ( eEDF ) |
| { |
| case NF_EVALDATEFORMAT_INTL : |
| bFormatTurn = sal_False; |
| DateFmt = pLoc->getDateFormat(); |
| break; |
| case NF_EVALDATEFORMAT_FORMAT : |
| bFormatTurn = sal_True; |
| DateFmt = pFormat->GetDateOrder(); |
| break; |
| case NF_EVALDATEFORMAT_INTL_FORMAT : |
| if ( nTryOrder == 1 ) |
| { |
| bFormatTurn = sal_False; |
| DateFmt = pLoc->getDateFormat(); |
| } |
| else |
| { |
| bFormatTurn = sal_True; |
| DateFmt = pFormat->GetDateOrder(); |
| } |
| break; |
| case NF_EVALDATEFORMAT_FORMAT_INTL : |
| if ( nTryOrder == 2 ) |
| { |
| bFormatTurn = sal_False; |
| DateFmt = pLoc->getDateFormat(); |
| } |
| else |
| { |
| bFormatTurn = sal_True; |
| DateFmt = pFormat->GetDateOrder(); |
| } |
| break; |
| default: |
| DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" ); |
| DateFmt = YMD; |
| bFormatTurn = sal_False; |
| } |
| if ( bFormatTurn ) |
| { |
| #if 0 |
| /* TODO: |
| We are currently not able to fully support a switch to another calendar during |
| input for the following reasons: |
| 1. We do have a problem if both (locale's default and format's) calendars |
| define the same YMD order and use the same date separator, there is no way |
| to distinguish between them if the input results in valid calendar input for |
| both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should |
| it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's |
| calendar be preferred? This could be confusing if a Calc cell was formatted |
| different to the locale's default and has no content yet, then the user has |
| no clue about the format or calendar being set. |
| 2. In Calc cell edit mode a date is always displayed and edited using the |
| default edit format of the default calendar (normally being Gregorian). If |
| input was ambiguous due to issue #1 we'd need a mechanism to tell that a |
| date was edited and not newly entered. Not feasible. Otherwise we'd need a |
| mechanism to use a specific edit format with a specific calendar according |
| to the format set. |
| 3. For some calendars like Japanese Gengou we'd need era input, which isn't |
| implemented at all. Though this is a rare and special case, forcing a |
| calendar dependent edit format as suggested in item #2 might require era |
| input, if it shouldn't result in a fallback to Gregorian calendar. |
| 4. Last and least: the GetMonth() method currently only matches month names of |
| the default calendar. Alternating month names of the actual format's |
| calendar would have to be implemented. No problem. |
| |
| */ |
| if ( pFormat->IsOtherCalendar( nStringScanNumFor ) ) |
| pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); |
| else |
| pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime, |
| nStringScanNumFor ); |
| #endif |
| } |
| |
| res = sal_True; |
| nCounter = 0; |
| // For incomplete dates, always assume first day of month if not specified. |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 ); |
| |
| switch (nAnzNums) // count of numbers in string |
| { |
| case 0: // none |
| if (nMonthPos) // only month (Jan) |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| else |
| res = sal_False; |
| break; |
| |
| case 1: // only one number |
| nCounter = 1; |
| switch (nMonthPos) // where is the month |
| { |
| case 0: // not found => only day entered |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| break; |
| case 1: // month at the beginning (Jan 01) |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| switch (DateFmt) |
| { |
| case MDY: |
| case YMD: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| break; |
| case DMY: |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| break; |
| case 3: // month at the end (10 Jan) |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| switch (DateFmt) |
| { |
| case DMY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| break; |
| case YMD: |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| break; |
| default: |
| res = sal_False; |
| break; |
| } // switch (nMonthPos) |
| break; |
| |
| case 2: // 2 numbers |
| nCounter = 2; |
| switch (nMonthPos) // where is the month |
| { |
| case 0: // not found |
| { |
| bool bHadExact; |
| sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0); |
| if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff ) |
| { // formatted as date and exactly 2 parts |
| bHadExact = true; |
| switch ( (nExactDateOrder >> 8) & 0xff ) |
| { |
| case 'Y': |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| case 'M': |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| break; |
| case 'D': |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| break; |
| default: |
| bHadExact = false; |
| } |
| switch ( nExactDateOrder & 0xff ) |
| { |
| case 'Y': |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| break; |
| case 'M': |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) ); |
| break; |
| case 'D': |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| break; |
| default: |
| bHadExact = false; |
| } |
| } |
| else |
| bHadExact = false; |
| if ( !bHadExact || !pCal->isValid() ) |
| { |
| if ( !bHadExact && nExactDateOrder ) |
| pCal->setGregorianDateTime( Date() ); // reset today |
| switch (DateFmt) |
| { |
| case MDY: |
| // M D |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| if ( !pCal->isValid() ) // 2nd try |
| { // M Y |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| } |
| break; |
| case DMY: |
| // D M |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) ); |
| if ( !pCal->isValid() ) // 2nd try |
| { // M Y |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| } |
| break; |
| case YMD: |
| // M D |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| if ( !pCal->isValid() ) // 2nd try |
| { // Y M |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| } |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| } |
| } |
| break; |
| case 1: // month at the beginning (Jan 01 01) |
| { |
| // The input is valid as MDY in almost any |
| // constellation, there is no date order (M)YD except if |
| // set in a format applied. |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0); |
| if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D')) |
| { |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| } |
| else |
| { |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| } |
| } |
| break; |
| case 2: // month in the middle (10 Jan 94) |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| switch (DateFmt) |
| { |
| case MDY: // yes, "10-Jan-94" is valid |
| case DMY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| break; |
| case YMD: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| break; |
| default: // else, e.g. month at the end (94 10 Jan) |
| res = sal_False; |
| break; |
| } // switch (nMonthPos) |
| break; |
| |
| default: // more than two numbers (31.12.94 8:23) (31.12. 8:23) |
| switch (nMonthPos) // where is the month |
| { |
| case 0: // not found |
| { |
| nCounter = 3; |
| if ( nTimePos > 1 ) |
| { // find first time number index (should only be 3 or 2 anyway) |
| for ( sal_uInt16 j = 0; j < nAnzNums; j++ ) |
| { |
| if ( nNums[j] == nTimePos - 2 ) |
| { |
| nCounter = j; |
| break; // for |
| } |
| } |
| } |
| // ISO 8601 yyyy-mm-dd forced recognition |
| DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt); |
| switch (eDF) |
| { |
| case MDY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) ); |
| if ( nCounter > 2 ) |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) ); |
| break; |
| case DMY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) ); |
| if ( nCounter > 2 ) |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) ); |
| break; |
| case YMD: |
| if ( nCounter > 2 ) |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| } |
| break; |
| case 1: // month at the beginning (Jan 01 01 8:23) |
| nCounter = 2; |
| switch (DateFmt) |
| { |
| case MDY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| break; |
| case 2: // month in the middle (10 Jan 94 8:23) |
| nCounter = 2; |
| pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 ); |
| switch (DateFmt) |
| { |
| case DMY: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) ); |
| break; |
| case YMD: |
| pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) ); |
| pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) ); |
| break; |
| default: |
| res = sal_False; |
| break; |
| } |
| break; |
| default: // else, e.g. month at the end (94 10 Jan 8:23) |
| nCounter = 2; |
| res = sal_False; |
| break; |
| } // switch (nMonthPos) |
| break; |
| } // switch (nAnzNums) |
| |
| if ( res && pCal->isValid() ) |
| { |
| double fDiff = DateTime(*pNullDate) - pCal->getEpochStart(); |
| fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() ); |
| fDays -= fDiff; |
| nTryOrder = nFormatOrder; // break for |
| } |
| else |
| res = sal_False; |
| |
| if ( aOrgCalendar.Len() ) |
| pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() ); // restore calendar |
| |
| #if NF_TEST_CALENDAR |
| { |
| using namespace ::com::sun::star; |
| struct entry { const char* lan; const char* cou; const char* cal; }; |
| const entry cals[] = { |
| { "en", "US", "gregorian" }, |
| { "ar", "TN", "hijri" }, |
| { "he", "IL", "jewish" }, |
| { "ja", "JP", "gengou" }, |
| { "ko", "KR", "hanja_yoil" }, |
| { "th", "TH", "buddhist" }, |
| { "zh", "TW", "ROC" }, |
| {0,0,0} |
| }; |
| lang::Locale aLocale; |
| sal_Bool bValid; |
| sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond; |
| sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet; |
| sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis; |
| sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis; |
| uno::Reference< lang::XMultiServiceFactory > xSMgr = |
| ::comphelper::getProcessServiceFactory(); |
| uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal( |
| xSMgr->createInstance( ::rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "com.sun.star.i18n.LocaleCalendar" ) ) ), |
| uno::UNO_QUERY ); |
| for ( const entry* p = cals; p->lan; ++p ) |
| { |
| aLocale.Language = ::rtl::OUString::createFromAscii( p->lan ); |
| aLocale.Country = ::rtl::OUString::createFromAscii( p->cou ); |
| xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ), |
| aLocale ); |
| double nDateTime = 0.0; // 1-Jan-1970 00:00:00 |
| nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET ); |
| nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS ); |
| nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 + |
| (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis); |
| nDST1 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET ); |
| nDST1millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS ); |
| nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 + |
| (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis); |
| nDateTime -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0; |
| xCal->setDateTime( nDateTime ); |
| nDST2 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET ); |
| nDST2millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS ); |
| nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 + |
| (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis); |
| if ( nDST1InMillis != nDST2InMillis ) |
| { |
| nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0; |
| xCal->setDateTime( nDateTime ); |
| } |
| nDaySet = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH ); |
| nMonthSet = xCal->getValue( i18n::CalendarFieldIndex::MONTH ); |
| nYearSet = xCal->getValue( i18n::CalendarFieldIndex::YEAR ); |
| nHourSet = xCal->getValue( i18n::CalendarFieldIndex::HOUR ); |
| nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE ); |
| nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND ); |
| nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET ); |
| nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS ); |
| nDST = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET ); |
| nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS ); |
| xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet ); |
| xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet ); |
| xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet ); |
| xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet ); |
| xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet ); |
| xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet ); |
| bValid = xCal->isValid(); |
| nDay = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH ); |
| nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH ); |
| nYear = xCal->getValue( i18n::CalendarFieldIndex::YEAR ); |
| nHour = xCal->getValue( i18n::CalendarFieldIndex::HOUR ); |
| nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE ); |
| nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND ); |
| bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear == |
| nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond |
| == nSecondSet; |
| } |
| } |
| #endif // NF_TEST_CALENDAR |
| |
| } |
| |
| return res; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ScanStartString |
| // |
| // ersten String analysieren |
| // Alles weg => sal_True |
| // sonst => sal_False |
| |
| sal_Bool ImpSvNumberInputScan::ScanStartString( const String& rString, |
| const SvNumberformat* pFormat ) |
| { |
| xub_StrLen nPos = 0; |
| int nDayOfWeek; |
| |
| // First of all, eat leading blanks |
| SkipBlanks(rString, nPos); |
| |
| // Yes, nMatchedAllStrings should know about the sign position |
| nSign = GetSign(rString, nPos); |
| if ( nSign ) // sign? |
| SkipBlanks(rString, nPos); |
| |
| // #102371# match against format string only if start string is not a sign character |
| if ( nMatchedAllStrings && !(nSign && rString.Len() == 1) ) |
| { // Match against format in any case, so later on for a "x1-2-3" input |
| // we may distinguish between a xy-m-d (or similar) date and a x0-0-0 |
| // format. No sign detection here! |
| if ( ScanStringNumFor( rString, nPos, pFormat, 0, sal_True ) ) |
| nMatchedAllStrings |= nMatchedStartString; |
| else |
| nMatchedAllStrings = 0; |
| } |
| |
| if ( GetDecSep(rString, nPos) ) // decimal separator in start string |
| { |
| nDecPos = 1; |
| SkipBlanks(rString, nPos); |
| } |
| else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)? |
| { |
| eScannedType = NUMBERFORMAT_CURRENCY; // !!! it IS currency !!! |
| SkipBlanks(rString, nPos); |
| if (nSign == 0) // no sign yet |
| { |
| nSign = GetSign(rString, nPos); |
| if ( nSign ) // DM -1 |
| SkipBlanks(rString, nPos); |
| } |
| } |
| else |
| { |
| nMonth = GetMonth(rString, nPos); |
| if ( nMonth ) // month (Jan 1)? |
| { |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!! |
| nMonthPos = 1; // month at the beginning |
| if ( nMonth < 0 ) |
| SkipChar( '.', rString, nPos ); // abbreviated |
| SkipBlanks(rString, nPos); |
| } |
| else |
| { |
| nDayOfWeek = GetDayOfWeek( rString, nPos ); |
| if ( nDayOfWeek ) |
| { // day of week is just parsed away |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!! |
| if ( nPos < rString.Len() ) |
| { |
| if ( nDayOfWeek < 0 ) |
| { // abbreviated |
| if ( rString.GetChar( nPos ) == '.' ) |
| ++nPos; |
| } |
| else |
| { // full long name |
| SkipBlanks(rString, nPos); |
| SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos ); |
| } |
| SkipBlanks(rString, nPos); |
| nMonth = GetMonth(rString, nPos); |
| if ( nMonth ) // month (Jan 1)? |
| { |
| nMonthPos = 1; // month a the beginning |
| if ( nMonth < 0 ) |
| SkipChar( '.', rString, nPos ); // abbreviated |
| SkipBlanks(rString, nPos); |
| } |
| } |
| } |
| } |
| } |
| |
| if (nPos < rString.Len()) // not everything consumed |
| { |
| // Does input StartString equal StartString of format? |
| // This time with sign detection! |
| if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) ) |
| return MatchedReturn(); |
| } |
| |
| return sal_True; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ScanMidString |
| // |
| // String in der Mitte analysieren |
| // Alles weg => sal_True |
| // sonst => sal_False |
| |
| sal_Bool ImpSvNumberInputScan::ScanMidString( const String& rString, |
| sal_uInt16 nStringPos, const SvNumberformat* pFormat ) |
| { |
| xub_StrLen nPos = 0; |
| short eOldScannedType = eScannedType; |
| |
| if ( nMatchedAllStrings ) |
| { // Match against format in any case, so later on for a "1-2-3-4" input |
| // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0 |
| // format. |
| if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) ) |
| nMatchedAllStrings |= nMatchedMidString; |
| else |
| nMatchedAllStrings = 0; |
| } |
| |
| SkipBlanks(rString, nPos); |
| if (GetDecSep(rString, nPos)) // decimal separator? |
| { |
| if (nDecPos == 1 || nDecPos == 3) // .12.4 or 1.E2.1 |
| return MatchedReturn(); |
| else if (nDecPos == 2) // . dup: 12.4. |
| { |
| if (bDecSepInDateSeps) // . also date separator |
| { |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_DATE && |
| eScannedType != NUMBERFORMAT_DATETIME) // already another type |
| return MatchedReturn(); |
| if (eScannedType == NUMBERFORMAT_UNDEFINED) |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date |
| SkipBlanks(rString, nPos); |
| } |
| else |
| return MatchedReturn(); |
| } |
| else |
| { |
| nDecPos = 2; // . in mid string |
| SkipBlanks(rString, nPos); |
| } |
| } |
| else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME) |
| && GetTime100SecSep( rString, nPos ) ) |
| { // hundredth seconds separator |
| if ( nDecPos ) |
| return MatchedReturn(); |
| nDecPos = 2; // . in mid string |
| SkipBlanks(rString, nPos); |
| } |
| |
| if (SkipChar('/', rString, nPos)) // fraction? |
| { |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type |
| && eScannedType != NUMBERFORMAT_DATE) // except date |
| return MatchedReturn(); // => jan/31/1994 |
| else if ( eScannedType != NUMBERFORMAT_DATE // analyzed date until now |
| && ( eSetType == NUMBERFORMAT_FRACTION // and preset was fraction |
| || (nAnzNums == 3 // or 3 numbers |
| && nStringPos > 2) ) ) // and what ??? |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_FRACTION; // !!! it IS a fraction |
| } |
| else |
| nPos--; // put '/' back |
| } |
| |
| if (GetThousandSep(rString, nPos, nStringPos)) // 1,000 |
| { |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type |
| && eScannedType != NUMBERFORMAT_CURRENCY) // except currency |
| return MatchedReturn(); |
| nThousand++; |
| } |
| |
| const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); |
| const String& rDate = pFormatter->GetDateSep(); |
| const String& rTime = pLoc->getTimeSep(); |
| sal_Unicode cTime = rTime.GetChar(0); |
| SkipBlanks(rString, nPos); |
| if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/ |
| || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY: |
| || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean |
| || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation! |
| { |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type |
| && eScannedType != NUMBERFORMAT_DATE) // except date |
| return MatchedReturn(); |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date |
| short nTmpMonth = GetMonth(rString, nPos); // 10. Jan 94 |
| if (nMonth && nTmpMonth) // month dup |
| return MatchedReturn(); |
| if (nTmpMonth) |
| { |
| nMonth = nTmpMonth; |
| nMonthPos = 2; // month in the middle |
| if ( nMonth < 0 && SkipChar( '.', rString, nPos ) ) |
| ; // short month may be abbreviated Jan. |
| else if ( SkipChar( '-', rString, nPos ) ) |
| ; // #79632# recognize 17-Jan-2001 to be a date |
| // #99065# short and long month name |
| else |
| SkipString( pLoc->getLongDateMonthSep(), rString, nPos ); |
| SkipBlanks(rString, nPos); |
| } |
| } |
| |
| short nTempMonth = GetMonth(rString, nPos); // month in the middle (10 Jan 94) |
| if (nTempMonth) |
| { |
| if (nMonth != 0) // month dup |
| return MatchedReturn(); |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type |
| && eScannedType != NUMBERFORMAT_DATE) // except date |
| return MatchedReturn(); |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date |
| nMonth = nTempMonth; |
| nMonthPos = 2; // month in the middle |
| if ( nMonth < 0 ) |
| SkipChar( '.', rString, nPos ); // abbreviated |
| SkipString( pLoc->getLongDateMonthSep(), rString, nPos ); |
| SkipBlanks(rString, nPos); |
| } |
| |
| if ( SkipChar('E', rString, nPos) // 10E, 10e, 10,Ee |
| || SkipChar('e', rString, nPos) ) |
| { |
| if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type |
| return MatchedReturn(); |
| else |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific |
| if ( nThousand+2 == nAnzNums // special case 1.E2 |
| && nDecPos == 2 ) |
| nDecPos = 3; // 1,100.E2 1,100,100.E3 |
| } |
| nESign = GetESign(rString, nPos); // signed exponent? |
| SkipBlanks(rString, nPos); |
| } |
| |
| if ( SkipString(rTime, rString, nPos) ) // time separator? |
| { |
| if (nDecPos) // already . => maybe error |
| { |
| if (bDecSepInDateSeps) // . also date sep |
| { |
| if ( eScannedType != NUMBERFORMAT_DATE && // already another type than date |
| eScannedType != NUMBERFORMAT_DATETIME) // or date time |
| return MatchedReturn(); |
| if (eScannedType == NUMBERFORMAT_DATE) |
| nDecPos = 0; // reset for time transition |
| } |
| else |
| return MatchedReturn(); |
| } |
| if ( ( eScannedType == NUMBERFORMAT_DATE // already date type |
| || eScannedType == NUMBERFORMAT_DATETIME) // or date time |
| && nAnzNums > 3) // and more than 3 numbers? (31.Dez.94 8:23) |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_DATETIME; // !!! it IS date with time |
| } |
| else if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type |
| && eScannedType != NUMBERFORMAT_TIME) // except time |
| return MatchedReturn(); |
| else |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_TIME; // !!! it IS a time |
| } |
| if ( !nTimePos ) |
| nTimePos = nStringPos + 1; |
| } |
| |
| if (nPos < rString.Len()) |
| { |
| switch (eScannedType) |
| { |
| case NUMBERFORMAT_DATE: |
| if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY) |
| { |
| // #68232# recognize long date separators like ", " in "September 5, 1999" |
| if (SkipString( pLoc->getLongDateDaySep(), rString, nPos )) |
| SkipBlanks( rString, nPos ); |
| } |
| else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 && |
| rString.GetChar(0) == 'T' && MayBeIso8601()) |
| { |
| // ISO 8601 combined date and time, yyyy-mm-ddThh:mm |
| ++nPos; |
| } |
| break; |
| #if NF_RECOGNIZE_ISO8601_TIMEZONES |
| case NUMBERFORMAT_DATETIME: |
| if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 && |
| MayBeIso8601()) |
| { |
| // ISO 8601 timezone offset |
| switch (rString.GetChar(0)) |
| { |
| case '+': |
| case '-': |
| if (nStringPos == nAnzStrings-2 || |
| nStringPos == nAnzStrings-4) |
| { |
| ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy] |
| // nTimezonePos needed for GetTimeRef() |
| if (!nTimezonePos) |
| nTimezonePos = nStringPos + 1; |
| } |
| break; |
| case ':': |
| if (nTimezonePos && nStringPos >= 11 && |
| nStringPos == nAnzStrings-2) |
| ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx:yy |
| break; |
| } |
| } |
| break; |
| #endif |
| } |
| } |
| |
| if (nPos < rString.Len()) // not everything consumed? |
| { |
| if ( nMatchedAllStrings & ~nMatchedVirgin ) |
| eScannedType = eOldScannedType; |
| else |
| return sal_False; |
| } |
| |
| return sal_True; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ScanEndString |
| // |
| // Schlussteil analysieren |
| // Alles weg => sal_True |
| // sonst => sal_False |
| |
| sal_Bool ImpSvNumberInputScan::ScanEndString( const String& rString, |
| const SvNumberformat* pFormat ) |
| { |
| xub_StrLen nPos = 0; |
| |
| if ( nMatchedAllStrings ) |
| { // Match against format in any case, so later on for a "1-2-3-4" input |
| // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0 |
| // format. |
| if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) ) |
| nMatchedAllStrings |= nMatchedEndString; |
| else |
| nMatchedAllStrings = 0; |
| } |
| |
| SkipBlanks(rString, nPos); |
| if (GetDecSep(rString, nPos)) // decimal separator? |
| { |
| if (nDecPos == 1 || nDecPos == 3) // .12.4 or 12.E4. |
| return MatchedReturn(); |
| else if (nDecPos == 2) // . dup: 12.4. |
| { |
| if (bDecSepInDateSeps) // . also date sep |
| { |
| if ( eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_DATE && |
| eScannedType != NUMBERFORMAT_DATETIME) // already another type |
| return MatchedReturn(); |
| if (eScannedType == NUMBERFORMAT_UNDEFINED) |
| eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date |
| SkipBlanks(rString, nPos); |
| } |
| else |
| return MatchedReturn(); |
| } |
| else |
| { |
| nDecPos = 3; // . in end string |
| SkipBlanks(rString, nPos); |
| } |
| } |
| |
| if ( nSign == 0 // conflict - not signed |
| && eScannedType != NUMBERFORMAT_DATE) // and not date |
| //!? catch time too? |
| { // not signed yet |
| nSign = GetSign(rString, nPos); // 1- DM |
| if (nNegCheck) // '(' as sign |
| return MatchedReturn(); |
| } |
| |
| SkipBlanks(rString, nPos); |
| if (nNegCheck && SkipChar(')', rString, nPos)) // skip ')' if appropriate |
| { |
| nNegCheck = 0; |
| SkipBlanks(rString, nPos); |
| } |
| |
| if ( GetCurrency(rString, nPos, pFormat) ) // currency symbol? |
| { |
| if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup |
| return MatchedReturn(); |
| else |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_CURRENCY; |
| } // behind currency a '-' is allowed |
| if (nSign == 0) // not signed yet |
| { |
| nSign = GetSign(rString, nPos); // DM - |
| SkipBlanks(rString, nPos); |
| if (nNegCheck) // 3 DM ( |
| return MatchedReturn(); |
| } |
| if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY |
| && SkipChar(')', rString, nPos) ) |
| { |
| nNegCheck = 0; // ')' skipped |
| SkipBlanks(rString, nPos); // only if currency |
| } |
| } |
| |
| if ( SkipChar('%', rString, nPos) ) // 1 % |
| { |
| if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type |
| return MatchedReturn(); |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_PERCENT; |
| } |
| |
| const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); |
| const String& rDate = pFormatter->GetDateSep(); |
| const String& rTime = pLoc->getTimeSep(); |
| if ( SkipString(rTime, rString, nPos) ) // 10: |
| { |
| if (nDecPos) // already , => error |
| return MatchedReturn(); |
| if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8: |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_DATETIME; |
| } |
| else if (eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_TIME) // already another type |
| return MatchedReturn(); |
| else |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_TIME; |
| } |
| if ( !nTimePos ) |
| nTimePos = nAnzStrings; |
| } |
| |
| sal_Unicode cTime = rTime.GetChar(0); |
| if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/ |
| || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY: |
| || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean |
| || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation! |
| { |
| if (eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_DATE) // already another type |
| return MatchedReturn(); |
| else |
| { |
| SkipBlanks(rString, nPos); |
| eScannedType = NUMBERFORMAT_DATE; |
| } |
| short nTmpMonth = GetMonth(rString, nPos); // 10. Jan |
| if (nMonth && nTmpMonth) // month dup |
| return MatchedReturn(); |
| if (nTmpMonth) |
| { |
| nMonth = nTmpMonth; |
| nMonthPos = 3; // month at end |
| if ( nMonth < 0 ) |
| SkipChar( '.', rString, nPos ); // abbreviated |
| SkipBlanks(rString, nPos); |
| } |
| } |
| |
| short nTempMonth = GetMonth(rString, nPos); // 10 Jan |
| if (nTempMonth) |
| { |
| if (nMonth) // month dup |
| return MatchedReturn(); |
| if (eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_DATE) // already another type |
| return MatchedReturn(); |
| eScannedType = NUMBERFORMAT_DATE; |
| nMonth = nTempMonth; |
| nMonthPos = 3; // month at end |
| if ( nMonth < 0 ) |
| SkipChar( '.', rString, nPos ); // abbreviated |
| SkipBlanks(rString, nPos); |
| } |
| |
| xub_StrLen nOrigPos = nPos; |
| if (GetTimeAmPm(rString, nPos)) |
| { |
| if (eScannedType != NUMBERFORMAT_UNDEFINED && |
| eScannedType != NUMBERFORMAT_TIME && |
| eScannedType != NUMBERFORMAT_DATETIME) // already another type |
| return MatchedReturn(); |
| else |
| { |
| // If not already scanned as time, 6.78am does not result in 6 |
| // seconds and 78 hundredths in the morning. Keep as suffix. |
| if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2) |
| nPos = nOrigPos; // rewind am/pm |
| else |
| { |
| SkipBlanks(rString, nPos); |
| if ( eScannedType != NUMBERFORMAT_DATETIME ) |
| eScannedType = NUMBERFORMAT_TIME; |
| } |
| } |
| } |
| |
| if ( nNegCheck && SkipChar(')', rString, nPos) ) |
| { |
| if (eScannedType == NUMBERFORMAT_CURRENCY) // only if currency |
| { |
| nNegCheck = 0; // skip ')' |
| SkipBlanks(rString, nPos); |
| } |
| else |
| return MatchedReturn(); |
| } |
| |
| if ( nPos < rString.Len() && |
| (eScannedType == NUMBERFORMAT_DATE |
| || eScannedType == NUMBERFORMAT_DATETIME) ) |
| { // day of week is just parsed away |
| xub_StrLen nOldPos = nPos; |
| const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(); |
| if ( StringContains( rSep, rString, nPos ) ) |
| { |
| nPos = nPos + rSep.Len(); |
| SkipBlanks(rString, nPos); |
| } |
| int nDayOfWeek = GetDayOfWeek( rString, nPos ); |
| if ( nDayOfWeek ) |
| { |
| if ( nPos < rString.Len() ) |
| { |
| if ( nDayOfWeek < 0 ) |
| { // short |
| if ( rString.GetChar( nPos ) == '.' ) |
| ++nPos; |
| } |
| SkipBlanks(rString, nPos); |
| } |
| } |
| else |
| nPos = nOldPos; |
| } |
| |
| #if NF_RECOGNIZE_ISO8601_TIMEZONES |
| if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME && |
| rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601()) |
| { |
| // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ |
| ++nPos; |
| } |
| #endif |
| |
| if (nPos < rString.Len()) // everything consumed? |
| { |
| // does input EndString equal EndString in Format? |
| if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) ) |
| return sal_False; |
| } |
| |
| return sal_True; |
| } |
| |
| |
| sal_Bool ImpSvNumberInputScan::ScanStringNumFor( |
| const String& rString, // String to scan |
| xub_StrLen nPos, // Position until which was consumed |
| const SvNumberformat* pFormat, // The format to match |
| sal_uInt16 nString, // Substring of format, 0xFFFF => last |
| sal_Bool bDontDetectNegation // Suppress sign detection |
| ) |
| { |
| if ( !pFormat ) |
| return sal_False; |
| const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration(); |
| const String* pStr; |
| String aString( rString ); |
| sal_Bool bFound = sal_False; |
| sal_Bool bFirst = sal_True; |
| sal_Bool bContinue = sal_True; |
| sal_uInt16 nSub; |
| do |
| { |
| // Don't try "lower" subformats ff the very first match was the second |
| // or third subformat. |
| nSub = nStringScanNumFor; |
| do |
| { // Step through subformats, first positive, then negative, then |
| // other, but not the last (text) subformat. |
| pStr = pFormat->GetNumForString( nSub, nString, sal_True ); |
| if ( pStr && pTransliteration->isEqual( aString, *pStr ) ) |
| { |
| bFound = sal_True; |
| bContinue = sal_False; |
| } |
| else if ( nSub < 2 ) |
| ++nSub; |
| else |
| bContinue = sal_False; |
| } while ( bContinue ); |
| if ( !bFound && bFirst && nPos ) |
| { // try remaining substring |
| bFirst = sal_False; |
| aString.Erase( 0, nPos ); |
| bContinue = sal_True; |
| } |
| } while ( bContinue ); |
| |
| if ( !bFound ) |
| { |
| if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0) |
| && pFormat->IsNegativeRealNegative() ) |
| { // simply negated twice? --1 |
| aString.EraseAllChars( ' ' ); |
| if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') ) |
| { |
| bFound = sal_True; |
| nStringScanSign = -1; |
| nSub = 0; //! not 1 |
| } |
| } |
| if ( !bFound ) |
| return sal_False; |
| } |
| else if ( !bDontDetectNegation && (nSub == 1) && |
| pFormat->IsNegativeRealNegative() ) |
| { // negative |
| if ( nStringScanSign < 0 ) |
| { |
| if ( (nSign < 0) && (nStringScanNumFor != 1) ) |
| nStringScanSign = 1; // triple negated --1 yyy |
| } |
| else if ( nStringScanSign == 0 ) |
| { |
| if ( nSign < 0 ) |
| { // nSign and nStringScanSign will be combined later, |
| // flip sign if doubly negated |
| if ( (nString == 0) && !bFirst |
| && SvNumberformat::HasStringNegativeSign( aString ) ) |
| nStringScanSign = -1; // direct double negation |
| else if ( pFormat->IsNegativeWithoutSign() ) |
| nStringScanSign = -1; // indirect double negation |
| } |
| else |
| nStringScanSign = -1; |
| } |
| else // > 0 |
| nStringScanSign = -1; |
| } |
| nStringScanNumFor = nSub; |
| return sal_True; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // IsNumberFormatMain |
| // |
| // Recognizes types of number, exponential, fraction, percent, currency, date, time. |
| // Else text => return sal_False |
| |
| sal_Bool ImpSvNumberInputScan::IsNumberFormatMain( |
| const String& rString, // string to be analyzed |
| double& , // OUT: result as number, if possible |
| const SvNumberformat* pFormat ) // maybe number format set to match against |
| { |
| Reset(); |
| NumberStringDivision( rString ); // breakdown into strings and numbers |
| if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements |
| return sal_False; // Njet, Nope, ... |
| |
| if (nAnzNums == 0) // no number in input |
| { |
| if ( nAnzStrings > 0 ) |
| { |
| // Here we may change the original, we don't need it anymore. |
| // This saves copies and ToUpper() in GetLogical() and is faster. |
| String& rStrArray = sStrArray[0]; |
| rStrArray.EraseTrailingChars( ' ' ); |
| rStrArray.EraseLeadingChars( ' ' ); |
| nLogical = GetLogical( rStrArray ); |
| if ( nLogical ) |
| { |
| eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| else |
| return sal_False; // simple text |
| } |
| else |
| return sal_False; // simple text |
| } |
| |
| sal_uInt16 i = 0; // mark any symbol |
| sal_uInt16 j = 0; // mark only numbers |
| |
| switch ( nAnzNums ) |
| { |
| case 1 : // Exactly 1 number in input |
| { // nAnzStrings >= 1 |
| if (GetNextNumber(i,j)) // i=1,0 |
| { // Number at start |
| if (eSetType == NUMBERFORMAT_FRACTION) // Fraction 1 = 1/1 |
| { |
| if (i >= nAnzStrings || // no end string nor decimal separator |
| sStrArray[i] == pFormatter->GetNumDecimalSep()) |
| { |
| eScannedType = NUMBERFORMAT_FRACTION; |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| } |
| } |
| else |
| { // Analyze start string |
| if (!ScanStartString( sStrArray[i], pFormat )) // i=0 |
| return sal_False; // already an error |
| i++; // next symbol, i=1 |
| } |
| GetNextNumber(i,j); // i=1,2 |
| if (eSetType == NUMBERFORMAT_FRACTION) // Fraction -1 = -1/1 |
| { |
| if (nSign && !nNegCheck && // Sign +, - |
| eScannedType == NUMBERFORMAT_UNDEFINED && // not date or currency |
| nDecPos == 0 && // no previous decimal separator |
| (i >= nAnzStrings || // no end string nor decimal separator |
| sStrArray[i] == pFormatter->GetNumDecimalSep()) |
| ) |
| { |
| eScannedType = NUMBERFORMAT_FRACTION; |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| } |
| if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat )) |
| return sal_False; |
| } |
| break; |
| case 2 : // Exactly 2 numbers in input |
| { // nAnzStrings >= 3 |
| if (!GetNextNumber(i,j)) // i=1,0 |
| { // Analyze start string |
| if (!ScanStartString( sStrArray[i], pFormat )) |
| return sal_False; // already an error |
| i++; // i=1 |
| } |
| GetNextNumber(i,j); // i=1,2 |
| if ( !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; // next symbol, i=2,3 |
| GetNextNumber(i,j); // i=3,4 |
| if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat )) |
| return sal_False; |
| if (eSetType == NUMBERFORMAT_FRACTION) // -1,200. as fraction |
| { |
| if (!nNegCheck && // no sign '(' |
| eScannedType == NUMBERFORMAT_UNDEFINED && |
| (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end |
| ) |
| { |
| eScannedType = NUMBERFORMAT_FRACTION; |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| } |
| } |
| break; |
| case 3 : // Exactly 3 numbers in input |
| { // nAnzStrings >= 5 |
| if (!GetNextNumber(i,j)) // i=1,0 |
| { // Analyze start string |
| if (!ScanStartString( sStrArray[i], pFormat )) |
| return sal_False; // already an error |
| i++; // i=1 |
| if (nDecPos == 1) // decimal separator at start => error |
| return sal_False; |
| } |
| GetNextNumber(i,j); // i=1,2 |
| if ( !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; // i=2,3 |
| if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end |
| return sal_False; |
| GetNextNumber(i,j); // i=3,4 |
| if ( !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; // i=4,5 |
| GetNextNumber(i,j); // i=5,6 |
| if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat )) |
| return sal_False; |
| if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction |
| { |
| if (!nNegCheck && // no sign '(' |
| eScannedType == NUMBERFORMAT_UNDEFINED && |
| (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end |
| ) |
| { |
| eScannedType = NUMBERFORMAT_FRACTION; |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| } |
| if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos ) |
| return sal_False; // #36857# not a real fraction |
| } |
| break; |
| default: // More than 3 numbers in input |
| { // nAnzStrings >= 7 |
| if (!GetNextNumber(i,j)) // i=1,0 |
| { // Analyze startstring |
| if (!ScanStartString( sStrArray[i], pFormat )) |
| return sal_False; // already an error |
| i++; // i=1 |
| if (nDecPos == 1) // decimal separator at start => error |
| return sal_False; |
| } |
| GetNextNumber(i,j); // i=1,2 |
| if ( !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; // i=2,3 |
| sal_uInt16 nThOld = 10; // just not 0 or 1 |
| while (nThOld != nThousand && j < nAnzNums-1) |
| // Execute at least one time |
| // but leave one number. |
| { // Loop over group separators |
| nThOld = nThousand; |
| if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end |
| return sal_False; |
| GetNextNumber(i,j); |
| if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; |
| } |
| if (eScannedType == NUMBERFORMAT_DATE || // long date or |
| eScannedType == NUMBERFORMAT_TIME || // long time or |
| eScannedType == NUMBERFORMAT_UNDEFINED) // long number |
| { |
| for (sal_uInt16 k = j; k < nAnzNums-1; k++) |
| { |
| if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at endd |
| return sal_False; |
| GetNextNumber(i,j); |
| if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) ) |
| return sal_False; |
| i++; |
| } |
| } |
| GetNextNumber(i,j); |
| if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat )) |
| return sal_False; |
| if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction |
| { |
| if (!nNegCheck && // no sign '(' |
| eScannedType == NUMBERFORMAT_UNDEFINED && |
| (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end |
| ) |
| { |
| eScannedType = NUMBERFORMAT_FRACTION; |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| return sal_True; |
| } |
| } |
| if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos ) |
| return sal_False; // #36857# not a real fraction |
| } |
| } |
| |
| if (eScannedType == NUMBERFORMAT_UNDEFINED) |
| { |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| // did match including nMatchedUsedAsReturn |
| sal_Bool bDidMatch = (nMatchedAllStrings != 0); |
| if ( nMatchedAllStrings ) |
| { |
| sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual( |
| nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False); |
| if ( !bMatch ) |
| nMatchedAllStrings = 0; |
| } |
| if ( nMatchedAllStrings ) |
| eScannedType = eSetType; |
| else if ( bDidMatch ) |
| return sal_False; |
| else |
| eScannedType = NUMBERFORMAT_NUMBER; |
| // everything else should have been recognized by now |
| } |
| else if ( eScannedType == NUMBERFORMAT_DATE ) |
| { // the very relaxed date input checks may interfere with a preset format |
| nMatchedAllStrings &= ~nMatchedVirgin; |
| sal_Bool bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0); |
| if ( nMatchedAllStrings ) |
| { |
| sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual( |
| nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False); |
| if ( !bMatch ) |
| nMatchedAllStrings = 0; |
| } |
| if ( nMatchedAllStrings ) |
| eScannedType = eSetType; |
| else if ( bWasReturn ) |
| return sal_False; |
| } |
| else |
| nMatchedAllStrings = 0; // reset flag to no substrings matched |
| |
| return sal_True; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // return sal_True or sal_False depending on the nMatched... state and remember usage |
| sal_Bool ImpSvNumberInputScan::MatchedReturn() |
| { |
| if ( nMatchedAllStrings & ~nMatchedVirgin ) |
| { |
| nMatchedAllStrings |= nMatchedUsedAsReturn; |
| return sal_True; |
| } |
| return sal_False; |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // Initialize uppercase months and weekdays |
| |
| void ImpSvNumberInputScan::InitText() |
| { |
| sal_Int32 j, nElems; |
| const CharClass* pChrCls = pFormatter->GetCharClass(); |
| const CalendarWrapper* pCal = pFormatter->GetCalendar(); |
| delete [] pUpperMonthText; |
| delete [] pUpperAbbrevMonthText; |
| ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems |
| = pCal->getMonths(); |
| nElems = xElems.getLength(); |
| pUpperMonthText = new String[nElems]; |
| pUpperAbbrevMonthText = new String[nElems]; |
| for ( j=0; j<nElems; j++ ) |
| { |
| pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName ); |
| pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName ); |
| } |
| delete [] pUpperDayText; |
| delete [] pUpperAbbrevDayText; |
| xElems = pCal->getDays(); |
| nElems = xElems.getLength(); |
| pUpperDayText = new String[nElems]; |
| pUpperAbbrevDayText = new String[nElems]; |
| for ( j=0; j<nElems; j++ ) |
| { |
| pUpperDayText[j] = pChrCls->upper( xElems[j].FullName ); |
| pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName ); |
| } |
| bTextInitialized = sal_True; |
| } |
| |
| |
| //=========================================================================== |
| // P U B L I C |
| |
| //--------------------------------------------------------------------------- |
| // ChangeIntl |
| // |
| // MUST be called if International/Locale is changed |
| |
| void ImpSvNumberInputScan::ChangeIntl() |
| { |
| sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0); |
| bDecSepInDateSeps = ( cDecSep == '-' || |
| cDecSep == '/' || |
| cDecSep == '.' || |
| cDecSep == pFormatter->GetDateSep().GetChar(0) ); |
| bTextInitialized = sal_False; |
| aUpperCurrSymbol.Erase(); |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // ChangeNullDate |
| |
| void ImpSvNumberInputScan::ChangeNullDate( |
| const sal_uInt16 Day, |
| const sal_uInt16 Month, |
| const sal_uInt16 Year ) |
| { |
| if ( pNullDate ) |
| *pNullDate = Date(Day, Month, Year); |
| else |
| pNullDate = new Date(Day, Month, Year); |
| } |
| |
| |
| //--------------------------------------------------------------------------- |
| // IsNumberFormat |
| // |
| // => does rString represent a number (also date, time et al) |
| |
| sal_Bool ImpSvNumberInputScan::IsNumberFormat( |
| const String& rString, // string to be analyzed |
| short& F_Type, // IN: old type, OUT: new type |
| double& fOutNumber, // OUT: number if convertable |
| const SvNumberformat* pFormat ) // maybe a number format to match against |
| { |
| String sResString; |
| String aString; |
| sal_Bool res; // return value |
| eSetType = F_Type; // old type set |
| |
| if ( !rString.Len() ) |
| res = sal_False; |
| else if (rString.Len() > 308) // arbitrary |
| res = sal_False; |
| else |
| { |
| // NoMoreUpperNeeded, all comparisons on UpperCase |
| aString = pFormatter->GetCharClass()->upper( rString ); |
| // convert native number to ASCII if necessary |
| TransformInput( aString ); |
| res = IsNumberFormatMain( aString, fOutNumber, pFormat ); |
| } |
| |
| if (res) |
| { |
| if ( nNegCheck // ')' not found for '(' |
| || (nSign && (eScannedType == NUMBERFORMAT_DATE |
| || eScannedType == NUMBERFORMAT_DATETIME)) |
| ) // signed date/datetime |
| res = sal_False; |
| else |
| { // check count of partial number strings |
| switch (eScannedType) |
| { |
| case NUMBERFORMAT_PERCENT: |
| case NUMBERFORMAT_CURRENCY: |
| case NUMBERFORMAT_NUMBER: |
| if (nDecPos == 1) // .05 |
| { |
| // matched MidStrings function like group separators |
| if ( nMatchedAllStrings ) |
| nThousand = nAnzNums - 1; |
| else if ( nAnzNums != 1 ) |
| res = sal_False; |
| } |
| else if (nDecPos == 2) // 1.05 |
| { |
| // matched MidStrings function like group separators |
| if ( nMatchedAllStrings ) |
| nThousand = nAnzNums - 1; |
| else if ( nAnzNums != nThousand+2 ) |
| res = sal_False; |
| } |
| else // 1,100 or 1,100. |
| { |
| // matched MidStrings function like group separators |
| if ( nMatchedAllStrings ) |
| nThousand = nAnzNums - 1; |
| else if ( nAnzNums != nThousand+1 ) |
| res = sal_False; |
| } |
| break; |
| |
| case NUMBERFORMAT_SCIENTIFIC: // 1.0e-2 |
| if (nDecPos == 1) // .05 |
| { |
| if (nAnzNums != 2) |
| res = sal_False; |
| } |
| else if (nDecPos == 2) // 1.05 |
| { |
| if (nAnzNums != nThousand+3) |
| res = sal_False; |
| } |
| else // 1,100 or 1,100. |
| { |
| if (nAnzNums != nThousand+2) |
| res = sal_False; |
| } |
| break; |
| |
| case NUMBERFORMAT_DATE: |
| if (nMonth) |
| { // month name and numbers |
| if (nAnzNums > 2) |
| res = sal_False; |
| } |
| else |
| { |
| if (nAnzNums > 3) |
| res = sal_False; |
| } |
| break; |
| |
| case NUMBERFORMAT_TIME: |
| if (nDecPos) |
| { // hundredth seconds included |
| if (nAnzNums > 4) |
| res = sal_False; |
| } |
| else |
| { |
| if (nAnzNums > 3) |
| res = sal_False; |
| } |
| break; |
| |
| case NUMBERFORMAT_DATETIME: |
| if (nMonth) |
| { // month name and numbers |
| if (nDecPos) |
| { // hundredth seconds included |
| if (nAnzNums > 6) |
| res = sal_False; |
| } |
| else |
| { |
| if (nAnzNums > 5) |
| res = sal_False; |
| } |
| } |
| else |
| { |
| if (nDecPos) |
| { // hundredth seconds included |
| if (nAnzNums > 7) |
| res = sal_False; |
| } |
| else |
| { |
| if (nAnzNums > 6) |
| res = sal_False; |
| } |
| } |
| break; |
| |
| default: |
| break; |
| } // switch |
| } // else |
| } // if (res) |
| |
| if (res) |
| { // we finally have a number |
| switch (eScannedType) |
| { |
| case NUMBERFORMAT_LOGICAL: |
| if (nLogical == 1) |
| fOutNumber = 1.0; // True |
| else if (nLogical == -1) |
| fOutNumber = 0.0; // False |
| else |
| res = sal_False; // Oops |
| break; |
| |
| case NUMBERFORMAT_PERCENT: |
| case NUMBERFORMAT_CURRENCY: |
| case NUMBERFORMAT_NUMBER: |
| case NUMBERFORMAT_SCIENTIFIC: |
| case NUMBERFORMAT_DEFINED: // if no category detected handle as number |
| { |
| if ( nDecPos == 1 ) // . at start |
| sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) ); |
| else |
| sResString.Erase(); |
| sal_uInt16 k; |
| for ( k = 0; k <= nThousand; k++) |
| sResString += sStrArray[nNums[k]]; // integer part |
| if ( nDecPos == 2 && k < nAnzNums ) // . somewhere |
| { |
| sResString += '.'; |
| sal_uInt16 nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ? |
| nAnzNums-1 : nAnzNums); |
| for ( ; k < nStop; k++) |
| sResString += sStrArray[nNums[k]]; // fractional part |
| } |
| |
| if (eScannedType != NUMBERFORMAT_SCIENTIFIC) |
| fOutNumber = StringToDouble(sResString); |
| else |
| { // append exponent |
| sResString += 'E'; |
| if ( nESign == -1 ) |
| sResString += '-'; |
| sResString += sStrArray[nNums[nAnzNums-1]]; |
| rtl_math_ConversionStatus eStatus; |
| fOutNumber = ::rtl::math::stringToDouble( |
| sResString, '.', ',', &eStatus, NULL ); |
| if ( eStatus == rtl_math_ConversionStatus_OutOfRange ) |
| { |
| F_Type = NUMBERFORMAT_TEXT; // overflow/underflow -> Text |
| if (nESign == -1) |
| fOutNumber = 0.0; |
| else |
| fOutNumber = DBL_MAX; |
| /*!*/ return sal_True; |
| } |
| } |
| |
| if ( nStringScanSign ) |
| { |
| if ( nSign ) |
| nSign *= nStringScanSign; |
| else |
| nSign = nStringScanSign; |
| } |
| if ( nSign < 0 ) |
| fOutNumber = -fOutNumber; |
| |
| if (eScannedType == NUMBERFORMAT_PERCENT) |
| fOutNumber/= 100.0; |
| } |
| break; |
| |
| case NUMBERFORMAT_FRACTION: |
| if (nAnzNums == 1) |
| fOutNumber = StringToDouble(sStrArray[nNums[0]]); |
| else if (nAnzNums == 2) |
| { |
| if (nThousand == 1) |
| { |
| sResString = sStrArray[nNums[0]]; |
| sResString += sStrArray[nNums[1]]; // integer part |
| fOutNumber = StringToDouble(sResString); |
| } |
| else |
| { |
| double fZaehler = StringToDouble(sStrArray[nNums[0]]); |
| double fNenner = StringToDouble(sStrArray[nNums[1]]); |
| if (fNenner != 0.0) |
| fOutNumber = fZaehler/fNenner; |
| else |
| res = sal_False; |
| } |
| } |
| else // nAnzNums > 2 |
| { |
| sal_uInt16 k = 1; |
| sResString = sStrArray[nNums[0]]; |
| if (nThousand > 0) |
| for (k = 1; k <= nThousand; k++) |
| sResString += sStrArray[nNums[k]]; |
| fOutNumber = StringToDouble(sResString); |
| |
| if (k == nAnzNums-2) |
| { |
| double fZaehler = StringToDouble(sStrArray[nNums[k]]); |
| double fNenner = StringToDouble(sStrArray[nNums[k+1]]); |
| if (fNenner != 0.0) |
| fOutNumber += fZaehler/fNenner; |
| else |
| res = sal_False; |
| } |
| } |
| |
| if ( nStringScanSign ) |
| { |
| if ( nSign ) |
| nSign *= nStringScanSign; |
| else |
| nSign = nStringScanSign; |
| } |
| if ( nSign < 0 ) |
| fOutNumber = -fOutNumber; |
| break; |
| |
| case NUMBERFORMAT_TIME: |
| GetTimeRef(fOutNumber, 0, nAnzNums); |
| if ( nSign < 0 ) |
| fOutNumber = -fOutNumber; |
| break; |
| |
| case NUMBERFORMAT_DATE: |
| { |
| sal_uInt16 nCounter = 0; // dummy here |
| res = GetDateRef( fOutNumber, nCounter, pFormat ); |
| } |
| break; |
| |
| case NUMBERFORMAT_DATETIME: |
| { |
| sal_uInt16 nCounter = 0; // needed here |
| res = GetDateRef( fOutNumber, nCounter, pFormat ); |
| if ( res ) |
| { |
| double fTime; |
| GetTimeRef( fTime, nCounter, nAnzNums - nCounter ); |
| fOutNumber += fTime; |
| } |
| } |
| break; |
| |
| default: |
| DBG_ERRORFILE( "Some number recognized but what's it?" ); |
| fOutNumber = 0.0; |
| break; |
| } |
| } |
| |
| if (res) // overflow/underflow -> Text |
| { |
| if (fOutNumber < -DBL_MAX) // -1.7E308 |
| { |
| F_Type = NUMBERFORMAT_TEXT; |
| fOutNumber = -DBL_MAX; |
| return sal_True; |
| } |
| else if (fOutNumber > DBL_MAX) // 1.7E308 |
| { |
| F_Type = NUMBERFORMAT_TEXT; |
| fOutNumber = DBL_MAX; |
| return sal_True; |
| } |
| } |
| |
| if (res == sal_False) |
| { |
| eScannedType = NUMBERFORMAT_TEXT; |
| fOutNumber = 0.0; |
| } |
| |
| F_Type = eScannedType; |
| return res; |
| } |
| |
| |
| |