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 // Splits the input into numbers and strings for further processing
221 // (Turing-Machine).
222 //---------------------------------------------------------------------------
223 // Initial State = GetChar
224 //---------------+-------------------+-------------------------+-------------
225 // Former State | Read Character | Action | New State
226 //---------------+-------------------+-------------------------+-------------
227 // GetChar | Digit | Symbol=Character | GetValue
228 // | Else | Symbol=Character | GetString
229 //---------------|-------------------+-------------------------+-------------
230 // GetValue | Digit | Symbol=Symbol+Character | GetValue
231 // | Else | Dec(CharPos) | Stop
232 //---------------+-------------------+-------------------------+-------------
233 // GetString | Digit | Dec(CharPos) | Stop
234 // | Else | Symbol=Symbol+Character | GetString
235 //---------------+-------------------+-------------------------+-------------
236
237 enum ScanState // States of the 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 // Reading a currency symbol
641 // '$' => sal_True
642 // else => 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 // Analyze the beginning of the string
1462 // Everything gone => sal_True
1463 // else => 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 if ( GetDecSep(rString, nPos) )
1506 {
1507 nDecPos = 1;
1508 SkipBlanks(rString, nPos);
1509 }
1510 }
1511 else
1512 {
1513 nMonth = GetMonth(rString, nPos);
1514 if ( nMonth ) // month (Jan 1)?
1515 {
1516 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
1517 nMonthPos = 1; // month at the beginning
1518 if ( nMonth < 0 )
1519 SkipChar( '.', rString, nPos ); // abbreviated
1520 SkipBlanks(rString, nPos);
1521 }
1522 else
1523 {
1524 nDayOfWeek = GetDayOfWeek( rString, nPos );
1525 if ( nDayOfWeek )
1526 { // day of week is just parsed away
1527 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date !!!
1528 if ( nPos < rString.Len() )
1529 {
1530 if ( nDayOfWeek < 0 )
1531 { // abbreviated
1532 if ( rString.GetChar( nPos ) == '.' )
1533 ++nPos;
1534 }
1535 else
1536 { // full long name
1537 SkipBlanks(rString, nPos);
1538 SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
1539 }
1540 SkipBlanks(rString, nPos);
1541 nMonth = GetMonth(rString, nPos);
1542 if ( nMonth ) // month (Jan 1)?
1543 {
1544 nMonthPos = 1; // month a the beginning
1545 if ( nMonth < 0 )
1546 SkipChar( '.', rString, nPos ); // abbreviated
1547 SkipBlanks(rString, nPos);
1548 }
1549 }
1550 }
1551 }
1552 }
1553
1554 if (nPos < rString.Len()) // not everything consumed
1555 {
1556 // Does input StartString equal StartString of format?
1557 // This time with sign detection!
1558 if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
1559 return MatchedReturn();
1560 }
1561
1562 return sal_True;
1563 }
1564
1565
1566 //---------------------------------------------------------------------------
1567 // ScanMidString
1568 //
1569 // Analyze the middle of the string
1570 // Everything gone => sal_True
1571 // else => sal_False
1572
ScanMidString(const String & rString,sal_uInt16 nStringPos,const SvNumberformat * pFormat)1573 sal_Bool ImpSvNumberInputScan::ScanMidString( const String& rString,
1574 sal_uInt16 nStringPos, const SvNumberformat* pFormat )
1575 {
1576 xub_StrLen nPos = 0;
1577 short eOldScannedType = eScannedType;
1578
1579 if ( nMatchedAllStrings )
1580 { // Match against format in any case, so later on for a "1-2-3-4" input
1581 // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1582 // format.
1583 if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
1584 nMatchedAllStrings |= nMatchedMidString;
1585 else
1586 nMatchedAllStrings = 0;
1587 }
1588
1589 SkipBlanks(rString, nPos);
1590 if (GetDecSep(rString, nPos)) // decimal separator?
1591 {
1592 if (nDecPos == 1 || nDecPos == 3) // .12.4 or 1.E2.1
1593 return MatchedReturn();
1594 else if (nDecPos == 2) // . dup: 12.4.
1595 {
1596 if (bDecSepInDateSeps) // . also date separator
1597 {
1598 if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
1599 eScannedType != NUMBERFORMAT_DATE &&
1600 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1601 return MatchedReturn();
1602 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1603 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1604 SkipBlanks(rString, nPos);
1605 }
1606 else
1607 return MatchedReturn();
1608 }
1609 else
1610 {
1611 nDecPos = 2; // . in mid string
1612 SkipBlanks(rString, nPos);
1613 }
1614 }
1615 else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME)
1616 && GetTime100SecSep( rString, nPos ) )
1617 { // hundredth seconds separator
1618 if ( nDecPos )
1619 return MatchedReturn();
1620 nDecPos = 2; // . in mid string
1621 SkipBlanks(rString, nPos);
1622 }
1623
1624 if (SkipChar('/', rString, nPos)) // fraction?
1625 {
1626 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1627 && eScannedType != NUMBERFORMAT_DATE) // except date
1628 return MatchedReturn(); // => jan/31/1994
1629 else if ( eScannedType != NUMBERFORMAT_DATE // analyzed date until now
1630 && ( eSetType == NUMBERFORMAT_FRACTION // and preset was fraction
1631 || (nAnzNums == 3 // or 3 numbers
1632 && nStringPos > 2) ) ) // and what ???
1633 {
1634 SkipBlanks(rString, nPos);
1635 eScannedType = NUMBERFORMAT_FRACTION; // !!! it IS a fraction
1636 }
1637 else
1638 nPos--; // put '/' back
1639 }
1640
1641 if (GetThousandSep(rString, nPos, nStringPos)) // 1,000
1642 {
1643 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1644 && eScannedType != NUMBERFORMAT_CURRENCY) // except currency
1645 return MatchedReturn();
1646 nThousand++;
1647 }
1648
1649 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1650 const String& rDate = pFormatter->GetDateSep();
1651 const String& rTime = pLoc->getTimeSep();
1652 sal_Unicode cTime = rTime.GetChar(0);
1653 SkipBlanks(rString, nPos);
1654 if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
1655 || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
1656 || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
1657 || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
1658 {
1659 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1660 && eScannedType != NUMBERFORMAT_DATE) // except date
1661 return MatchedReturn();
1662 SkipBlanks(rString, nPos);
1663 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1664 short nTmpMonth = GetMonth(rString, nPos); // 10. Jan 94
1665 if (nMonth && nTmpMonth) // month dup
1666 return MatchedReturn();
1667 if (nTmpMonth)
1668 {
1669 nMonth = nTmpMonth;
1670 nMonthPos = 2; // month in the middle
1671 if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
1672 ; // short month may be abbreviated Jan.
1673 else if ( SkipChar( '-', rString, nPos ) )
1674 ; // #79632# recognize 17-Jan-2001 to be a date
1675 // #99065# short and long month name
1676 else
1677 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1678 SkipBlanks(rString, nPos);
1679 }
1680 }
1681
1682 short nTempMonth = GetMonth(rString, nPos); // month in the middle (10 Jan 94)
1683 if (nTempMonth)
1684 {
1685 if (nMonth != 0) // month dup
1686 return MatchedReturn();
1687 if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1688 && eScannedType != NUMBERFORMAT_DATE) // except date
1689 return MatchedReturn();
1690 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1691 nMonth = nTempMonth;
1692 nMonthPos = 2; // month in the middle
1693 if ( nMonth < 0 )
1694 SkipChar( '.', rString, nPos ); // abbreviated
1695 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1696 SkipBlanks(rString, nPos);
1697 }
1698
1699 if ( SkipChar('E', rString, nPos) // 10E, 10e, 10,Ee
1700 || SkipChar('e', rString, nPos) )
1701 {
1702 if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1703 return MatchedReturn();
1704 else
1705 {
1706 SkipBlanks(rString, nPos);
1707 eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific
1708 if ( nThousand+2 == nAnzNums // special case 1.E2
1709 && nDecPos == 2 )
1710 nDecPos = 3; // 1,100.E2 1,100,100.E3
1711 }
1712 nESign = GetESign(rString, nPos); // signed exponent?
1713 SkipBlanks(rString, nPos);
1714 }
1715
1716 if ( SkipString(rTime, rString, nPos) ) // time separator?
1717 {
1718 if (nDecPos) // already . => maybe error
1719 {
1720 if (bDecSepInDateSeps) // . also date sep
1721 {
1722 if ( eScannedType != NUMBERFORMAT_DATE && // already another type than date
1723 eScannedType != NUMBERFORMAT_DATETIME) // or date time
1724 return MatchedReturn();
1725 if (eScannedType == NUMBERFORMAT_DATE)
1726 nDecPos = 0; // reset for time transition
1727 }
1728 else
1729 return MatchedReturn();
1730 }
1731 if ( ( eScannedType == NUMBERFORMAT_DATE // already date type
1732 || eScannedType == NUMBERFORMAT_DATETIME) // or date time
1733 && nAnzNums > 3) // and more than 3 numbers? (31.Dez.94 8:23)
1734 {
1735 SkipBlanks(rString, nPos);
1736 eScannedType = NUMBERFORMAT_DATETIME; // !!! it IS date with time
1737 }
1738 else if ( eScannedType != NUMBERFORMAT_UNDEFINED // already another type
1739 && eScannedType != NUMBERFORMAT_TIME) // except time
1740 return MatchedReturn();
1741 else
1742 {
1743 SkipBlanks(rString, nPos);
1744 eScannedType = NUMBERFORMAT_TIME; // !!! it IS a time
1745 }
1746 if ( !nTimePos )
1747 nTimePos = nStringPos + 1;
1748 }
1749
1750 if (nPos < rString.Len())
1751 {
1752 switch (eScannedType)
1753 {
1754 case NUMBERFORMAT_DATE:
1755 if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
1756 {
1757 // #68232# recognize long date separators like ", " in "September 5, 1999"
1758 if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
1759 SkipBlanks( rString, nPos );
1760 }
1761 else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 &&
1762 rString.GetChar(0) == 'T' && MayBeIso8601())
1763 {
1764 // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
1765 ++nPos;
1766 }
1767 break;
1768 #if NF_RECOGNIZE_ISO8601_TIMEZONES
1769 case NUMBERFORMAT_DATETIME:
1770 if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 &&
1771 MayBeIso8601())
1772 {
1773 // ISO 8601 timezone offset
1774 switch (rString.GetChar(0))
1775 {
1776 case '+':
1777 case '-':
1778 if (nStringPos == nAnzStrings-2 ||
1779 nStringPos == nAnzStrings-4)
1780 {
1781 ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
1782 // nTimezonePos needed for GetTimeRef()
1783 if (!nTimezonePos)
1784 nTimezonePos = nStringPos + 1;
1785 }
1786 break;
1787 case ':':
1788 if (nTimezonePos && nStringPos >= 11 &&
1789 nStringPos == nAnzStrings-2)
1790 ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx:yy
1791 break;
1792 }
1793 }
1794 break;
1795 #endif
1796 }
1797 }
1798
1799 if (nPos < rString.Len()) // not everything consumed?
1800 {
1801 if ( nMatchedAllStrings & ~nMatchedVirgin )
1802 eScannedType = eOldScannedType;
1803 else
1804 return sal_False;
1805 }
1806
1807 return sal_True;
1808 }
1809
1810
1811 //---------------------------------------------------------------------------
1812 // ScanEndString
1813 //
1814 // Analyze the conclusion
1815 // Everything gone => sal_True
1816 // else => sal_False
1817
ScanEndString(const String & rString,const SvNumberformat * pFormat)1818 sal_Bool ImpSvNumberInputScan::ScanEndString( const String& rString,
1819 const SvNumberformat* pFormat )
1820 {
1821 xub_StrLen nPos = 0;
1822
1823 if ( nMatchedAllStrings )
1824 { // Match against format in any case, so later on for a "1-2-3-4" input
1825 // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1826 // format.
1827 if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
1828 nMatchedAllStrings |= nMatchedEndString;
1829 else
1830 nMatchedAllStrings = 0;
1831 }
1832
1833 SkipBlanks(rString, nPos);
1834 if (GetDecSep(rString, nPos)) // decimal separator?
1835 {
1836 if (nDecPos == 1 || nDecPos == 3) // .12.4 or 12.E4.
1837 return MatchedReturn();
1838 else if (nDecPos == 2) // . dup: 12.4.
1839 {
1840 if (bDecSepInDateSeps) // . also date sep
1841 {
1842 if ( eScannedType != NUMBERFORMAT_UNDEFINED &&
1843 eScannedType != NUMBERFORMAT_DATE &&
1844 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1845 return MatchedReturn();
1846 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1847 eScannedType = NUMBERFORMAT_DATE; // !!! it IS a date
1848 SkipBlanks(rString, nPos);
1849 }
1850 else
1851 return MatchedReturn();
1852 }
1853 else
1854 {
1855 nDecPos = 3; // . in end string
1856 SkipBlanks(rString, nPos);
1857 }
1858 }
1859
1860 if ( nSign == 0 // conflict - not signed
1861 && eScannedType != NUMBERFORMAT_DATE) // and not date
1862 //!? catch time too?
1863 { // not signed yet
1864 nSign = GetSign(rString, nPos); // 1- DM
1865 if (nNegCheck) // '(' as sign
1866 return MatchedReturn();
1867 }
1868
1869 SkipBlanks(rString, nPos);
1870 if (nNegCheck && SkipChar(')', rString, nPos)) // skip ')' if appropriate
1871 {
1872 nNegCheck = 0;
1873 SkipBlanks(rString, nPos);
1874 }
1875
1876 if ( GetCurrency(rString, nPos, pFormat) ) // currency symbol?
1877 {
1878 if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup
1879 return MatchedReturn();
1880 else
1881 {
1882 SkipBlanks(rString, nPos);
1883 eScannedType = NUMBERFORMAT_CURRENCY;
1884 } // behind currency a '-' is allowed
1885 if (nSign == 0) // not signed yet
1886 {
1887 nSign = GetSign(rString, nPos); // DM -
1888 SkipBlanks(rString, nPos);
1889 if (nNegCheck) // 3 DM (
1890 return MatchedReturn();
1891 }
1892 if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY
1893 && SkipChar(')', rString, nPos) )
1894 {
1895 nNegCheck = 0; // ')' skipped
1896 SkipBlanks(rString, nPos); // only if currency
1897 }
1898 }
1899
1900 if ( SkipChar('%', rString, nPos) ) // 1 %
1901 {
1902 if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1903 return MatchedReturn();
1904 SkipBlanks(rString, nPos);
1905 eScannedType = NUMBERFORMAT_PERCENT;
1906 }
1907
1908 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1909 const String& rDate = pFormatter->GetDateSep();
1910 const String& rTime = pLoc->getTimeSep();
1911 if ( SkipString(rTime, rString, nPos) ) // 10:
1912 {
1913 if (nDecPos) // already , => error
1914 return MatchedReturn();
1915 if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8:
1916 {
1917 SkipBlanks(rString, nPos);
1918 eScannedType = NUMBERFORMAT_DATETIME;
1919 }
1920 else if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1921 eScannedType != NUMBERFORMAT_TIME) // already another type
1922 return MatchedReturn();
1923 else
1924 {
1925 SkipBlanks(rString, nPos);
1926 eScannedType = NUMBERFORMAT_TIME;
1927 }
1928 if ( !nTimePos )
1929 nTimePos = nAnzStrings;
1930 }
1931
1932 sal_Unicode cTime = rTime.GetChar(0);
1933 if ( SkipString(rDate, rString, nPos) // 10., 10-, 10/
1934 || ((cTime != '.') && SkipChar('.', rString, nPos)) // TRICKY:
1935 || ((cTime != '/') && SkipChar('/', rString, nPos)) // short boolean
1936 || ((cTime != '-') && SkipChar('-', rString, nPos)) ) // evaluation!
1937 {
1938 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1939 eScannedType != NUMBERFORMAT_DATE) // already another type
1940 return MatchedReturn();
1941 else
1942 {
1943 SkipBlanks(rString, nPos);
1944 eScannedType = NUMBERFORMAT_DATE;
1945 }
1946 short nTmpMonth = GetMonth(rString, nPos); // 10. Jan
1947 if (nMonth && nTmpMonth) // month dup
1948 return MatchedReturn();
1949 if (nTmpMonth)
1950 {
1951 nMonth = nTmpMonth;
1952 nMonthPos = 3; // month at end
1953 if ( nMonth < 0 )
1954 SkipChar( '.', rString, nPos ); // abbreviated
1955 SkipBlanks(rString, nPos);
1956 }
1957 }
1958
1959 short nTempMonth = GetMonth(rString, nPos); // 10 Jan
1960 if (nTempMonth)
1961 {
1962 if (nMonth) // month dup
1963 return MatchedReturn();
1964 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1965 eScannedType != NUMBERFORMAT_DATE) // already another type
1966 return MatchedReturn();
1967 eScannedType = NUMBERFORMAT_DATE;
1968 nMonth = nTempMonth;
1969 nMonthPos = 3; // month at end
1970 if ( nMonth < 0 )
1971 SkipChar( '.', rString, nPos ); // abbreviated
1972 SkipBlanks(rString, nPos);
1973 }
1974
1975 xub_StrLen nOrigPos = nPos;
1976 if (GetTimeAmPm(rString, nPos))
1977 {
1978 if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1979 eScannedType != NUMBERFORMAT_TIME &&
1980 eScannedType != NUMBERFORMAT_DATETIME) // already another type
1981 return MatchedReturn();
1982 else
1983 {
1984 // If not already scanned as time, 6.78am does not result in 6
1985 // seconds and 78 hundredths in the morning. Keep as suffix.
1986 if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2)
1987 nPos = nOrigPos; // rewind am/pm
1988 else
1989 {
1990 SkipBlanks(rString, nPos);
1991 if ( eScannedType != NUMBERFORMAT_DATETIME )
1992 eScannedType = NUMBERFORMAT_TIME;
1993 }
1994 }
1995 }
1996
1997 if ( nNegCheck && SkipChar(')', rString, nPos) )
1998 {
1999 if (eScannedType == NUMBERFORMAT_CURRENCY) // only if currency
2000 {
2001 nNegCheck = 0; // skip ')'
2002 SkipBlanks(rString, nPos);
2003 }
2004 else
2005 return MatchedReturn();
2006 }
2007
2008 if ( nPos < rString.Len() &&
2009 (eScannedType == NUMBERFORMAT_DATE
2010 || eScannedType == NUMBERFORMAT_DATETIME) )
2011 { // day of week is just parsed away
2012 xub_StrLen nOldPos = nPos;
2013 const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
2014 if ( StringContains( rSep, rString, nPos ) )
2015 {
2016 nPos = nPos + rSep.Len();
2017 SkipBlanks(rString, nPos);
2018 }
2019 int nDayOfWeek = GetDayOfWeek( rString, nPos );
2020 if ( nDayOfWeek )
2021 {
2022 if ( nPos < rString.Len() )
2023 {
2024 if ( nDayOfWeek < 0 )
2025 { // short
2026 if ( rString.GetChar( nPos ) == '.' )
2027 ++nPos;
2028 }
2029 SkipBlanks(rString, nPos);
2030 }
2031 }
2032 else
2033 nPos = nOldPos;
2034 }
2035
2036 #if NF_RECOGNIZE_ISO8601_TIMEZONES
2037 if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME &&
2038 rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601())
2039 {
2040 // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
2041 ++nPos;
2042 }
2043 #endif
2044
2045 if (nPos < rString.Len()) // everything consumed?
2046 {
2047 // does input EndString equal EndString in Format?
2048 if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
2049 return sal_False;
2050 }
2051
2052 return sal_True;
2053 }
2054
2055
ScanStringNumFor(const String & rString,xub_StrLen nPos,const SvNumberformat * pFormat,sal_uInt16 nString,sal_Bool bDontDetectNegation)2056 sal_Bool ImpSvNumberInputScan::ScanStringNumFor(
2057 const String& rString, // String to scan
2058 xub_StrLen nPos, // Position until which was consumed
2059 const SvNumberformat* pFormat, // The format to match
2060 sal_uInt16 nString, // Substring of format, 0xFFFF => last
2061 sal_Bool bDontDetectNegation // Suppress sign detection
2062 )
2063 {
2064 if ( !pFormat )
2065 return sal_False;
2066 const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
2067 const String* pStr;
2068 String aString( rString );
2069 sal_Bool bFound = sal_False;
2070 sal_Bool bFirst = sal_True;
2071 sal_Bool bContinue = sal_True;
2072 sal_uInt16 nSub;
2073 do
2074 {
2075 // Don't try "lower" subformats ff the very first match was the second
2076 // or third subformat.
2077 nSub = nStringScanNumFor;
2078 do
2079 { // Step through subformats, first positive, then negative, then
2080 // other, but not the last (text) subformat.
2081 pStr = pFormat->GetNumForString( nSub, nString, sal_True );
2082 if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
2083 {
2084 bFound = sal_True;
2085 bContinue = sal_False;
2086 }
2087 else if ( nSub < 2 )
2088 ++nSub;
2089 else
2090 bContinue = sal_False;
2091 } while ( bContinue );
2092 if ( !bFound && bFirst && nPos )
2093 { // try remaining substring
2094 bFirst = sal_False;
2095 aString.Erase( 0, nPos );
2096 bContinue = sal_True;
2097 }
2098 } while ( bContinue );
2099
2100 if ( !bFound )
2101 {
2102 if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0)
2103 && pFormat->IsNegativeRealNegative() )
2104 { // simply negated twice? --1
2105 aString.EraseAllChars( ' ' );
2106 if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') )
2107 {
2108 bFound = sal_True;
2109 nStringScanSign = -1;
2110 nSub = 0; //! not 1
2111 }
2112 }
2113 if ( !bFound )
2114 return sal_False;
2115 }
2116 else if ( !bDontDetectNegation && (nSub == 1) &&
2117 pFormat->IsNegativeRealNegative() )
2118 { // negative
2119 if ( nStringScanSign < 0 )
2120 {
2121 if ( (nSign < 0) && (nStringScanNumFor != 1) )
2122 nStringScanSign = 1; // triple negated --1 yyy
2123 }
2124 else if ( nStringScanSign == 0 )
2125 {
2126 if ( nSign < 0 )
2127 { // nSign and nStringScanSign will be combined later,
2128 // flip sign if doubly negated
2129 if ( (nString == 0) && !bFirst
2130 && SvNumberformat::HasStringNegativeSign( aString ) )
2131 nStringScanSign = -1; // direct double negation
2132 else if ( pFormat->IsNegativeWithoutSign() )
2133 nStringScanSign = -1; // indirect double negation
2134 }
2135 else
2136 nStringScanSign = -1;
2137 }
2138 else // > 0
2139 nStringScanSign = -1;
2140 }
2141 nStringScanNumFor = nSub;
2142 return sal_True;
2143 }
2144
2145
2146 //---------------------------------------------------------------------------
2147 // IsNumberFormatMain
2148 //
2149 // Recognizes types of number, exponential, fraction, percent, currency, date, time.
2150 // Else text => return sal_False
2151
IsNumberFormatMain(const String & rString,double &,const SvNumberformat * pFormat)2152 sal_Bool ImpSvNumberInputScan::IsNumberFormatMain(
2153 const String& rString, // string to be analyzed
2154 double& , // OUT: result as number, if possible
2155 const SvNumberformat* pFormat ) // maybe number format set to match against
2156 {
2157 Reset();
2158 NumberStringDivision( rString ); // breakdown into strings and numbers
2159 if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
2160 return sal_False; // Njet, Nope, ...
2161
2162 if (nAnzNums == 0) // no number in input
2163 {
2164 if ( nAnzStrings > 0 )
2165 {
2166 // Here we may change the original, we don't need it anymore.
2167 // This saves copies and ToUpper() in GetLogical() and is faster.
2168 String& rStrArray = sStrArray[0];
2169 rStrArray.EraseTrailingChars( ' ' );
2170 rStrArray.EraseLeadingChars( ' ' );
2171 nLogical = GetLogical( rStrArray );
2172 if ( nLogical )
2173 {
2174 eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN
2175 nMatchedAllStrings &= ~nMatchedVirgin;
2176 return sal_True;
2177 }
2178 else
2179 return sal_False; // simple text
2180 }
2181 else
2182 return sal_False; // simple text
2183 }
2184
2185 sal_uInt16 i = 0; // mark any symbol
2186 sal_uInt16 j = 0; // mark only numbers
2187
2188 switch ( nAnzNums )
2189 {
2190 case 1 : // Exactly 1 number in input
2191 { // nAnzStrings >= 1
2192 if (GetNextNumber(i,j)) // i=1,0
2193 { // Number at start
2194 if (eSetType == NUMBERFORMAT_FRACTION) // Fraction 1 = 1/1
2195 {
2196 if (i >= nAnzStrings || // no end string nor decimal separator
2197 sStrArray[i] == pFormatter->GetNumDecimalSep())
2198 {
2199 eScannedType = NUMBERFORMAT_FRACTION;
2200 nMatchedAllStrings &= ~nMatchedVirgin;
2201 return sal_True;
2202 }
2203 }
2204 }
2205 else
2206 { // Analyze start string
2207 if (!ScanStartString( sStrArray[i], pFormat )) // i=0
2208 return sal_False; // already an error
2209 i++; // next symbol, i=1
2210 }
2211 GetNextNumber(i,j); // i=1,2
2212 if (eSetType == NUMBERFORMAT_FRACTION) // Fraction -1 = -1/1
2213 {
2214 if (nSign && !nNegCheck && // Sign +, -
2215 eScannedType == NUMBERFORMAT_UNDEFINED && // not date or currency
2216 nDecPos == 0 && // no previous decimal separator
2217 (i >= nAnzStrings || // no end string nor decimal separator
2218 sStrArray[i] == pFormatter->GetNumDecimalSep())
2219 )
2220 {
2221 eScannedType = NUMBERFORMAT_FRACTION;
2222 nMatchedAllStrings &= ~nMatchedVirgin;
2223 return sal_True;
2224 }
2225 }
2226 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2227 return sal_False;
2228 }
2229 break;
2230 case 2 : // Exactly 2 numbers in input
2231 { // nAnzStrings >= 3
2232 if (!GetNextNumber(i,j)) // i=1,0
2233 { // Analyze start string
2234 if (!ScanStartString( sStrArray[i], pFormat ))
2235 return sal_False; // already an error
2236 i++; // i=1
2237 }
2238 GetNextNumber(i,j); // i=1,2
2239 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2240 return sal_False;
2241 i++; // next symbol, i=2,3
2242 GetNextNumber(i,j); // i=3,4
2243 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2244 return sal_False;
2245 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200. as fraction
2246 {
2247 if (!nNegCheck && // no sign '('
2248 eScannedType == NUMBERFORMAT_UNDEFINED &&
2249 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2250 )
2251 {
2252 eScannedType = NUMBERFORMAT_FRACTION;
2253 nMatchedAllStrings &= ~nMatchedVirgin;
2254 return sal_True;
2255 }
2256 }
2257 }
2258 break;
2259 case 3 : // Exactly 3 numbers in input
2260 { // nAnzStrings >= 5
2261 if (!GetNextNumber(i,j)) // i=1,0
2262 { // Analyze start string
2263 if (!ScanStartString( sStrArray[i], pFormat ))
2264 return sal_False; // already an error
2265 i++; // i=1
2266 if (nDecPos == 1) // decimal separator at start => error
2267 return sal_False;
2268 }
2269 GetNextNumber(i,j); // i=1,2
2270 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2271 return sal_False;
2272 i++; // i=2,3
2273 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
2274 return sal_False;
2275 GetNextNumber(i,j); // i=3,4
2276 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2277 return sal_False;
2278 i++; // i=4,5
2279 GetNextNumber(i,j); // i=5,6
2280 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2281 return sal_False;
2282 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
2283 {
2284 if (!nNegCheck && // no sign '('
2285 eScannedType == NUMBERFORMAT_UNDEFINED &&
2286 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2287 )
2288 {
2289 eScannedType = NUMBERFORMAT_FRACTION;
2290 nMatchedAllStrings &= ~nMatchedVirgin;
2291 return sal_True;
2292 }
2293 }
2294 if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2295 return sal_False; // #36857# not a real fraction
2296 }
2297 break;
2298 default: // More than 3 numbers in input
2299 { // nAnzStrings >= 7
2300 if (!GetNextNumber(i,j)) // i=1,0
2301 { // Analyze startstring
2302 if (!ScanStartString( sStrArray[i], pFormat ))
2303 return sal_False; // already an error
2304 i++; // i=1
2305 if (nDecPos == 1) // decimal separator at start => error
2306 return sal_False;
2307 }
2308 GetNextNumber(i,j); // i=1,2
2309 if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2310 return sal_False;
2311 i++; // i=2,3
2312 sal_uInt16 nThOld = 10; // just not 0 or 1
2313 while (nThOld != nThousand && j < nAnzNums-1)
2314 // Execute at least one time
2315 // but leave one number.
2316 { // Loop over group separators
2317 nThOld = nThousand;
2318 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at end
2319 return sal_False;
2320 GetNextNumber(i,j);
2321 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2322 return sal_False;
2323 i++;
2324 }
2325 if (eScannedType == NUMBERFORMAT_DATE || // long date or
2326 eScannedType == NUMBERFORMAT_TIME || // long time or
2327 eScannedType == NUMBERFORMAT_UNDEFINED) // long number
2328 {
2329 for (sal_uInt16 k = j; k < nAnzNums-1; k++)
2330 {
2331 if (eScannedType == NUMBERFORMAT_SCIENTIFIC) // E only at endd
2332 return sal_False;
2333 GetNextNumber(i,j);
2334 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2335 return sal_False;
2336 i++;
2337 }
2338 }
2339 GetNextNumber(i,j);
2340 if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2341 return sal_False;
2342 if (eSetType == NUMBERFORMAT_FRACTION) // -1,200,100. as fraction
2343 {
2344 if (!nNegCheck && // no sign '('
2345 eScannedType == NUMBERFORMAT_UNDEFINED &&
2346 (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
2347 )
2348 {
2349 eScannedType = NUMBERFORMAT_FRACTION;
2350 nMatchedAllStrings &= ~nMatchedVirgin;
2351 return sal_True;
2352 }
2353 }
2354 if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2355 return sal_False; // #36857# not a real fraction
2356 }
2357 }
2358
2359 if (eScannedType == NUMBERFORMAT_UNDEFINED)
2360 {
2361 nMatchedAllStrings &= ~nMatchedVirgin;
2362 // did match including nMatchedUsedAsReturn
2363 sal_Bool bDidMatch = (nMatchedAllStrings != 0);
2364 if ( nMatchedAllStrings )
2365 {
2366 sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2367 nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2368 if ( !bMatch )
2369 nMatchedAllStrings = 0;
2370 }
2371 if ( nMatchedAllStrings )
2372 eScannedType = eSetType;
2373 else if ( bDidMatch )
2374 return sal_False;
2375 else
2376 eScannedType = NUMBERFORMAT_NUMBER;
2377 // everything else should have been recognized by now
2378 }
2379 else if ( eScannedType == NUMBERFORMAT_DATE )
2380 { // the very relaxed date input checks may interfere with a preset format
2381 nMatchedAllStrings &= ~nMatchedVirgin;
2382 sal_Bool bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
2383 if ( nMatchedAllStrings )
2384 {
2385 sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2386 nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2387 if ( !bMatch )
2388 nMatchedAllStrings = 0;
2389 }
2390 if ( nMatchedAllStrings )
2391 eScannedType = eSetType;
2392 else if ( bWasReturn )
2393 return sal_False;
2394 }
2395 else
2396 nMatchedAllStrings = 0; // reset flag to no substrings matched
2397
2398 return sal_True;
2399 }
2400
2401
2402 //---------------------------------------------------------------------------
2403 // return sal_True or sal_False depending on the nMatched... state and remember usage
MatchedReturn()2404 sal_Bool ImpSvNumberInputScan::MatchedReturn()
2405 {
2406 if ( nMatchedAllStrings & ~nMatchedVirgin )
2407 {
2408 nMatchedAllStrings |= nMatchedUsedAsReturn;
2409 return sal_True;
2410 }
2411 return sal_False;
2412 }
2413
2414
2415 //---------------------------------------------------------------------------
2416 // Initialize uppercase months and weekdays
2417
InitText()2418 void ImpSvNumberInputScan::InitText()
2419 {
2420 sal_Int32 j, nElems;
2421 const CharClass* pChrCls = pFormatter->GetCharClass();
2422 const CalendarWrapper* pCal = pFormatter->GetCalendar();
2423 delete [] pUpperMonthText;
2424 delete [] pUpperAbbrevMonthText;
2425 ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems
2426 = pCal->getMonths();
2427 nElems = xElems.getLength();
2428 pUpperMonthText = new String[nElems];
2429 pUpperAbbrevMonthText = new String[nElems];
2430 for ( j=0; j<nElems; j++ )
2431 {
2432 pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName );
2433 pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName );
2434 }
2435 delete [] pUpperDayText;
2436 delete [] pUpperAbbrevDayText;
2437 xElems = pCal->getDays();
2438 nElems = xElems.getLength();
2439 pUpperDayText = new String[nElems];
2440 pUpperAbbrevDayText = new String[nElems];
2441 for ( j=0; j<nElems; j++ )
2442 {
2443 pUpperDayText[j] = pChrCls->upper( xElems[j].FullName );
2444 pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName );
2445 }
2446 bTextInitialized = sal_True;
2447 }
2448
2449
2450 //===========================================================================
2451 // P U B L I C
2452
2453 //---------------------------------------------------------------------------
2454 // ChangeIntl
2455 //
2456 // MUST be called if International/Locale is changed
2457
ChangeIntl()2458 void ImpSvNumberInputScan::ChangeIntl()
2459 {
2460 sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0);
2461 bDecSepInDateSeps = ( cDecSep == '-' ||
2462 cDecSep == '/' ||
2463 cDecSep == '.' ||
2464 cDecSep == pFormatter->GetDateSep().GetChar(0) );
2465 bTextInitialized = sal_False;
2466 aUpperCurrSymbol.Erase();
2467 }
2468
2469
2470 //---------------------------------------------------------------------------
2471 // ChangeNullDate
2472
ChangeNullDate(const sal_uInt16 Day,const sal_uInt16 Month,const sal_uInt16 Year)2473 void ImpSvNumberInputScan::ChangeNullDate(
2474 const sal_uInt16 Day,
2475 const sal_uInt16 Month,
2476 const sal_uInt16 Year )
2477 {
2478 if ( pNullDate )
2479 *pNullDate = Date(Day, Month, Year);
2480 else
2481 pNullDate = new Date(Day, Month, Year);
2482 }
2483
2484
2485 //---------------------------------------------------------------------------
2486 // IsNumberFormat
2487 //
2488 // => does rString represent a number (also date, time et al)
2489
IsNumberFormat(const String & rString,short & F_Type,double & fOutNumber,const SvNumberformat * pFormat)2490 sal_Bool ImpSvNumberInputScan::IsNumberFormat(
2491 const String& rString, // string to be analyzed
2492 short& F_Type, // IN: old type, OUT: new type
2493 double& fOutNumber, // OUT: number if convertable
2494 const SvNumberformat* pFormat ) // maybe a number format to match against
2495 {
2496 String sResString;
2497 String aString;
2498 sal_Bool res; // return value
2499 eSetType = F_Type; // old type set
2500
2501 if ( !rString.Len() )
2502 res = sal_False;
2503 else if (rString.Len() > 308) // arbitrary
2504 res = sal_False;
2505 else
2506 {
2507 // NoMoreUpperNeeded, all comparisons on UpperCase
2508 aString = pFormatter->GetCharClass()->upper( rString );
2509 // convert native number to ASCII if necessary
2510 TransformInput( aString );
2511 res = IsNumberFormatMain( aString, fOutNumber, pFormat );
2512 }
2513
2514 if (res)
2515 {
2516 if ( nNegCheck // ')' not found for '('
2517 || (nSign && (eScannedType == NUMBERFORMAT_DATE
2518 || eScannedType == NUMBERFORMAT_DATETIME))
2519 ) // signed date/datetime
2520 res = sal_False;
2521 else
2522 { // check count of partial number strings
2523 switch (eScannedType)
2524 {
2525 case NUMBERFORMAT_PERCENT:
2526 case NUMBERFORMAT_CURRENCY:
2527 case NUMBERFORMAT_NUMBER:
2528 if (nDecPos == 1) // .05
2529 {
2530 // matched MidStrings function like group separators
2531 if ( nMatchedAllStrings )
2532 nThousand = nAnzNums - 1;
2533 else if ( nAnzNums != 1 )
2534 res = sal_False;
2535 }
2536 else if (nDecPos == 2) // 1.05
2537 {
2538 // matched MidStrings function like group separators
2539 if ( nMatchedAllStrings )
2540 nThousand = nAnzNums - 1;
2541 else if ( nAnzNums != nThousand+2 )
2542 res = sal_False;
2543 }
2544 else // 1,100 or 1,100.
2545 {
2546 // matched MidStrings function like group separators
2547 if ( nMatchedAllStrings )
2548 nThousand = nAnzNums - 1;
2549 else if ( nAnzNums != nThousand+1 )
2550 res = sal_False;
2551 }
2552 break;
2553
2554 case NUMBERFORMAT_SCIENTIFIC: // 1.0e-2
2555 if (nDecPos == 1) // .05
2556 {
2557 if (nAnzNums != 2)
2558 res = sal_False;
2559 }
2560 else if (nDecPos == 2) // 1.05
2561 {
2562 if (nAnzNums != nThousand+3)
2563 res = sal_False;
2564 }
2565 else // 1,100 or 1,100.
2566 {
2567 if (nAnzNums != nThousand+2)
2568 res = sal_False;
2569 }
2570 break;
2571
2572 case NUMBERFORMAT_DATE:
2573 if (nMonth)
2574 { // month name and numbers
2575 if (nAnzNums > 2)
2576 res = sal_False;
2577 }
2578 else
2579 {
2580 if (nAnzNums > 3)
2581 res = sal_False;
2582 }
2583 break;
2584
2585 case NUMBERFORMAT_TIME:
2586 if (nDecPos)
2587 { // hundredth seconds included
2588 if (nAnzNums > 4)
2589 res = sal_False;
2590 }
2591 else
2592 {
2593 if (nAnzNums > 3)
2594 res = sal_False;
2595 }
2596 break;
2597
2598 case NUMBERFORMAT_DATETIME:
2599 if (nMonth)
2600 { // month name and numbers
2601 if (nDecPos)
2602 { // hundredth seconds included
2603 if (nAnzNums > 6)
2604 res = sal_False;
2605 }
2606 else
2607 {
2608 if (nAnzNums > 5)
2609 res = sal_False;
2610 }
2611 }
2612 else
2613 {
2614 if (nDecPos)
2615 { // hundredth seconds included
2616 if (nAnzNums > 7)
2617 res = sal_False;
2618 }
2619 else
2620 {
2621 if (nAnzNums > 6)
2622 res = sal_False;
2623 }
2624 }
2625 break;
2626
2627 default:
2628 break;
2629 } // switch
2630 } // else
2631 } // if (res)
2632
2633 if (res)
2634 { // we finally have a number
2635 switch (eScannedType)
2636 {
2637 case NUMBERFORMAT_LOGICAL:
2638 if (nLogical == 1)
2639 fOutNumber = 1.0; // True
2640 else if (nLogical == -1)
2641 fOutNumber = 0.0; // False
2642 else
2643 res = sal_False; // Oops
2644 break;
2645
2646 case NUMBERFORMAT_PERCENT:
2647 case NUMBERFORMAT_CURRENCY:
2648 case NUMBERFORMAT_NUMBER:
2649 case NUMBERFORMAT_SCIENTIFIC:
2650 case NUMBERFORMAT_DEFINED: // if no category detected handle as number
2651 {
2652 if ( nDecPos == 1 ) // . at start
2653 sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) );
2654 else
2655 sResString.Erase();
2656 sal_uInt16 k;
2657 for ( k = 0; k <= nThousand; k++)
2658 sResString += sStrArray[nNums[k]]; // integer part
2659 if ( nDecPos == 2 && k < nAnzNums ) // . somewhere
2660 {
2661 sResString += '.';
2662 sal_uInt16 nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ?
2663 nAnzNums-1 : nAnzNums);
2664 for ( ; k < nStop; k++)
2665 sResString += sStrArray[nNums[k]]; // fractional part
2666 }
2667
2668 if (eScannedType != NUMBERFORMAT_SCIENTIFIC)
2669 fOutNumber = StringToDouble(sResString);
2670 else
2671 { // append exponent
2672 sResString += 'E';
2673 if ( nESign == -1 )
2674 sResString += '-';
2675 sResString += sStrArray[nNums[nAnzNums-1]];
2676 rtl_math_ConversionStatus eStatus;
2677 fOutNumber = ::rtl::math::stringToDouble(
2678 sResString, '.', ',', &eStatus, NULL );
2679 if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
2680 {
2681 F_Type = NUMBERFORMAT_TEXT; // overflow/underflow -> Text
2682 if (nESign == -1)
2683 fOutNumber = 0.0;
2684 else
2685 fOutNumber = DBL_MAX;
2686 /*!*/ return sal_True;
2687 }
2688 }
2689
2690 if ( nStringScanSign )
2691 {
2692 if ( nSign )
2693 nSign *= nStringScanSign;
2694 else
2695 nSign = nStringScanSign;
2696 }
2697 if ( nSign < 0 )
2698 fOutNumber = -fOutNumber;
2699
2700 if (eScannedType == NUMBERFORMAT_PERCENT)
2701 fOutNumber/= 100.0;
2702 }
2703 break;
2704
2705 case NUMBERFORMAT_FRACTION:
2706 if (nAnzNums == 1)
2707 fOutNumber = StringToDouble(sStrArray[nNums[0]]);
2708 else if (nAnzNums == 2)
2709 {
2710 if (nThousand == 1)
2711 {
2712 sResString = sStrArray[nNums[0]];
2713 sResString += sStrArray[nNums[1]]; // integer part
2714 fOutNumber = StringToDouble(sResString);
2715 }
2716 else
2717 {
2718 double fZaehler = StringToDouble(sStrArray[nNums[0]]);
2719 double fNenner = StringToDouble(sStrArray[nNums[1]]);
2720 if (fNenner != 0.0)
2721 fOutNumber = fZaehler/fNenner;
2722 else
2723 res = sal_False;
2724 }
2725 }
2726 else // nAnzNums > 2
2727 {
2728 sal_uInt16 k = 1;
2729 sResString = sStrArray[nNums[0]];
2730 if (nThousand > 0)
2731 for (k = 1; k <= nThousand; k++)
2732 sResString += sStrArray[nNums[k]];
2733 fOutNumber = StringToDouble(sResString);
2734
2735 if (k == nAnzNums-2)
2736 {
2737 double fZaehler = StringToDouble(sStrArray[nNums[k]]);
2738 double fNenner = StringToDouble(sStrArray[nNums[k+1]]);
2739 if (fNenner != 0.0)
2740 fOutNumber += fZaehler/fNenner;
2741 else
2742 res = sal_False;
2743 }
2744 }
2745
2746 if ( nStringScanSign )
2747 {
2748 if ( nSign )
2749 nSign *= nStringScanSign;
2750 else
2751 nSign = nStringScanSign;
2752 }
2753 if ( nSign < 0 )
2754 fOutNumber = -fOutNumber;
2755 break;
2756
2757 case NUMBERFORMAT_TIME:
2758 GetTimeRef(fOutNumber, 0, nAnzNums);
2759 if ( nSign < 0 )
2760 fOutNumber = -fOutNumber;
2761 break;
2762
2763 case NUMBERFORMAT_DATE:
2764 {
2765 sal_uInt16 nCounter = 0; // dummy here
2766 res = GetDateRef( fOutNumber, nCounter, pFormat );
2767 }
2768 break;
2769
2770 case NUMBERFORMAT_DATETIME:
2771 {
2772 sal_uInt16 nCounter = 0; // needed here
2773 res = GetDateRef( fOutNumber, nCounter, pFormat );
2774 if ( res )
2775 {
2776 double fTime;
2777 GetTimeRef( fTime, nCounter, nAnzNums - nCounter );
2778 fOutNumber += fTime;
2779 }
2780 }
2781 break;
2782
2783 default:
2784 DBG_ERRORFILE( "Some number recognized but what's it?" );
2785 fOutNumber = 0.0;
2786 break;
2787 }
2788 }
2789
2790 if (res) // overflow/underflow -> Text
2791 {
2792 if (fOutNumber < -DBL_MAX) // -1.7E308
2793 {
2794 F_Type = NUMBERFORMAT_TEXT;
2795 fOutNumber = -DBL_MAX;
2796 return sal_True;
2797 }
2798 else if (fOutNumber > DBL_MAX) // 1.7E308
2799 {
2800 F_Type = NUMBERFORMAT_TEXT;
2801 fOutNumber = DBL_MAX;
2802 return sal_True;
2803 }
2804 }
2805
2806 if (res == sal_False)
2807 {
2808 eScannedType = NUMBERFORMAT_TEXT;
2809 fOutNumber = 0.0;
2810 }
2811
2812 F_Type = eScannedType;
2813 return res;
2814 }
2815
2816
2817
2818