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