diff options
Diffstat (limited to 'svl/source/numbers/zforfind.cxx')
-rw-r--r-- | svl/source/numbers/zforfind.cxx | 2810 |
1 files changed, 0 insertions, 2810 deletions
diff --git a/svl/source/numbers/zforfind.cxx b/svl/source/numbers/zforfind.cxx deleted file mode 100644 index 976372d6e7..0000000000 --- a/svl/source/numbers/zforfind.cxx +++ /dev/null @@ -1,2810 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 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 ), - eScannedType( NUMBERFORMAT_UNDEFINED ), - eSetType( NUMBERFORMAT_UNDEFINED ) -{ - 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() -{ - 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 ) -{ - return c < 128 && isdigit( (unsigned char) c ); -} - - -//--------------------------------------------------------------------------- -// -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: - OSL_FAIL( "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: { - sal_uInt16 nDay = ImplGetDay(0); - sal_uInt16 nYear = ImplGetYear(0); - if (nDay == 0 || nDay > 32) { - pCal->setValue( CalendarFieldIndex::YEAR, nYear); - } - else - 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; - - // 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 - { - int 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); - } - } - } - } - } - - // skip any trailing '-' or '/' chars - if (nPos < rString.Len()) - { - while (SkipChar ('-', rString, nPos) || SkipChar ('/', rString, nPos)) { - // do nothing - } - } - 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; -} - - - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |