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