PageRenderTime 465ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 2ms

/libreoffice-3.6.0.2/binfilter/bf_svtools/source/numbers/svt_zforfind.cxx

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