PageRenderTime 31ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/binfilter/bf_svtools/source/numbers/svt_zforfind.cxx

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