PageRenderTime 74ms CodeModel.GetById 33ms 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

Large files files are truncated, but you can click here to view the full file

  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

Large files files are truncated, but you can click here to view the full file