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