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