PageRenderTime 48ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 1ms

/libreoffice-3.6.0.2/svl/source/numbers/zforfind.cxx

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