1999-08-16 21:50:52 +00:00
/*
1999-11-22 20:25:35 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2012-02-13 19:23:47 +00:00
* Copyright ( C ) 1997 - 2012 , International Business Machines Corporation and *
1999-11-22 20:25:35 +00:00
* others . All Rights Reserved . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1999-08-16 21:50:52 +00:00
*
* File DECIMFMT . CPP
*
* Modification History :
*
* Date Name Description
* 02 / 19 / 97 aliu Converted from java .
* 03 / 20 / 97 clhuang Implemented with new APIs .
* 03 / 31 / 97 aliu Moved isLONG_MIN to DigitList , and fixed it .
* 04 / 3 / 97 aliu Rewrote parsing and formatting completely , and
* cleaned up and debugged . Actually works now .
* Implemented NAN and INF handling , for both parsing
* and formatting . Extensive testing & debugging .
* 04 / 10 / 97 aliu Modified to compile on AIX .
* 04 / 16 / 97 aliu Rewrote to use DigitList , which has been resurrected .
* Changed DigitCount to int per code review .
* 07 / 09 / 97 helena Made ParsePosition into a class .
* 08 / 26 / 97 aliu Extensive changes to applyPattern ; completely
* rewritten from the Java .
* 09 / 09 / 97 aliu Ported over support for exponential formats .
* 07 / 20 / 98 stephen JDK 1.2 sync up .
* Various instances of ' 0 ' replaced with ' NULL '
* Check for grouping size in subFormat ( )
* Brought subParse ( ) in line with Java 1.2
* Added method appendAffix ( )
* 08 / 24 / 1998 srl Removed Mutex calls . This is not a thread safe class !
* 02 / 22 / 99 stephen Removed character literals for EBCDIC safety
* 06 / 24 / 99 helena Integrated Alan ' s NF enhancements and Java2 bug fixes
* 06 / 28 / 99 stephen Fixed bugs in toPattern ( ) .
2010-01-28 19:39:24 +00:00
* 06 / 29 / 99 stephen Fixed operator = to copy fFormatWidth , fPad ,
1999-08-16 21:50:52 +00:00
* fPadPosition
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2010-01-28 19:39:24 +00:00
2002-09-20 01:54:48 +00:00
# include "unicode/utypes.h"
# if !UCONFIG_NO_FORMATTING
2009-12-17 22:15:20 +00:00
# include "fphdlimp.h"
1999-12-28 23:57:50 +00:00
# include "unicode/decimfmt.h"
2003-04-21 22:48:16 +00:00
# include "unicode/choicfmt.h"
2002-07-12 21:42:24 +00:00
# include "unicode/ucurr.h"
# include "unicode/ustring.h"
1999-12-28 23:57:50 +00:00
# include "unicode/dcfmtsym.h"
2004-09-02 19:08:28 +00:00
# include "unicode/ures.h"
2002-03-19 03:01:28 +00:00
# include "unicode/uchar.h"
2011-05-04 12:23:42 +00:00
# include "unicode/uniset.h"
2004-04-27 21:47:09 +00:00
# include "unicode/curramt.h"
2009-02-12 22:55:29 +00:00
# include "unicode/currpinf.h"
# include "unicode/plurrule.h"
2011-07-27 05:53:56 +00:00
# include "unicode/utf16.h"
2011-08-24 18:06:46 +00:00
# include "unicode/numsys.h"
2012-02-24 20:27:21 +00:00
# include "unicode/localpointer.h"
2011-03-12 14:57:18 +00:00
# include "uresimp.h"
2003-07-12 00:23:05 +00:00
# include "ucurrimp.h"
2010-05-20 21:16:44 +00:00
# include "charstr.h"
2010-02-26 02:29:00 +00:00
# include "cmemory.h"
2011-04-26 06:39:29 +00:00
# include "patternprops.h"
2002-07-12 21:42:24 +00:00
# include "digitlst.h"
2002-05-14 23:24:58 +00:00
# include "cstring.h"
2003-04-21 22:48:16 +00:00
# include "umutex.h"
# include "uassert.h"
2004-10-18 02:43:33 +00:00
# include "putilimp.h"
2009-01-13 16:58:35 +00:00
# include <math.h>
2009-02-12 22:55:29 +00:00
# include "hash.h"
2011-05-04 12:23:42 +00:00
# include "decfmtst.h"
2012-05-30 00:41:57 +00:00
# include "dcfmtimp.h"
1999-08-16 21:50:52 +00:00
2001-10-08 23:26:58 +00:00
U_NAMESPACE_BEGIN
2010-01-16 19:59:59 +00:00
2012-10-12 19:52:43 +00:00
2012-05-30 00:41:57 +00:00
/* == Fastpath calculation. ==
*/
# if UCONFIG_FORMAT_FASTPATHS_49
inline DecimalFormatInternal & internalData ( uint8_t * reserved ) {
return * reinterpret_cast < DecimalFormatInternal * > ( reserved ) ;
}
inline const DecimalFormatInternal & internalData ( const uint8_t * reserved ) {
return * reinterpret_cast < const DecimalFormatInternal * > ( reserved ) ;
}
# else
# endif
2010-01-16 19:59:59 +00:00
/* For currency parsing purose,
2010-01-28 19:39:24 +00:00
* Need to remember all prefix patterns and suffix patterns of
* every currency format pattern ,
2010-01-16 19:59:59 +00:00
* including the pattern of default currecny style
* and plural currency style . And the patterns are set through applyPattern .
*/
struct AffixPatternsForCurrency : public UMemory {
// negative prefix pattern
UnicodeString negPrefixPatternForCurrency ;
// negative suffix pattern
UnicodeString negSuffixPatternForCurrency ;
// positive prefix pattern
UnicodeString posPrefixPatternForCurrency ;
// positive suffix pattern
UnicodeString posSuffixPatternForCurrency ;
int8_t patternType ;
2010-01-28 19:39:24 +00:00
AffixPatternsForCurrency ( const UnicodeString & negPrefix ,
2010-01-16 19:59:59 +00:00
const UnicodeString & negSuffix ,
const UnicodeString & posPrefix ,
const UnicodeString & posSuffix ,
int8_t type ) {
negPrefixPatternForCurrency = negPrefix ;
negSuffixPatternForCurrency = negSuffix ;
posPrefixPatternForCurrency = posPrefix ;
posSuffixPatternForCurrency = posSuffix ;
patternType = type ;
}
} ;
/* affix for currency formatting when the currency sign in the pattern
2010-01-28 19:39:24 +00:00
* equals to 3 , such as the pattern contains 3 currency sign or
2010-01-16 19:59:59 +00:00
* the formatter style is currency plural format style .
*/
struct AffixesForCurrency : public UMemory {
// negative prefix
UnicodeString negPrefixForCurrency ;
// negative suffix
UnicodeString negSuffixForCurrency ;
// positive prefix
UnicodeString posPrefixForCurrency ;
// positive suffix
UnicodeString posSuffixForCurrency ;
2010-01-28 19:39:24 +00:00
2010-01-16 19:59:59 +00:00
int32_t formatWidth ;
AffixesForCurrency ( const UnicodeString & negPrefix ,
const UnicodeString & negSuffix ,
const UnicodeString & posPrefix ,
const UnicodeString & posSuffix ) {
negPrefixForCurrency = negPrefix ;
negSuffixForCurrency = negSuffix ;
posPrefixForCurrency = posPrefix ;
posSuffixForCurrency = posSuffix ;
}
} ;
2009-02-12 22:55:29 +00:00
U_CDECL_BEGIN
/**
* @ internal ICU 4.2
*/
2010-01-16 19:59:59 +00:00
static UBool U_CALLCONV decimfmtAffixValueComparator ( UHashTok val1 , UHashTok val2 ) ;
2009-02-12 22:55:29 +00:00
/**
* @ internal ICU 4.2
*/
2010-01-16 19:59:59 +00:00
static UBool U_CALLCONV decimfmtAffixPatternValueComparator ( UHashTok val1 , UHashTok val2 ) ;
2009-02-12 22:55:29 +00:00
2010-01-16 19:59:59 +00:00
static UBool
2009-04-17 18:52:52 +00:00
U_CALLCONV decimfmtAffixValueComparator ( UHashTok val1 , UHashTok val2 ) {
2010-01-28 19:39:24 +00:00
const AffixesForCurrency * affix_1 =
2010-01-16 19:59:59 +00:00
( AffixesForCurrency * ) val1 . pointer ;
2010-01-28 19:39:24 +00:00
const AffixesForCurrency * affix_2 =
2010-01-16 19:59:59 +00:00
( AffixesForCurrency * ) val2 . pointer ;
2009-02-12 22:55:29 +00:00
return affix_1 - > negPrefixForCurrency = = affix_2 - > negPrefixForCurrency & &
affix_1 - > negSuffixForCurrency = = affix_2 - > negSuffixForCurrency & &
affix_1 - > posPrefixForCurrency = = affix_2 - > posPrefixForCurrency & &
affix_1 - > posSuffixForCurrency = = affix_2 - > posSuffixForCurrency ;
}
2010-01-16 19:59:59 +00:00
static UBool
2009-04-17 18:52:52 +00:00
U_CALLCONV decimfmtAffixPatternValueComparator ( UHashTok val1 , UHashTok val2 ) {
2010-01-28 19:39:24 +00:00
const AffixPatternsForCurrency * affix_1 =
2010-01-16 19:59:59 +00:00
( AffixPatternsForCurrency * ) val1 . pointer ;
2010-01-28 19:39:24 +00:00
const AffixPatternsForCurrency * affix_2 =
2010-01-16 19:59:59 +00:00
( AffixPatternsForCurrency * ) val2 . pointer ;
2010-01-28 19:39:24 +00:00
return affix_1 - > negPrefixPatternForCurrency = =
2009-02-12 22:55:29 +00:00
affix_2 - > negPrefixPatternForCurrency & &
2010-01-28 19:39:24 +00:00
affix_1 - > negSuffixPatternForCurrency = =
2009-02-12 22:55:29 +00:00
affix_2 - > negSuffixPatternForCurrency & &
2010-01-28 19:39:24 +00:00
affix_1 - > posPrefixPatternForCurrency = =
2009-02-12 22:55:29 +00:00
affix_2 - > posPrefixPatternForCurrency & &
2010-01-28 19:39:24 +00:00
affix_1 - > posSuffixPatternForCurrency = =
2009-03-10 20:53:27 +00:00
affix_2 - > posSuffixPatternForCurrency & &
affix_1 - > patternType = = affix_2 - > patternType ;
2009-02-12 22:55:29 +00:00
}
2009-12-14 05:57:34 +00:00
U_CDECL_END
2001-09-17 21:50:19 +00:00
# ifdef FMT_DEBUG
1999-08-16 21:50:52 +00:00
# include <stdio.h>
2012-05-30 00:41:57 +00:00
static void _debugout ( const char * f , int l , const UnicodeString & s ) {
1999-08-16 21:50:52 +00:00
char buf [ 2000 ] ;
2002-03-12 01:32:42 +00:00
s . extract ( ( int32_t ) 0 , s . length ( ) , buf ) ;
2012-05-30 00:41:57 +00:00
printf ( " %s:%d: %s \n " , f , l , buf ) ;
1999-08-16 21:50:52 +00:00
}
2012-05-30 00:41:57 +00:00
# define debugout(x) _debugout(__FILE__,__LINE__,x)
# define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
static const UnicodeString dbg_null ( " <NULL> " , " " ) ;
# define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null))
1999-08-16 21:50:52 +00:00
# else
# define debugout(x)
# define debug(x)
# endif
2009-12-17 22:15:20 +00:00
1999-08-16 21:50:52 +00:00
// *****************************************************************************
// class DecimalFormat
// *****************************************************************************
2003-08-31 20:53:46 +00:00
UOBJECT_DEFINE_RTTI_IMPLEMENTATION ( DecimalFormat )
1999-08-16 21:50:52 +00:00
// Constants for characters used in programmatic (unlocalized) patterns.
2003-08-31 20:53:46 +00:00
# define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
2004-03-25 17:42:28 +00:00
# define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
2003-08-31 20:53:46 +00:00
# define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
# define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
# define kPatternPerMill ((UChar)0x2030)
# define kPatternPercent ((UChar)0x0025) /*'%'*/
# define kPatternDigit ((UChar)0x0023) /*'#'*/
# define kPatternSeparator ((UChar)0x003B) /*';'*/
# define kPatternExponent ((UChar)0x0045) /*'E'*/
# define kPatternPlus ((UChar)0x002B) /*'+'*/
# define kPatternMinus ((UChar)0x002D) /*'-'*/
# define kPatternPadEscape ((UChar)0x002A) /*'*'*/
# define kQuote ((UChar)0x0027) /*'\''*/
/**
* The CURRENCY_SIGN is the standard Unicode symbol for currency . It
* is used in patterns and substitued with either the currency symbol ,
* or if it is doubled , with the international currency symbol . If the
* CURRENCY_SIGN is seen in a pattern , then the decimal separator is
* replaced with the monetary decimal separator .
*/
2004-02-13 01:53:12 +00:00
# define kCurrencySign ((UChar)0x00A4)
# define kDefaultPad ((UChar)0x0020) /* */
1999-08-16 21:50:52 +00:00
const int32_t DecimalFormat : : kDoubleIntegerDigits = 309 ;
const int32_t DecimalFormat : : kDoubleFractionDigits = 340 ;
2003-10-29 00:20:05 +00:00
const int32_t DecimalFormat : : kMaxScientificIntegerDigits = 8 ;
1999-08-16 21:50:52 +00:00
/**
* These are the tags we expect to see in normal resource bundle files associated
* with a locale .
*/
2010-06-04 18:29:02 +00:00
const char DecimalFormat : : fgNumberPatterns [ ] = " NumberPatterns " ; // Deprecated - not used
static const char fgNumberElements [ ] = " NumberElements " ;
static const char fgLatn [ ] = " latn " ;
static const char fgPatterns [ ] = " patterns " ;
static const char fgDecimalFormat [ ] = " decimalFormat " ;
static const char fgCurrencyFormat [ ] = " currencyFormat " ;
2009-02-12 22:55:29 +00:00
static const UChar fgTripleCurrencySign [ ] = { 0xA4 , 0xA4 , 0xA4 , 0 } ;
1999-08-16 21:50:52 +00:00
2004-03-25 17:42:28 +00:00
inline int32_t _min ( int32_t a , int32_t b ) { return ( a < b ) ? a : b ; }
inline int32_t _max ( int32_t a , int32_t b ) { return ( a < b ) ? b : a ; }
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance in the default locale.
2010-01-28 19:39:24 +00:00
2010-02-26 02:29:00 +00:00
DecimalFormat : : DecimalFormat ( UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2001-09-28 21:41:48 +00:00
UParseError parseError ;
construct ( status , parseError ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance with the specified number format
// pattern in the default locale.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
DecimalFormat : : DecimalFormat ( const UnicodeString & pattern ,
2010-02-26 02:29:00 +00:00
UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2001-09-28 21:41:48 +00:00
UParseError parseError ;
construct ( status , parseError , & pattern ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance with the specified number format
// pattern and the number format symbols in the default locale. The
// created instance owns the symbols.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
DecimalFormat : : DecimalFormat ( const UnicodeString & pattern ,
DecimalFormatSymbols * symbolsToAdopt ,
2010-02-26 02:29:00 +00:00
UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2001-09-28 21:41:48 +00:00
UParseError parseError ;
2000-10-12 19:04:06 +00:00
if ( symbolsToAdopt = = NULL )
status = U_ILLEGAL_ARGUMENT_ERROR ;
2001-09-28 21:41:48 +00:00
construct ( status , parseError , & pattern , symbolsToAdopt ) ;
1999-08-16 21:50:52 +00:00
}
2010-01-28 19:39:24 +00:00
2001-08-16 00:55:16 +00:00
DecimalFormat : : DecimalFormat ( const UnicodeString & pattern ,
DecimalFormatSymbols * symbolsToAdopt ,
UParseError & parseErr ,
2010-02-26 02:29:00 +00:00
UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2001-08-16 00:55:16 +00:00
if ( symbolsToAdopt = = NULL )
status = U_ILLEGAL_ARGUMENT_ERROR ;
construct ( status , parseErr , & pattern , symbolsToAdopt ) ;
}
2010-02-26 02:29:00 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance with the specified number format
// pattern and the number format symbols in the default locale. The
// created instance owns the clone of the symbols.
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
DecimalFormat : : DecimalFormat ( const UnicodeString & pattern ,
const DecimalFormatSymbols & symbols ,
2010-02-26 02:29:00 +00:00
UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2001-09-28 21:41:48 +00:00
UParseError parseError ;
construct ( status , parseError , & pattern , new DecimalFormatSymbols ( symbols ) ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
2009-02-12 22:55:29 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance with the specified number format
// pattern, the number format symbols, and the number format style.
// The created instance owns the clone of the symbols.
2010-01-28 19:39:24 +00:00
2009-02-12 22:55:29 +00:00
DecimalFormat : : DecimalFormat ( const UnicodeString & pattern ,
DecimalFormatSymbols * symbolsToAdopt ,
2011-04-29 00:00:47 +00:00
UNumberFormatStyle style ,
2010-02-26 02:29:00 +00:00
UErrorCode & status ) {
2012-05-30 00:41:57 +00:00
init ( status ) ;
2010-02-26 02:29:00 +00:00
fStyle = style ;
2009-02-12 22:55:29 +00:00
UParseError parseError ;
construct ( status , parseError , & pattern , symbolsToAdopt ) ;
}
2010-02-26 02:29:00 +00:00
//-----------------------------------------------------------------------------
// Common DecimalFormat initialization.
// Put all fields of an uninitialized object into a known state.
// Common code, shared by all constructors.
void
2012-05-30 00:41:57 +00:00
DecimalFormat : : init ( UErrorCode & status ) {
2010-02-26 02:29:00 +00:00
fPosPrefixPattern = 0 ;
fPosSuffixPattern = 0 ;
fNegPrefixPattern = 0 ;
fNegSuffixPattern = 0 ;
fCurrencyChoice = 0 ;
fMultiplier = NULL ;
fGroupingSize = 0 ;
fGroupingSize2 = 0 ;
fDecimalSeparatorAlwaysShown = FALSE ;
fSymbols = NULL ;
fUseSignificantDigits = FALSE ;
fMinSignificantDigits = 1 ;
fMaxSignificantDigits = 6 ;
fUseExponentialNotation = FALSE ;
fMinExponentDigits = 0 ;
fExponentSignAlwaysShown = FALSE ;
2012-10-12 19:52:43 +00:00
fBoolFlags . clear ( ) ;
2010-02-26 02:29:00 +00:00
fRoundingIncrement = 0 ;
fRoundingMode = kRoundHalfEven ;
fPad = 0 ;
fFormatWidth = 0 ;
fPadPosition = kPadBeforePrefix ;
2011-04-29 00:00:47 +00:00
fStyle = UNUM_DECIMAL ;
2010-02-26 02:29:00 +00:00
fCurrencySignCount = 0 ;
fAffixPatternsForCurrency = NULL ;
fAffixesForCurrency = NULL ;
fPluralAffixesForCurrency = NULL ;
fCurrencyPluralInfo = NULL ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_HAVE_PARSEALLINPUT
fParseAllInput = UNUM_MAYBE ;
# endif
# if UCONFIG_FORMAT_FASTPATHS_49
DecimalFormatInternal & data = internalData ( fReserved ) ;
data . fFastpathStatus = kFastpathUNKNOWN ; // don't try to calculate the fastpath until later.
# endif
// only do this once per obj.
DecimalFormatStaticSets : : initSets ( & status ) ;
2010-02-26 02:29:00 +00:00
}
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Constructs a DecimalFormat instance with the specified number format
// pattern and the number format symbols in the desired locale. The
// created instance owns the symbols.
void
DecimalFormat : : construct ( UErrorCode & status ,
2001-08-16 00:55:16 +00:00
UParseError & parseErr ,
1999-08-16 21:50:52 +00:00
const UnicodeString * pattern ,
2002-05-13 19:33:05 +00:00
DecimalFormatSymbols * symbolsToAdopt )
1999-08-16 21:50:52 +00:00
{
fSymbols = symbolsToAdopt ; // Do this BEFORE aborting on status failure!!!
fRoundingIncrement = NULL ;
fRoundingMode = kRoundHalfEven ;
1999-10-27 01:08:39 +00:00
fPad = kPatternPadEscape ;
fPadPosition = kPadBeforePrefix ;
2000-10-12 19:04:06 +00:00
if ( U_FAILURE ( status ) )
return ;
1999-08-16 21:50:52 +00:00
fPosPrefixPattern = fPosSuffixPattern = NULL ;
fNegPrefixPattern = fNegSuffixPattern = NULL ;
2010-02-26 02:29:00 +00:00
setMultiplier ( 1 ) ;
1999-08-16 21:50:52 +00:00
fGroupingSize = 3 ;
2000-06-07 00:15:59 +00:00
fGroupingSize2 = 0 ;
1999-08-16 21:50:52 +00:00
fDecimalSeparatorAlwaysShown = FALSE ;
fUseExponentialNotation = FALSE ;
fMinExponentDigits = 0 ;
2000-10-12 19:04:06 +00:00
if ( fSymbols = = NULL )
2001-08-16 00:55:16 +00:00
{
2002-05-13 19:33:05 +00:00
fSymbols = new DecimalFormatSymbols ( Locale : : getDefault ( ) , status ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fSymbols = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
2001-08-16 00:55:16 +00:00
}
2011-08-24 18:06:46 +00:00
UErrorCode nsStatus = U_ZERO_ERROR ;
NumberingSystem * ns = NumberingSystem : : createInstance ( nsStatus ) ;
if ( U_FAILURE ( nsStatus ) ) {
status = nsStatus ;
return ;
}
1999-08-16 21:50:52 +00:00
UnicodeString str ;
// Uses the default locale's number format pattern if there isn't
// one specified.
if ( pattern = = NULL )
{
2004-09-02 19:08:28 +00:00
int32_t len = 0 ;
2011-08-24 18:06:46 +00:00
UResourceBundle * top = ures_open ( NULL , Locale : : getDefault ( ) . getName ( ) , & status ) ;
2000-05-15 18:39:17 +00:00
2011-08-24 18:06:46 +00:00
UResourceBundle * resource = ures_getByKeyWithFallback ( top , fgNumberElements , NULL , & status ) ;
resource = ures_getByKeyWithFallback ( resource , ns - > getName ( ) , resource , & status ) ;
2011-03-12 14:57:18 +00:00
resource = ures_getByKeyWithFallback ( resource , fgPatterns , resource , & status ) ;
const UChar * resStr = ures_getStringByKeyWithFallback ( resource , fgDecimalFormat , & len , & status ) ;
2011-08-24 18:06:46 +00:00
if ( status = = U_MISSING_RESOURCE_ERROR & & uprv_strcmp ( fgLatn , ns - > getName ( ) ) ) {
status = U_ZERO_ERROR ;
resource = ures_getByKeyWithFallback ( top , fgNumberElements , resource , & status ) ;
resource = ures_getByKeyWithFallback ( resource , fgLatn , resource , & status ) ;
resource = ures_getByKeyWithFallback ( resource , fgPatterns , resource , & status ) ;
resStr = ures_getStringByKeyWithFallback ( resource , fgDecimalFormat , & len , & status ) ;
}
2004-09-02 19:08:28 +00:00
str . setTo ( TRUE , resStr , len ) ;
1999-08-16 21:50:52 +00:00
pattern = & str ;
2004-09-02 19:08:28 +00:00
ures_close ( resource ) ;
2011-08-24 18:06:46 +00:00
ures_close ( top ) ;
1999-08-16 21:50:52 +00:00
}
2011-08-30 03:22:38 +00:00
delete ns ;
2000-10-12 19:04:06 +00:00
if ( U_FAILURE ( status ) )
2001-08-16 00:55:16 +00:00
{
2000-10-12 19:04:06 +00:00
return ;
2001-08-16 00:55:16 +00:00
}
2002-05-13 19:33:05 +00:00
2003-08-07 19:01:31 +00:00
if ( pattern - > indexOf ( ( UChar ) kCurrencySign ) > = 0 ) {
// If it looks like we are going to use a currency pattern
// then do the time consuming lookup.
2006-08-08 21:39:04 +00:00
setCurrencyForSymbols ( ) ;
2002-05-13 19:33:05 +00:00
} else {
2009-02-12 22:55:29 +00:00
setCurrencyInternally ( NULL , status ) ;
}
const UnicodeString * patternUsed ;
UnicodeString currencyPluralPatternForOther ;
// apply pattern
2011-04-29 00:00:47 +00:00
if ( fStyle = = UNUM_CURRENCY_PLURAL ) {
2009-02-12 22:55:29 +00:00
fCurrencyPluralInfo = new CurrencyPluralInfo ( fSymbols - > getLocale ( ) , status ) ;
if ( U_FAILURE ( status ) ) {
return ;
}
// the pattern used in format is not fixed until formatting,
2010-01-28 19:39:24 +00:00
// in which, the number is known and
2009-02-12 22:55:29 +00:00
// will be used to pick the right pattern based on plural count.
// Here, set the pattern as the pattern of plural count == "other".
// For most locale, the patterns are probably the same for all
// plural count. If not, the right pattern need to be re-applied
// during format.
2011-06-03 05:23:57 +00:00
fCurrencyPluralInfo - > getCurrencyPluralPattern ( UNICODE_STRING ( " other " , 5 ) , currencyPluralPatternForOther ) ;
2009-02-12 22:55:29 +00:00
patternUsed = & currencyPluralPatternForOther ;
// TODO: not needed?
setCurrencyForSymbols ( ) ;
2010-01-28 19:39:24 +00:00
2009-02-12 22:55:29 +00:00
} else {
patternUsed = pattern ;
}
if ( patternUsed - > indexOf ( kCurrencySign ) ! = - 1 ) {
2010-01-28 19:39:24 +00:00
// initialize for currency, not only for plural format,
2009-02-12 22:55:29 +00:00
// but also for mix parsing
if ( fCurrencyPluralInfo = = NULL ) {
fCurrencyPluralInfo = new CurrencyPluralInfo ( fSymbols - > getLocale ( ) , status ) ;
if ( U_FAILURE ( status ) ) {
return ;
}
}
// need it for mix parsing
setupCurrencyAffixPatterns ( status ) ;
// expanded affixes for plural names
2011-07-07 18:46:19 +00:00
if ( patternUsed - > indexOf ( fgTripleCurrencySign , 3 , 0 ) ! = - 1 ) {
2009-02-12 22:55:29 +00:00
setupCurrencyAffixes ( * patternUsed , TRUE , TRUE , status ) ;
}
2010-01-28 19:39:24 +00:00
}
2009-02-12 22:55:29 +00:00
applyPatternWithoutExpandAffix ( * patternUsed , FALSE , parseErr , status ) ;
// expand affixes
if ( fCurrencySignCount ! = fgCurrencySignCountInPluralFormat ) {
expandAffixAdjustWidth ( NULL ) ;
2002-05-13 19:33:05 +00:00
}
2006-05-03 00:00:34 +00:00
// If it was a currency format, apply the appropriate rounding by
// resetting the currency. NOTE: this copies fCurrency on top of itself.
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
setCurrencyInternally ( getCurrency ( ) , status ) ;
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
DecimalFormatInternal & data = internalData ( fReserved ) ;
data . fFastpathStatus = kFastpathNO ; // allow it to be calculated
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
void
DecimalFormat : : setupCurrencyAffixPatterns ( UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return ;
}
UParseError parseErr ;
fAffixPatternsForCurrency = initHashForAffixPattern ( status ) ;
if ( U_FAILURE ( status ) ) {
return ;
}
2011-08-24 18:06:46 +00:00
NumberingSystem * ns = NumberingSystem : : createInstance ( fSymbols - > getLocale ( ) , status ) ;
2011-08-30 03:22:38 +00:00
if ( U_FAILURE ( status ) ) {
return ;
}
2011-08-24 18:06:46 +00:00
2009-02-12 22:55:29 +00:00
// Save the default currency patterns of this locale.
// Here, chose onlyApplyPatternWithoutExpandAffix without
// expanding the affix patterns into affixes.
UnicodeString currencyPattern ;
2010-06-04 18:29:02 +00:00
UErrorCode error = U_ZERO_ERROR ;
UResourceBundle * resource = ures_open ( NULL , fSymbols - > getLocale ( ) . getName ( ) , & error ) ;
2011-08-24 18:06:46 +00:00
UResourceBundle * numElements = ures_getByKeyWithFallback ( resource , fgNumberElements , NULL , & error ) ;
resource = ures_getByKeyWithFallback ( numElements , ns - > getName ( ) , resource , & error ) ;
2011-03-12 14:57:18 +00:00
resource = ures_getByKeyWithFallback ( resource , fgPatterns , resource , & error ) ;
2009-02-12 22:55:29 +00:00
int32_t patLen = 0 ;
2011-03-12 14:57:18 +00:00
const UChar * patResStr = ures_getStringByKeyWithFallback ( resource , fgCurrencyFormat , & patLen , & error ) ;
2011-08-24 18:06:46 +00:00
if ( error = = U_MISSING_RESOURCE_ERROR & & uprv_strcmp ( ns - > getName ( ) , fgLatn ) ) {
error = U_ZERO_ERROR ;
resource = ures_getByKeyWithFallback ( numElements , fgLatn , resource , & error ) ;
resource = ures_getByKeyWithFallback ( resource , fgPatterns , resource , & error ) ;
patResStr = ures_getStringByKeyWithFallback ( resource , fgCurrencyFormat , & patLen , & error ) ;
}
ures_close ( numElements ) ;
2009-02-12 22:55:29 +00:00
ures_close ( resource ) ;
2011-08-30 03:22:38 +00:00
delete ns ;
2009-02-12 22:55:29 +00:00
if ( U_SUCCESS ( error ) ) {
applyPatternWithoutExpandAffix ( UnicodeString ( patResStr , patLen ) , false ,
parseErr , status ) ;
AffixPatternsForCurrency * affixPtn = new AffixPatternsForCurrency (
* fNegPrefixPattern ,
* fNegSuffixPattern ,
* fPosPrefixPattern ,
2009-03-10 20:53:27 +00:00
* fPosSuffixPattern ,
UCURR_SYMBOL_NAME ) ;
2011-06-03 05:23:57 +00:00
fAffixPatternsForCurrency - > put ( UNICODE_STRING ( " default " , 7 ) , affixPtn , status ) ;
2009-02-12 22:55:29 +00:00
}
2010-01-28 19:39:24 +00:00
2009-02-12 22:55:29 +00:00
// save the unique currency plural patterns of this locale.
Hashtable * pluralPtn = fCurrencyPluralInfo - > fPluralCountToCurrencyUnitPattern ;
const UHashElement * element = NULL ;
int32_t pos = - 1 ;
Hashtable pluralPatternSet ;
while ( ( element = pluralPtn - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok valueTok = element - > value ;
const UnicodeString * value = ( UnicodeString * ) valueTok . pointer ;
const UHashTok keyTok = element - > key ;
const UnicodeString * key = ( UnicodeString * ) keyTok . pointer ;
if ( pluralPatternSet . geti ( * value ) ! = 1 ) {
pluralPatternSet . puti ( * value , 1 , status ) ;
applyPatternWithoutExpandAffix ( * value , false , parseErr , status ) ;
AffixPatternsForCurrency * affixPtn = new AffixPatternsForCurrency (
* fNegPrefixPattern ,
* fNegSuffixPattern ,
* fPosPrefixPattern ,
2009-03-10 20:53:27 +00:00
* fPosSuffixPattern ,
UCURR_LONG_NAME ) ;
2009-02-12 22:55:29 +00:00
fAffixPatternsForCurrency - > put ( * key , affixPtn , status ) ;
}
2006-05-03 00:00:34 +00:00
}
1999-08-16 21:50:52 +00:00
}
2009-02-12 22:55:29 +00:00
void
2010-01-28 19:39:24 +00:00
DecimalFormat : : setupCurrencyAffixes ( const UnicodeString & pattern ,
2009-02-12 22:55:29 +00:00
UBool setupForCurrentPattern ,
UBool setupForPluralPattern ,
UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return ;
}
UParseError parseErr ;
if ( setupForCurrentPattern ) {
if ( fAffixesForCurrency ) {
deleteHashForAffix ( fAffixesForCurrency ) ;
}
fAffixesForCurrency = initHashForAffix ( status ) ;
if ( U_SUCCESS ( status ) ) {
applyPatternWithoutExpandAffix ( pattern , false , parseErr , status ) ;
const PluralRules * pluralRules = fCurrencyPluralInfo - > getPluralRules ( ) ;
StringEnumeration * keywords = pluralRules - > getKeywords ( status ) ;
if ( U_SUCCESS ( status ) ) {
2011-06-03 05:23:57 +00:00
const UnicodeString * pluralCount ;
while ( ( pluralCount = keywords - > snext ( status ) ) ! = NULL ) {
2009-02-12 22:55:29 +00:00
if ( U_SUCCESS ( status ) ) {
2011-06-03 05:23:57 +00:00
expandAffixAdjustWidth ( pluralCount ) ;
2009-02-12 22:55:29 +00:00
AffixesForCurrency * affix = new AffixesForCurrency (
fNegativePrefix , fNegativeSuffix , fPositivePrefix , fPositiveSuffix ) ;
2011-06-03 05:23:57 +00:00
fAffixesForCurrency - > put ( * pluralCount , affix , status ) ;
2009-02-12 22:55:29 +00:00
}
}
}
2010-01-28 19:39:24 +00:00
delete keywords ;
2009-02-12 22:55:29 +00:00
}
}
if ( U_FAILURE ( status ) ) {
return ;
}
if ( setupForPluralPattern ) {
if ( fPluralAffixesForCurrency ) {
deleteHashForAffix ( fPluralAffixesForCurrency ) ;
}
fPluralAffixesForCurrency = initHashForAffix ( status ) ;
if ( U_SUCCESS ( status ) ) {
const PluralRules * pluralRules = fCurrencyPluralInfo - > getPluralRules ( ) ;
StringEnumeration * keywords = pluralRules - > getKeywords ( status ) ;
if ( U_SUCCESS ( status ) ) {
2011-06-03 05:23:57 +00:00
const UnicodeString * pluralCount ;
while ( ( pluralCount = keywords - > snext ( status ) ) ! = NULL ) {
2009-02-12 22:55:29 +00:00
if ( U_SUCCESS ( status ) ) {
UnicodeString ptn ;
2011-06-03 05:23:57 +00:00
fCurrencyPluralInfo - > getCurrencyPluralPattern ( * pluralCount , ptn ) ;
applyPatternInternally ( * pluralCount , ptn , false , parseErr , status ) ;
2009-02-12 22:55:29 +00:00
AffixesForCurrency * affix = new AffixesForCurrency (
fNegativePrefix , fNegativeSuffix , fPositivePrefix , fPositiveSuffix ) ;
2011-06-03 05:23:57 +00:00
fPluralAffixesForCurrency - > put ( * pluralCount , affix , status ) ;
2009-02-12 22:55:29 +00:00
}
}
}
2010-01-28 19:39:24 +00:00
delete keywords ;
2009-02-12 22:55:29 +00:00
}
}
}
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
DecimalFormat : : ~ DecimalFormat ( )
{
delete fPosPrefixPattern ;
delete fPosSuffixPattern ;
delete fNegPrefixPattern ;
delete fNegSuffixPattern ;
2003-04-21 22:48:16 +00:00
delete fCurrencyChoice ;
2010-02-26 02:29:00 +00:00
delete fMultiplier ;
2000-08-24 20:56:13 +00:00
delete fSymbols ;
1999-08-16 21:50:52 +00:00
delete fRoundingIncrement ;
2009-02-12 22:55:29 +00:00
deleteHashForAffixPattern ( ) ;
deleteHashForAffix ( fAffixesForCurrency ) ;
deleteHashForAffix ( fPluralAffixesForCurrency ) ;
delete fCurrencyPluralInfo ;
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
// copy constructor
2000-08-07 23:06:28 +00:00
2010-02-26 02:29:00 +00:00
DecimalFormat : : DecimalFormat ( const DecimalFormat & source ) :
NumberFormat ( source ) {
2012-05-30 00:41:57 +00:00
UErrorCode status = U_ZERO_ERROR ;
init ( status ) ; // if this fails, 'source' isn't initialized properly either.
1999-08-16 21:50:52 +00:00
* this = source ;
}
//------------------------------------------------------------------------------
// assignment operator
2012-09-27 18:50:24 +00:00
template < class T >
static void _copy_ptr ( T * * pdest , const T * source ) {
2012-10-12 23:18:49 +00:00
if ( source = = NULL ) {
1999-08-16 21:50:52 +00:00
delete * pdest ;
* pdest = NULL ;
2012-10-12 23:18:49 +00:00
} else if ( * pdest = = NULL ) {
2012-09-27 18:50:24 +00:00
* pdest = new T ( * source ) ;
2012-10-12 23:18:49 +00:00
} else {
* * pdest = * source ;
2012-09-27 18:50:24 +00:00
}
}
template < class T >
static void _clone_ptr ( T * * pdest , const T * source ) {
2012-10-12 23:18:49 +00:00
delete * pdest ;
2012-09-27 18:50:24 +00:00
if ( source = = NULL ) {
2012-10-12 23:18:49 +00:00
* pdest = NULL ;
1999-08-16 21:50:52 +00:00
} else {
2012-10-12 23:18:49 +00:00
* pdest = static_cast < T * > ( source - > clone ( ) ) ;
1999-08-16 21:50:52 +00:00
}
}
DecimalFormat &
DecimalFormat : : operator = ( const DecimalFormat & rhs )
{
2004-04-03 17:56:14 +00:00
if ( this ! = & rhs ) {
NumberFormat : : operator = ( rhs ) ;
fPositivePrefix = rhs . fPositivePrefix ;
fPositiveSuffix = rhs . fPositiveSuffix ;
fNegativePrefix = rhs . fNegativePrefix ;
fNegativeSuffix = rhs . fNegativeSuffix ;
2012-09-27 18:50:24 +00:00
_copy_ptr ( & fPosPrefixPattern , rhs . fPosPrefixPattern ) ;
_copy_ptr ( & fPosSuffixPattern , rhs . fPosSuffixPattern ) ;
_copy_ptr ( & fNegPrefixPattern , rhs . fNegPrefixPattern ) ;
_copy_ptr ( & fNegSuffixPattern , rhs . fNegSuffixPattern ) ;
_clone_ptr ( & fCurrencyChoice , rhs . fCurrencyChoice ) ;
2010-02-26 02:29:00 +00:00
setRoundingIncrement ( rhs . getRoundingIncrement ( ) ) ;
2007-06-06 01:17:15 +00:00
fRoundingMode = rhs . fRoundingMode ;
2010-02-26 02:29:00 +00:00
setMultiplier ( rhs . getMultiplier ( ) ) ;
2004-04-03 17:56:14 +00:00
fGroupingSize = rhs . fGroupingSize ;
fGroupingSize2 = rhs . fGroupingSize2 ;
fDecimalSeparatorAlwaysShown = rhs . fDecimalSeparatorAlwaysShown ;
2012-09-27 18:50:24 +00:00
_copy_ptr ( & fSymbols , rhs . fSymbols ) ;
2004-04-03 17:56:14 +00:00
fUseExponentialNotation = rhs . fUseExponentialNotation ;
fExponentSignAlwaysShown = rhs . fExponentSignAlwaysShown ;
2012-10-12 19:52:43 +00:00
fBoolFlags = rhs . fBoolFlags ;
2004-04-03 17:56:14 +00:00
/*Bertrand A. D. Update 98.03.17*/
2009-02-12 22:55:29 +00:00
fCurrencySignCount = rhs . fCurrencySignCount ;
2004-04-03 17:56:14 +00:00
/*end of Update*/
fMinExponentDigits = rhs . fMinExponentDigits ;
2010-01-28 19:39:24 +00:00
2004-04-03 17:56:14 +00:00
/* sfb 990629 */
fFormatWidth = rhs . fFormatWidth ;
fPad = rhs . fPad ;
fPadPosition = rhs . fPadPosition ;
/* end sfb */
fMinSignificantDigits = rhs . fMinSignificantDigits ;
2004-05-20 21:14:06 +00:00
fMaxSignificantDigits = rhs . fMaxSignificantDigits ;
2004-04-03 17:56:14 +00:00
fUseSignificantDigits = rhs . fUseSignificantDigits ;
2009-02-12 22:55:29 +00:00
fFormatPattern = rhs . fFormatPattern ;
fStyle = rhs . fStyle ;
fCurrencySignCount = rhs . fCurrencySignCount ;
2012-09-27 18:50:24 +00:00
_clone_ptr ( & fCurrencyPluralInfo , rhs . fCurrencyPluralInfo ) ;
deleteHashForAffixPattern ( ) ;
2009-02-12 22:55:29 +00:00
if ( rhs . fAffixPatternsForCurrency ) {
UErrorCode status = U_ZERO_ERROR ;
fAffixPatternsForCurrency = initHashForAffixPattern ( status ) ;
2010-01-28 19:39:24 +00:00
copyHashForAffixPattern ( rhs . fAffixPatternsForCurrency ,
2009-02-12 22:55:29 +00:00
fAffixPatternsForCurrency , status ) ;
}
2012-09-27 18:50:24 +00:00
deleteHashForAffix ( fAffixesForCurrency ) ;
2009-02-12 22:55:29 +00:00
if ( rhs . fAffixesForCurrency ) {
UErrorCode status = U_ZERO_ERROR ;
fAffixesForCurrency = initHashForAffixPattern ( status ) ;
copyHashForAffix ( rhs . fAffixesForCurrency , fAffixesForCurrency , status ) ;
}
2012-09-27 18:50:24 +00:00
deleteHashForAffix ( fPluralAffixesForCurrency ) ;
2009-02-12 22:55:29 +00:00
if ( rhs . fPluralAffixesForCurrency ) {
UErrorCode status = U_ZERO_ERROR ;
fPluralAffixesForCurrency = initHashForAffixPattern ( status ) ;
copyHashForAffix ( rhs . fPluralAffixesForCurrency , fPluralAffixesForCurrency , status ) ;
}
2004-04-03 17:56:14 +00:00
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2004-04-03 17:56:14 +00:00
return * this ;
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
2000-05-18 22:08:39 +00:00
UBool
1999-08-16 21:50:52 +00:00
DecimalFormat : : operator = = ( const Format & that ) const
{
2000-08-07 23:06:28 +00:00
if ( this = = & that )
return TRUE ;
1999-08-16 21:50:52 +00:00
2004-02-13 01:53:12 +00:00
// NumberFormat::operator== guarantees this cast is safe
1999-08-16 21:50:52 +00:00
const DecimalFormat * other = ( DecimalFormat * ) & that ;
2001-09-17 21:50:19 +00:00
# ifdef FMT_DEBUG
1999-08-16 21:50:52 +00:00
// This code makes it easy to determine why two format objects that should
// be equal aren't.
2000-05-18 22:08:39 +00:00
UBool first = TRUE ;
1999-08-16 21:50:52 +00:00
if ( ! NumberFormat : : operator = = ( that ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " NumberFormat::!= " ) ;
2009-02-12 22:55:29 +00:00
} else {
1999-08-16 21:50:52 +00:00
if ( ! ( ( fPosPrefixPattern = = other - > fPosPrefixPattern & & // both null
fPositivePrefix = = other - > fPositivePrefix )
| | ( fPosPrefixPattern ! = 0 & & other - > fPosPrefixPattern ! = 0 & &
* fPosPrefixPattern = = * other - > fPosPrefixPattern ) ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Pos Prefix != " ) ;
}
if ( ! ( ( fPosSuffixPattern = = other - > fPosSuffixPattern & & // both null
fPositiveSuffix = = other - > fPositiveSuffix )
| | ( fPosSuffixPattern ! = 0 & & other - > fPosSuffixPattern ! = 0 & &
* fPosSuffixPattern = = * other - > fPosSuffixPattern ) ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Pos Suffix != " ) ;
}
if ( ! ( ( fNegPrefixPattern = = other - > fNegPrefixPattern & & // both null
fNegativePrefix = = other - > fNegativePrefix )
| | ( fNegPrefixPattern ! = 0 & & other - > fNegPrefixPattern ! = 0 & &
* fNegPrefixPattern = = * other - > fNegPrefixPattern ) ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Neg Prefix " ) ;
if ( fNegPrefixPattern = = NULL ) {
debug ( " NULL( " ) ;
debugout ( fNegativePrefix ) ;
debug ( " ) " ) ;
} else {
debugout ( * fNegPrefixPattern ) ;
}
debug ( " != " ) ;
if ( other - > fNegPrefixPattern = = NULL ) {
debug ( " NULL( " ) ;
debugout ( other - > fNegativePrefix ) ;
debug ( " ) " ) ;
} else {
debugout ( * other - > fNegPrefixPattern ) ;
}
}
if ( ! ( ( fNegSuffixPattern = = other - > fNegSuffixPattern & & // both null
fNegativeSuffix = = other - > fNegativeSuffix )
| | ( fNegSuffixPattern ! = 0 & & other - > fNegSuffixPattern ! = 0 & &
* fNegSuffixPattern = = * other - > fNegSuffixPattern ) ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Neg Suffix " ) ;
if ( fNegSuffixPattern = = NULL ) {
debug ( " NULL( " ) ;
debugout ( fNegativeSuffix ) ;
debug ( " ) " ) ;
} else {
debugout ( * fNegSuffixPattern ) ;
}
debug ( " != " ) ;
if ( other - > fNegSuffixPattern = = NULL ) {
debug ( " NULL( " ) ;
debugout ( other - > fNegativeSuffix ) ;
debug ( " ) " ) ;
} else {
debugout ( * other - > fNegSuffixPattern ) ;
}
}
if ( ! ( ( fRoundingIncrement = = other - > fRoundingIncrement ) // both null
| | ( fRoundingIncrement ! = NULL & &
other - > fRoundingIncrement ! = NULL & &
* fRoundingIncrement = = * other - > fRoundingIncrement ) ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Rounding Increment != " ) ;
}
2010-02-26 02:29:00 +00:00
if ( getMultiplier ( ) ! = other - > getMultiplier ( ) ) {
1999-08-16 21:50:52 +00:00
if ( first ) { printf ( " [ " ) ; first = FALSE ; }
2010-02-26 02:29:00 +00:00
printf ( " Multiplier %ld != %ld " , getMultiplier ( ) , other - > getMultiplier ( ) ) ;
1999-08-16 21:50:52 +00:00
}
if ( fGroupingSize ! = other - > fGroupingSize ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
printf ( " Grouping Size %ld != %ld " , fGroupingSize , other - > fGroupingSize ) ;
}
2000-06-07 00:15:59 +00:00
if ( fGroupingSize2 ! = other - > fGroupingSize2 ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
printf ( " Secondary Grouping Size %ld != %ld " , fGroupingSize2 , other - > fGroupingSize2 ) ;
}
1999-08-16 21:50:52 +00:00
if ( fDecimalSeparatorAlwaysShown ! = other - > fDecimalSeparatorAlwaysShown ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
printf ( " Dec Sep Always %d != %d " , fDecimalSeparatorAlwaysShown , other - > fDecimalSeparatorAlwaysShown ) ;
}
if ( fUseExponentialNotation ! = other - > fUseExponentialNotation ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Use Exp != " ) ;
}
if ( ! ( ! fUseExponentialNotation | |
fMinExponentDigits ! = other - > fMinExponentDigits ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Exp Digits != " ) ;
}
if ( * fSymbols ! = * ( other - > fSymbols ) ) {
if ( first ) { printf ( " [ " ) ; first = FALSE ; } else { printf ( " , " ) ; }
debug ( " Symbols != " ) ;
}
2004-04-03 17:56:14 +00:00
// TODO Add debug stuff for significant digits here
2009-02-12 22:55:29 +00:00
if ( fUseSignificantDigits ! = other - > fUseSignificantDigits ) {
debug ( " fUseSignificantDigits != " ) ;
}
if ( fUseSignificantDigits & &
fMinSignificantDigits ! = other - > fMinSignificantDigits ) {
debug ( " fMinSignificantDigits != " ) ;
}
if ( fUseSignificantDigits & &
fMaxSignificantDigits ! = other - > fMaxSignificantDigits ) {
debug ( " fMaxSignificantDigits != " ) ;
}
1999-08-16 21:50:52 +00:00
if ( ! first ) { printf ( " ] " ) ; }
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount ! = other - > fCurrencySignCount ) {
debug ( " fCurrencySignCount != " ) ;
}
if ( fCurrencyPluralInfo = = other - > fCurrencyPluralInfo ) {
debug ( " fCurrencyPluralInfo == " ) ;
if ( fCurrencyPluralInfo = = NULL ) {
debug ( " fCurrencyPluralInfo == NULL " ) ;
}
}
if ( fCurrencyPluralInfo ! = NULL & & other - > fCurrencyPluralInfo ! = NULL & &
* fCurrencyPluralInfo ! = * ( other - > fCurrencyPluralInfo ) ) {
debug ( " fCurrencyPluralInfo != " ) ;
}
if ( fCurrencyPluralInfo ! = NULL & & other - > fCurrencyPluralInfo = = NULL | |
fCurrencyPluralInfo = = NULL & & other - > fCurrencyPluralInfo ! = NULL ) {
debug ( " fCurrencyPluralInfo one NULL, the other not " ) ;
}
if ( fCurrencyPluralInfo = = NULL & & other - > fCurrencyPluralInfo = = NULL ) {
debug ( " fCurrencyPluralInfo == " ) ;
}
}
1999-08-16 21:50:52 +00:00
# endif
return ( NumberFormat : : operator = = ( that ) & &
2010-01-28 19:39:24 +00:00
( ( fCurrencySignCount = = fgCurrencySignCountInPluralFormat ) ?
2009-02-12 22:55:29 +00:00
( fAffixPatternsForCurrency - > equals ( * other - > fAffixPatternsForCurrency ) ) :
( ( ( fPosPrefixPattern = = other - > fPosPrefixPattern & & // both null
1999-08-16 21:50:52 +00:00
fPositivePrefix = = other - > fPositivePrefix )
| | ( fPosPrefixPattern ! = 0 & & other - > fPosPrefixPattern ! = 0 & &
* fPosPrefixPattern = = * other - > fPosPrefixPattern ) ) & &
( ( fPosSuffixPattern = = other - > fPosSuffixPattern & & // both null
fPositiveSuffix = = other - > fPositiveSuffix )
| | ( fPosSuffixPattern ! = 0 & & other - > fPosSuffixPattern ! = 0 & &
* fPosSuffixPattern = = * other - > fPosSuffixPattern ) ) & &
( ( fNegPrefixPattern = = other - > fNegPrefixPattern & & // both null
fNegativePrefix = = other - > fNegativePrefix )
| | ( fNegPrefixPattern ! = 0 & & other - > fNegPrefixPattern ! = 0 & &
* fNegPrefixPattern = = * other - > fNegPrefixPattern ) ) & &
( ( fNegSuffixPattern = = other - > fNegSuffixPattern & & // both null
fNegativeSuffix = = other - > fNegativeSuffix )
| | ( fNegSuffixPattern ! = 0 & & other - > fNegSuffixPattern ! = 0 & &
2009-02-12 22:55:29 +00:00
* fNegSuffixPattern = = * other - > fNegSuffixPattern ) ) ) ) & &
1999-08-16 21:50:52 +00:00
( ( fRoundingIncrement = = other - > fRoundingIncrement ) // both null
| | ( fRoundingIncrement ! = NULL & &
other - > fRoundingIncrement ! = NULL & &
* fRoundingIncrement = = * other - > fRoundingIncrement ) ) & &
2010-02-26 02:29:00 +00:00
getMultiplier ( ) = = other - > getMultiplier ( ) & &
1999-08-16 21:50:52 +00:00
fGroupingSize = = other - > fGroupingSize & &
2000-06-07 00:15:59 +00:00
fGroupingSize2 = = other - > fGroupingSize2 & &
1999-08-16 21:50:52 +00:00
fDecimalSeparatorAlwaysShown = = other - > fDecimalSeparatorAlwaysShown & &
fUseExponentialNotation = = other - > fUseExponentialNotation & &
( ! fUseExponentialNotation | |
fMinExponentDigits = = other - > fMinExponentDigits ) & &
2004-04-03 17:56:14 +00:00
* fSymbols = = * ( other - > fSymbols ) & &
fUseSignificantDigits = = other - > fUseSignificantDigits & &
( ! fUseSignificantDigits | |
( fMinSignificantDigits = = other - > fMinSignificantDigits & &
2009-02-12 22:55:29 +00:00
fMaxSignificantDigits = = other - > fMaxSignificantDigits ) ) & &
fCurrencySignCount = = other - > fCurrencySignCount & &
( ( fCurrencyPluralInfo = = other - > fCurrencyPluralInfo & &
fCurrencyPluralInfo = = NULL ) | |
( fCurrencyPluralInfo ! = NULL & & other - > fCurrencyPluralInfo ! = NULL & &
* fCurrencyPluralInfo = = * ( other - > fCurrencyPluralInfo ) ) ) ) ;
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
Format *
DecimalFormat : : clone ( ) const
{
return new DecimalFormat ( * this ) ;
}
//------------------------------------------------------------------------------
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : format ( int32_t number ,
2002-11-23 01:11:50 +00:00
UnicodeString & appendTo ,
1999-08-16 21:50:52 +00:00
FieldPosition & fieldPosition ) const
2003-10-31 22:47:25 +00:00
{
2004-11-11 23:34:58 +00:00
return format ( ( int64_t ) number , appendTo , fieldPosition ) ;
2003-10-31 22:47:25 +00:00
}
2010-01-28 19:39:24 +00:00
2012-10-12 19:52:43 +00:00
UnicodeString &
DecimalFormat : : format ( int32_t number ,
UnicodeString & appendTo ,
FieldPosition & fieldPosition ,
UErrorCode & status ) const
{
return format ( ( int64_t ) number , appendTo , fieldPosition , status ) ;
}
2009-12-17 22:15:20 +00:00
UnicodeString &
DecimalFormat : : format ( int32_t number ,
UnicodeString & appendTo ,
2010-01-28 19:39:24 +00:00
FieldPositionIterator * posIter ,
2009-12-17 22:15:20 +00:00
UErrorCode & status ) const
{
return format ( ( int64_t ) number , appendTo , posIter , status ) ;
}
2003-10-31 22:47:25 +00:00
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
void DecimalFormat : : handleChanged ( ) {
DecimalFormatInternal & data = internalData ( fReserved ) ;
if ( data . fFastpathStatus = = kFastpathUNKNOWN ) {
return ; // still constructing. Wait.
}
data . fFastpathStatus = kFastpathNO ;
2012-09-17 19:03:01 +00:00
if ( fGroupingSize ! = 0 & & isGroupingUsed ( ) ) {
debug ( " No fastpath: fGroupingSize!=0 and grouping is used " ) ;
# ifdef FMT_DEBUG
printf ( " groupingsize=%d \n " , fGroupingSize ) ;
# endif
} else if ( fGroupingSize2 ! = 0 & & isGroupingUsed ( ) ) {
2012-05-30 00:41:57 +00:00
debug ( " No fastpath: fGroupingSize2!=0 " ) ;
} else if ( fUseExponentialNotation ) {
debug ( " No fastpath: fUseExponentialNotation " ) ;
} else if ( fFormatWidth ! = 0 ) {
debug ( " No fastpath: fFormatWidth!=0 " ) ;
} else if ( fMinSignificantDigits ! = 1 ) {
debug ( " No fastpath: fMinSignificantDigits!=1 " ) ;
} else if ( fMultiplier ! = NULL ) {
debug ( " No fastpath: fMultiplier!=NULL " ) ;
} else if ( 0x0030 ! = getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) . char32At ( 0 ) ) {
debug ( " No fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0) " ) ;
} else if ( fDecimalSeparatorAlwaysShown ) {
debug ( " No fastpath: fDecimalSeparatorAlwaysShown " ) ;
} else if ( getMinimumFractionDigits ( ) > 0 ) {
debug ( " No fastpath: fMinFractionDigits>0 " ) ;
} else if ( fCurrencySignCount > fgCurrencySignCountZero ) {
debug ( " No fastpath: fCurrencySignCount > fgCurrencySignCountZero " ) ;
2012-06-18 14:14:22 +00:00
} else if ( fRoundingIncrement ! = 0 ) {
debug ( " No fastpath: fRoundingIncrement!=0 " ) ;
2012-05-30 00:41:57 +00:00
} else {
data . fFastpathStatus = kFastpathYES ;
debug ( " kFastpathYES! " ) ;
}
}
# endif
2003-10-31 22:47:25 +00:00
//------------------------------------------------------------------------------
2010-01-28 19:39:24 +00:00
2003-10-31 22:47:25 +00:00
UnicodeString &
DecimalFormat : : format ( int64_t number ,
UnicodeString & appendTo ,
FieldPosition & fieldPosition ) const
1999-08-16 21:50:52 +00:00
{
2012-10-12 19:52:43 +00:00
UErrorCode status = U_ZERO_ERROR ; /* ignored */
FieldPositionOnlyHandler handler ( fieldPosition ) ;
return _format ( number , appendTo , handler , status ) ;
}
UnicodeString &
DecimalFormat : : format ( int64_t number ,
UnicodeString & appendTo ,
FieldPosition & fieldPosition ,
UErrorCode & status ) const
{
2012-06-18 14:14:22 +00:00
FieldPositionOnlyHandler handler ( fieldPosition ) ;
return _format ( number , appendTo , handler , status ) ;
2009-12-17 22:15:20 +00:00
}
2000-11-02 02:42:40 +00:00
2009-12-17 22:15:20 +00:00
UnicodeString &
DecimalFormat : : format ( int64_t number ,
UnicodeString & appendTo ,
2010-01-28 19:39:24 +00:00
FieldPositionIterator * posIter ,
2009-12-17 22:15:20 +00:00
UErrorCode & status ) const
{
FieldPositionIteratorHandler handler ( posIter , status ) ;
2012-06-18 14:14:22 +00:00
return _format ( number , appendTo , handler , status ) ;
2009-12-17 22:15:20 +00:00
}
UnicodeString &
DecimalFormat : : _format ( int64_t number ,
UnicodeString & appendTo ,
2012-06-18 14:14:22 +00:00
FieldPositionHandler & handler ,
UErrorCode & status ) const
2009-12-17 22:15:20 +00:00
{
2012-05-30 00:41:57 +00:00
// Bottleneck function for formatting int64_t
2012-06-18 14:14:22 +00:00
if ( U_FAILURE ( status ) ) {
return appendTo ;
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
// const UnicodeString *posPrefix = fPosPrefixPattern;
// const UnicodeString *posSuffix = fPosSuffixPattern;
// const UnicodeString *negSuffix = fNegSuffixPattern;
const DecimalFormatInternal & data = internalData ( fReserved ) ;
# ifdef FMT_DEBUG
data . dump ( ) ;
printf ( " fastpath? [%d] \n " , number ) ;
# endif
2012-05-30 18:21:49 +00:00
if ( data . fFastpathStatus = = kFastpathYES ) {
2012-05-30 00:41:57 +00:00
# define kZero 0x0030
const int32_t MAX_IDX = MAX_DIGITS + 2 ;
UChar outputStr [ MAX_IDX ] ;
int32_t destIdx = MAX_IDX ;
outputStr [ - - destIdx ] = 0 ; // term
int64_t n = number ;
2012-05-30 18:21:49 +00:00
if ( number < 1 ) {
// Negative numbers are slightly larger than positive
// output the first digit (or the leading zero)
outputStr [ - - destIdx ] = ( - ( n % 10 ) + kZero ) ;
n / = - 10 ;
2012-05-30 00:41:57 +00:00
}
2012-05-30 18:21:49 +00:00
// get any remaining digits
while ( n > 0 ) {
2012-05-30 00:41:57 +00:00
outputStr [ - - destIdx ] = ( n % 10 ) + kZero ;
n / = 10 ;
2012-05-30 18:21:49 +00:00
}
2012-05-30 00:41:57 +00:00
// Slide the number to the start of the output str
U_ASSERT ( destIdx > = 0 ) ;
int32_t length = MAX_IDX - destIdx - 1 ;
2012-09-17 19:03:01 +00:00
/*int32_t prefixLen = */ appendAffix ( appendTo , number , handler , number < 0 , TRUE ) ;
2012-05-30 00:41:57 +00:00
int32_t maxIntDig = getMaximumIntegerDigits ( ) ;
2012-07-06 22:47:27 +00:00
int32_t destlength = length < = maxIntDig ? length : maxIntDig ; // dest length pinned to max int digits
2012-10-12 21:53:41 +00:00
if ( length > maxIntDig & & fBoolFlags . contains ( UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS ) ) {
2012-10-12 19:52:43 +00:00
status = U_ILLEGAL_ARGUMENT_ERROR ;
}
2012-07-06 22:47:27 +00:00
int32_t prependZero = getMinimumIntegerDigits ( ) - destlength ;
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
2012-07-06 22:47:27 +00:00
printf ( " prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d \n " , prependZero , length , getMinimumIntegerDigits ( ) , maxIntDig , destlength , length - destlength ) ;
2012-05-30 00:41:57 +00:00
# endif
int32_t intBegin = appendTo . length ( ) ;
while ( ( prependZero - - ) > 0 ) {
2012-11-02 19:41:57 +00:00
appendTo . append ( ( UChar ) 0x0030 ) ; // '0'
2012-05-30 00:41:57 +00:00
}
2012-07-06 22:47:27 +00:00
appendTo . append ( outputStr + destIdx +
( length - destlength ) , // skip any leading digits
destlength ) ;
2012-05-30 00:41:57 +00:00
handler . addAttribute ( kIntegerField , intBegin , appendTo . length ( ) ) ;
2012-09-17 19:03:01 +00:00
/*int32_t suffixLen =*/ appendAffix ( appendTo , number , handler , number < 0 , FALSE ) ;
2012-05-30 00:41:57 +00:00
//outputStr[length]=0;
# ifdef FMT_DEBUG
printf ( " Writing [%s] length [%d] max %d for [%d] \n " , outputStr + destIdx , length , MAX_IDX , number ) ;
# endif
# undef kZero
return appendTo ;
} // end fastpath
# endif
// Else the slow way - via DigitList
2009-12-17 22:15:20 +00:00
DigitList digits ;
2010-02-26 02:29:00 +00:00
digits . set ( number ) ;
return _format ( digits , appendTo , handler , status ) ;
1999-08-16 21:50:52 +00:00
}
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
UnicodeString &
DecimalFormat : : format ( double number ,
2002-11-23 01:11:50 +00:00
UnicodeString & appendTo ,
1999-08-16 21:50:52 +00:00
FieldPosition & fieldPosition ) const
{
2012-10-12 19:52:43 +00:00
UErrorCode status = U_ZERO_ERROR ; /* ignored */
FieldPositionOnlyHandler handler ( fieldPosition ) ;
return _format ( number , appendTo , handler , status ) ;
}
UnicodeString &
DecimalFormat : : format ( double number ,
UnicodeString & appendTo ,
FieldPosition & fieldPosition ,
UErrorCode & status ) const
{
2009-12-17 22:15:20 +00:00
FieldPositionOnlyHandler handler ( fieldPosition ) ;
2012-06-18 14:14:22 +00:00
return _format ( number , appendTo , handler , status ) ;
2009-12-17 22:15:20 +00:00
}
UnicodeString &
DecimalFormat : : format ( double number ,
UnicodeString & appendTo ,
2010-01-28 19:39:24 +00:00
FieldPositionIterator * posIter ,
2009-12-17 22:15:20 +00:00
UErrorCode & status ) const
{
FieldPositionIteratorHandler handler ( posIter , status ) ;
2012-06-18 14:14:22 +00:00
return _format ( number , appendTo , handler , status ) ;
2009-12-17 22:15:20 +00:00
}
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
UnicodeString &
DecimalFormat : : _format ( double number ,
UnicodeString & appendTo ,
2012-06-18 14:14:22 +00:00
FieldPositionHandler & handler ,
UErrorCode & status ) const
2009-12-17 22:15:20 +00:00
{
2012-06-18 14:14:22 +00:00
if ( U_FAILURE ( status ) ) {
return appendTo ;
}
1999-08-16 21:50:52 +00:00
// Special case for NaN, sets the begin and end index to be the
// the string length of localized name of NaN.
2010-02-26 02:29:00 +00:00
// TODO: let NaNs go through DigitList.
1999-12-28 23:57:50 +00:00
if ( uprv_isNaN ( number ) )
1999-08-16 21:50:52 +00:00
{
2009-12-17 22:15:20 +00:00
int begin = appendTo . length ( ) ;
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kNaNSymbol ) ;
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kIntegerField , begin , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
addPadding ( appendTo , handler , 0 , 0 ) ;
2002-11-23 01:11:50 +00:00
return appendTo ;
1999-08-16 21:50:52 +00:00
}
2010-02-26 02:29:00 +00:00
DigitList digits ;
digits . set ( number ) ;
_format ( digits , appendTo , handler , status ) ;
// No way to return status from here.
return appendTo ;
}
//------------------------------------------------------------------------------
UnicodeString &
DecimalFormat : : format ( const StringPiece & number ,
UnicodeString & toAppendTo ,
FieldPositionIterator * posIter ,
UErrorCode & status ) const
{
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
// don't bother if the int64 path is not optimized
int32_t len = number . length ( ) ;
if ( len > 0 & & len < 10 ) { /* 10 or more digits may not be an int64 */
const char * data = number . data ( ) ;
int64_t num = 0 ;
UBool neg = FALSE ;
UBool ok = TRUE ;
int32_t start = 0 ;
if ( data [ start ] = = ' + ' ) {
start + + ;
} else if ( data [ start ] = = ' - ' ) {
neg = TRUE ;
start + + ;
}
int32_t place = 1 ; /* 1, 10, ... */
for ( int32_t i = len - 1 ; i > = start ; i - - ) {
if ( data [ i ] > = ' 0 ' & & data [ i ] < = ' 9 ' ) {
num + = place * ( int64_t ) ( data [ i ] - ' 0 ' ) ;
} else {
ok = FALSE ;
break ;
}
place * = 10 ;
}
if ( ok ) {
if ( neg ) {
num = - num ; // add minus bit
}
// format as int64_t
return format ( num , toAppendTo , posIter , status ) ;
}
// else fall through
}
# endif
2010-02-26 02:29:00 +00:00
DigitList dnum ;
dnum . set ( number , status ) ;
if ( U_FAILURE ( status ) ) {
return toAppendTo ;
}
FieldPositionIteratorHandler handler ( posIter , status ) ;
_format ( dnum , toAppendTo , handler , status ) ;
return toAppendTo ;
}
UnicodeString &
DecimalFormat : : format ( const DigitList & number ,
UnicodeString & appendTo ,
FieldPositionIterator * posIter ,
UErrorCode & status ) const {
FieldPositionIteratorHandler handler ( posIter , status ) ;
_format ( number , appendTo , handler , status ) ;
return appendTo ;
}
UnicodeString &
DecimalFormat : : format ( const DigitList & number ,
UnicodeString & appendTo ,
FieldPosition & pos ,
UErrorCode & status ) const {
FieldPositionOnlyHandler handler ( pos ) ;
_format ( number , appendTo , handler , status ) ;
return appendTo ;
}
2012-11-14 18:49:38 +00:00
DigitList &
DecimalFormat : : _round ( const DigitList & number , DigitList & adjustedNum , UBool & isNegative , UErrorCode & status ) const {
if ( U_FAILURE ( status ) ) {
return adjustedNum ;
}
adjustedNum = number ;
isNegative = false ;
if ( number . isNaN ( ) ) {
return adjustedNum ;
2010-02-26 02:29:00 +00:00
}
2008-01-14 20:10:54 +00:00
// Do this BEFORE checking to see if value is infinite or negative! Sets the
// begin and end index to be length of the string composed of
// localized name of Infinite and the positive/negative localized
// signs.
2010-02-26 02:29:00 +00:00
adjustedNum . setRoundingMode ( fRoundingMode ) ;
if ( fMultiplier ! = NULL ) {
adjustedNum . mult ( * fMultiplier , status ) ;
2012-11-14 18:49:38 +00:00
if ( U_FAILURE ( status ) ) {
return adjustedNum ;
}
2010-02-26 02:29:00 +00:00
}
2008-01-14 20:10:54 +00:00
2012-11-14 18:49:38 +00:00
/*
2010-02-26 02:29:00 +00:00
* Note : sign is important for zero as well as non - zero numbers .
* Proper detection of - 0.0 is needed to deal with the
1999-08-16 21:50:52 +00:00
* issues raised by bugs 4106658 , 4106667 , and 4147706. Liu 7 / 6 / 98.
*/
2012-11-14 18:49:38 +00:00
isNegative = ! adjustedNum . isPositive ( ) ;
1999-08-16 21:50:52 +00:00
// Apply rounding after multiplier
2012-11-14 18:49:38 +00:00
2011-05-02 19:15:03 +00:00
adjustedNum . fContext . status & = ~ DEC_Inexact ;
1999-08-16 21:50:52 +00:00
if ( fRoundingIncrement ! = NULL ) {
2010-02-26 02:29:00 +00:00
adjustedNum . div ( * fRoundingIncrement , status ) ;
adjustedNum . toIntegralValue ( ) ;
adjustedNum . mult ( * fRoundingIncrement , status ) ;
adjustedNum . trim ( ) ;
2012-11-14 18:49:38 +00:00
if ( U_FAILURE ( status ) ) {
return adjustedNum ;
}
1999-08-16 21:50:52 +00:00
}
2011-05-02 19:15:03 +00:00
if ( fRoundingMode = = kRoundUnnecessary & & ( adjustedNum . fContext . status & DEC_Inexact ) ) {
status = U_FORMAT_INEXACT_ERROR ;
2012-11-14 18:49:38 +00:00
return adjustedNum ;
2011-05-02 19:15:03 +00:00
}
1999-08-16 21:50:52 +00:00
2010-02-26 02:29:00 +00:00
if ( adjustedNum . isInfinite ( ) ) {
2012-11-14 18:49:38 +00:00
return adjustedNum ;
1999-08-16 21:50:52 +00:00
}
2010-06-04 05:42:19 +00:00
if ( fUseExponentialNotation | | areSignificantDigitsUsed ( ) ) {
int32_t sigDigits = precision ( ) ;
if ( sigDigits > 0 ) {
adjustedNum . round ( sigDigits ) ;
1999-08-16 21:50:52 +00:00
}
2010-06-04 05:42:19 +00:00
} else {
// Fixed point format. Round to a set number of fraction digits.
int32_t numFractionDigits = precision ( ) ;
adjustedNum . roundFixedPoint ( numFractionDigits ) ;
1999-08-16 21:50:52 +00:00
}
2011-05-02 19:15:03 +00:00
if ( fRoundingMode = = kRoundUnnecessary & & ( adjustedNum . fContext . status & DEC_Inexact ) ) {
status = U_FORMAT_INEXACT_ERROR ;
2012-11-14 18:49:38 +00:00
return adjustedNum ;
}
return adjustedNum ;
}
UnicodeString &
DecimalFormat : : _format ( const DigitList & number ,
UnicodeString & appendTo ,
FieldPositionHandler & handler ,
UErrorCode & status ) const
{
if ( U_FAILURE ( status ) ) {
return appendTo ;
}
// Special case for NaN, sets the begin and end index to be the
// the string length of localized name of NaN.
if ( number . isNaN ( ) )
{
int begin = appendTo . length ( ) ;
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kNaNSymbol ) ;
handler . addAttribute ( kIntegerField , begin , appendTo . length ( ) ) ;
addPadding ( appendTo , handler , 0 , 0 ) ;
return appendTo ;
}
DigitList adjustedNum ;
UBool isNegative ;
_round ( number , adjustedNum , isNegative , status ) ;
if ( U_FAILURE ( status ) ) {
return appendTo ;
}
// Special case for INFINITE,
if ( adjustedNum . isInfinite ( ) ) {
int32_t prefixLen = appendAffix ( appendTo , adjustedNum . getDouble ( ) , handler , isNegative , TRUE ) ;
int begin = appendTo . length ( ) ;
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kInfinitySymbol ) ;
handler . addAttribute ( kIntegerField , begin , appendTo . length ( ) ) ;
int32_t suffixLen = appendAffix ( appendTo , adjustedNum . getDouble ( ) , handler , isNegative , FALSE ) ;
addPadding ( appendTo , handler , prefixLen , suffixLen ) ;
2011-05-02 19:15:03 +00:00
return appendTo ;
}
2012-10-12 19:52:43 +00:00
return subformat ( appendTo , handler , adjustedNum , FALSE , status ) ;
2010-01-15 22:28:39 +00:00
}
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : format ( const Formattable & obj ,
2002-11-23 01:11:50 +00:00
UnicodeString & appendTo ,
1999-08-16 21:50:52 +00:00
FieldPosition & fieldPosition ,
UErrorCode & status ) const
{
2002-11-23 01:11:50 +00:00
return NumberFormat : : format ( obj , appendTo , fieldPosition , status ) ;
1999-08-16 21:50:52 +00:00
}
2000-06-07 00:15:59 +00:00
/**
* Return true if a grouping separator belongs at the given
* position , based on whether grouping is in use and the values of
* the primary and secondary grouping interval .
* @ param pos the number of integer digits to the right of
* the current position . Zero indicates the position after the
* rightmost integer digit .
* @ return true if a grouping character belongs at the current
* position .
*/
UBool DecimalFormat : : isGroupingPosition ( int32_t pos ) const {
UBool result = FALSE ;
if ( isGroupingUsed ( ) & & ( pos > 0 ) & & ( fGroupingSize > 0 ) ) {
if ( ( fGroupingSize2 > 0 ) & & ( pos > fGroupingSize ) ) {
result = ( ( pos - fGroupingSize ) % fGroupingSize2 ) = = 0 ;
} else {
result = pos % fGroupingSize = = 0 ;
}
}
return result ;
}
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
/**
2010-02-26 02:29:00 +00:00
* Complete the formatting of a finite number . On entry , the DigitList must
1999-08-16 21:50:52 +00:00
* be filled in with the correct digits .
*/
UnicodeString &
2002-11-23 01:11:50 +00:00
DecimalFormat : : subformat ( UnicodeString & appendTo ,
2009-12-17 22:15:20 +00:00
FieldPositionHandler & handler ,
2000-11-02 02:42:40 +00:00
DigitList & digits ,
2012-10-12 19:52:43 +00:00
UBool isInteger ,
UErrorCode & status ) const
1999-08-16 21:50:52 +00:00
{
2010-10-08 20:14:26 +00:00
// char zero = '0';
2010-08-13 21:23:00 +00:00
// DigitList returns digits as '0' thru '9', so we will need to
// always need to subtract the character 0 to get the numeric value to use for indexing.
UChar32 localizedDigits [ 10 ] ;
localizedDigits [ 0 ] = getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 1 ] = getConstSymbol ( DecimalFormatSymbols : : kOneDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 2 ] = getConstSymbol ( DecimalFormatSymbols : : kTwoDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 3 ] = getConstSymbol ( DecimalFormatSymbols : : kThreeDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 4 ] = getConstSymbol ( DecimalFormatSymbols : : kFourDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 5 ] = getConstSymbol ( DecimalFormatSymbols : : kFiveDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 6 ] = getConstSymbol ( DecimalFormatSymbols : : kSixDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 7 ] = getConstSymbol ( DecimalFormatSymbols : : kSevenDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 8 ] = getConstSymbol ( DecimalFormatSymbols : : kEightDigitSymbol ) . char32At ( 0 ) ;
localizedDigits [ 9 ] = getConstSymbol ( DecimalFormatSymbols : : kNineDigitSymbol ) . char32At ( 0 ) ;
2006-01-09 23:03:31 +00:00
const UnicodeString * grouping ;
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
2006-01-09 23:03:31 +00:00
grouping = & getConstSymbol ( DecimalFormatSymbols : : kMonetaryGroupingSeparatorSymbol ) ;
} else {
grouping = & getConstSymbol ( DecimalFormatSymbols : : kGroupingSeparatorSymbol ) ;
}
2002-10-12 01:09:00 +00:00
const UnicodeString * decimal ;
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
2002-10-12 01:09:00 +00:00
decimal = & getConstSymbol ( DecimalFormatSymbols : : kMonetarySeparatorSymbol ) ;
} else {
decimal = & getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ;
}
2004-04-12 23:37:44 +00:00
UBool useSigDig = areSignificantDigitsUsed ( ) ;
1999-08-16 21:50:52 +00:00
int32_t maxIntDig = getMaximumIntegerDigits ( ) ;
int32_t minIntDig = getMinimumIntegerDigits ( ) ;
// Appends the prefix.
2003-04-21 22:48:16 +00:00
double doubleValue = digits . getDouble ( ) ;
2010-02-26 02:29:00 +00:00
int32_t prefixLen = appendAffix ( appendTo , doubleValue , handler , ! digits . isPositive ( ) , TRUE ) ;
1999-08-16 21:50:52 +00:00
if ( fUseExponentialNotation )
{
2009-12-17 22:15:20 +00:00
int currentLength = appendTo . length ( ) ;
int intBegin = currentLength ;
int intEnd = - 1 ;
int fracBegin = - 1 ;
1999-08-16 21:50:52 +00:00
2004-03-25 17:42:28 +00:00
int32_t minFracDig = 0 ;
if ( useSigDig ) {
maxIntDig = minIntDig = 1 ;
minFracDig = getMinimumSignificantDigits ( ) - 1 ;
} else {
minFracDig = getMinimumFractionDigits ( ) ;
if ( maxIntDig > kMaxScientificIntegerDigits ) {
maxIntDig = 1 ;
if ( maxIntDig < minIntDig ) {
maxIntDig = minIntDig ;
}
}
if ( maxIntDig > minIntDig ) {
minIntDig = 1 ;
}
}
1999-08-16 21:50:52 +00:00
// Minimum integer digits are handled in exponential format by
// adjusting the exponent. For example, 0.01234 with 3 minimum
// integer digits is "123.4E-4".
// Maximum integer digits are interpreted as indicating the
// repeating range. This is useful for engineering notation, in
// which the exponent is restricted to a multiple of 3. For
// example, 0.01234 with 3 maximum integer digits is "12.34e-3".
// If maximum integer digits are defined and are larger than
// minimum integer digits, then minimum integer digits are
// ignored.
2010-02-26 02:29:00 +00:00
digits . reduce ( ) ; // Removes trailing zero digits.
int32_t exponent = digits . getDecimalAt ( ) ;
1999-08-16 21:50:52 +00:00
if ( maxIntDig > 1 & & maxIntDig ! = minIntDig ) {
// A exponent increment is defined; adjust to it.
exponent = ( exponent > 0 ) ? ( exponent - 1 ) / maxIntDig
: ( exponent / maxIntDig ) - 1 ;
exponent * = maxIntDig ;
} else {
// No exponent increment is defined; use minimum integer digits.
// If none is specified, as in "#E0", generate 1 integer digit.
2004-03-25 17:42:28 +00:00
exponent - = ( minIntDig > 0 | | minFracDig > 0 )
1999-08-16 21:50:52 +00:00
? minIntDig : 1 ;
}
// We now output a minimum number of digits, and more if there
// are more digits, up to the maximum number of digits. We
// place the decimal point after the "integer" digits, which
// are the first (decimalAt - exponent) digits.
2004-03-25 17:42:28 +00:00
int32_t minimumDigits = minIntDig + minFracDig ;
1999-08-16 21:50:52 +00:00
// The number of integer digits is handled specially if the number
// is zero, since then there may be no digits.
2000-11-02 02:42:40 +00:00
int32_t integerDigits = digits . isZero ( ) ? minIntDig :
2010-02-26 02:29:00 +00:00
digits . getDecimalAt ( ) - exponent ;
int32_t totalDigits = digits . getCount ( ) ;
2000-10-12 19:04:06 +00:00
if ( minimumDigits > totalDigits )
totalDigits = minimumDigits ;
if ( integerDigits > totalDigits )
totalDigits = integerDigits ;
1999-08-16 21:50:52 +00:00
// totalDigits records total number of digits needs to be processed
int32_t i ;
for ( i = 0 ; i < totalDigits ; + + i )
{
if ( i = = integerDigits )
{
2009-12-17 22:15:20 +00:00
intEnd = appendTo . length ( ) ;
handler . addAttribute ( kIntegerField , intBegin , intEnd ) ;
1999-08-16 21:50:52 +00:00
2002-11-23 01:11:50 +00:00
appendTo + = * decimal ;
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
fracBegin = appendTo . length ( ) ;
handler . addAttribute ( kDecimalSeparatorField , fracBegin - 1 , fracBegin ) ;
1999-08-16 21:50:52 +00:00
}
// Restores the digit character or pads the buffer with zeros.
2010-02-26 02:29:00 +00:00
UChar32 c = ( UChar32 ) ( ( i < digits . getCount ( ) ) ?
2010-08-13 21:23:00 +00:00
localizedDigits [ digits . getDigitValue ( i ) ] :
localizedDigits [ 0 ] ) ;
2002-11-23 01:11:50 +00:00
appendTo + = c ;
1999-08-16 21:50:52 +00:00
}
2009-12-17 22:15:20 +00:00
currentLength = appendTo . length ( ) ;
if ( intEnd < 0 ) {
handler . addAttribute ( kIntegerField , intBegin , currentLength ) ;
1999-08-16 21:50:52 +00:00
}
2009-12-17 22:15:20 +00:00
if ( fracBegin > 0 ) {
handler . addAttribute ( kFractionField , fracBegin , currentLength ) ;
1999-08-16 21:50:52 +00:00
}
// The exponent is output using the pattern-specified minimum
// exponent digits. There is no maximum limit to the exponent
2002-11-23 01:11:50 +00:00
// digits, since truncating the exponent would appendTo in an
1999-08-16 21:50:52 +00:00
// unacceptable inaccuracy.
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kExponentialSymbol ) ;
2002-10-12 01:09:00 +00:00
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kExponentSymbolField , currentLength , appendTo . length ( ) ) ;
currentLength = appendTo . length ( ) ;
1999-08-16 21:50:52 +00:00
// For zero values, we force the exponent to zero. We
// must do this here, and not earlier, because the value
// is used to determine integer digit count above.
2000-11-02 02:42:40 +00:00
if ( digits . isZero ( ) )
2000-10-12 19:04:06 +00:00
exponent = 0 ;
1999-08-16 21:50:52 +00:00
2000-11-02 02:42:40 +00:00
if ( exponent < 0 ) {
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kExponentSignField , currentLength , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
} else if ( fExponentSignAlwaysShown ) {
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kExponentSignField , currentLength , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
}
2000-11-02 02:42:40 +00:00
2009-12-17 22:15:20 +00:00
currentLength = appendTo . length ( ) ;
2000-11-02 02:42:40 +00:00
DigitList expDigits ;
expDigits . set ( exponent ) ;
2004-11-11 23:34:58 +00:00
{
2003-10-29 00:20:05 +00:00
int expDig = fMinExponentDigits ;
if ( fUseExponentialNotation & & expDig < 1 ) {
expDig = 1 ;
}
2010-02-26 02:29:00 +00:00
for ( i = expDigits . getDecimalAt ( ) ; i < expDig ; + + i )
2010-08-13 21:23:00 +00:00
appendTo + = ( localizedDigits [ 0 ] ) ;
2004-11-11 23:34:58 +00:00
}
2010-02-26 02:29:00 +00:00
for ( i = 0 ; i < expDigits . getDecimalAt ( ) ; + + i )
1999-08-16 21:50:52 +00:00
{
2010-02-26 02:29:00 +00:00
UChar32 c = ( UChar32 ) ( ( i < expDigits . getCount ( ) ) ?
2010-08-13 21:23:00 +00:00
localizedDigits [ expDigits . getDigitValue ( i ) ] :
localizedDigits [ 0 ] ) ;
2002-11-23 01:11:50 +00:00
appendTo + = c ;
1999-08-16 21:50:52 +00:00
}
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kExponentField , currentLength , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
}
else // Not using exponential notation
{
2009-12-17 22:15:20 +00:00
int currentLength = appendTo . length ( ) ;
int intBegin = currentLength ;
1999-08-16 21:50:52 +00:00
2004-03-25 17:42:28 +00:00
int32_t sigCount = 0 ;
int32_t minSigDig = getMinimumSignificantDigits ( ) ;
int32_t maxSigDig = getMaximumSignificantDigits ( ) ;
if ( ! useSigDig ) {
2004-04-03 17:56:14 +00:00
minSigDig = 0 ;
2004-03-25 17:42:28 +00:00
maxSigDig = INT32_MAX ;
}
1999-08-16 21:50:52 +00:00
// Output the integer portion. Here 'count' is the total
// number of integer digits we will display, including both
// leading zeros required to satisfy getMinimumIntegerDigits,
// and actual digits present in the number.
2004-03-25 17:42:28 +00:00
int32_t count = useSigDig ?
2010-02-26 02:29:00 +00:00
_max ( 1 , digits . getDecimalAt ( ) ) : minIntDig ;
if ( digits . getDecimalAt ( ) > 0 & & count < digits . getDecimalAt ( ) ) {
count = digits . getDecimalAt ( ) ;
2004-03-25 17:42:28 +00:00
}
1999-08-16 21:50:52 +00:00
// Handle the case where getMaximumIntegerDigits() is smaller
// than the real number of integer digits. If this is so, we
// output the least significant max integer digits. For example,
// the value 1997 printed with 2 max integer digits is just "97".
2004-03-25 17:42:28 +00:00
int32_t digitIndex = 0 ; // Index into digitList.fDigits[]
if ( count > maxIntDig & & maxIntDig > = 0 ) {
1999-08-16 21:50:52 +00:00
count = maxIntDig ;
2010-02-26 02:29:00 +00:00
digitIndex = digits . getDecimalAt ( ) - count ;
2012-10-12 21:53:41 +00:00
if ( fBoolFlags . contains ( UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS ) ) {
2012-10-12 19:52:43 +00:00
status = U_ILLEGAL_ARGUMENT_ERROR ;
}
1999-08-16 21:50:52 +00:00
}
2002-11-23 01:11:50 +00:00
int32_t sizeBeforeIntegerPart = appendTo . length ( ) ;
1999-08-16 21:50:52 +00:00
int32_t i ;
for ( i = count - 1 ; i > = 0 ; - - i )
{
2010-02-26 02:29:00 +00:00
if ( i < digits . getDecimalAt ( ) & & digitIndex < digits . getCount ( ) & &
2004-03-25 17:42:28 +00:00
sigCount < maxSigDig ) {
1999-08-16 21:50:52 +00:00
// Output a real digit
2010-08-13 21:23:00 +00:00
appendTo + = ( UChar32 ) localizedDigits [ digits . getDigitValue ( digitIndex + + ) ] ;
2004-03-25 17:42:28 +00:00
+ + sigCount ;
1999-08-16 21:50:52 +00:00
}
else
{
2004-03-25 17:42:28 +00:00
// Output a zero (leading or trailing)
2010-08-13 21:23:00 +00:00
appendTo + = localizedDigits [ 0 ] ;
2004-03-25 17:42:28 +00:00
if ( sigCount > 0 ) {
+ + sigCount ;
}
1999-08-16 21:50:52 +00:00
}
2000-06-07 00:15:59 +00:00
// Output grouping separator if necessary.
if ( isGroupingPosition ( i ) ) {
2009-12-17 22:15:20 +00:00
currentLength = appendTo . length ( ) ;
2002-11-23 01:11:50 +00:00
appendTo . append ( * grouping ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kGroupingSeparatorField , currentLength , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
}
}
2009-12-17 22:15:20 +00:00
// TODO(dlf): this looks like it was a bug, we marked the int field as ending
// before the zero was generated.
1999-08-16 21:50:52 +00:00
// Record field information for caller.
2009-12-17 22:15:20 +00:00
// if (fieldPosition.getField() == NumberFormat::kIntegerField)
// fieldPosition.setEndIndex(appendTo.length());
1999-08-16 21:50:52 +00:00
// Determine whether or not there are any printable fractional
// digits. If we've used up the digits we know there aren't.
2010-02-26 02:29:00 +00:00
UBool fractionPresent = ( ! isInteger & & digitIndex < digits . getCount ( ) ) | |
2004-04-29 05:57:38 +00:00
( useSigDig ? ( sigCount < minSigDig ) : ( getMinimumFractionDigits ( ) > 0 ) ) ;
1999-08-16 21:50:52 +00:00
// If there is no fraction present, and we haven't printed any
// integer digits, then print a zero. Otherwise we won't print
// _any_ digits, and we won't be able to parse this string.
2002-11-23 01:11:50 +00:00
if ( ! fractionPresent & & appendTo . length ( ) = = sizeBeforeIntegerPart )
2010-08-13 21:23:00 +00:00
appendTo + = localizedDigits [ 0 ] ;
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
currentLength = appendTo . length ( ) ;
handler . addAttribute ( kIntegerField , intBegin , currentLength ) ;
1999-08-16 21:50:52 +00:00
// Output the decimal separator if we always do so.
2009-12-17 22:15:20 +00:00
if ( fDecimalSeparatorAlwaysShown | | fractionPresent ) {
2002-11-23 01:11:50 +00:00
appendTo + = * decimal ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kDecimalSeparatorField , currentLength , appendTo . length ( ) ) ;
currentLength = appendTo . length ( ) ;
}
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
int fracBegin = currentLength ;
1999-08-16 21:50:52 +00:00
2004-03-25 17:42:28 +00:00
count = useSigDig ? INT32_MAX : getMaximumFractionDigits ( ) ;
if ( useSigDig & & ( sigCount = = maxSigDig | |
2010-02-26 02:29:00 +00:00
( sigCount > = minSigDig & & digitIndex = = digits . getCount ( ) ) ) ) {
2004-03-25 17:42:28 +00:00
count = 0 ;
}
for ( i = 0 ; i < count ; + + i ) {
// Here is where we escape from the loop. We escape
// if we've output the maximum fraction digits
// (specified in the for expression above). We also
// stop when we've output the minimum digits and
// either: we have an integer, so there is no
// fractional stuff to display, or we're out of
// significant digits.
if ( ! useSigDig & & i > = getMinimumFractionDigits ( ) & &
2010-02-26 02:29:00 +00:00
( isInteger | | digitIndex > = digits . getCount ( ) ) ) {
2004-03-25 17:42:28 +00:00
break ;
1999-08-16 21:50:52 +00:00
}
2000-11-02 02:42:40 +00:00
2004-03-25 17:42:28 +00:00
// Output leading fractional zeros. These are zeros
// that come after the decimal but before any
// significant digits. These are only output if
// abs(number being formatted) < 1.0.
2010-02-26 02:29:00 +00:00
if ( - 1 - i > ( digits . getDecimalAt ( ) - 1 ) ) {
2010-08-13 21:23:00 +00:00
appendTo + = localizedDigits [ 0 ] ;
2004-03-25 17:42:28 +00:00
continue ;
}
// Output a digit, if we have any precision left, or a
// zero if we don't. We don't want to output noise digits.
2010-02-26 02:29:00 +00:00
if ( ! isInteger & & digitIndex < digits . getCount ( ) ) {
2010-08-13 21:23:00 +00:00
appendTo + = ( UChar32 ) localizedDigits [ digits . getDigitValue ( digitIndex + + ) ] ;
2004-03-25 17:42:28 +00:00
} else {
2010-08-13 21:23:00 +00:00
appendTo + = localizedDigits [ 0 ] ;
2004-03-25 17:42:28 +00:00
}
// If we reach the maximum number of significant
// digits, or if we output all the real digits and
// reach the minimum, then we are done.
+ + sigCount ;
if ( useSigDig & &
( sigCount = = maxSigDig | |
2010-02-26 02:29:00 +00:00
( digitIndex = = digits . getCount ( ) & & sigCount > = minSigDig ) ) ) {
2004-03-25 17:42:28 +00:00
break ;
1999-08-16 21:50:52 +00:00
}
}
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kFractionField , fracBegin , appendTo . length ( ) ) ;
1999-08-16 21:50:52 +00:00
}
2010-02-26 02:29:00 +00:00
int32_t suffixLen = appendAffix ( appendTo , doubleValue , handler , ! digits . isPositive ( ) , FALSE ) ;
1999-08-16 21:50:52 +00:00
2009-12-17 22:15:20 +00:00
addPadding ( appendTo , handler , prefixLen , suffixLen ) ;
2002-11-23 01:11:50 +00:00
return appendTo ;
1999-08-16 21:50:52 +00:00
}
/**
* Inserts the character fPad as needed to expand result to fFormatWidth .
* @ param result the string to be padded
*/
2002-11-23 01:11:50 +00:00
void DecimalFormat : : addPadding ( UnicodeString & appendTo ,
2009-12-17 22:15:20 +00:00
FieldPositionHandler & handler ,
2003-04-21 22:48:16 +00:00
int32_t prefixLen ,
int32_t suffixLen ) const
2001-03-08 19:40:09 +00:00
{
1999-08-16 21:50:52 +00:00
if ( fFormatWidth > 0 ) {
2002-11-23 01:11:50 +00:00
int32_t len = fFormatWidth - appendTo . length ( ) ;
1999-08-16 21:50:52 +00:00
if ( len > 0 ) {
2001-09-17 21:50:19 +00:00
UnicodeString padding ;
1999-08-16 21:50:52 +00:00
for ( int32_t i = 0 ; i < len ; + + i ) {
2001-09-17 21:50:19 +00:00
padding + = fPad ;
1999-08-16 21:50:52 +00:00
}
switch ( fPadPosition ) {
case kPadAfterPrefix :
2003-04-21 22:48:16 +00:00
appendTo . insert ( prefixLen , padding ) ;
break ;
1999-08-16 21:50:52 +00:00
case kPadBeforePrefix :
2002-11-23 01:11:50 +00:00
appendTo . insert ( 0 , padding ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPadBeforeSuffix :
2003-04-21 22:48:16 +00:00
appendTo . insert ( appendTo . length ( ) - suffixLen , padding ) ;
break ;
1999-08-16 21:50:52 +00:00
case kPadAfterSuffix :
2002-11-23 01:11:50 +00:00
appendTo + = padding ;
1999-08-16 21:50:52 +00:00
break ;
}
2009-12-17 22:15:20 +00:00
if ( fPadPosition = = kPadBeforePrefix | | fPadPosition = = kPadAfterPrefix ) {
handler . shiftLast ( len ) ;
2003-04-21 22:48:16 +00:00
}
1999-08-16 21:50:52 +00:00
}
}
}
//------------------------------------------------------------------------------
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : parse ( const UnicodeString & text ,
Formattable & result ,
UErrorCode & status ) const
{
NumberFormat : : parse ( text , result , status ) ;
}
void
DecimalFormat : : parse ( const UnicodeString & text ,
Formattable & result ,
2004-04-15 06:20:42 +00:00
ParsePosition & parsePosition ) const {
2012-02-19 06:45:47 +00:00
parse ( text , result , parsePosition , NULL ) ;
2004-04-15 06:20:42 +00:00
}
2012-02-19 06:45:47 +00:00
CurrencyAmount * DecimalFormat : : parseCurrency ( const UnicodeString & text ,
ParsePosition & pos ) const {
Formattable parseResult ;
int32_t start = pos . getIndex ( ) ;
UChar curbuf [ 4 ] ;
parse ( text , parseResult , pos , curbuf ) ;
2012-02-24 20:27:21 +00:00
if ( pos . getIndex ( ) ! = start ) {
2012-02-19 06:45:47 +00:00
UErrorCode ec = U_ZERO_ERROR ;
2012-02-24 20:27:21 +00:00
LocalPointer < CurrencyAmount > currAmt ( new CurrencyAmount ( parseResult , curbuf , ec ) ) ;
if ( U_FAILURE ( ec ) ) {
2012-02-19 06:45:47 +00:00
pos . setIndex ( start ) ; // indicate failure
2012-02-24 20:27:21 +00:00
} else {
2012-02-24 22:54:57 +00:00
return currAmt . orphan ( ) ;
2012-02-19 06:45:47 +00:00
}
}
2012-02-24 22:54:57 +00:00
return NULL ;
2004-04-15 06:20:42 +00:00
}
/**
2012-02-19 06:45:47 +00:00
* Parses the given text as a number , optionally providing a currency amount .
2004-04-15 06:20:42 +00:00
* @ param text the string to parse
2012-02-19 06:45:47 +00:00
* @ param result output parameter for the numeric result .
2004-04-15 06:20:42 +00:00
* @ param parsePosition input - output position ; on input , the
* position within text to match ; must have 0 < = pos . getIndex ( ) <
* text . length ( ) ; on output , the position after the last matched
* character . If the parse fails , the position in unchanged upon
* output .
2012-02-19 06:45:47 +00:00
* @ param currency if non - NULL , it should point to a 4 - UChar buffer .
* In this case the text is parsed as a currency format , and the
* ISO 4217 code for the parsed currency is put into the buffer .
* Otherwise the text is parsed as a non - currency format .
2004-04-15 06:20:42 +00:00
*/
void DecimalFormat : : parse ( const UnicodeString & text ,
Formattable & result ,
ParsePosition & parsePosition ,
2012-02-19 06:45:47 +00:00
UChar * currency ) const {
2012-02-14 07:05:58 +00:00
int32_t startIdx , backup ;
int32_t i = startIdx = backup = parsePosition . getIndex ( ) ;
2000-11-02 02:42:40 +00:00
2010-02-26 02:29:00 +00:00
// clear any old contents in the result. In particular, clears any DigitList
// that it may be holding.
result . setLong ( 0 ) ;
2003-04-21 19:18:27 +00:00
// Handle NaN as a special case:
2010-01-28 19:39:24 +00:00
2003-04-21 19:18:27 +00:00
// Skip padding characters, if around prefix
if ( fFormatWidth > 0 & & ( fPadPosition = = kPadBeforePrefix | |
fPadPosition = = kPadAfterPrefix ) ) {
i = skipPadding ( text , i ) ;
1999-08-16 21:50:52 +00:00
}
2011-05-04 12:23:42 +00:00
if ( isLenient ( ) ) {
// skip any leading whitespace
i = backup = skipUWhiteSpace ( text , i ) ;
}
2000-10-24 16:09:39 +00:00
// If the text is composed of the representation of NaN, returns NaN.length
2002-10-12 01:09:00 +00:00
const UnicodeString * nan = & getConstSymbol ( DecimalFormatSymbols : : kNaNSymbol ) ;
2003-04-21 19:18:27 +00:00
int32_t nanLen = ( text . compare ( i , nan - > length ( ) , * nan )
? 0 : nan - > length ( ) ) ;
2000-08-07 23:06:28 +00:00
if ( nanLen ) {
2003-04-21 19:18:27 +00:00
i + = nanLen ;
if ( fFormatWidth > 0 & & ( fPadPosition = = kPadBeforeSuffix | |
fPadPosition = = kPadAfterSuffix ) ) {
i = skipPadding ( text , i ) ;
}
parsePosition . setIndex ( i ) ;
1999-12-28 23:57:50 +00:00
result . setDouble ( uprv_getNaN ( ) ) ;
1999-08-16 21:50:52 +00:00
return ;
}
2010-01-28 19:39:24 +00:00
2003-04-21 19:18:27 +00:00
// NaN parse failed; start over
i = backup ;
2011-05-04 12:23:42 +00:00
parsePosition . setIndex ( i ) ;
1999-08-16 21:50:52 +00:00
2000-11-02 02:42:40 +00:00
// status is used to record whether a number is infinite.
2000-05-18 22:08:39 +00:00
UBool status [ fgStatusLength ] ;
2012-05-30 00:41:57 +00:00
DigitList * digits = result . getInternalDigitList ( ) ; // get one from the stack buffer
2010-02-26 02:29:00 +00:00
if ( digits = = NULL ) {
return ; // no way to report error from here.
}
1999-08-16 21:50:52 +00:00
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
2010-02-26 02:29:00 +00:00
if ( ! parseForCurrency ( text , parsePosition , * digits ,
2009-02-12 22:55:29 +00:00
status , currency ) ) {
2012-05-30 00:41:57 +00:00
return ;
2009-02-12 22:55:29 +00:00
}
} else {
2010-01-28 19:39:24 +00:00
if ( ! subparse ( text ,
2009-02-12 22:55:29 +00:00
fNegPrefixPattern , fNegSuffixPattern ,
fPosPrefixPattern , fPosSuffixPattern ,
2009-03-10 20:53:27 +00:00
FALSE , UCURR_SYMBOL_NAME ,
2010-02-26 02:29:00 +00:00
parsePosition , * digits , status , currency ) ) {
2012-05-30 00:41:57 +00:00
debug ( " !subparse(...) - rewind " ) ;
2012-02-14 07:05:58 +00:00
parsePosition . setIndex ( startIdx ) ;
2009-02-12 22:55:29 +00:00
return ;
}
2000-11-02 02:42:40 +00:00
}
1999-08-16 21:50:52 +00:00
// Handle infinity
if ( status [ fgStatusInfinite ] ) {
1999-12-28 23:57:50 +00:00
double inf = uprv_getInfinity ( ) ;
2010-02-26 02:29:00 +00:00
result . setDouble ( digits - > isPositive ( ) ? inf : - inf ) ;
2012-05-30 00:41:57 +00:00
// TODO: set the dl to infinity, and let it fall into the code below.
1999-08-16 21:50:52 +00:00
}
2004-04-27 21:47:09 +00:00
else {
2010-02-26 02:29:00 +00:00
if ( fMultiplier ! = NULL ) {
UErrorCode ec = U_ZERO_ERROR ;
digits - > div ( * fMultiplier , ec ) ;
2003-10-31 22:47:25 +00:00
}
2010-02-26 02:29:00 +00:00
// Negative zero special case:
// if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
// if not parsing integerOnly, leave as -0, which a double can represent.
if ( digits - > isZero ( ) & & ! digits - > isPositive ( ) & & isParseIntegerOnly ( ) ) {
digits - > setPositive ( TRUE ) ;
2003-10-31 22:47:25 +00:00
}
2010-02-26 02:29:00 +00:00
result . adoptDigitList ( digits ) ;
2003-10-31 22:47:25 +00:00
}
1999-08-16 21:50:52 +00:00
}
2000-10-24 16:09:39 +00:00
2009-02-12 22:55:29 +00:00
UBool
DecimalFormat : : parseForCurrency ( const UnicodeString & text ,
ParsePosition & parsePosition ,
DigitList & digits ,
UBool * status ,
UChar * currency ) const {
int origPos = parsePosition . getIndex ( ) ;
int maxPosIndex = origPos ;
int maxErrorPos = - 1 ;
// First, parse against current pattern.
// Since current pattern could be set by applyPattern(),
// it could be an arbitrary pattern, and it may not be the one
// defined in current locale.
UBool tmpStatus [ fgStatusLength ] ;
ParsePosition tmpPos ( origPos ) ;
DigitList tmpDigitList ;
2009-03-10 20:53:27 +00:00
UBool found ;
2011-04-29 00:00:47 +00:00
if ( fStyle = = UNUM_CURRENCY_PLURAL ) {
2010-01-28 19:39:24 +00:00
found = subparse ( text ,
2009-03-10 20:53:27 +00:00
fNegPrefixPattern , fNegSuffixPattern ,
fPosPrefixPattern , fPosSuffixPattern ,
TRUE , UCURR_LONG_NAME ,
tmpPos , tmpDigitList , tmpStatus , currency ) ;
} else {
2010-01-28 19:39:24 +00:00
found = subparse ( text ,
2009-03-10 20:53:27 +00:00
fNegPrefixPattern , fNegSuffixPattern ,
fPosPrefixPattern , fPosSuffixPattern ,
TRUE , UCURR_SYMBOL_NAME ,
tmpPos , tmpDigitList , tmpStatus , currency ) ;
}
2009-02-12 22:55:29 +00:00
if ( found ) {
if ( tmpPos . getIndex ( ) > maxPosIndex ) {
maxPosIndex = tmpPos . getIndex ( ) ;
for ( int32_t i = 0 ; i < fgStatusLength ; + + i ) {
status [ i ] = tmpStatus [ i ] ;
}
digits = tmpDigitList ;
}
} else {
maxErrorPos = tmpPos . getErrorIndex ( ) ;
}
// Then, parse against affix patterns.
// Those are currency patterns and currency plural patterns.
int32_t pos = - 1 ;
const UHashElement * element = NULL ;
while ( ( element = fAffixPatternsForCurrency - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok valueTok = element - > value ;
const AffixPatternsForCurrency * affixPtn = ( AffixPatternsForCurrency * ) valueTok . pointer ;
UBool tmpStatus [ fgStatusLength ] ;
ParsePosition tmpPos ( origPos ) ;
DigitList tmpDigitList ;
2010-01-28 19:39:24 +00:00
UBool result = subparse ( text ,
2009-02-12 22:55:29 +00:00
& affixPtn - > negPrefixPatternForCurrency ,
2010-01-28 19:39:24 +00:00
& affixPtn - > negSuffixPatternForCurrency ,
& affixPtn - > posPrefixPatternForCurrency ,
2009-02-12 22:55:29 +00:00
& affixPtn - > posSuffixPatternForCurrency ,
2009-03-10 20:53:27 +00:00
TRUE , affixPtn - > patternType ,
2009-02-12 22:55:29 +00:00
tmpPos , tmpDigitList , tmpStatus , currency ) ;
if ( result ) {
found = true ;
if ( tmpPos . getIndex ( ) > maxPosIndex ) {
maxPosIndex = tmpPos . getIndex ( ) ;
for ( int32_t i = 0 ; i < fgStatusLength ; + + i ) {
status [ i ] = tmpStatus [ i ] ;
}
digits = tmpDigitList ;
}
} else {
maxErrorPos = ( tmpPos . getErrorIndex ( ) > maxErrorPos ) ?
tmpPos . getErrorIndex ( ) : maxErrorPos ;
}
}
// Finally, parse against simple affix to find the match.
// For example, in TestMonster suite,
// if the to-be-parsed text is "-\u00A40,00".
// complexAffixCompare will not find match,
// since there is no ISO code matches "\u00A4",
// and the parse stops at "\u00A4".
// We will just use simple affix comparison (look for exact match)
// to pass it.
UBool tmpStatus_2 [ fgStatusLength ] ;
ParsePosition tmpPos_2 ( origPos ) ;
DigitList tmpDigitList_2 ;
// set currencySignCount to 0 so that compareAffix function will
// fall to compareSimpleAffix path, not compareComplexAffix path.
// ?? TODO: is it right? need "false"?
2010-01-28 19:39:24 +00:00
UBool result = subparse ( text ,
2009-02-12 22:55:29 +00:00
& fNegativePrefix , & fNegativeSuffix ,
& fPositivePrefix , & fPositiveSuffix ,
2009-03-10 20:53:27 +00:00
FALSE , UCURR_SYMBOL_NAME ,
2010-01-28 19:39:24 +00:00
tmpPos_2 , tmpDigitList_2 , tmpStatus_2 ,
2009-02-12 22:55:29 +00:00
currency ) ;
if ( result ) {
if ( tmpPos_2 . getIndex ( ) > maxPosIndex ) {
maxPosIndex = tmpPos_2 . getIndex ( ) ;
for ( int32_t i = 0 ; i < fgStatusLength ; + + i ) {
status [ i ] = tmpStatus_2 [ i ] ;
}
digits = tmpDigitList_2 ;
}
found = true ;
} else {
maxErrorPos = ( tmpPos_2 . getErrorIndex ( ) > maxErrorPos ) ?
tmpPos_2 . getErrorIndex ( ) : maxErrorPos ;
}
if ( ! found ) {
//parsePosition.setIndex(origPos);
parsePosition . setErrorIndex ( maxErrorPos ) ;
} else {
parsePosition . setIndex ( maxPosIndex ) ;
parsePosition . setErrorIndex ( - 1 ) ;
}
return found ;
}
1999-08-16 21:50:52 +00:00
/**
* Parse the given text into a number . The text is parsed beginning at
* parsePosition , until an unparseable character is seen .
2004-04-15 06:20:42 +00:00
* @ param text the string to parse .
2009-02-12 22:55:29 +00:00
* @ param negPrefix negative prefix .
* @ param negSuffix negative suffix .
* @ param posPrefix positive prefix .
* @ param posSuffix positive suffix .
* @ param currencyParsing whether it is currency parsing or not .
2009-03-10 20:53:27 +00:00
* @ param type the currency type to parse against , LONG_NAME only or not .
1999-08-16 21:50:52 +00:00
* @ param parsePosition The position at which to being parsing . Upon
2004-04-15 06:20:42 +00:00
* return , the first unparsed character .
* @ param digits the DigitList to set to the parsed value .
* @ param status output param containing boolean status flags indicating
1999-08-16 21:50:52 +00:00
* whether the value was infinite and whether it was positive .
2004-04-15 06:20:42 +00:00
* @ param currency return value for parsed currency , for generic
* currency parsing mode , or NULL for normal parsing . In generic
* currency parsing mode , any currency is parsed , not just the
* currency that this formatter is set to .
1999-08-16 21:50:52 +00:00
*/
2010-01-28 19:39:24 +00:00
UBool DecimalFormat : : subparse ( const UnicodeString & text ,
2009-02-12 22:55:29 +00:00
const UnicodeString * negPrefix ,
const UnicodeString * negSuffix ,
const UnicodeString * posPrefix ,
const UnicodeString * posSuffix ,
UBool currencyParsing ,
2009-03-10 20:53:27 +00:00
int8_t type ,
2009-02-12 22:55:29 +00:00
ParsePosition & parsePosition ,
2004-04-15 06:20:42 +00:00
DigitList & digits , UBool * status ,
UChar * currency ) const
1999-08-16 21:50:52 +00:00
{
2010-02-26 02:29:00 +00:00
// The parsing process builds up the number as char string, in the neutral format that
// will be acceptable to the decNumber library, then at the end passes that string
// off for conversion to a decNumber.
UErrorCode err = U_ZERO_ERROR ;
2010-05-20 21:16:44 +00:00
CharString parsedNum ;
2010-02-26 02:29:00 +00:00
digits . setToZero ( ) ;
2002-03-12 01:32:42 +00:00
int32_t position = parsePosition . getIndex ( ) ;
int32_t oldStart = position ;
2012-05-30 00:41:57 +00:00
int32_t textLength = text . length ( ) ; // One less pointer to follow
2011-05-04 12:23:42 +00:00
UBool strictParse = ! isLenient ( ) ;
2012-05-30 00:41:57 +00:00
UChar32 zero = getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) . char32At ( 0 ) ;
# ifdef FMT_DEBUG
UChar dbgbuf [ 300 ] ;
UnicodeString s ( dbgbuf , 0 , 300 ) ; ;
s . append ( ( UnicodeString ) " PARSE \" " ) . append ( text . tempSubString ( position ) ) . append ( ( UnicodeString ) " \" " ) ;
# define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); }
DBGAPPD ( negPrefix ) ;
DBGAPPD ( negSuffix ) ;
DBGAPPD ( posPrefix ) ;
DBGAPPD ( posSuffix ) ;
debugout ( s ) ;
2012-09-17 19:03:01 +00:00
printf ( " currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d \n " , currencyParsing , fFormatWidth , ( isParseIntegerOnly ( ) ) ? ' Y ' : ' N ' , text . length ( ) , negPrefix ! = NULL ? negPrefix - > length ( ) : - 1 ) ;
2012-05-30 00:41:57 +00:00
# endif
UBool fastParseOk = false ; /* TRUE iff fast parse is OK */
2012-11-30 22:19:58 +00:00
// UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
2012-05-30 00:41:57 +00:00
if ( ! currencyParsing & &
1999-08-16 21:50:52 +00:00
2012-05-30 00:41:57 +00:00
( (
# if UCONFIG_HAVE_PARSEALLINPUT
fParseAllInput = = UNUM_YES ) | |
( fParseAllInput = = UNUM_MAYBE & &
# endif
fFormatWidth = = 0 & &
// (negPrefix!=NULL&&negPrefix->isEmpty()) ||
text . length ( ) > 0 & &
2012-09-17 19:03:01 +00:00
text . length ( ) < 32 & &
2012-05-30 00:41:57 +00:00
( posPrefix = = NULL | | posPrefix - > isEmpty ( ) ) & &
( posSuffix = = NULL | | posSuffix - > isEmpty ( ) ) & &
// (negPrefix==NULL||negPrefix->isEmpty()) &&
// (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
TRUE
)
) ) { // optimized path
int j = position ;
int l = text . length ( ) ;
int digitCount = 0 ;
UChar32 ch = text . char32At ( j ) ;
const UnicodeString * decimalString = & getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ;
UChar32 decimalChar = 0 ;
2012-09-17 19:03:01 +00:00
UBool intOnly = FALSE ;
2012-05-30 00:41:57 +00:00
int32_t decimalCount = decimalString - > countChar32 ( 0 , 3 ) ;
if ( isParseIntegerOnly ( ) ) {
decimalChar = 0 ; // not allowed
2012-09-17 19:03:01 +00:00
intOnly = TRUE ;
2012-05-30 00:41:57 +00:00
} else if ( decimalCount = = 1 ) {
decimalChar = decimalString - > char32At ( 0 ) ;
} else if ( decimalCount = = 0 ) {
decimalChar = 0 ;
} else {
j = l + 1 ; //=break
}
if ( ch = = ' - ' ) {
/* for now- no negs. */
j = l + 1 ; //=break
/*
parsedNum . append ( ' - ' , err ) ;
j + = U16_LENGTH ( ch ) ;
if ( j < l ) ch = text . char32At ( j ) ;
*/
} else {
parsedNum . append ( ' + ' , err ) ;
}
while ( j < l ) {
int32_t digit = ch - zero ;
if ( digit > = 0 & & digit < = 9 ) {
parsedNum . append ( ( char ) ( digit + ' 0 ' ) , err ) ;
if ( ( digitCount > 0 ) | | digit ! = 0 | | j = = ( l - 1 ) ) {
digitCount + + ;
}
} else if ( ch = = decimalChar ) {
parsedNum . append ( ( char ) ( ' . ' ) , err ) ;
decimalChar = 0 ; // no more decimals.
2012-11-30 22:19:58 +00:00
// fastParseHadDecimal=TRUE;
2012-09-17 19:03:01 +00:00
} else if ( intOnly & & ! u_isdigit ( ch ) ) {
break ; // hit a non-integer. (fall through if integer, to slow parse)
2012-05-30 00:41:57 +00:00
} else {
digitCount = - 1 ; // fail
break ;
}
j + = U16_LENGTH ( ch ) ;
ch = text . char32At ( j ) ; // for next
}
2012-09-17 19:03:01 +00:00
if (
( ( j = = l ) | | intOnly )
& & ( digitCount > 0 ) ) {
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
printf ( " PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d! \n " , j , parsedNum . data ( ) , digitCount , fGroupingSize , fGroupingSize2 ) ;
# endif
fastParseOk = true ; // Fast parse OK!
# ifdef SKIP_OPT
debug ( " SKIP_OPT " ) ;
/* for testing, try it the slow way. also */
fastParseOk = false ;
parsedNum . clear ( ) ;
# else
parsePosition . setIndex ( position = j ) ;
status [ fgStatusInfinite ] = false ;
# endif
} else {
// was not OK. reset, retry
# ifdef FMT_DEBUG
printf ( " Fall through: j=%d, l=%d, digitCount=%d \n " , j , l , digitCount ) ;
# endif
parsedNum . clear ( ) ;
}
2012-09-17 19:03:01 +00:00
} else {
# ifdef FMT_DEBUG
printf ( " Could not fastpath parse. " ) ;
printf ( " fFormatWidth=%d " , fFormatWidth ) ;
printf ( " text.length()=%d " , text . length ( ) ) ;
printf ( " posPrefix=%p posSuffix=%p " , posPrefix , posSuffix ) ;
printf ( " \n " ) ;
# endif
2012-05-30 00:41:57 +00:00
}
if ( ! fastParseOk
# if UCONFIG_HAVE_PARSEALLINPUT
& & fParseAllInput ! = UNUM_YES
# endif
)
{
2003-04-21 19:18:27 +00:00
// Match padding before prefix
if ( fFormatWidth > 0 & & fPadPosition = = kPadBeforePrefix ) {
position = skipPadding ( text , position ) ;
}
2003-04-04 20:55:10 +00:00
// Match positive and negative prefixes; prefer longest match.
2009-03-10 20:53:27 +00:00
int32_t posMatch = compareAffix ( text , position , FALSE , TRUE , posPrefix , currencyParsing , type , currency ) ;
2011-05-04 12:23:42 +00:00
int32_t negMatch = compareAffix ( text , position , TRUE , TRUE , negPrefix , currencyParsing , type , currency ) ;
2003-04-04 20:55:10 +00:00
if ( posMatch > = 0 & & negMatch > = 0 ) {
if ( posMatch > negMatch ) {
negMatch = - 1 ;
} else if ( negMatch > posMatch ) {
posMatch = - 1 ;
2010-01-28 19:39:24 +00:00
}
1999-08-16 21:50:52 +00:00
}
2003-04-04 20:55:10 +00:00
if ( posMatch > = 0 ) {
position + = posMatch ;
2010-02-26 02:29:00 +00:00
parsedNum . append ( ' + ' , err ) ;
2003-04-04 20:55:10 +00:00
} else if ( negMatch > = 0 ) {
position + = negMatch ;
2010-02-26 02:29:00 +00:00
parsedNum . append ( ' - ' , err ) ;
2011-05-04 12:23:42 +00:00
} else if ( strictParse ) {
1999-08-16 21:50:52 +00:00
parsePosition . setErrorIndex ( position ) ;
return FALSE ;
2012-02-14 07:05:58 +00:00
} else {
// Temporary set positive. This might be changed after checking suffix
parsedNum . append ( ' + ' , err ) ;
1999-08-16 21:50:52 +00:00
}
2000-10-12 19:04:06 +00:00
2003-04-21 19:18:27 +00:00
// Match padding before prefix
if ( fFormatWidth > 0 & & fPadPosition = = kPadAfterPrefix ) {
position = skipPadding ( text , position ) ;
}
2011-05-04 12:23:42 +00:00
if ( ! strictParse ) {
position = skipUWhiteSpace ( text , position ) ;
}
1999-08-16 21:50:52 +00:00
// process digits or Inf, find decimal position
2002-10-12 01:09:00 +00:00
const UnicodeString * inf = & getConstSymbol ( DecimalFormatSymbols : : kInfinitySymbol ) ;
int32_t infLen = ( text . compare ( position , inf - > length ( ) , * inf )
? 0 : inf - > length ( ) ) ;
2000-10-12 19:04:06 +00:00
position + = infLen ; // infLen is non-zero when it does equal to infinity
2011-05-04 12:23:42 +00:00
status [ fgStatusInfinite ] = infLen ! = 0 ;
if ( infLen ! = 0 ) {
2010-02-26 02:29:00 +00:00
parsedNum . append ( " Infinity " , err ) ;
} else {
1999-08-16 21:50:52 +00:00
// We now have a string of digits, possibly with grouping symbols,
// and decimal points. We want to process these into a DigitList.
// We don't want to put a bunch of leading zeros into the DigitList
// though, so we keep track of the location of the decimal point,
// put only significant digits into the DigitList, and adjust the
// exponent as needed.
2002-10-12 01:09:00 +00:00
2011-05-04 12:23:42 +00:00
UBool strictFail = FALSE ; // did we exit with a strict parse failure?
int32_t lastGroup = - 1 ; // where did we last see a grouping separator?
int32_t digitStart = position ;
int32_t gs2 = fGroupingSize2 = = 0 ? fGroupingSize : fGroupingSize2 ;
const UnicodeString * decimalString ;
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
decimalString = & getConstSymbol ( DecimalFormatSymbols : : kMonetarySeparatorSymbol ) ;
2002-10-12 01:09:00 +00:00
} else {
2011-05-04 12:23:42 +00:00
decimalString = & getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ;
2002-10-12 01:09:00 +00:00
}
2011-05-04 12:23:42 +00:00
const UnicodeString * groupingString = & getConstSymbol ( DecimalFormatSymbols : : kGroupingSeparatorSymbol ) ;
2012-05-30 00:41:57 +00:00
UChar32 decimalChar = decimalString - > char32At ( 0 ) ;
2011-05-04 12:23:42 +00:00
UChar32 groupingChar = groupingString - > char32At ( 0 ) ;
2012-05-30 00:41:57 +00:00
int32_t decimalStringLength = decimalString - > length ( ) ;
int32_t decimalCharLength = U16_LENGTH ( decimalChar ) ;
int32_t groupingStringLength = groupingString - > length ( ) ;
int32_t groupingCharLength = U16_LENGTH ( groupingChar ) ;
2000-05-18 22:08:39 +00:00
UBool sawDecimal = FALSE ;
2011-09-07 14:30:32 +00:00
UChar32 sawDecimalChar = 0xFFFF ;
UBool sawGrouping = FALSE ;
UChar32 sawGroupingChar = 0xFFFF ;
2000-08-07 23:06:28 +00:00
UBool sawDigit = FALSE ;
2000-10-12 19:04:06 +00:00
int32_t backup = - 1 ;
2000-08-07 23:06:28 +00:00
int32_t digit ;
2011-05-04 12:23:42 +00:00
// equivalent grouping and decimal support
2011-09-07 14:30:32 +00:00
const UnicodeSet * decimalSet = NULL ;
const UnicodeSet * groupingSet = NULL ;
2011-05-04 12:23:42 +00:00
if ( decimalCharLength = = decimalStringLength ) {
2011-09-07 14:30:32 +00:00
decimalSet = DecimalFormatStaticSets : : getSimilarDecimals ( decimalChar , strictParse ) ;
2011-05-04 12:23:42 +00:00
}
if ( groupingCharLength = = groupingStringLength ) {
if ( strictParse ) {
2011-09-07 14:30:32 +00:00
groupingSet = DecimalFormatStaticSets : : gStaticSets - > fStrictDefaultGroupingSeparators ;
2011-05-04 12:23:42 +00:00
} else {
2011-09-07 14:30:32 +00:00
groupingSet = DecimalFormatStaticSets : : gStaticSets - > fDefaultGroupingSeparators ;
2011-05-04 12:23:42 +00:00
}
}
2011-09-07 14:30:32 +00:00
// We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
// If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
// If a character matches decimalSet, don't consider it to be a member of the groupingSet.
1999-08-16 21:50:52 +00:00
// We have to track digitCount ourselves, because digits.fCount will
// pin when the maximum allowable digits is reached.
int32_t digitCount = 0 ;
2011-05-04 12:23:42 +00:00
int32_t integerDigitCount = 0 ;
1999-08-16 21:50:52 +00:00
2003-04-21 19:18:27 +00:00
for ( ; position < textLength ; )
1999-08-16 21:50:52 +00:00
{
2003-04-21 19:18:27 +00:00
UChar32 ch = text . char32At ( position ) ;
1999-08-16 21:50:52 +00:00
/* We recognize all digit ranges, not only the Latin digit range
* ' 0 ' . . ' 9 ' . We do so by using the Character . digit ( ) method ,
* which converts a valid Unicode digit to the range 0. .9 .
*
* The character ' ch ' may be a digit . If so , place its value
* from 0 to 9 in ' digit ' . First try using the locale digit ,
* which may or MAY NOT be a standard Unicode digit range . If
* this fails , try using the standard Unicode digit ranges by
2010-01-28 19:39:24 +00:00
* calling Character . digit ( ) . If this also fails , digit will
1999-08-16 21:50:52 +00:00
* have a value outside the range 0. .9 .
*/
2000-08-07 23:06:28 +00:00
digit = ch - zero ;
if ( digit < 0 | | digit > 9 )
{
2001-07-09 22:40:08 +00:00
digit = u_charDigitValue ( ch ) ;
2000-08-07 23:06:28 +00:00
}
2010-08-13 21:23:00 +00:00
// As a last resort, look through the localized digits if the zero digit
// is not a "standard" Unicode digit.
if ( ( digit < 0 | | digit > 9 ) & & u_charDigitValue ( zero ) ! = 0 ) {
digit = 0 ;
if ( getConstSymbol ( ( DecimalFormatSymbols : : ENumberFormatSymbol ) ( DecimalFormatSymbols : : kZeroDigitSymbol ) ) . char32At ( 0 ) = = ch ) {
break ;
}
for ( digit = 1 ; digit < 10 ; digit + + ) {
if ( getConstSymbol ( ( DecimalFormatSymbols : : ENumberFormatSymbol ) ( DecimalFormatSymbols : : kOneDigitSymbol + digit - 1 ) ) . char32At ( 0 ) = = ch ) {
break ;
}
}
}
1999-08-16 21:50:52 +00:00
2010-02-26 02:29:00 +00:00
if ( digit > = 0 & & digit < = 9 )
2000-08-07 23:06:28 +00:00
{
2011-05-04 12:23:42 +00:00
if ( strictParse & & backup ! = - 1 ) {
// comma followed by digit, so group before comma is a
// secondary group. If there was a group separator
// before that, the group must == the secondary group
// length, else it can be <= the the secondary group
// length.
if ( ( lastGroup ! = - 1 & & backup - lastGroup - 1 ! = gs2 ) | |
( lastGroup = = - 1 & & position - digitStart - 1 > gs2 ) ) {
strictFail = TRUE ;
break ;
}
lastGroup = backup ;
}
2000-10-24 16:09:39 +00:00
// Cancel out backup setting (see grouping handler below)
backup = - 1 ;
2000-08-07 23:06:28 +00:00
sawDigit = TRUE ;
2011-05-04 12:23:42 +00:00
// Note: this will append leading zeros
2010-05-20 21:16:44 +00:00
parsedNum . append ( ( char ) ( digit + ' 0 ' ) , err ) ;
2011-05-04 12:23:42 +00:00
// count any digit that's not a leading zero
if ( digit > 0 | | digitCount > 0 | | sawDecimal ) {
digitCount + = 1 ;
// count any integer digit that's not a leading zero
if ( ! sawDecimal ) {
integerDigitCount + = 1 ;
}
}
2003-04-21 19:18:27 +00:00
position + = U16_LENGTH ( ch ) ;
1999-08-16 21:50:52 +00:00
}
2011-09-07 14:30:32 +00:00
else if ( groupingStringLength > 0 & &
matchGrouping ( groupingChar , sawGrouping , sawGroupingChar , groupingSet ,
decimalChar , decimalSet ,
ch ) & & isGroupingUsed ( ) )
1999-08-16 21:50:52 +00:00
{
2011-05-04 12:23:42 +00:00
if ( sawDecimal ) {
break ;
}
if ( strictParse ) {
if ( ( ! sawDigit | | backup ! = - 1 ) ) {
// leading group, or two group separators in a row
strictFail = TRUE ;
break ;
}
}
1999-08-16 21:50:52 +00:00
// Ignore grouping characters, if we are using them, but require
// that they be followed by a digit. Otherwise we backup and
// reprocess them.
backup = position ;
2011-05-04 12:23:42 +00:00
position + = groupingStringLength ;
2011-09-07 14:30:32 +00:00
sawGrouping = TRUE ;
// Once we see a grouping character, we only accept that grouping character from then on.
sawGroupingChar = ch ;
1999-08-16 21:50:52 +00:00
}
2011-09-07 14:30:32 +00:00
else if ( matchDecimal ( decimalChar , sawDecimal , sawDecimalChar , decimalSet , ch ) )
2000-10-12 19:04:06 +00:00
{
2011-05-04 12:23:42 +00:00
if ( strictParse ) {
if ( backup ! = - 1 | |
( lastGroup ! = - 1 & & position - lastGroup ! = fGroupingSize + 1 ) ) {
strictFail = TRUE ;
break ;
}
}
2000-10-12 19:04:06 +00:00
// If we're only parsing integers, or if we ALREADY saw the
// decimal, then don't parse this one.
2011-05-04 12:23:42 +00:00
if ( isParseIntegerOnly ( ) | | sawDecimal ) {
break ;
}
2000-10-24 16:09:39 +00:00
2010-02-26 02:29:00 +00:00
parsedNum . append ( ' . ' , err ) ;
2011-05-04 12:23:42 +00:00
position + = decimalStringLength ;
2000-10-12 19:04:06 +00:00
sawDecimal = TRUE ;
2011-09-07 14:30:32 +00:00
// Once we see a decimal character, we only accept that decimal character from then on.
sawDecimalChar = ch ;
// decimalSet is considered to consist of (ch,ch)
2000-10-12 19:04:06 +00:00
}
2002-10-12 01:09:00 +00:00
else {
2012-10-12 19:52:43 +00:00
if ( ! fBoolFlags . contains ( UNUM_PARSE_NO_EXPONENT ) | | // don't parse if this is set unless..
fUseExponentialNotation /* should be: isScientificNotation() but it is not const (?!) see bug #9619 */ ) { // .. it's an exponent format - ignore setting and parse anyways
const UnicodeString * tmp ;
tmp = & getConstSymbol ( DecimalFormatSymbols : : kExponentialSymbol ) ;
// TODO: CASE
if ( ! text . caseCompare ( position , tmp - > length ( ) , * tmp , U_FOLD_CASE_DEFAULT ) ) // error code is set below if !sawDigit
2000-08-07 23:06:28 +00:00
{
2012-10-12 19:52:43 +00:00
// Parse sign, if present
int32_t pos = position + tmp - > length ( ) ;
char exponentSign = ' + ' ;
if ( pos < textLength )
2002-10-12 01:09:00 +00:00
{
2012-10-12 19:52:43 +00:00
tmp = & getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
2002-10-12 01:09:00 +00:00
if ( ! text . compare ( pos , tmp - > length ( ) , * tmp ) )
{
2003-04-21 19:18:27 +00:00
pos + = tmp - > length ( ) ;
2002-10-12 01:09:00 +00:00
}
2012-10-12 19:52:43 +00:00
else {
tmp = & getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
if ( ! text . compare ( pos , tmp - > length ( ) , * tmp ) )
{
exponentSign = ' - ' ;
pos + = tmp - > length ( ) ;
}
}
2002-10-12 01:09:00 +00:00
}
2000-08-07 23:06:28 +00:00
2012-10-12 19:52:43 +00:00
UBool sawExponentDigit = FALSE ;
while ( pos < textLength ) {
ch = text [ ( int32_t ) pos ] ;
digit = ch - zero ;
2002-10-12 01:09:00 +00:00
2012-10-12 19:52:43 +00:00
if ( digit < 0 | | digit > 9 ) {
digit = u_charDigitValue ( ch ) ;
}
if ( 0 < = digit & & digit < = 9 ) {
if ( ! sawExponentDigit ) {
parsedNum . append ( ' E ' , err ) ;
parsedNum . append ( exponentSign , err ) ;
sawExponentDigit = TRUE ;
}
+ + pos ;
parsedNum . append ( ( char ) ( digit + ' 0 ' ) , err ) ;
} else {
break ;
2010-02-26 02:29:00 +00:00
}
2002-10-12 01:09:00 +00:00
}
2012-10-12 19:52:43 +00:00
if ( sawExponentDigit ) {
position = pos ; // Advance past the exponent
}
1999-08-16 21:50:52 +00:00
2012-10-12 19:52:43 +00:00
break ; // Whether we fail or succeed, we exit this loop
} else {
break ;
}
} else { // not parsing exponent
2002-10-12 01:09:00 +00:00
break ;
2012-10-12 19:52:43 +00:00
}
1999-08-16 21:50:52 +00:00
}
}
2000-08-07 23:06:28 +00:00
if ( backup ! = - 1 )
{
position = backup ;
}
1999-08-16 21:50:52 +00:00
2011-05-04 12:23:42 +00:00
if ( strictParse & & ! sawDecimal ) {
if ( lastGroup ! = - 1 & & position - lastGroup ! = fGroupingSize + 1 ) {
strictFail = TRUE ;
}
}
if ( strictFail ) {
// only set with strictParse and a grouping separator error
parsePosition . setIndex ( oldStart ) ;
parsePosition . setErrorIndex ( position ) ;
2012-05-30 00:41:57 +00:00
debug ( " strictFail! " ) ;
2011-05-04 12:23:42 +00:00
return FALSE ;
}
1999-08-16 21:50:52 +00:00
// If there was no decimal point we have an integer
// If none of the text string was recognized. For example, parse
// "x" with pattern "#0.00" (return index and error index both 0)
// parse "$" with pattern "$#0.00". (return index 0 and error index
// 1).
if ( ! sawDigit & & digitCount = = 0 ) {
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
debug ( " none of text rec " ) ;
printf ( " position=%d \n " , position ) ;
# endif
1999-08-16 21:50:52 +00:00
parsePosition . setIndex ( oldStart ) ;
parsePosition . setErrorIndex ( oldStart ) ;
return FALSE ;
}
}
2003-04-21 19:18:27 +00:00
// Match padding before suffix
if ( fFormatWidth > 0 & & fPadPosition = = kPadBeforeSuffix ) {
position = skipPadding ( text , position ) ;
}
2011-05-04 12:23:42 +00:00
int32_t posSuffixMatch = - 1 , negSuffixMatch = - 1 ;
2003-04-04 20:55:10 +00:00
// Match positive and negative suffixes; prefer longest match.
2011-05-04 12:23:42 +00:00
if ( posMatch > = 0 | | ( ! strictParse & & negMatch < 0 ) ) {
posSuffixMatch = compareAffix ( text , position , FALSE , FALSE , posSuffix , currencyParsing , type , currency ) ;
2000-08-07 23:06:28 +00:00
}
2003-04-04 20:55:10 +00:00
if ( negMatch > = 0 ) {
2011-05-04 12:23:42 +00:00
negSuffixMatch = compareAffix ( text , position , TRUE , FALSE , negSuffix , currencyParsing , type , currency ) ;
2000-08-07 23:06:28 +00:00
}
2011-05-04 12:23:42 +00:00
if ( posSuffixMatch > = 0 & & negSuffixMatch > = 0 ) {
if ( posSuffixMatch > negSuffixMatch ) {
negSuffixMatch = - 1 ;
} else if ( negSuffixMatch > posSuffixMatch ) {
posSuffixMatch = - 1 ;
2010-01-28 19:39:24 +00:00
}
1999-08-16 21:50:52 +00:00
}
2003-04-04 20:55:10 +00:00
// Fail if neither or both
2011-05-04 12:23:42 +00:00
if ( strictParse & & ( ( posSuffixMatch > = 0 ) = = ( negSuffixMatch > = 0 ) ) ) {
1999-08-16 21:50:52 +00:00
parsePosition . setErrorIndex ( position ) ;
2012-05-30 00:41:57 +00:00
debug ( " neither or both " ) ;
1999-08-16 21:50:52 +00:00
return FALSE ;
}
2011-05-04 12:23:42 +00:00
position + = ( posSuffixMatch > = 0 ? posSuffixMatch : ( negSuffixMatch > = 0 ? negSuffixMatch : 0 ) ) ;
2003-04-21 19:18:27 +00:00
// Match padding before suffix
if ( fFormatWidth > 0 & & fPadPosition = = kPadAfterSuffix ) {
position = skipPadding ( text , position ) ;
}
parsePosition . setIndex ( position ) ;
1999-08-16 21:50:52 +00:00
2011-05-04 12:23:42 +00:00
parsedNum . data ( ) [ 0 ] = ( posSuffixMatch > = 0 | | ( ! strictParse & & negMatch < 0 & & negSuffixMatch < 0 ) ) ? ' + ' : ' - ' ;
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
printf ( " PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s \n " , position , parsedNum . data ( ) , parsePosition . getIndex ( ) , oldStart , u_errorName ( err ) ) ;
# endif
} /* end SLOW parse */
if ( parsePosition . getIndex ( ) = = oldStart )
2000-08-07 23:06:28 +00:00
{
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
printf ( " PP didnt move, err \n " ) ;
# endif
1999-08-16 21:50:52 +00:00
parsePosition . setErrorIndex ( position ) ;
return FALSE ;
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_HAVE_PARSEALLINPUT
else if ( fParseAllInput = = UNUM_YES & & parsePosition . getIndex ( ) ! = textLength )
{
# ifdef FMT_DEBUG
printf ( " PP didnt consume all (UNUM_YES), err \n " ) ;
# endif
parsePosition . setErrorIndex ( position ) ;
return FALSE ;
}
# endif
2012-09-17 19:03:01 +00:00
// uint32_t bits = (fastParseOk?kFastpathOk:0) |
// (fastParseHadDecimal?0:kNoDecimal);
//printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
digits . set ( parsedNum . toStringPiece ( ) ,
err ,
0 //bits
) ;
2010-02-26 02:29:00 +00:00
if ( U_FAILURE ( err ) ) {
2012-05-30 00:41:57 +00:00
# ifdef FMT_DEBUG
printf ( " err setting %s \n " , u_errorName ( err ) ) ;
# endif
2010-02-26 02:29:00 +00:00
parsePosition . setErrorIndex ( position ) ;
return FALSE ;
}
1999-08-16 21:50:52 +00:00
return TRUE ;
}
2003-04-21 19:18:27 +00:00
/**
* Starting at position , advance past a run of pad characters , if any .
* Return the index of the first character after position that is not a pad
* character . Result is > = position .
*/
int32_t DecimalFormat : : skipPadding ( const UnicodeString & text , int32_t position ) const {
2003-04-21 22:48:16 +00:00
int32_t padLen = U16_LENGTH ( fPad ) ;
2003-04-21 19:18:27 +00:00
while ( position < text . length ( ) & &
2003-04-21 22:48:16 +00:00
text . char32At ( position ) = = fPad ) {
2003-04-21 19:18:27 +00:00
position + = padLen ;
}
return position ;
}
2003-04-21 22:48:16 +00:00
/**
* Return the length matched by the given affix , or - 1 if none .
* Runs of white space in the affix , match runs of white space in
* the input . Pattern white space and input white space are
* determined differently ; see code .
* @ param text input text
* @ param pos offset into input at which to begin matching
* @ param isNegative
* @ param isPrefix
2009-02-12 22:55:29 +00:00
* @ param affixPat affix pattern used for currency affix comparison .
* @ param currencyParsing whether it is currency parsing or not
2009-03-10 20:53:27 +00:00
* @ param type the currency type to parse against , LONG_NAME only or not .
2004-04-15 06:20:42 +00:00
* @ param currency return value for parsed currency , for generic
* currency parsing mode , or null for normal parsing . In generic
* currency parsing mode , any currency is parsed , not just the
* currency that this formatter is set to .
2003-04-21 22:48:16 +00:00
* @ return length of input that matches , or - 1 if match failure
*/
int32_t DecimalFormat : : compareAffix ( const UnicodeString & text ,
int32_t pos ,
UBool isNegative ,
2004-04-15 06:20:42 +00:00
UBool isPrefix ,
2009-02-12 22:55:29 +00:00
const UnicodeString * affixPat ,
UBool currencyParsing ,
2009-03-10 20:53:27 +00:00
int8_t type ,
2007-03-02 00:28:09 +00:00
UChar * currency ) const
{
const UnicodeString * patternToCompare ;
2009-02-12 22:55:29 +00:00
if ( fCurrencyChoice ! = NULL | | currency ! = NULL | |
( fCurrencySignCount > fgCurrencySignCountZero & & currencyParsing ) ) {
2010-01-28 19:39:24 +00:00
2009-02-12 22:55:29 +00:00
if ( affixPat ! = NULL ) {
2009-03-10 20:53:27 +00:00
return compareComplexAffix ( * affixPat , text , pos , type , currency ) ;
2003-04-21 22:48:16 +00:00
}
}
2010-01-28 19:39:24 +00:00
2007-03-02 00:28:09 +00:00
if ( isNegative ) {
if ( isPrefix ) {
patternToCompare = & fNegativePrefix ;
}
else {
patternToCompare = & fNegativeSuffix ;
}
}
else {
if ( isPrefix ) {
patternToCompare = & fPositivePrefix ;
}
else {
patternToCompare = & fPositiveSuffix ;
}
2003-04-21 22:48:16 +00:00
}
2011-05-04 12:23:42 +00:00
return compareSimpleAffix ( * patternToCompare , text , pos , isLenient ( ) ) ;
2003-04-21 22:48:16 +00:00
}
2003-04-04 20:55:10 +00:00
/**
* Return the length matched by the given affix , or - 1 if none .
* Runs of white space in the affix , match runs of white space in
* the input . Pattern white space and input white space are
* determined differently ; see code .
* @ param affix pattern string , taken as a literal
* @ param input input text
* @ param pos offset into input at which to begin matching
* @ return length of input that matches , or - 1 if match failure
*/
2003-04-21 22:48:16 +00:00
int32_t DecimalFormat : : compareSimpleAffix ( const UnicodeString & affix ,
const UnicodeString & input ,
2011-05-04 12:23:42 +00:00
int32_t pos ,
UBool lenient ) {
2003-04-04 20:55:10 +00:00
int32_t start = pos ;
2011-05-04 12:23:42 +00:00
UChar32 affixChar = affix . char32At ( 0 ) ;
int32_t affixLength = affix . length ( ) ;
int32_t inputLength = input . length ( ) ;
int32_t affixCharLength = U16_LENGTH ( affixChar ) ;
UnicodeSet * affixSet ;
if ( ! lenient ) {
affixSet = DecimalFormatStaticSets : : gStaticSets - > fStrictDashEquivalents ;
// If the affix is exactly one character long and that character
// is in the dash set and the very next input character is also
// in the dash set, return a match.
if ( affixCharLength = = affixLength & & affixSet - > contains ( affixChar ) ) {
if ( affixSet - > contains ( input . char32At ( pos ) ) ) {
return 1 ;
}
}
for ( int32_t i = 0 ; i < affixLength ; ) {
UChar32 c = affix . char32At ( i ) ;
int32_t len = U16_LENGTH ( c ) ;
if ( PatternProps : : isWhiteSpace ( c ) ) {
// We may have a pattern like: \u200F \u0020
// and input text like: \u200F \u0020
// Note that U+200F and U+0020 are Pattern_White_Space but only
// U+0020 is UWhiteSpace. So we have to first do a direct
// match of the run of Pattern_White_Space in the pattern,
// then match any extra characters.
UBool literalMatch = FALSE ;
while ( pos < inputLength & &
input . char32At ( pos ) = = c ) {
literalMatch = TRUE ;
i + = len ;
pos + = len ;
if ( i = = affixLength ) {
break ;
}
c = affix . char32At ( i ) ;
len = U16_LENGTH ( c ) ;
if ( ! PatternProps : : isWhiteSpace ( c ) ) {
break ;
}
2003-05-19 21:06:22 +00:00
}
2011-05-04 12:23:42 +00:00
// Advance over run in pattern
i = skipPatternWhiteSpace ( affix , i ) ;
// Advance over run in input text
// Must see at least one white space char in input,
// unless we've already matched some characters literally.
int32_t s = pos ;
pos = skipUWhiteSpace ( input , pos ) ;
if ( pos = = s & & ! literalMatch ) {
return - 1 ;
2003-05-19 20:04:57 +00:00
}
2011-05-04 12:23:42 +00:00
// If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
// Otherwise, the previous lines may have skipped over text (such as U+00A0) that
// is also in the affix.
i = skipUWhiteSpace ( affix , i ) ;
} else {
if ( pos < inputLength & &
input . char32At ( pos ) = = c ) {
i + = len ;
pos + = len ;
} else {
return - 1 ;
}
}
}
} else {
UBool match = FALSE ;
affixSet = DecimalFormatStaticSets : : gStaticSets - > fDashEquivalents ;
2003-04-04 20:55:10 +00:00
2011-05-04 12:23:42 +00:00
if ( affixCharLength = = affixLength & & affixSet - > contains ( affixChar ) ) {
2003-04-21 22:48:16 +00:00
pos = skipUWhiteSpace ( input , pos ) ;
2011-05-04 12:23:42 +00:00
if ( affixSet - > contains ( input . char32At ( pos ) ) ) {
return pos - start + 1 ;
2003-04-04 20:55:10 +00:00
}
2011-05-04 12:23:42 +00:00
}
2008-06-20 00:43:45 +00:00
2011-05-04 12:23:42 +00:00
for ( int32_t i = 0 ; i < affixLength ; )
{
//i = skipRuleWhiteSpace(affix, i);
2008-06-20 00:43:45 +00:00
i = skipUWhiteSpace ( affix , i ) ;
2011-05-04 12:23:42 +00:00
pos = skipUWhiteSpace ( input , pos ) ;
if ( i > = affixLength | | pos > = inputLength ) {
break ;
}
UChar32 c = affix . char32At ( i ) ;
int32_t len = U16_LENGTH ( c ) ;
if ( input . char32At ( pos ) ! = c ) {
2003-04-04 20:55:10 +00:00
return - 1 ;
}
2011-05-04 12:23:42 +00:00
match = TRUE ;
i + = len ;
pos + = len ;
}
if ( affixLength > 0 & & ! match ) {
return - 1 ;
2003-04-04 20:55:10 +00:00
}
}
return pos - start ;
}
2000-10-24 16:09:39 +00:00
2003-04-21 22:48:16 +00:00
/**
2011-04-26 06:39:29 +00:00
* Skip over a run of zero or more Pattern_White_Space characters at
2003-04-21 22:48:16 +00:00
* pos in text .
*/
2011-04-26 06:39:29 +00:00
int32_t DecimalFormat : : skipPatternWhiteSpace ( const UnicodeString & text , int32_t pos ) {
const UChar * s = text . getBuffer ( ) ;
return ( int32_t ) ( PatternProps : : skipWhiteSpace ( s + pos , text . length ( ) - pos ) - s ) ;
2003-04-21 22:48:16 +00:00
}
/**
* Skip over a run of zero or more isUWhiteSpace ( ) characters at pos
* in text .
*/
int32_t DecimalFormat : : skipUWhiteSpace ( const UnicodeString & text , int32_t pos ) {
while ( pos < text . length ( ) ) {
UChar32 c = text . char32At ( pos ) ;
if ( ! u_isUWhiteSpace ( c ) ) {
break ;
}
pos + = U16_LENGTH ( c ) ;
}
return pos ;
}
/**
* Return the length matched by the given affix , or - 1 if none .
* @ param affixPat pattern string
* @ param input input text
* @ param pos offset into input at which to begin matching
2009-03-10 20:53:27 +00:00
* @ param type the currency type to parse against , LONG_NAME only or not .
2004-04-15 06:20:42 +00:00
* @ param currency return value for parsed currency , for generic
* currency parsing mode , or null for normal parsing . In generic
* currency parsing mode , any currency is parsed , not just the
* currency that this formatter is set to .
2003-04-21 22:48:16 +00:00
* @ return length of input that matches , or - 1 if match failure
*/
int32_t DecimalFormat : : compareComplexAffix ( const UnicodeString & affixPat ,
const UnicodeString & text ,
2004-04-15 06:20:42 +00:00
int32_t pos ,
2009-03-10 20:53:27 +00:00
int8_t type ,
2006-07-10 23:40:17 +00:00
UChar * currency ) const
{
int32_t start = pos ;
2004-04-15 06:20:42 +00:00
U_ASSERT ( currency ! = NULL | |
2009-02-12 22:55:29 +00:00
( fCurrencyChoice ! = NULL & & * getCurrency ( ) ! = 0 ) | |
fCurrencySignCount > fgCurrencySignCountZero ) ;
2003-04-21 22:48:16 +00:00
2010-01-28 19:39:24 +00:00
for ( int32_t i = 0 ;
2009-02-28 02:07:55 +00:00
i < affixPat . length ( ) & & pos > = 0 ; ) {
2003-04-21 22:48:16 +00:00
UChar32 c = affixPat . char32At ( i ) ;
i + = U16_LENGTH ( c ) ;
if ( c = = kQuote ) {
U_ASSERT ( i < = affixPat . length ( ) ) ;
c = affixPat . char32At ( i ) ;
i + = U16_LENGTH ( c ) ;
const UnicodeString * affix = NULL ;
switch ( c ) {
case kCurrencySign : {
2009-02-12 22:55:29 +00:00
// since the currency names in choice format is saved
2010-01-28 19:39:24 +00:00
// the same way as other currency names,
2009-02-12 22:55:29 +00:00
// do not need to do currency choice parsing here.
// the general currency parsing parse against all names,
// including names in choice format.
2003-04-21 22:48:16 +00:00
UBool intl = i < affixPat . length ( ) & &
affixPat . char32At ( i ) = = kCurrencySign ;
2009-02-12 22:55:29 +00:00
if ( intl ) {
+ + i ;
}
UBool plural = i < affixPat . length ( ) & &
affixPat . char32At ( i ) = = kCurrencySign ;
if ( plural ) {
+ + i ;
intl = FALSE ;
}
2004-04-15 06:20:42 +00:00
// Parse generic currency -- anything for which we
// have a display name, or any 3-letter ISO code.
2009-02-12 22:55:29 +00:00
// Try to parse display name for our locale; first
// determine our locale.
const char * loc = fCurrencyPluralInfo - > getLocale ( ) . getName ( ) ;
ParsePosition ppos ( pos ) ;
UChar curr [ 4 ] ;
UErrorCode ec = U_ZERO_ERROR ;
// Delegate parse of display name => ISO code to Currency
2009-03-10 20:53:27 +00:00
uprv_parseCurrency ( loc , text , ppos , type , curr , ec ) ;
2009-02-12 22:55:29 +00:00
// If parse succeeds, populate currency[0]
if ( U_SUCCESS ( ec ) & & ppos . getIndex ( ) ! = pos ) {
if ( currency ) {
2004-04-15 06:20:42 +00:00
u_strcpy ( currency , curr ) ;
2011-07-12 03:22:59 +00:00
} else {
// The formatter is currency-style but the client has not requested
// the value of the parsed currency. In this case, if that value does
// not match the formatter's current value, then the parse fails.
UChar effectiveCurr [ 4 ] ;
getEffectiveCurrency ( effectiveCurr , ec ) ;
if ( U_FAILURE ( ec ) | | u_strncmp ( curr , effectiveCurr , 4 ) ! = 0 ) {
pos = - 1 ;
continue ;
}
2004-04-15 06:20:42 +00:00
}
2009-02-12 22:55:29 +00:00
pos = ppos . getIndex ( ) ;
2011-05-04 12:23:42 +00:00
} else if ( ! isLenient ( ) ) {
2009-02-12 22:55:29 +00:00
pos = - 1 ;
2003-04-21 22:48:16 +00:00
}
continue ;
}
case kPatternPercent :
affix = & getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ;
break ;
case kPatternPerMill :
affix = & getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ;
break ;
case kPatternPlus :
affix = & getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
break ;
case kPatternMinus :
affix = & getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
break ;
default :
// fall through to affix!=0 test, which will fail
break ;
}
if ( affix ! = NULL ) {
pos = match ( text , pos , * affix ) ;
continue ;
}
}
pos = match ( text , pos , c ) ;
2011-04-26 06:39:29 +00:00
if ( PatternProps : : isWhiteSpace ( c ) ) {
i = skipPatternWhiteSpace ( affixPat , i ) ;
2003-04-21 22:48:16 +00:00
}
}
2006-07-10 23:40:17 +00:00
return pos - start ;
2003-04-21 22:48:16 +00:00
}
/**
* Match a single character at text [ pos ] and return the index of the
* next character upon success . Return - 1 on failure . If
2011-04-26 06:39:29 +00:00
* ch is a Pattern_White_Space then match a run of white space in text .
2003-04-21 22:48:16 +00:00
*/
int32_t DecimalFormat : : match ( const UnicodeString & text , int32_t pos , UChar32 ch ) {
2011-04-26 06:39:29 +00:00
if ( PatternProps : : isWhiteSpace ( ch ) ) {
2003-04-21 22:48:16 +00:00
// Advance over run of white space in input text
// Must see at least one white space char in input
int32_t s = pos ;
2011-04-26 06:39:29 +00:00
pos = skipPatternWhiteSpace ( text , pos ) ;
2003-04-21 22:48:16 +00:00
if ( pos = = s ) {
return - 1 ;
}
return pos ;
}
return ( pos > = 0 & & text . char32At ( pos ) = = ch ) ?
( pos + U16_LENGTH ( ch ) ) : - 1 ;
}
/**
* Match a string at text [ pos ] and return the index of the next
* character upon success . Return - 1 on failure . Match a run of
* white space in str with a run of white space in text .
*/
int32_t DecimalFormat : : match ( const UnicodeString & text , int32_t pos , const UnicodeString & str ) {
for ( int32_t i = 0 ; i < str . length ( ) & & pos > = 0 ; ) {
UChar32 ch = str . char32At ( i ) ;
i + = U16_LENGTH ( ch ) ;
2011-04-26 06:39:29 +00:00
if ( PatternProps : : isWhiteSpace ( ch ) ) {
i = skipPatternWhiteSpace ( str , i ) ;
2003-04-21 22:48:16 +00:00
}
pos = match ( text , pos , ch ) ;
}
return pos ;
}
2011-05-04 12:23:42 +00:00
UBool DecimalFormat : : matchSymbol ( const UnicodeString & text , int32_t position , int32_t length , const UnicodeString & symbol ,
UnicodeSet * sset , UChar32 schar )
{
if ( sset ! = NULL ) {
return sset - > contains ( schar ) ;
}
return text . compare ( position , length , symbol ) = = 0 ;
}
2011-09-07 14:30:32 +00:00
UBool DecimalFormat : : matchDecimal ( UChar32 symbolChar ,
UBool sawDecimal , UChar32 sawDecimalChar ,
const UnicodeSet * sset , UChar32 schar ) {
if ( sawDecimal ) {
return schar = = sawDecimalChar ;
} else if ( schar = = symbolChar ) {
return TRUE ;
} else if ( sset ! = NULL ) {
return sset - > contains ( schar ) ;
} else {
return FALSE ;
}
}
UBool DecimalFormat : : matchGrouping ( UChar32 groupingChar ,
UBool sawGrouping , UChar32 sawGroupingChar ,
const UnicodeSet * sset ,
2011-12-12 23:29:51 +00:00
UChar32 /*decimalChar*/ , const UnicodeSet * decimalSet ,
2011-09-07 14:30:32 +00:00
UChar32 schar ) {
if ( sawGrouping ) {
return schar = = sawGroupingChar ; // previously found
} else if ( schar = = groupingChar ) {
return TRUE ; // char from symbols
} else if ( sset ! = NULL ) {
return sset - > contains ( schar ) & & // in groupingSet but...
( ( decimalSet = = NULL ) | | ! decimalSet - > contains ( schar ) ) ; // Exclude decimalSet from groupingSet
} else {
return FALSE ;
}
}
2011-05-04 12:23:42 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the pointer to the localized decimal format symbols
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
const DecimalFormatSymbols *
DecimalFormat : : getDecimalFormatSymbols ( ) const
{
return fSymbols ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// De-owning the current localized symbols and adopt the new symbols.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : adoptDecimalFormatSymbols ( DecimalFormatSymbols * symbolsToAdopt )
{
2003-07-12 00:23:05 +00:00
if ( symbolsToAdopt = = NULL ) {
return ; // do not allow caller to set fSymbols to NULL
}
UBool sameSymbols = FALSE ;
if ( fSymbols ! = NULL ) {
sameSymbols = ( UBool ) ( getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) = =
symbolsToAdopt - > getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) & &
getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) = =
symbolsToAdopt - > getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) ) ;
1999-08-16 21:50:52 +00:00
delete fSymbols ;
2003-07-12 00:23:05 +00:00
}
1999-08-16 21:50:52 +00:00
fSymbols = symbolsToAdopt ;
2003-07-12 00:23:05 +00:00
if ( ! sameSymbols ) {
// If the currency symbols are the same, there is no need to recalculate.
setCurrencyForSymbols ( ) ;
}
2009-02-12 22:55:29 +00:00
expandAffixes ( NULL ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
// Setting the symbols is equlivalent to adopting a newly created localized
// symbols.
void
DecimalFormat : : setDecimalFormatSymbols ( const DecimalFormatSymbols & symbols )
{
adoptDecimalFormatSymbols ( new DecimalFormatSymbols ( symbols ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2009-02-12 22:55:29 +00:00
2010-01-28 19:39:24 +00:00
const CurrencyPluralInfo *
2009-02-12 22:55:29 +00:00
DecimalFormat : : getCurrencyPluralInfo ( void ) const
{
return fCurrencyPluralInfo ;
}
2010-01-28 19:39:24 +00:00
void
2009-02-12 22:55:29 +00:00
DecimalFormat : : adoptCurrencyPluralInfo ( CurrencyPluralInfo * toAdopt )
{
if ( toAdopt ! = NULL ) {
2010-01-28 19:39:24 +00:00
delete fCurrencyPluralInfo ;
2009-02-12 22:55:29 +00:00
fCurrencyPluralInfo = toAdopt ;
// re-set currency affix patterns and currency affixes.
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
UErrorCode status = U_ZERO_ERROR ;
if ( fAffixPatternsForCurrency ) {
deleteHashForAffixPattern ( ) ;
}
setupCurrencyAffixPatterns ( status ) ;
if ( fCurrencySignCount = = fgCurrencySignCountInPluralFormat ) {
// only setup the affixes of the plural pattern.
setupCurrencyAffixes ( fFormatPattern , FALSE , TRUE , status ) ;
}
}
2010-01-28 19:39:24 +00:00
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
2010-01-28 19:39:24 +00:00
void
2009-02-12 22:55:29 +00:00
DecimalFormat : : setCurrencyPluralInfo ( const CurrencyPluralInfo & info )
{
adoptCurrencyPluralInfo ( info . clone ( ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
2002-05-13 19:33:05 +00:00
/**
* Update the currency object to match the symbols . This method
* is used only when the caller has passed in a symbols object
* that may not be the default object for its locale .
*/
void
DecimalFormat : : setCurrencyForSymbols ( ) {
/*Bug 4212072
Update the affix strings accroding to symbols in order to keep
the affix strings up to date .
[ Richard / GCL ]
*/
// With the introduction of the Currency object, the currency
// symbols in the DFS object are ignored. For backward
// compatibility, we check any explicitly set DFS object. If it
// is a default symbols object for its locale, we change the
// currency object to one for that locale. If it is custom,
// we set the currency to null.
UErrorCode ec = U_ZERO_ERROR ;
2003-07-12 00:23:05 +00:00
const UChar * c = NULL ;
const char * loc = fSymbols - > getLocale ( ) . getName ( ) ;
2010-01-28 19:39:24 +00:00
UChar intlCurrencySymbol [ 4 ] ;
2003-11-13 23:24:45 +00:00
ucurr_forLocale ( loc , intlCurrencySymbol , 4 , & ec ) ;
2003-07-12 00:23:05 +00:00
UnicodeString currencySymbol ;
uprv_getStaticCurrencyName ( intlCurrencySymbol , loc , currencySymbol , ec ) ;
if ( U_SUCCESS ( ec )
& & getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) = = currencySymbol
2011-07-07 18:46:19 +00:00
& & getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) = = UnicodeString ( intlCurrencySymbol ) )
2003-07-12 00:23:05 +00:00
{
// Trap an error in mapping locale to currency. If we can't
// map, then don't fail and set the currency to "".
c = intlCurrencySymbol ;
2002-05-13 19:33:05 +00:00
}
2004-02-13 01:53:12 +00:00
ec = U_ZERO_ERROR ; // reset local error code!
2009-02-12 22:55:29 +00:00
setCurrencyInternally ( c , ec ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2002-05-13 19:33:05 +00:00
}
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the positive prefix of the number pattern.
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : getPositivePrefix ( UnicodeString & result ) const
{
result = fPositivePrefix ;
return result ;
}
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Sets the positive prefix of the number pattern.
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : setPositivePrefix ( const UnicodeString & newValue )
{
fPositivePrefix = newValue ;
delete fPosPrefixPattern ;
fPosPrefixPattern = 0 ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the negative prefix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : getNegativePrefix ( UnicodeString & result ) const
{
result = fNegativePrefix ;
return result ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the negative prefix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : setNegativePrefix ( const UnicodeString & newValue )
{
fNegativePrefix = newValue ;
delete fNegPrefixPattern ;
fNegPrefixPattern = 0 ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the positive suffix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : getPositiveSuffix ( UnicodeString & result ) const
{
result = fPositiveSuffix ;
return result ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Sets the positive suffix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : setPositiveSuffix ( const UnicodeString & newValue )
{
fPositiveSuffix = newValue ;
delete fPosSuffixPattern ;
fPosSuffixPattern = 0 ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the negative suffix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : getNegativeSuffix ( UnicodeString & result ) const
{
result = fNegativeSuffix ;
return result ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Sets the negative suffix of the number pattern.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : setNegativeSuffix ( const UnicodeString & newValue )
{
fNegativeSuffix = newValue ;
delete fNegSuffixPattern ;
fNegSuffixPattern = 0 ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the multiplier of the number pattern.
2010-02-26 02:29:00 +00:00
// Multipliers are stored as decimal numbers (DigitLists) because that
// is the most convenient for muliplying or dividing the numbers to be formatted.
// A NULL multiplier implies one, and the scaling operations are skipped.
2000-08-07 23:06:28 +00:00
2010-02-26 02:29:00 +00:00
int32_t
DecimalFormat : : getMultiplier ( ) const
1999-08-16 21:50:52 +00:00
{
2010-02-26 02:29:00 +00:00
if ( fMultiplier = = NULL ) {
return 1 ;
} else {
return fMultiplier - > getLong ( ) ;
}
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Sets the multiplier of the number pattern.
void
DecimalFormat : : setMultiplier ( int32_t newValue )
{
2008-01-14 20:10:54 +00:00
// if (newValue == 0) {
// throw new IllegalArgumentException("Bad multiplier: " + newValue);
// }
2010-02-26 02:29:00 +00:00
if ( newValue = = 0 ) {
newValue = 1 ; // one being the benign default value for a multiplier.
}
if ( newValue = = 1 ) {
delete fMultiplier ;
fMultiplier = NULL ;
} else {
if ( fMultiplier = = NULL ) {
fMultiplier = new DigitList ;
}
if ( fMultiplier ! = NULL ) {
fMultiplier - > set ( newValue ) ;
}
2007-07-17 22:39:44 +00:00
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
/**
* Get the rounding increment .
* @ return A positive rounding increment , or 0.0 if rounding
* is not in effect .
* @ see # setRoundingIncrement
* @ see # getRoundingMode
* @ see # setRoundingMode
*/
2004-03-29 23:23:04 +00:00
double DecimalFormat : : getRoundingIncrement ( ) const {
2010-02-26 02:29:00 +00:00
if ( fRoundingIncrement = = NULL ) {
return 0.0 ;
} else {
return fRoundingIncrement - > getDouble ( ) ;
}
1999-08-16 21:50:52 +00:00
}
/**
* Set the rounding increment . This method also controls whether
* rounding is enabled .
* @ param newValue A positive rounding increment , or 0.0 to disable rounding .
* Negative increments are equivalent to 0.0 .
* @ see # getRoundingIncrement
* @ see # getRoundingMode
* @ see # setRoundingMode
*/
void DecimalFormat : : setRoundingIncrement ( double newValue ) {
if ( newValue > 0.0 ) {
if ( fRoundingIncrement = = NULL ) {
fRoundingIncrement = new DigitList ( ) ;
}
2008-01-11 18:44:41 +00:00
if ( fRoundingIncrement ! = NULL ) {
2010-02-26 02:29:00 +00:00
fRoundingIncrement - > set ( newValue ) ;
2008-02-23 19:15:18 +00:00
return ;
2008-01-11 18:44:41 +00:00
}
2010-01-28 19:39:24 +00:00
}
2008-01-11 18:44:41 +00:00
// These statements are executed if newValue is less than 0.0
// or fRoundingIncrement could not be created.
delete fRoundingIncrement ;
fRoundingIncrement = NULL ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Get the rounding mode .
* @ return A rounding mode
* @ see # setRoundingIncrement
* @ see # getRoundingIncrement
* @ see # setRoundingMode
*/
2004-03-31 22:09:40 +00:00
DecimalFormat : : ERoundingMode DecimalFormat : : getRoundingMode ( ) const {
1999-08-16 21:50:52 +00:00
return fRoundingMode ;
}
/**
* Set the rounding mode . This has no effect unless the rounding
* increment is greater than zero .
* @ param roundingMode A rounding mode
* @ see # setRoundingIncrement
* @ see # getRoundingIncrement
* @ see # getRoundingMode
*/
void DecimalFormat : : setRoundingMode ( ERoundingMode roundingMode ) {
fRoundingMode = roundingMode ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Get the width to which the output of < code > format ( ) < / code > is padded .
* @ return the format width , or zero if no padding is in effect
* @ see # setFormatWidth
* @ see # getPadCharacter
* @ see # setPadCharacter
* @ see # getPadPosition
* @ see # setPadPosition
*/
2004-03-29 23:23:04 +00:00
int32_t DecimalFormat : : getFormatWidth ( ) const {
1999-08-16 21:50:52 +00:00
return fFormatWidth ;
}
/**
* Set the width to which the output of < code > format ( ) < / code > is padded .
* This method also controls whether padding is enabled .
* @ param width the width to which to pad the result of
* < code > format ( ) < / code > , or zero to disable padding . A negative
* width is equivalent to 0.
* @ see # getFormatWidth
* @ see # getPadCharacter
* @ see # setPadCharacter
* @ see # getPadPosition
* @ see # setPadPosition
*/
void DecimalFormat : : setFormatWidth ( int32_t width ) {
fFormatWidth = ( width > 0 ) ? width : 0 ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2004-03-29 23:23:04 +00:00
UnicodeString DecimalFormat : : getPadCharacterString ( ) const {
2011-07-07 18:46:19 +00:00
return UnicodeString ( fPad ) ;
1999-08-16 21:50:52 +00:00
}
2003-04-15 15:58:20 +00:00
void DecimalFormat : : setPadCharacter ( const UnicodeString & padChar ) {
2001-09-17 21:50:19 +00:00
if ( padChar . length ( ) > 0 ) {
2003-04-21 22:48:16 +00:00
fPad = padChar . char32At ( 0 ) ;
2001-09-17 21:50:19 +00:00
}
else {
2003-04-21 22:48:16 +00:00
fPad = kDefaultPad ;
2001-09-17 21:50:19 +00:00
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Get the position at which padding will take place . This is the location
* at which padding will be inserted if the result of < code > format ( ) < / code >
* is shorter than the format width .
* @ return the pad position , one of < code > kPadBeforePrefix < / code > ,
* < code > kPadAfterPrefix < / code > , < code > kPadBeforeSuffix < / code > , or
* < code > kPadAfterSuffix < / code > .
* @ see # setFormatWidth
* @ see # getFormatWidth
* @ see # setPadCharacter
* @ see # getPadCharacter
* @ see # setPadPosition
* @ see # kPadBeforePrefix
* @ see # kPadAfterPrefix
* @ see # kPadBeforeSuffix
* @ see # kPadAfterSuffix
*/
2004-03-29 23:23:04 +00:00
DecimalFormat : : EPadPosition DecimalFormat : : getPadPosition ( ) const {
1999-08-16 21:50:52 +00:00
return fPadPosition ;
}
/**
* < strong > < font face = helvetica color = red > NEW < / font > < / strong >
* Set the position at which padding will take place . This is the location
* at which padding will be inserted if the result of < code > format ( ) < / code >
* is shorter than the format width . This has no effect unless padding is
* enabled .
* @ param padPos the pad position , one of < code > kPadBeforePrefix < / code > ,
* < code > kPadAfterPrefix < / code > , < code > kPadBeforeSuffix < / code > , or
* < code > kPadAfterSuffix < / code > .
* @ see # setFormatWidth
* @ see # getFormatWidth
* @ see # setPadCharacter
* @ see # getPadCharacter
* @ see # getPadPosition
* @ see # kPadBeforePrefix
* @ see # kPadAfterPrefix
* @ see # kPadBeforeSuffix
* @ see # kPadAfterSuffix
*/
void DecimalFormat : : setPadPosition ( EPadPosition padPos ) {
fPadPosition = padPos ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Return whether or not scientific notation is used .
* @ return TRUE if this object formats and parses scientific notation
* @ see # setScientificNotation
* @ see # getMinimumExponentDigits
* @ see # setMinimumExponentDigits
* @ see # isExponentSignAlwaysShown
* @ see # setExponentSignAlwaysShown
*/
2000-05-18 22:08:39 +00:00
UBool DecimalFormat : : isScientificNotation ( ) {
1999-08-16 21:50:52 +00:00
return fUseExponentialNotation ;
}
/**
* Set whether or not scientific notation is used .
* @ param useScientific TRUE if this object formats and parses scientific
* notation
* @ see # isScientificNotation
* @ see # getMinimumExponentDigits
* @ see # setMinimumExponentDigits
* @ see # isExponentSignAlwaysShown
* @ see # setExponentSignAlwaysShown
*/
2000-05-18 22:08:39 +00:00
void DecimalFormat : : setScientificNotation ( UBool useScientific ) {
1999-08-16 21:50:52 +00:00
fUseExponentialNotation = useScientific ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Return the minimum exponent digits that will be shown .
* @ return the minimum exponent digits that will be shown
* @ see # setScientificNotation
* @ see # isScientificNotation
* @ see # setMinimumExponentDigits
* @ see # isExponentSignAlwaysShown
* @ see # setExponentSignAlwaysShown
*/
2004-03-29 23:23:04 +00:00
int8_t DecimalFormat : : getMinimumExponentDigits ( ) const {
1999-08-16 21:50:52 +00:00
return fMinExponentDigits ;
}
/**
* Set the minimum exponent digits that will be shown . This has no
* effect unless scientific notation is in use .
* @ param minExpDig a value > = 1 indicating the fewest exponent digits
* that will be shown . Values less than 1 will be treated as 1.
* @ see # setScientificNotation
* @ see # isScientificNotation
* @ see # getMinimumExponentDigits
* @ see # isExponentSignAlwaysShown
* @ see # setExponentSignAlwaysShown
*/
void DecimalFormat : : setMinimumExponentDigits ( int8_t minExpDig ) {
2000-08-09 20:46:49 +00:00
fMinExponentDigits = ( int8_t ) ( ( minExpDig > 0 ) ? minExpDig : 1 ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Return whether the exponent sign is always shown .
* @ return TRUE if the exponent is always prefixed with either the
* localized minus sign or the localized plus sign , false if only negative
* exponents are prefixed with the localized minus sign .
* @ see # setScientificNotation
* @ see # isScientificNotation
* @ see # setMinimumExponentDigits
* @ see # getMinimumExponentDigits
* @ see # setExponentSignAlwaysShown
*/
2000-05-18 22:08:39 +00:00
UBool DecimalFormat : : isExponentSignAlwaysShown ( ) {
1999-08-16 21:50:52 +00:00
return fExponentSignAlwaysShown ;
}
/**
* Set whether the exponent sign is always shown . This has no effect
* unless scientific notation is in use .
* @ param expSignAlways TRUE if the exponent is always prefixed with either
* the localized minus sign or the localized plus sign , false if only
* negative exponents are prefixed with the localized minus sign .
* @ see # setScientificNotation
* @ see # isScientificNotation
* @ see # setMinimumExponentDigits
* @ see # getMinimumExponentDigits
* @ see # isExponentSignAlwaysShown
*/
2000-05-18 22:08:39 +00:00
void DecimalFormat : : setExponentSignAlwaysShown ( UBool expSignAlways ) {
1999-08-16 21:50:52 +00:00
fExponentSignAlwaysShown = expSignAlways ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
// Gets the grouping size of the number pattern. For example, thousand or 10
// thousand groupings.
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
int32_t
DecimalFormat : : getGroupingSize ( ) const
{
return fGroupingSize ;
}
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Gets the grouping size of the number pattern.
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : setGroupingSize ( int32_t newValue )
{
fGroupingSize = newValue ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
2000-06-07 00:15:59 +00:00
//------------------------------------------------------------------------------
2000-08-07 23:06:28 +00:00
2000-06-07 00:15:59 +00:00
int32_t
DecimalFormat : : getSecondaryGroupingSize ( ) const
{
return fGroupingSize2 ;
}
2000-08-07 23:06:28 +00:00
2000-06-07 00:15:59 +00:00
//------------------------------------------------------------------------------
2000-08-07 23:06:28 +00:00
2000-06-07 00:15:59 +00:00
void
DecimalFormat : : setSecondaryGroupingSize ( int32_t newValue )
{
fGroupingSize2 = newValue ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2000-06-07 00:15:59 +00:00
}
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Checks if to show the decimal separator.
2000-08-07 23:06:28 +00:00
2000-05-18 22:08:39 +00:00
UBool
1999-08-16 21:50:52 +00:00
DecimalFormat : : isDecimalSeparatorAlwaysShown ( ) const
{
return fDecimalSeparatorAlwaysShown ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Sets to always show the decimal separator.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
2000-05-18 22:08:39 +00:00
DecimalFormat : : setDecimalSeparatorAlwaysShown ( UBool newValue )
1999-08-16 21:50:52 +00:00
{
fDecimalSeparatorAlwaysShown = newValue ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Emits the pattern of this DecimalFormat instance.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : toPattern ( UnicodeString & result ) const
{
return toPattern ( result , FALSE ) ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
// Emits the localized pattern this DecimalFormat instance.
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
UnicodeString &
DecimalFormat : : toLocalizedPattern ( UnicodeString & result ) const
{
return toPattern ( result , TRUE ) ;
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
/**
* Expand the affix pattern strings into the expanded affix strings . If any
* affix pattern string is null , do not expand it . This method should be
* called any time the symbols or the affix patterns change in order to keep
* the expanded affix strings up to date .
2009-02-12 22:55:29 +00:00
* This method also will be called before formatting if format currency
2010-01-28 19:39:24 +00:00
* plural names , since the plural name is not a static one , it is
2009-02-12 22:55:29 +00:00
* based on the currency plural count , the affix will be known only
2010-01-28 19:39:24 +00:00
* after the currency plural count is know .
2009-02-12 22:55:29 +00:00
* In which case , the parameter
* ' pluralCount ' will be a non - null currency plural count .
* In all other cases , the ' pluralCount ' is null , which means it is not needed .
1999-08-16 21:50:52 +00:00
*/
2009-02-12 22:55:29 +00:00
void DecimalFormat : : expandAffixes ( const UnicodeString * pluralCount ) {
2009-12-17 22:15:20 +00:00
FieldPositionHandler none ;
1999-08-16 21:50:52 +00:00
if ( fPosPrefixPattern ! = 0 ) {
2009-12-17 22:15:20 +00:00
expandAffix ( * fPosPrefixPattern , fPositivePrefix , 0 , none , FALSE , pluralCount ) ;
1999-08-16 21:50:52 +00:00
}
if ( fPosSuffixPattern ! = 0 ) {
2009-12-17 22:15:20 +00:00
expandAffix ( * fPosSuffixPattern , fPositiveSuffix , 0 , none , FALSE , pluralCount ) ;
1999-08-16 21:50:52 +00:00
}
if ( fNegPrefixPattern ! = 0 ) {
2009-12-17 22:15:20 +00:00
expandAffix ( * fNegPrefixPattern , fNegativePrefix , 0 , none , FALSE , pluralCount ) ;
1999-08-16 21:50:52 +00:00
}
if ( fNegSuffixPattern ! = 0 ) {
2009-12-17 22:15:20 +00:00
expandAffix ( * fNegSuffixPattern , fNegativeSuffix , 0 , none , FALSE , pluralCount ) ;
1999-08-16 21:50:52 +00:00
}
2001-09-17 21:50:19 +00:00
# ifdef FMT_DEBUG
1999-08-16 21:50:52 +00:00
UnicodeString s ;
2012-05-30 00:41:57 +00:00
s . append ( UnicodeString ( " [ " ) )
. append ( DEREFSTR ( fPosPrefixPattern ) ) . append ( ( UnicodeString ) " | " ) . append ( DEREFSTR ( fPosSuffixPattern ) )
. append ( ( UnicodeString ) " ; " ) . append ( DEREFSTR ( fNegPrefixPattern ) ) . append ( ( UnicodeString ) " | " ) . append ( DEREFSTR ( fNegSuffixPattern ) )
. append ( ( UnicodeString ) " ]->[ " )
. append ( fPositivePrefix ) . append ( ( UnicodeString ) " | " ) . append ( fPositiveSuffix )
. append ( ( UnicodeString ) " ; " ) . append ( fNegativePrefix ) . append ( ( UnicodeString ) " | " ) . append ( fNegativeSuffix )
. append ( ( UnicodeString ) " ] \n " ) ;
1999-08-16 21:50:52 +00:00
debugout ( s ) ;
# endif
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
/**
* Expand an affix pattern into an affix string . All characters in the
* pattern are literal unless prefixed by kQuote . The following characters
* after kQuote are recognized : PATTERN_PERCENT , PATTERN_PER_MILLE ,
* PATTERN_MINUS , and kCurrencySign . If kCurrencySign is doubled ( kQuote +
* kCurrencySign + kCurrencySign ) , it is interpreted as an international
2010-01-28 19:39:24 +00:00
* currency sign . If CURRENCY_SIGN is tripled , it is interpreted as
2009-02-12 22:55:29 +00:00
* currency plural long names , such as " US Dollars " .
* Any other character after a kQuote represents itself .
1999-08-16 21:50:52 +00:00
* kQuote must be followed by another character ; kQuote may not occur by
* itself at the end of the pattern .
*
2003-04-21 22:48:16 +00:00
* This method is used in two distinct ways . First , it is used to expand
* the stored affix patterns into actual affixes . For this usage , doFormat
* must be false . Second , it is used to expand the stored affix patterns
* given a specific number ( doFormat = = true ) , for those rare cases in
* which a currency format references a ChoiceFormat ( e . g . , en_IN display
* name for INR ) . The number itself is taken from digitList .
*
* When used in the first way , this method has a side effect : It sets
* currencyChoice to a ChoiceFormat object , if the currency ' s display name
* in this locale is a ChoiceFormat pattern ( very rare ) . It only does this
* if currencyChoice is null to start with .
*
1999-08-16 21:50:52 +00:00
* @ param pattern the non - null , fPossibly empty pattern
2002-11-23 01:11:50 +00:00
* @ param affix string to receive the expanded equivalent of pattern .
* Previous contents are deleted .
2003-04-21 22:48:16 +00:00
* @ param doFormat if false , then the pattern will be expanded , and if a
* currency symbol is encountered that expands to a ChoiceFormat , the
* currencyChoice member variable will be initialized if it is null . If
* doFormat is true , then it is assumed that the currencyChoice has been
* created , and it will be used to format the value in digitList .
2009-02-12 22:55:29 +00:00
* @ param pluralCount the plural count . It is only used for currency
* plural format . In which case , it is the plural
* count of the currency amount . For example ,
* in en_US , it is the singular " one " , or the plural
* " other " . For all other cases , it is null , and
* is not being used .
1999-08-16 21:50:52 +00:00
*/
void DecimalFormat : : expandAffix ( const UnicodeString & pattern ,
2003-04-21 22:48:16 +00:00
UnicodeString & affix ,
double number ,
2009-12-17 22:15:20 +00:00
FieldPositionHandler & handler ,
2009-02-12 22:55:29 +00:00
UBool doFormat ,
const UnicodeString * pluralCount ) const {
1999-08-16 21:50:52 +00:00
affix . remove ( ) ;
1999-12-08 02:11:04 +00:00
for ( int i = 0 ; i < pattern . length ( ) ; ) {
2003-04-21 22:48:16 +00:00
UChar32 c = pattern . char32At ( i ) ;
i + = U16_LENGTH ( c ) ;
1999-08-16 21:50:52 +00:00
if ( c = = kQuote ) {
2003-04-21 22:48:16 +00:00
c = pattern . char32At ( i ) ;
i + = U16_LENGTH ( c ) ;
2009-12-17 22:15:20 +00:00
int beginIdx = affix . length ( ) ;
1999-08-16 21:50:52 +00:00
switch ( c ) {
2002-05-13 19:33:05 +00:00
case kCurrencySign : {
// As of ICU 2.2 we use the currency object, and
// ignore the currency symbols in the DFS, unless
// we have a null currency object. This occurs if
// resurrecting a pre-2.2 object or if the user
// sets a custom DFS.
UBool intl = i < pattern . length ( ) & &
pattern . char32At ( i ) = = kCurrencySign ;
2009-02-12 22:55:29 +00:00
UBool plural = FALSE ;
2002-05-13 19:33:05 +00:00
if ( intl ) {
+ + i ;
2009-02-12 22:55:29 +00:00
plural = i < pattern . length ( ) & &
pattern . char32At ( i ) = = kCurrencySign ;
if ( plural ) {
intl = FALSE ;
+ + i ;
}
1999-08-16 21:50:52 +00:00
}
2003-06-11 23:02:19 +00:00
const UChar * currencyUChars = getCurrency ( ) ;
if ( currencyUChars [ 0 ] ! = 0 ) {
2002-08-23 17:54:40 +00:00
UErrorCode ec = U_ZERO_ERROR ;
2009-02-12 22:55:29 +00:00
if ( plural & & pluralCount ! = NULL ) {
// plural name is only needed when pluralCount != null,
// which means when formatting currency plural names.
// For other cases, pluralCount == null,
// and plural names are not needed.
int32_t len ;
2011-06-03 05:23:57 +00:00
CharString pluralCountChar ;
pluralCountChar . appendInvariantChars ( * pluralCount , ec ) ;
2009-02-12 22:55:29 +00:00
UBool isChoiceFormat ;
const UChar * s = ucurr_getPluralName ( currencyUChars ,
fSymbols ! = NULL ? fSymbols - > getLocale ( ) . getName ( ) :
Locale : : getDefault ( ) . getName ( ) , & isChoiceFormat ,
2011-06-03 05:23:57 +00:00
pluralCountChar . data ( ) , & len , & ec ) ;
2009-02-12 22:55:29 +00:00
affix + = UnicodeString ( s , len ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kCurrencyField , beginIdx , affix . length ( ) ) ;
2009-02-12 22:55:29 +00:00
} else if ( intl ) {
2011-07-07 18:46:19 +00:00
affix . append ( currencyUChars , - 1 ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kCurrencyField , beginIdx , affix . length ( ) ) ;
2002-10-12 01:09:00 +00:00
} else {
int32_t len ;
2003-04-11 20:02:25 +00:00
UBool isChoiceFormat ;
2008-01-11 18:44:41 +00:00
// If fSymbols is NULL, use default locale
2010-01-28 19:39:24 +00:00
const UChar * s = ucurr_getName ( currencyUChars ,
2009-12-17 22:15:20 +00:00
fSymbols ! = NULL ? fSymbols - > getLocale ( ) . getName ( ) : Locale : : getDefault ( ) . getName ( ) ,
UCURR_SYMBOL_NAME , & isChoiceFormat , & len , & ec ) ;
2003-04-11 20:02:25 +00:00
if ( isChoiceFormat ) {
2003-04-21 22:48:16 +00:00
// Two modes here: If doFormat is false, we set up
// currencyChoice. If doFormat is true, we use the
// previously created currencyChoice to format the
// value in digitList.
if ( ! doFormat ) {
// If the currency is handled by a ChoiceFormat,
// then we're not going to use the expanded
// patterns. Instantiate the ChoiceFormat and
// return.
if ( fCurrencyChoice = = NULL ) {
// TODO Replace double-check with proper thread-safe code
2011-07-07 18:46:19 +00:00
ChoiceFormat * fmt = new ChoiceFormat ( UnicodeString ( s ) , ec ) ;
2003-04-21 22:48:16 +00:00
if ( U_SUCCESS ( ec ) ) {
umtx_lock ( NULL ) ;
if ( fCurrencyChoice = = NULL ) {
// Cast away const
( ( DecimalFormat * ) this ) - > fCurrencyChoice = fmt ;
fmt = NULL ;
}
umtx_unlock ( NULL ) ;
delete fmt ;
}
}
// We could almost return null or "" here, since the
// expanded affixes are almost not used at all
// in this situation. However, one method --
// toPattern() -- still does use the expanded
// affixes, in order to set up a padding
// pattern. We use the CURRENCY_SIGN as a
// placeholder.
affix . append ( kCurrencySign ) ;
} else {
if ( fCurrencyChoice ! = NULL ) {
FieldPosition pos ( 0 ) ; // ignored
if ( number < 0 ) {
number = - number ;
}
fCurrencyChoice - > format ( number , affix , pos ) ;
} else {
// We only arrive here if the currency choice
// format in the locale data is INVALID.
2011-07-07 18:46:19 +00:00
affix . append ( currencyUChars , - 1 ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kCurrencyField , beginIdx , affix . length ( ) ) ;
2003-04-21 22:48:16 +00:00
}
}
continue ;
2003-04-11 20:02:25 +00:00
}
affix + = UnicodeString ( s , len ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kCurrencyField , beginIdx , affix . length ( ) ) ;
2002-10-12 01:09:00 +00:00
}
2002-05-13 19:33:05 +00:00
} else {
2002-10-12 01:09:00 +00:00
if ( intl ) {
affix + = getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) ;
} else {
affix + = getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) ;
}
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kCurrencyField , beginIdx , affix . length ( ) ) ;
2002-05-13 19:33:05 +00:00
}
break ;
2002-10-12 01:09:00 +00:00
}
1999-08-16 21:50:52 +00:00
case kPatternPercent :
2002-10-12 01:09:00 +00:00
affix + = getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kPercentField , beginIdx , affix . length ( ) ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternPerMill :
2002-10-12 01:09:00 +00:00
affix + = getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kPermillField , beginIdx , affix . length ( ) ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternPlus :
2002-10-12 01:09:00 +00:00
affix + = getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kSignField , beginIdx , affix . length ( ) ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternMinus :
2002-10-12 01:09:00 +00:00
affix + = getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
2009-12-17 22:15:20 +00:00
handler . addAttribute ( kSignField , beginIdx , affix . length ( ) ) ;
2001-09-17 21:50:19 +00:00
break ;
default :
affix . append ( c ) ;
1999-08-16 21:50:52 +00:00
break ;
}
}
2001-09-17 21:50:19 +00:00
else {
affix . append ( c ) ;
}
1999-08-16 21:50:52 +00:00
}
}
2000-08-07 23:06:28 +00:00
2003-04-21 22:48:16 +00:00
/**
* Append an affix to the given StringBuffer .
* @ param buf buffer to append to
* @ param isNegative
* @ param isPrefix
*/
int32_t DecimalFormat : : appendAffix ( UnicodeString & buf , double number ,
2009-12-17 22:15:20 +00:00
FieldPositionHandler & handler ,
2003-04-21 22:48:16 +00:00
UBool isNegative , UBool isPrefix ) const {
2009-02-12 22:55:29 +00:00
// plural format precedes choice format
2010-01-28 19:39:24 +00:00
if ( fCurrencyChoice ! = 0 & &
2009-02-12 22:55:29 +00:00
fCurrencySignCount ! = fgCurrencySignCountInPluralFormat ) {
2007-07-17 21:46:59 +00:00
const UnicodeString * affixPat ;
2003-04-21 22:48:16 +00:00
if ( isPrefix ) {
affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern ;
} else {
affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern ;
}
2007-07-17 21:46:59 +00:00
if ( affixPat ) {
UnicodeString affixBuf ;
2009-12-17 22:15:20 +00:00
expandAffix ( * affixPat , affixBuf , number , handler , TRUE , NULL ) ;
2007-07-17 21:46:59 +00:00
buf . append ( affixBuf ) ;
return affixBuf . length ( ) ;
}
// else someone called a function that reset the pattern.
2003-04-21 22:48:16 +00:00
}
2010-01-28 19:39:24 +00:00
2007-07-17 21:46:59 +00:00
const UnicodeString * affix ;
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount = = fgCurrencySignCountInPluralFormat ) {
UnicodeString pluralCount = fCurrencyPluralInfo - > getPluralRules ( ) - > select ( number ) ;
AffixesForCurrency * oneSet ;
2011-04-29 00:00:47 +00:00
if ( fStyle = = UNUM_CURRENCY_PLURAL ) {
2009-02-12 22:55:29 +00:00
oneSet = ( AffixesForCurrency * ) fPluralAffixesForCurrency - > get ( pluralCount ) ;
} else {
oneSet = ( AffixesForCurrency * ) fAffixesForCurrency - > get ( pluralCount ) ;
}
if ( isPrefix ) {
2010-01-28 19:39:24 +00:00
affix = isNegative ? & oneSet - > negPrefixForCurrency :
2009-02-12 22:55:29 +00:00
& oneSet - > posPrefixForCurrency ;
} else {
2010-01-28 19:39:24 +00:00
affix = isNegative ? & oneSet - > negSuffixForCurrency :
2009-02-12 22:55:29 +00:00
& oneSet - > posSuffixForCurrency ;
}
2003-04-21 22:48:16 +00:00
} else {
2009-02-12 22:55:29 +00:00
if ( isPrefix ) {
affix = isNegative ? & fNegativePrefix : & fPositivePrefix ;
} else {
affix = isNegative ? & fNegativeSuffix : & fPositiveSuffix ;
}
2003-04-21 22:48:16 +00:00
}
2009-12-17 22:15:20 +00:00
int32_t begin = ( int ) buf . length ( ) ;
2003-04-21 22:48:16 +00:00
buf . append ( * affix ) ;
2009-12-17 22:15:20 +00:00
if ( handler . isRecording ( ) ) {
int32_t offset = ( int ) ( * affix ) . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) ) ;
if ( offset > - 1 ) {
UnicodeString aff = getConstSymbol ( DecimalFormatSymbols : : kCurrencySymbol ) ;
handler . addAttribute ( kCurrencyField , begin + offset , begin + offset + aff . length ( ) ) ;
}
offset = ( int ) ( * affix ) . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) ) ;
if ( offset > - 1 ) {
UnicodeString aff = getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) ;
handler . addAttribute ( kCurrencyField , begin + offset , begin + offset + aff . length ( ) ) ;
}
offset = ( int ) ( * affix ) . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ) ;
if ( offset > - 1 ) {
UnicodeString aff = getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
handler . addAttribute ( kSignField , begin + offset , begin + offset + aff . length ( ) ) ;
}
offset = ( int ) ( * affix ) . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ) ;
if ( offset > - 1 ) {
UnicodeString aff = getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ;
handler . addAttribute ( kPercentField , begin + offset , begin + offset + aff . length ( ) ) ;
}
offset = ( int ) ( * affix ) . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ) ;
if ( offset > - 1 ) {
UnicodeString aff = getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ;
handler . addAttribute ( kPermillField , begin + offset , begin + offset + aff . length ( ) ) ;
}
}
2003-04-21 22:48:16 +00:00
return affix - > length ( ) ;
}
1999-08-16 21:50:52 +00:00
/**
* Appends an affix pattern to the given StringBuffer , quoting special
* characters as needed . Uses the internal affix pattern , if that exists ,
* or the literal affix , if the internal affix pattern is null . The
* appended string will generate the same affix pattern ( or literal affix )
* when passed to toPattern ( ) .
*
2002-11-23 01:11:50 +00:00
* @ param appendTo the affix string is appended to this
1999-08-16 21:50:52 +00:00
* @ param affixPattern a pattern such as fPosPrefixPattern ; may be null
* @ param expAffix a corresponding expanded affix , such as fPositivePrefix .
* Ignored unless affixPattern is null . If affixPattern is null , then
* expAffix is appended as a literal affix .
* @ param localized true if the appended pattern should contain localized
* pattern characters ; otherwise , non - localized pattern chars are appended
*/
2003-04-21 22:48:16 +00:00
void DecimalFormat : : appendAffixPattern ( UnicodeString & appendTo ,
const UnicodeString * affixPattern ,
const UnicodeString & expAffix ,
UBool localized ) const {
1999-08-16 21:50:52 +00:00
if ( affixPattern = = 0 ) {
2003-04-21 22:48:16 +00:00
appendAffixPattern ( appendTo , expAffix , localized ) ;
1999-08-16 21:50:52 +00:00
} else {
int i ;
1999-12-08 02:11:04 +00:00
for ( int pos = 0 ; pos < affixPattern - > length ( ) ; pos = i ) {
1999-08-16 21:50:52 +00:00
i = affixPattern - > indexOf ( kQuote , pos ) ;
if ( i < 0 ) {
UnicodeString s ;
1999-12-08 02:11:04 +00:00
affixPattern - > extractBetween ( pos , affixPattern - > length ( ) , s ) ;
2003-04-21 22:48:16 +00:00
appendAffixPattern ( appendTo , s , localized ) ;
1999-08-16 21:50:52 +00:00
break ;
}
if ( i > pos ) {
UnicodeString s ;
affixPattern - > extractBetween ( pos , i , s ) ;
2003-04-21 22:48:16 +00:00
appendAffixPattern ( appendTo , s , localized ) ;
1999-08-16 21:50:52 +00:00
}
2001-09-17 21:50:19 +00:00
UChar32 c = affixPattern - > char32At ( + + i ) ;
1999-08-16 21:50:52 +00:00
+ + i ;
if ( c = = kQuote ) {
2002-11-23 01:11:50 +00:00
appendTo . append ( c ) . append ( c ) ;
1999-08-16 21:50:52 +00:00
// Fall through and append another kQuote below
} else if ( c = = kCurrencySign & &
1999-12-08 02:11:04 +00:00
i < affixPattern - > length ( ) & &
2001-09-17 21:50:19 +00:00
affixPattern - > char32At ( i ) = = kCurrencySign ) {
1999-08-16 21:50:52 +00:00
+ + i ;
2002-11-23 01:11:50 +00:00
appendTo . append ( c ) . append ( c ) ;
1999-08-16 21:50:52 +00:00
} else if ( localized ) {
switch ( c ) {
case kPatternPercent :
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternPerMill :
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternPlus :
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
1999-08-16 21:50:52 +00:00
break ;
case kPatternMinus :
2002-11-23 01:11:50 +00:00
appendTo + = getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ;
1999-08-16 21:50:52 +00:00
break ;
2001-09-17 21:50:19 +00:00
default :
2002-11-23 01:11:50 +00:00
appendTo . append ( c ) ;
1999-08-16 21:50:52 +00:00
}
2001-09-17 21:50:19 +00:00
} else {
2002-11-23 01:11:50 +00:00
appendTo . append ( c ) ;
1999-08-16 21:50:52 +00:00
}
}
}
}
/**
* Append an affix to the given StringBuffer , using quotes if
* there are special characters . Single quotes themselves must be
* escaped in either case .
*/
void
2003-04-21 22:48:16 +00:00
DecimalFormat : : appendAffixPattern ( UnicodeString & appendTo ,
const UnicodeString & affix ,
UBool localized ) const {
2000-05-18 22:08:39 +00:00
UBool needQuote ;
1999-08-16 21:50:52 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
needQuote = affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kGroupingSeparatorSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kDigitSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPatternSeparatorSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ) > = 0
| | affix . indexOf ( getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ) > = 0
1999-08-16 21:50:52 +00:00
| | affix . indexOf ( kCurrencySign ) > = 0 ;
}
else {
needQuote = affix . indexOf ( kPatternZeroDigit ) > = 0
| | affix . indexOf ( kPatternGroupingSeparator ) > = 0
| | affix . indexOf ( kPatternDecimalSeparator ) > = 0
| | affix . indexOf ( kPatternPercent ) > = 0
| | affix . indexOf ( kPatternPerMill ) > = 0
| | affix . indexOf ( kPatternDigit ) > = 0
| | affix . indexOf ( kPatternSeparator ) > = 0
| | affix . indexOf ( kPatternExponent ) > = 0
| | affix . indexOf ( kPatternPlus ) > = 0
| | affix . indexOf ( kPatternMinus ) > = 0
| | affix . indexOf ( kCurrencySign ) > = 0 ;
}
if ( needQuote )
2002-11-23 01:11:50 +00:00
appendTo + = ( UChar ) 0x0027 /*'\''*/ ;
2000-04-03 23:53:59 +00:00
if ( affix . indexOf ( ( UChar ) 0x0027 /*'\''*/ ) < 0 )
2002-11-23 01:11:50 +00:00
appendTo + = affix ;
1999-08-16 21:50:52 +00:00
else {
2003-04-21 22:48:16 +00:00
for ( int32_t j = 0 ; j < affix . length ( ) ; ) {
2001-09-20 21:34:19 +00:00
UChar32 c = affix . char32At ( j ) ;
2003-04-21 22:48:16 +00:00
j + = U16_LENGTH ( c ) ;
2002-11-23 01:11:50 +00:00
appendTo + = c ;
2000-10-12 19:04:06 +00:00
if ( c = = 0x0027 /*'\''*/ )
2002-11-23 01:11:50 +00:00
appendTo + = c ;
1999-08-16 21:50:52 +00:00
}
}
2000-10-12 19:04:06 +00:00
if ( needQuote )
2002-11-23 01:11:50 +00:00
appendTo + = ( UChar ) 0x0027 /*'\''*/ ;
1999-08-16 21:50:52 +00:00
}
//------------------------------------------------------------------------------
UnicodeString &
2000-05-18 22:08:39 +00:00
DecimalFormat : : toPattern ( UnicodeString & result , UBool localized ) const
1999-08-16 21:50:52 +00:00
{
2011-04-29 00:00:47 +00:00
if ( fStyle = = UNUM_CURRENCY_PLURAL ) {
2009-02-12 22:55:29 +00:00
// the prefix or suffix pattern might not be defined yet,
// so they can not be synthesized,
// instead, get them directly.
// but it might not be the actual pattern used in formatting.
2010-01-28 19:39:24 +00:00
// the actual pattern used in formatting depends on the
2009-02-12 22:55:29 +00:00
// formatted number's plural count.
result = fFormatPattern ;
return result ;
}
1999-08-16 21:50:52 +00:00
result . remove ( ) ;
2004-04-29 18:54:22 +00:00
UChar32 zero , sigDigit = kPatternSignificantDigit ;
2002-10-12 01:09:00 +00:00
UnicodeString digit , group ;
1999-08-16 21:50:52 +00:00
int32_t i ;
int32_t roundingDecimalPos = 0 ; // Pos of decimal in roundingDigits
UnicodeString roundingDigits ;
int32_t padPos = ( fFormatWidth > 0 ) ? fPadPosition : - 1 ;
UnicodeString padSpec ;
2004-04-12 23:37:44 +00:00
UBool useSigDig = areSignificantDigitsUsed ( ) ;
2001-09-17 21:50:19 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
digit . append ( getConstSymbol ( DecimalFormatSymbols : : kDigitSymbol ) ) ;
group . append ( getConstSymbol ( DecimalFormatSymbols : : kGroupingSeparatorSymbol ) ) ;
zero = getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) . char32At ( 0 ) ;
2004-04-29 18:54:22 +00:00
if ( useSigDig ) {
sigDigit = getConstSymbol ( DecimalFormatSymbols : : kSignificantDigitSymbol ) . char32At ( 0 ) ;
}
2001-09-17 21:50:19 +00:00
}
else {
digit . append ( ( UChar ) kPatternDigit ) ;
group . append ( ( UChar ) kPatternGroupingSeparator ) ;
zero = ( UChar32 ) kPatternZeroDigit ;
}
2000-10-12 19:04:06 +00:00
if ( fFormatWidth > 0 ) {
2001-09-17 21:50:19 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
padSpec . append ( getConstSymbol ( DecimalFormatSymbols : : kPadEscapeSymbol ) ) ;
2001-09-17 21:50:19 +00:00
}
else {
padSpec . append ( ( UChar ) kPatternPadEscape ) ;
}
padSpec . append ( fPad ) ;
1999-08-16 21:50:52 +00:00
}
2000-10-12 19:04:06 +00:00
if ( fRoundingIncrement ! = NULL ) {
2010-02-26 02:29:00 +00:00
for ( i = 0 ; i < fRoundingIncrement - > getCount ( ) ; + + i ) {
2010-07-28 16:08:12 +00:00
roundingDigits . append ( zero + ( fRoundingIncrement - > getDigitValue ( i ) ) ) ; // Convert to Unicode digit
2001-09-17 21:50:19 +00:00
}
2010-02-26 02:29:00 +00:00
roundingDecimalPos = fRoundingIncrement - > getDecimalAt ( ) ;
1999-08-16 21:50:52 +00:00
}
for ( int32_t part = 0 ; part < 2 ; + + part ) {
2000-08-07 23:06:28 +00:00
if ( padPos = = kPadBeforePrefix ) {
result . append ( padSpec ) ;
}
2003-04-21 22:48:16 +00:00
appendAffixPattern ( result ,
2000-08-07 23:06:28 +00:00
( part = = 0 ? fPosPrefixPattern : fNegPrefixPattern ) ,
( part = = 0 ? fPositivePrefix : fNegativePrefix ) ,
localized ) ;
2001-09-27 22:46:58 +00:00
if ( padPos = = kPadAfterPrefix & & ! padSpec . isEmpty ( ) ) {
2000-08-07 23:06:28 +00:00
result . append ( padSpec ) ;
}
int32_t sub0Start = result . length ( ) ;
2004-03-25 17:42:28 +00:00
int32_t g = isGroupingUsed ( ) ? _max ( 0 , fGroupingSize ) : 0 ;
2000-08-07 23:06:28 +00:00
if ( g > 0 & & fGroupingSize2 > 0 & & fGroupingSize2 ! = fGroupingSize ) {
g + = fGroupingSize2 ;
}
2004-03-25 17:42:28 +00:00
int32_t maxDig = 0 , minDig = 0 , maxSigDig = 0 ;
if ( useSigDig ) {
minDig = getMinimumSignificantDigits ( ) ;
maxDig = maxSigDig = getMaximumSignificantDigits ( ) ;
} else {
minDig = getMinimumIntegerDigits ( ) ;
maxDig = getMaximumIntegerDigits ( ) ;
}
2003-10-29 00:20:05 +00:00
if ( fUseExponentialNotation ) {
2004-03-25 17:42:28 +00:00
if ( maxDig > kMaxScientificIntegerDigits ) {
maxDig = 1 ;
2003-10-29 00:20:05 +00:00
}
2004-03-25 17:42:28 +00:00
} else if ( useSigDig ) {
maxDig = _max ( maxDig , g + 1 ) ;
2003-10-29 00:20:05 +00:00
} else {
2004-03-25 17:42:28 +00:00
maxDig = _max ( _max ( g , getMinimumIntegerDigits ( ) ) ,
roundingDecimalPos ) + 1 ;
2003-10-29 00:20:05 +00:00
}
2004-03-25 17:42:28 +00:00
for ( i = maxDig ; i > 0 ; - - i ) {
if ( ! fUseExponentialNotation & & i < maxDig & &
2000-08-07 23:06:28 +00:00
isGroupingPosition ( i ) ) {
result . append ( group ) ;
}
2004-03-25 17:42:28 +00:00
if ( useSigDig ) {
// #@,@### (maxSigDig == 5, minSigDig == 2)
// 65 4321 (1-based pos, count from the right)
// Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig)
// Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig
if ( maxSigDig > = i & & i > ( maxSigDig - minDig ) ) {
result . append ( sigDigit ) ;
} else {
result . append ( digit ) ;
}
} else {
if ( ! roundingDigits . isEmpty ( ) ) {
int32_t pos = roundingDecimalPos - i ;
if ( pos > = 0 & & pos < roundingDigits . length ( ) ) {
result . append ( ( UChar ) ( roundingDigits . char32At ( pos ) - kPatternZeroDigit + zero ) ) ;
continue ;
}
}
if ( i < = minDig ) {
result . append ( zero ) ;
} else {
result . append ( digit ) ;
2000-08-07 23:06:28 +00:00
}
2001-09-18 20:40:48 +00:00
}
2000-08-07 23:06:28 +00:00
}
2004-03-25 17:42:28 +00:00
if ( ! useSigDig ) {
if ( getMaximumFractionDigits ( ) > 0 | | fDecimalSeparatorAlwaysShown ) {
if ( localized ) {
result + = getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ;
}
else {
result . append ( ( UChar ) kPatternDecimalSeparator ) ;
}
2001-09-17 21:50:19 +00:00
}
2004-03-25 17:42:28 +00:00
int32_t pos = roundingDecimalPos ;
for ( i = 0 ; i < getMaximumFractionDigits ( ) ; + + i ) {
if ( ! roundingDigits . isEmpty ( ) & & pos < roundingDigits . length ( ) ) {
if ( pos < 0 ) {
result . append ( zero ) ;
}
else {
result . append ( ( UChar ) ( roundingDigits . char32At ( pos ) - kPatternZeroDigit + zero ) ) ;
}
+ + pos ;
continue ;
}
if ( i < getMinimumFractionDigits ( ) ) {
2001-09-18 20:40:48 +00:00
result . append ( zero ) ;
}
else {
2004-03-25 17:42:28 +00:00
result . append ( digit ) ;
2001-09-18 20:40:48 +00:00
}
2001-09-18 22:17:21 +00:00
}
1999-08-16 21:50:52 +00:00
}
if ( fUseExponentialNotation ) {
2001-09-17 21:50:19 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
result + = getConstSymbol ( DecimalFormatSymbols : : kExponentialSymbol ) ;
2001-09-17 21:50:19 +00:00
}
else {
result . append ( ( UChar ) kPatternExponent ) ;
}
1999-08-16 21:50:52 +00:00
if ( fExponentSignAlwaysShown ) {
2001-09-17 21:50:19 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
result + = getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ;
2001-09-17 21:50:19 +00:00
}
else {
result . append ( ( UChar ) kPatternPlus ) ;
}
1999-08-16 21:50:52 +00:00
}
for ( i = 0 ; i < fMinExponentDigits ; + + i ) {
result . append ( zero ) ;
}
}
2001-09-27 22:46:58 +00:00
if ( ! padSpec . isEmpty ( ) & & ! fUseExponentialNotation ) {
1999-08-16 21:50:52 +00:00
int32_t add = fFormatWidth - result . length ( ) + sub0Start
- ( ( part = = 0 )
? fPositivePrefix . length ( ) + fPositiveSuffix . length ( )
: fNegativePrefix . length ( ) + fNegativeSuffix . length ( ) ) ;
while ( add > 0 ) {
result . insert ( sub0Start , digit ) ;
2004-03-25 17:42:28 +00:00
+ + maxDig ;
1999-08-16 21:50:52 +00:00
- - add ;
2000-06-07 00:15:59 +00:00
// Only add a grouping separator if we have at least
// 2 additional characters to be added, so we don't
// end up with ",###".
2004-03-25 17:42:28 +00:00
if ( add > 1 & & isGroupingPosition ( maxDig ) ) {
1999-08-16 21:50:52 +00:00
result . insert ( sub0Start , group ) ;
2010-01-28 19:39:24 +00:00
- - add ;
1999-08-16 21:50:52 +00:00
}
}
}
2001-09-27 22:46:58 +00:00
if ( fPadPosition = = kPadBeforeSuffix & & ! padSpec . isEmpty ( ) ) {
1999-08-16 21:50:52 +00:00
result . append ( padSpec ) ;
}
if ( part = = 0 ) {
2003-04-21 22:48:16 +00:00
appendAffixPattern ( result , fPosSuffixPattern , fPositiveSuffix , localized ) ;
2001-09-27 22:46:58 +00:00
if ( fPadPosition = = kPadAfterSuffix & & ! padSpec . isEmpty ( ) ) {
1999-08-16 21:50:52 +00:00
result . append ( padSpec ) ;
}
2000-05-18 22:08:39 +00:00
UBool isDefault = FALSE ;
1999-08-16 21:50:52 +00:00
if ( ( fNegSuffixPattern = = fPosSuffixPattern & & // both null
fNegativeSuffix = = fPositiveSuffix )
| | ( fNegSuffixPattern ! = 0 & & fPosSuffixPattern ! = 0 & &
2001-09-17 21:50:19 +00:00
* fNegSuffixPattern = = * fPosSuffixPattern ) )
{
if ( fNegPrefixPattern ! = NULL & & fPosPrefixPattern ! = NULL )
{
1999-08-16 21:50:52 +00:00
int32_t length = fPosPrefixPattern - > length ( ) ;
isDefault = fNegPrefixPattern - > length ( ) = = ( length + 2 ) & &
2002-03-12 01:32:42 +00:00
( * fNegPrefixPattern ) [ ( int32_t ) 0 ] = = kQuote & &
( * fNegPrefixPattern ) [ ( int32_t ) 1 ] = = kPatternMinus & &
1999-08-16 21:50:52 +00:00
fNegPrefixPattern - > compare ( 2 , length , * fPosPrefixPattern , 0 , length ) = = 0 ;
}
if ( ! isDefault & &
2001-09-17 21:50:19 +00:00
fNegPrefixPattern = = NULL & & fPosPrefixPattern = = NULL )
{
1999-08-16 21:50:52 +00:00
int32_t length = fPositivePrefix . length ( ) ;
isDefault = fNegativePrefix . length ( ) = = ( length + 1 ) & &
2002-10-12 01:09:00 +00:00
fNegativePrefix . compare ( getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ) = = 0 & &
1999-08-16 21:50:52 +00:00
fNegativePrefix . compare ( 1 , length , fPositivePrefix , 0 , length ) = = 0 ;
}
}
if ( isDefault ) {
break ; // Don't output default negative subpattern
} else {
2001-09-17 21:50:19 +00:00
if ( localized ) {
2002-10-12 01:09:00 +00:00
result + = getConstSymbol ( DecimalFormatSymbols : : kPatternSeparatorSymbol ) ;
2001-09-17 21:50:19 +00:00
}
else {
result . append ( ( UChar ) kPatternSeparator ) ;
}
1999-08-16 21:50:52 +00:00
}
} else {
2003-04-21 22:48:16 +00:00
appendAffixPattern ( result , fNegSuffixPattern , fNegativeSuffix , localized ) ;
2001-09-27 22:46:58 +00:00
if ( fPadPosition = = kPadAfterSuffix & & ! padSpec . isEmpty ( ) ) {
1999-08-16 21:50:52 +00:00
result . append ( padSpec ) ;
}
}
}
return result ;
}
//------------------------------------------------------------------------------
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : applyPattern ( const UnicodeString & pattern , UErrorCode & status )
{
2001-08-16 00:55:16 +00:00
UParseError parseError ;
applyPattern ( pattern , FALSE , parseError , status ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
2000-08-07 23:06:28 +00:00
2001-08-16 00:55:16 +00:00
void
DecimalFormat : : applyPattern ( const UnicodeString & pattern ,
2010-01-28 19:39:24 +00:00
UParseError & parseError ,
2001-08-16 00:55:16 +00:00
UErrorCode & status )
{
applyPattern ( pattern , FALSE , parseError , status ) ;
}
//------------------------------------------------------------------------------
1999-08-16 21:50:52 +00:00
void
DecimalFormat : : applyLocalizedPattern ( const UnicodeString & pattern , UErrorCode & status )
{
2001-08-16 00:55:16 +00:00
UParseError parseError ;
applyPattern ( pattern , TRUE , parseError , status ) ;
}
//------------------------------------------------------------------------------
void
DecimalFormat : : applyLocalizedPattern ( const UnicodeString & pattern ,
UParseError & parseError ,
UErrorCode & status )
{
applyPattern ( pattern , TRUE , parseError , status ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
//------------------------------------------------------------------------------
void
2009-02-12 22:55:29 +00:00
DecimalFormat : : applyPatternWithoutExpandAffix ( const UnicodeString & pattern ,
UBool localized ,
UParseError & parseError ,
UErrorCode & status )
1999-08-16 21:50:52 +00:00
{
2000-10-12 19:04:06 +00:00
if ( U_FAILURE ( status ) )
2001-08-16 00:55:16 +00:00
{
2000-10-12 19:04:06 +00:00
return ;
2001-08-16 00:55:16 +00:00
}
// Clear error struct
2001-11-15 21:13:37 +00:00
parseError . offset = - 1 ;
2001-08-16 00:55:16 +00:00
parseError . preContext [ 0 ] = parseError . postContext [ 0 ] = ( UChar ) 0 ;
1999-08-16 21:50:52 +00:00
// Set the significant pattern symbols
2004-03-25 17:42:28 +00:00
UChar32 zeroDigit = kPatternZeroDigit ; // '0'
UChar32 sigDigit = kPatternSignificantDigit ; // '@'
2001-09-17 21:50:19 +00:00
UnicodeString groupingSeparator ( ( UChar ) kPatternGroupingSeparator ) ;
UnicodeString decimalSeparator ( ( UChar ) kPatternDecimalSeparator ) ;
UnicodeString percent ( ( UChar ) kPatternPercent ) ;
UnicodeString perMill ( ( UChar ) kPatternPerMill ) ;
2004-03-25 17:42:28 +00:00
UnicodeString digit ( ( UChar ) kPatternDigit ) ; // '#'
2001-09-17 21:50:19 +00:00
UnicodeString separator ( ( UChar ) kPatternSeparator ) ;
UnicodeString exponent ( ( UChar ) kPatternExponent ) ;
UnicodeString plus ( ( UChar ) kPatternPlus ) ;
UnicodeString minus ( ( UChar ) kPatternMinus ) ;
UnicodeString padEscape ( ( UChar ) kPatternPadEscape ) ;
1999-08-16 21:50:52 +00:00
// Substitute with the localized symbols if necessary
if ( localized ) {
2002-10-12 01:09:00 +00:00
zeroDigit = getConstSymbol ( DecimalFormatSymbols : : kZeroDigitSymbol ) . char32At ( 0 ) ;
2004-03-25 17:42:28 +00:00
sigDigit = getConstSymbol ( DecimalFormatSymbols : : kSignificantDigitSymbol ) . char32At ( 0 ) ;
2002-10-12 01:09:00 +00:00
groupingSeparator . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kGroupingSeparatorSymbol ) ) ;
decimalSeparator . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kDecimalSeparatorSymbol ) ) ;
percent . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kPercentSymbol ) ) ;
perMill . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kPerMillSymbol ) ) ;
digit . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kDigitSymbol ) ) ;
separator . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kPatternSeparatorSymbol ) ) ;
exponent . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kExponentialSymbol ) ) ;
plus . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kPlusSignSymbol ) ) ;
minus . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kMinusSignSymbol ) ) ;
padEscape . remove ( ) . append ( getConstSymbol ( DecimalFormatSymbols : : kPadEscapeSymbol ) ) ;
1999-08-16 21:50:52 +00:00
}
2000-08-09 20:46:49 +00:00
UChar nineDigit = ( UChar ) ( zeroDigit + 9 ) ;
2001-09-17 21:50:19 +00:00
int32_t digitLen = digit . length ( ) ;
int32_t groupSepLen = groupingSeparator . length ( ) ;
int32_t decimalSepLen = decimalSeparator . length ( ) ;
1999-08-16 21:50:52 +00:00
2002-03-12 01:32:42 +00:00
int32_t pos = 0 ;
2001-09-17 21:50:19 +00:00
int32_t patLen = pattern . length ( ) ;
1999-08-16 21:50:52 +00:00
// Part 0 is the positive pattern. Part 1, if present, is the negative
// pattern.
2001-09-17 21:50:19 +00:00
for ( int32_t part = 0 ; part < 2 & & pos < patLen ; + + part ) {
1999-08-16 21:50:52 +00:00
// The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
// 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
// between the prefix and suffix, and consists of pattern
// characters. In the prefix and suffix, percent, perMill, and
// currency symbols are recognized and translated.
int32_t subpart = 1 , sub0Start = 0 , sub0Limit = 0 , sub2Limit = 0 ;
2000-08-07 23:06:28 +00:00
1999-08-16 21:50:52 +00:00
// It's important that we don't change any fields of this object
// prematurely. We set the following variables for the multiplier,
// grouping, etc., and then only change the actual object fields if
// everything parses correctly. This also lets us register
// the data from part 0 and ignore the part 1, except for the
// prefix and suffix.
UnicodeString prefix ;
UnicodeString suffix ;
int32_t decimalPos = - 1 ;
int32_t multiplier = 1 ;
2004-03-25 17:42:28 +00:00
int32_t digitLeftCount = 0 , zeroDigitCount = 0 , digitRightCount = 0 , sigDigitCount = 0 ;
1999-08-16 21:50:52 +00:00
int8_t groupingCount = - 1 ;
2000-06-07 00:15:59 +00:00
int8_t groupingCount2 = - 1 ;
1999-08-16 21:50:52 +00:00
int32_t padPos = - 1 ;
2003-12-02 01:55:53 +00:00
UChar32 padChar = 0 ;
1999-08-16 21:50:52 +00:00
int32_t roundingPos = - 1 ;
DigitList roundingInc ;
int8_t expDigits = - 1 ;
2000-05-18 22:08:39 +00:00
UBool expSignAlways = FALSE ;
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
// The affix is either the prefix or the suffix.
UnicodeString * affix = & prefix ;
2010-01-28 19:39:24 +00:00
1999-08-16 21:50:52 +00:00
int32_t start = pos ;
2000-05-18 22:08:39 +00:00
UBool isPartDone = FALSE ;
2001-09-17 21:50:19 +00:00
UChar32 ch ;
1999-08-16 21:50:52 +00:00
2004-03-25 17:42:28 +00:00
for ( ; ! isPartDone & & pos < patLen ; ) {
2001-09-17 21:50:19 +00:00
// Todo: account for surrogate pairs
ch = pattern . char32At ( pos ) ;
1999-08-16 21:50:52 +00:00
switch ( subpart ) {
case 0 : // Pattern proper subpart (between prefix & suffix)
// Process the digits, decimal, and grouping characters. We
// record five pieces of information. We expect the digits
// to occur in the pattern ####00.00####, and we record the
// number of left digits, zero (central) digits, and right
// digits. The position of the last grouping character is
// recorded (should be somewhere within the first two blocks
// of characters), as is the position of the decimal point,
// if any (should be in the zero digits). If there is no
// decimal point, then there should be no right digits.
2001-09-17 21:50:19 +00:00
if ( pattern . compare ( pos , digitLen , digit ) = = 0 ) {
2004-03-25 17:42:28 +00:00
if ( zeroDigitCount > 0 | | sigDigitCount > 0 ) {
1999-08-16 21:50:52 +00:00
+ + digitRightCount ;
} else {
+ + digitLeftCount ;
}
if ( groupingCount > = 0 & & decimalPos < 0 ) {
+ + groupingCount ;
}
2001-09-17 21:50:19 +00:00
pos + = digitLen ;
2004-03-25 17:42:28 +00:00
} else if ( ( ch > = zeroDigit & & ch < = nineDigit ) | |
ch = = sigDigit ) {
1999-08-16 21:50:52 +00:00
if ( digitRightCount > 0 ) {
// Unexpected '0'
debug ( " Unexpected '0' " )
2001-08-17 02:20:35 +00:00
status = U_UNEXPECTED_TOKEN ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
2004-03-25 17:42:28 +00:00
if ( ch = = sigDigit ) {
+ + sigDigitCount ;
} else {
if ( ch ! = zeroDigit & & roundingPos < 0 ) {
roundingPos = digitLeftCount + zeroDigitCount ;
}
if ( roundingPos > = 0 ) {
roundingInc . append ( ( char ) ( ch - zeroDigit + ' 0 ' ) ) ;
}
2012-02-13 19:23:47 +00:00
+ + zeroDigitCount ;
2004-03-25 17:42:28 +00:00
}
1999-08-16 21:50:52 +00:00
if ( groupingCount > = 0 & & decimalPos < 0 ) {
+ + groupingCount ;
}
2004-03-25 17:42:28 +00:00
pos + = U16_LENGTH ( ch ) ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , groupSepLen , groupingSeparator ) = = 0 ) {
1999-08-16 21:50:52 +00:00
if ( decimalPos > = 0 ) {
// Grouping separator after decimal
debug ( " Grouping separator after decimal " )
2001-08-17 02:20:35 +00:00
status = U_UNEXPECTED_TOKEN ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
2000-06-07 00:15:59 +00:00
groupingCount2 = groupingCount ;
1999-08-16 21:50:52 +00:00
groupingCount = 0 ;
2001-09-17 21:50:19 +00:00
pos + = groupSepLen ;
} else if ( pattern . compare ( pos , decimalSepLen , decimalSeparator ) = = 0 ) {
1999-08-16 21:50:52 +00:00
if ( decimalPos > = 0 ) {
// Multiple decimal separators
debug ( " Multiple decimal separators " )
2002-12-11 22:28:34 +00:00
status = U_MULTIPLE_DECIMAL_SEPARATORS ;
2001-08-17 02:20:35 +00:00
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
// Intentionally incorporate the digitRightCount,
// even though it is illegal for this to be > 0
// at this point. We check pattern syntax below.
decimalPos = digitLeftCount + zeroDigitCount + digitRightCount ;
2001-09-17 21:50:19 +00:00
pos + = decimalSepLen ;
1999-08-16 21:50:52 +00:00
} else {
2001-09-17 21:50:19 +00:00
if ( pattern . compare ( pos , exponent . length ( ) , exponent ) = = 0 ) {
1999-08-16 21:50:52 +00:00
if ( expDigits > = 0 ) {
// Multiple exponential symbols
debug ( " Multiple exponential symbols " )
2001-08-17 02:20:35 +00:00
status = U_MULTIPLE_EXPONENTIAL_SYMBOLS ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
if ( groupingCount > = 0 ) {
// Grouping separator in exponential pattern
debug ( " Grouping separator in exponential pattern " )
2001-08-17 02:20:35 +00:00
status = U_MALFORMED_EXPONENTIAL_PATTERN ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
2004-03-25 17:42:28 +00:00
pos + = exponent . length ( ) ;
1999-08-16 21:50:52 +00:00
// Check for positive prefix
2004-03-25 17:42:28 +00:00
if ( pos < patLen
& & pattern . compare ( pos , plus . length ( ) , plus ) = = 0 ) {
1999-08-16 21:50:52 +00:00
expSignAlways = TRUE ;
2001-09-17 21:50:19 +00:00
pos + = plus . length ( ) ;
1999-08-16 21:50:52 +00:00
}
// Use lookahead to parse out the exponential part of the
// pattern, then jump into suffix subpart.
expDigits = 0 ;
2004-03-25 17:42:28 +00:00
while ( pos < patLen & &
pattern . char32At ( pos ) = = zeroDigit ) {
1999-08-16 21:50:52 +00:00
+ + expDigits ;
2004-03-25 17:42:28 +00:00
pos + = U16_LENGTH ( zeroDigit ) ;
1999-08-16 21:50:52 +00:00
}
2004-03-25 17:42:28 +00:00
// 1. Require at least one mantissa pattern digit
// 2. Disallow "#+ @" in mantissa
// 3. Require at least one exponent pattern digit
if ( ( ( digitLeftCount + zeroDigitCount ) < 1 & &
( sigDigitCount + digitRightCount ) < 1 ) | |
( sigDigitCount > 0 & & digitLeftCount > 0 ) | |
1999-08-16 21:50:52 +00:00
expDigits < 1 ) {
// Malformed exponential pattern
debug ( " Malformed exponential pattern " )
2001-08-17 02:20:35 +00:00
status = U_MALFORMED_EXPONENTIAL_PATTERN ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
}
// Transition to suffix subpart
subpart = 2 ; // suffix subpart
affix = & suffix ;
2001-09-17 21:50:19 +00:00
sub0Limit = pos ;
1999-08-16 21:50:52 +00:00
continue ;
}
break ;
case 1 : // Prefix subpart
case 2 : // Suffix subpart
// Process the prefix / suffix characters
// Process unquoted characters seen in prefix or suffix
// subpart.
2004-02-20 19:38:59 +00:00
// Several syntax characters implicitly begins the
// next subpart if we are in the prefix; otherwise
// they are illegal if unquoted.
if ( ! pattern . compare ( pos , digitLen , digit ) | |
! pattern . compare ( pos , groupSepLen , groupingSeparator ) | |
! pattern . compare ( pos , decimalSepLen , decimalSeparator ) | |
2004-03-25 17:42:28 +00:00
( ch > = zeroDigit & & ch < = nineDigit ) | |
ch = = sigDigit ) {
1999-08-16 21:50:52 +00:00
if ( subpart = = 1 ) { // prefix subpart
subpart = 0 ; // pattern proper subpart
2001-09-17 21:50:19 +00:00
sub0Start = pos ; // Reprocess this character
1999-08-16 21:50:52 +00:00
continue ;
2004-02-20 19:38:59 +00:00
} else {
status = U_UNQUOTED_SPECIAL ;
syntaxError ( pattern , pos , parseError ) ;
return ;
1999-08-16 21:50:52 +00:00
}
} else if ( ch = = kCurrencySign ) {
2004-03-25 17:42:28 +00:00
affix - > append ( kQuote ) ; // Encode currency
1999-08-16 21:50:52 +00:00
// Use lookahead to determine if the currency sign is
// doubled or not.
2004-03-25 17:42:28 +00:00
U_ASSERT ( U16_LENGTH ( kCurrencySign ) = = 1 ) ;
if ( ( pos + 1 ) < pattern . length ( ) & & pattern [ pos + 1 ] = = kCurrencySign ) {
1999-08-16 21:50:52 +00:00
affix - > append ( kCurrencySign ) ;
+ + pos ; // Skip over the doubled character
2010-01-28 19:39:24 +00:00
if ( ( pos + 1 ) < pattern . length ( ) & &
2009-02-12 22:55:29 +00:00
pattern [ pos + 1 ] = = kCurrencySign ) {
affix - > append ( kCurrencySign ) ;
+ + pos ; // Skip over the doubled character
fCurrencySignCount = fgCurrencySignCountInPluralFormat ;
} else {
fCurrencySignCount = fgCurrencySignCountInISOFormat ;
}
} else {
fCurrencySignCount = fgCurrencySignCountInSymbolFormat ;
1999-08-16 21:50:52 +00:00
}
// Fall through to append(ch)
} else if ( ch = = kQuote ) {
// A quote outside quotes indicates either the opening
// quote or two quotes, which is a quote literal. That is,
// we have the first quote in 'do' or o''clock.
2004-03-25 17:42:28 +00:00
U_ASSERT ( U16_LENGTH ( kQuote ) = = 1 ) ;
2001-09-17 21:50:19 +00:00
+ + pos ;
if ( pos < pattern . length ( ) & & pattern [ pos ] = = kQuote ) {
1999-08-16 21:50:52 +00:00
affix - > append ( kQuote ) ; // Encode quote
// Fall through to append(ch)
} else {
subpart + = 2 ; // open quote
continue ;
}
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , separator . length ( ) , separator ) = = 0 ) {
1999-08-16 21:50:52 +00:00
// Don't allow separators in the prefix, and don't allow
// separators in the second pattern (part == 1).
if ( subpart = = 1 | | part = = 1 ) {
// Unexpected separator
debug ( " Unexpected separator " )
2001-08-17 02:20:35 +00:00
status = U_UNEXPECTED_TOKEN ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
sub2Limit = pos ;
isPartDone = TRUE ; // Go to next part
2001-09-17 21:50:19 +00:00
pos + = separator . length ( ) ;
1999-08-16 21:50:52 +00:00
break ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , percent . length ( ) , percent ) = = 0 ) {
1999-08-16 21:50:52 +00:00
// Next handle characters which are appended directly.
if ( multiplier ! = 1 ) {
// Too many percent/perMill characters
2001-09-17 21:50:19 +00:00
debug ( " Too many percent characters " )
2001-08-17 02:20:35 +00:00
status = U_MULTIPLE_PERCENT_SYMBOLS ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
affix - > append ( kQuote ) ; // Encode percent/perMill
2004-03-25 17:42:28 +00:00
affix - > append ( kPatternPercent ) ; // Use unlocalized pattern char
2001-09-17 21:50:19 +00:00
multiplier = 100 ;
pos + = percent . length ( ) ;
2004-03-25 17:42:28 +00:00
break ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , perMill . length ( ) , perMill ) = = 0 ) {
// Next handle characters which are appended directly.
if ( multiplier ! = 1 ) {
// Too many percent/perMill characters
debug ( " Too many perMill characters " )
status = U_MULTIPLE_PERMILL_SYMBOLS ;
syntaxError ( pattern , pos , parseError ) ;
return ;
1999-08-16 21:50:52 +00:00
}
2001-09-17 21:50:19 +00:00
affix - > append ( kQuote ) ; // Encode percent/perMill
2004-03-25 17:42:28 +00:00
affix - > append ( kPatternPerMill ) ; // Use unlocalized pattern char
2001-09-17 21:50:19 +00:00
multiplier = 1000 ;
pos + = perMill . length ( ) ;
2004-03-25 17:42:28 +00:00
break ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , padEscape . length ( ) , padEscape ) = = 0 ) {
1999-08-16 21:50:52 +00:00
if ( padPos > = 0 | | // Multiple pad specifiers
1999-12-08 02:11:04 +00:00
( pos + 1 ) = = pattern . length ( ) ) { // Nothing after padEscape
1999-08-16 21:50:52 +00:00
debug ( " Multiple pad specifiers " )
2001-08-17 02:20:35 +00:00
status = U_MULTIPLE_PAD_SPECIFIERS ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
padPos = pos ;
2003-04-21 22:48:16 +00:00
pos + = padEscape . length ( ) ;
padChar = pattern . char32At ( pos ) ;
pos + = U16_LENGTH ( padChar ) ;
2004-03-25 17:42:28 +00:00
break ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , minus . length ( ) , minus ) = = 0 ) {
1999-08-16 21:50:52 +00:00
affix - > append ( kQuote ) ; // Encode minus
2004-03-25 17:42:28 +00:00
affix - > append ( kPatternMinus ) ;
2001-09-17 21:50:19 +00:00
pos + = minus . length ( ) ;
2004-03-25 17:42:28 +00:00
break ;
2001-09-17 21:50:19 +00:00
} else if ( pattern . compare ( pos , plus . length ( ) , plus ) = = 0 ) {
1999-08-16 21:50:52 +00:00
affix - > append ( kQuote ) ; // Encode plus
2004-03-25 17:42:28 +00:00
affix - > append ( kPatternPlus ) ;
2001-09-17 21:50:19 +00:00
pos + = plus . length ( ) ;
2004-03-25 17:42:28 +00:00
break ;
1999-08-16 21:50:52 +00:00
}
// Unquoted, non-special characters fall through to here, as
// well as other code which needs to append something to the
// affix.
affix - > append ( ch ) ;
2004-03-25 17:42:28 +00:00
pos + = U16_LENGTH ( ch ) ;
1999-08-16 21:50:52 +00:00
break ;
case 3 : // Prefix subpart, in quote
case 4 : // Suffix subpart, in quote
// A quote within quotes indicates either the closing
// quote or two quotes, which is a quote literal. That is,
// we have the second quote in 'do' or 'don''t'.
if ( ch = = kQuote ) {
2004-03-25 17:42:28 +00:00
+ + pos ;
2001-09-17 21:50:19 +00:00
if ( pos < pattern . length ( ) & & pattern [ pos ] = = kQuote ) {
1999-08-16 21:50:52 +00:00
affix - > append ( kQuote ) ; // Encode quote
// Fall through to append(ch)
} else {
subpart - = 2 ; // close quote
continue ;
}
}
affix - > append ( ch ) ;
2004-03-25 17:42:28 +00:00
pos + = U16_LENGTH ( ch ) ;
1999-08-16 21:50:52 +00:00
break ;
}
}
if ( sub0Limit = = 0 ) {
1999-12-08 02:11:04 +00:00
sub0Limit = pattern . length ( ) ;
1999-08-16 21:50:52 +00:00
}
if ( sub2Limit = = 0 ) {
1999-12-08 02:11:04 +00:00
sub2Limit = pattern . length ( ) ;
1999-08-16 21:50:52 +00:00
}
/* Handle patterns with no '0' pattern character. These patterns
* are legal , but must be recodified to make sense . " ##.### " - >
* " #0.### " . " .### " - > " .0## " .
*
* We allow patterns of the form " #### " to produce a zeroDigitCount
* of zero ( got that ? ) ; although this seems like it might make it
* possible for format ( ) to produce empty strings , format ( ) checks
* for this condition and outputs a zero digit in this situation .
* Having a zeroDigitCount of zero yields a minimum integer digits
* of zero , which allows proper round - trip patterns . We don ' t want
* " # " to become " #0 " when toPattern ( ) is called ( even though that ' s
* what it really is , semantically ) .
*/
2004-03-25 17:42:28 +00:00
if ( zeroDigitCount = = 0 & & sigDigitCount = = 0 & &
digitLeftCount > 0 & & decimalPos > = 0 ) {
1999-08-16 21:50:52 +00:00
// Handle "###.###" and "###." and ".###"
int n = decimalPos ;
2000-10-12 19:04:06 +00:00
if ( n = = 0 )
+ + n ; // Handle ".###"
1999-08-16 21:50:52 +00:00
digitRightCount = digitLeftCount - n ;
digitLeftCount = n - 1 ;
zeroDigitCount = 1 ;
}
// Do syntax checking on the digits, decimal points, and quotes.
2004-03-25 17:42:28 +00:00
if ( ( decimalPos < 0 & & digitRightCount > 0 & & sigDigitCount = = 0 ) | |
1999-08-16 21:50:52 +00:00
( decimalPos > = 0 & &
2004-03-25 17:42:28 +00:00
( sigDigitCount > 0 | |
decimalPos < digitLeftCount | |
1999-08-16 21:50:52 +00:00
decimalPos > ( digitLeftCount + zeroDigitCount ) ) ) | |
2000-06-07 00:15:59 +00:00
groupingCount = = 0 | | groupingCount2 = = 0 | |
2004-03-25 17:42:28 +00:00
( sigDigitCount > 0 & & zeroDigitCount > 0 ) | |
2001-09-17 21:50:19 +00:00
subpart > 2 )
{ // subpart > 2 == unmatched quote
1999-08-16 21:50:52 +00:00
debug ( " Syntax error " )
2001-08-17 02:20:35 +00:00
status = U_PATTERN_SYNTAX_ERROR ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
// Make sure pad is at legal position before or after affix.
if ( padPos > = 0 ) {
if ( padPos = = start ) {
padPos = kPadBeforePrefix ;
} else if ( padPos + 2 = = sub0Start ) {
padPos = kPadAfterPrefix ;
} else if ( padPos = = sub0Limit ) {
padPos = kPadBeforeSuffix ;
} else if ( padPos + 2 = = sub2Limit ) {
padPos = kPadAfterSuffix ;
} else {
// Illegal pad position
debug ( " Illegal pad position " )
2001-08-17 02:20:35 +00:00
status = U_ILLEGAL_PAD_POSITION ;
syntaxError ( pattern , pos , parseError ) ;
1999-08-16 21:50:52 +00:00
return ;
}
}
if ( part = = 0 ) {
delete fPosPrefixPattern ;
delete fPosSuffixPattern ;
delete fNegPrefixPattern ;
delete fNegSuffixPattern ;
fPosPrefixPattern = new UnicodeString ( prefix ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fPosPrefixPattern = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
fPosSuffixPattern = new UnicodeString ( suffix ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fPosSuffixPattern = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
delete fPosPrefixPattern ;
return ;
}
1999-08-16 21:50:52 +00:00
fNegPrefixPattern = 0 ;
fNegSuffixPattern = 0 ;
fUseExponentialNotation = ( expDigits > = 0 ) ;
if ( fUseExponentialNotation ) {
fMinExponentDigits = expDigits ;
}
2002-03-26 05:27:25 +00:00
fExponentSignAlwaysShown = expSignAlways ;
2004-04-03 17:56:14 +00:00
int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount ;
1999-08-16 21:50:52 +00:00
// The effectiveDecimalPos is the position the decimal is at or
// would be at if there is no decimal. Note that if
// decimalPos<0, then digitTotalCount == digitLeftCount +
// zeroDigitCount.
2004-04-03 17:56:14 +00:00
int32_t effectiveDecimalPos = decimalPos > = 0 ? decimalPos : digitTotalCount ;
UBool isSigDig = ( sigDigitCount > 0 ) ;
2004-04-12 23:37:44 +00:00
setSignificantDigitsUsed ( isSigDig ) ;
2004-04-03 17:56:14 +00:00
if ( isSigDig ) {
2004-03-25 17:42:28 +00:00
setMinimumSignificantDigits ( sigDigitCount ) ;
setMaximumSignificantDigits ( sigDigitCount + digitRightCount ) ;
} else {
int32_t minInt = effectiveDecimalPos - digitLeftCount ;
setMinimumIntegerDigits ( minInt ) ;
setMaximumIntegerDigits ( fUseExponentialNotation
1999-08-16 21:50:52 +00:00
? digitLeftCount + getMinimumIntegerDigits ( )
: kDoubleIntegerDigits ) ;
2004-03-25 17:42:28 +00:00
setMaximumFractionDigits ( decimalPos > = 0
1999-08-16 21:50:52 +00:00
? ( digitTotalCount - decimalPos ) : 0 ) ;
2004-03-25 17:42:28 +00:00
setMinimumFractionDigits ( decimalPos > = 0
1999-08-16 21:50:52 +00:00
? ( digitLeftCount + zeroDigitCount - decimalPos ) : 0 ) ;
2004-03-25 17:42:28 +00:00
}
1999-08-16 21:50:52 +00:00
setGroupingUsed ( groupingCount > 0 ) ;
fGroupingSize = ( groupingCount > 0 ) ? groupingCount : 0 ;
2000-06-07 00:15:59 +00:00
fGroupingSize2 = ( groupingCount2 > 0 & & groupingCount2 ! = groupingCount )
? groupingCount2 : 0 ;
2010-02-26 02:29:00 +00:00
setMultiplier ( multiplier ) ;
1999-08-16 21:50:52 +00:00
setDecimalSeparatorAlwaysShown ( decimalPos = = 0
| | decimalPos = = digitTotalCount ) ;
if ( padPos > = 0 ) {
fPadPosition = ( EPadPosition ) padPos ;
// To compute the format width, first set up sub0Limit -
// sub0Start. Add in prefix/suffix length later.
// fFormatWidth = prefix.length() + suffix.length() +
// sub0Limit - sub0Start;
fFormatWidth = sub0Limit - sub0Start ;
fPad = padChar ;
} else {
fFormatWidth = 0 ;
}
if ( roundingPos > = 0 ) {
2010-02-26 02:29:00 +00:00
roundingInc . setDecimalAt ( effectiveDecimalPos - roundingPos ) ;
1999-08-16 21:50:52 +00:00
if ( fRoundingIncrement ! = NULL ) {
* fRoundingIncrement = roundingInc ;
} else {
fRoundingIncrement = new DigitList ( roundingInc ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2010-02-26 02:29:00 +00:00
if ( fRoundingIncrement = = NULL ) {
2002-06-29 09:31:05 +00:00
status = U_MEMORY_ALLOCATION_ERROR ;
delete fPosPrefixPattern ;
delete fPosSuffixPattern ;
return ;
}
1999-08-16 21:50:52 +00:00
}
fRoundingMode = kRoundHalfEven ;
} else {
setRoundingIncrement ( 0.0 ) ;
}
} else {
fNegPrefixPattern = new UnicodeString ( prefix ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fNegPrefixPattern = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
fNegSuffixPattern = new UnicodeString ( suffix ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fNegSuffixPattern = = 0 ) {
delete fNegPrefixPattern ;
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
}
}
1999-12-08 02:11:04 +00:00
if ( pattern . length ( ) = = 0 ) {
1999-08-16 21:50:52 +00:00
delete fNegPrefixPattern ;
delete fNegSuffixPattern ;
fNegPrefixPattern = NULL ;
fNegSuffixPattern = NULL ;
if ( fPosPrefixPattern ! = NULL ) {
fPosPrefixPattern - > remove ( ) ;
} else {
fPosPrefixPattern = new UnicodeString ( ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fPosPrefixPattern = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
}
if ( fPosSuffixPattern ! = NULL ) {
fPosSuffixPattern - > remove ( ) ;
} else {
fPosSuffixPattern = new UnicodeString ( ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fPosSuffixPattern = = 0 ) {
delete fPosPrefixPattern ;
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
}
setMinimumIntegerDigits ( 0 ) ;
setMaximumIntegerDigits ( kDoubleIntegerDigits ) ;
setMinimumFractionDigits ( 0 ) ;
setMaximumFractionDigits ( kDoubleFractionDigits ) ;
fUseExponentialNotation = FALSE ;
2009-02-12 22:55:29 +00:00
fCurrencySignCount = 0 ;
1999-08-16 21:50:52 +00:00
setGroupingUsed ( FALSE ) ;
fGroupingSize = 0 ;
2000-06-07 00:15:59 +00:00
fGroupingSize2 = 0 ;
2010-02-26 02:29:00 +00:00
setMultiplier ( 1 ) ;
1999-08-16 21:50:52 +00:00
setDecimalSeparatorAlwaysShown ( FALSE ) ;
fFormatWidth = 0 ;
setRoundingIncrement ( 0.0 ) ;
}
// If there was no negative pattern, or if the negative pattern is
// identical to the positive pattern, then prepend the minus sign to the
// positive pattern to form the negative pattern.
if ( fNegPrefixPattern = = NULL | |
( * fNegPrefixPattern = = * fPosPrefixPattern
& & * fNegSuffixPattern = = * fPosSuffixPattern ) ) {
2012-09-27 18:50:24 +00:00
_copy_ptr ( & fNegSuffixPattern , fPosSuffixPattern ) ;
1999-08-16 21:50:52 +00:00
if ( fNegPrefixPattern = = NULL ) {
fNegPrefixPattern = new UnicodeString ( ) ;
2002-07-02 15:10:30 +00:00
/* test for NULL */
2002-06-29 09:31:05 +00:00
if ( fNegPrefixPattern = = 0 ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return ;
}
1999-08-16 21:50:52 +00:00
} else {
fNegPrefixPattern - > remove ( ) ;
}
fNegPrefixPattern - > append ( kQuote ) . append ( kPatternMinus )
. append ( * fPosPrefixPattern ) ;
}
2001-09-17 21:50:19 +00:00
# ifdef FMT_DEBUG
1999-08-16 21:50:52 +00:00
UnicodeString s ;
2012-05-30 00:41:57 +00:00
s . append ( ( UnicodeString ) " \" " ) . append ( pattern ) . append ( ( UnicodeString ) " \" -> " ) ;
1999-08-16 21:50:52 +00:00
debugout ( s ) ;
# endif
2009-02-12 22:55:29 +00:00
// save the pattern
fFormatPattern = pattern ;
}
void
DecimalFormat : : expandAffixAdjustWidth ( const UnicodeString * pluralCount ) {
expandAffixes ( pluralCount ) ;
1999-08-16 21:50:52 +00:00
if ( fFormatWidth > 0 ) {
// Finish computing format width (see above)
2010-01-28 19:39:24 +00:00
// TODO: how to handle fFormatWidth,
2009-02-12 22:55:29 +00:00
// need to save in f(Plural)AffixesForCurrecy?
fFormatWidth + = fPositivePrefix . length ( ) + fPositiveSuffix . length ( ) ;
1999-08-16 21:50:52 +00:00
}
}
2009-02-12 22:55:29 +00:00
void
DecimalFormat : : applyPattern ( const UnicodeString & pattern ,
UBool localized ,
UParseError & parseError ,
UErrorCode & status )
2010-01-28 19:39:24 +00:00
{
2009-02-12 22:55:29 +00:00
// do the following re-set first. since they change private data by
// apply pattern again.
if ( pattern . indexOf ( kCurrencySign ) ! = - 1 ) {
2010-01-28 19:39:24 +00:00
if ( fCurrencyPluralInfo = = NULL ) {
// initialize currencyPluralInfo if needed
2009-02-12 22:55:29 +00:00
fCurrencyPluralInfo = new CurrencyPluralInfo ( fSymbols - > getLocale ( ) , status ) ;
}
if ( fAffixPatternsForCurrency = = NULL ) {
setupCurrencyAffixPatterns ( status ) ;
}
2011-07-07 18:46:19 +00:00
if ( pattern . indexOf ( fgTripleCurrencySign , 3 , 0 ) ! = - 1 ) {
2009-02-12 22:55:29 +00:00
// only setup the affixes of the current pattern.
setupCurrencyAffixes ( pattern , TRUE , FALSE , status ) ;
}
}
applyPatternWithoutExpandAffix ( pattern , localized , parseError , status ) ;
expandAffixAdjustWidth ( NULL ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
void
2010-01-28 19:39:24 +00:00
DecimalFormat : : applyPatternInternally ( const UnicodeString & pluralCount ,
2009-02-12 22:55:29 +00:00
const UnicodeString & pattern ,
UBool localized ,
UParseError & parseError ,
UErrorCode & status ) {
applyPatternWithoutExpandAffix ( pattern , localized , parseError , status ) ;
expandAffixAdjustWidth ( & pluralCount ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
1999-08-16 21:50:52 +00:00
/**
* Sets the maximum number of digits allowed in the integer portion of a
* number . This override limits the integer digit count to 309.
* @ see NumberFormat # setMaximumIntegerDigits
*/
void DecimalFormat : : setMaximumIntegerDigits ( int32_t newValue ) {
2004-03-25 17:42:28 +00:00
NumberFormat : : setMaximumIntegerDigits ( _min ( newValue , kDoubleIntegerDigits ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Sets the minimum number of digits allowed in the integer portion of a
* number . This override limits the integer digit count to 309.
* @ see NumberFormat # setMinimumIntegerDigits
*/
void DecimalFormat : : setMinimumIntegerDigits ( int32_t newValue ) {
2004-03-25 17:42:28 +00:00
NumberFormat : : setMinimumIntegerDigits ( _min ( newValue , kDoubleIntegerDigits ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Sets the maximum number of digits allowed in the fraction portion of a
* number . This override limits the fraction digit count to 340.
* @ see NumberFormat # setMaximumFractionDigits
*/
void DecimalFormat : : setMaximumFractionDigits ( int32_t newValue ) {
2004-03-25 17:42:28 +00:00
NumberFormat : : setMaximumFractionDigits ( _min ( newValue , kDoubleFractionDigits ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
/**
* Sets the minimum number of digits allowed in the fraction portion of a
* number . This override limits the fraction digit count to 340.
* @ see NumberFormat # setMinimumFractionDigits
*/
void DecimalFormat : : setMinimumFractionDigits ( int32_t newValue ) {
2004-03-25 17:42:28 +00:00
NumberFormat : : setMinimumFractionDigits ( _min ( newValue , kDoubleFractionDigits ) ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2004-03-25 17:42:28 +00:00
}
int32_t DecimalFormat : : getMinimumSignificantDigits ( ) const {
2004-04-03 17:56:14 +00:00
return fMinSignificantDigits ;
2004-03-25 17:42:28 +00:00
}
int32_t DecimalFormat : : getMaximumSignificantDigits ( ) const {
2004-04-03 17:56:14 +00:00
return fMaxSignificantDigits ;
2004-03-25 17:42:28 +00:00
}
void DecimalFormat : : setMinimumSignificantDigits ( int32_t min ) {
if ( min < 1 ) {
2010-01-28 19:39:24 +00:00
min = 1 ;
2004-03-25 17:42:28 +00:00
}
2004-04-03 17:56:14 +00:00
// pin max sig dig to >= min
int32_t max = _max ( fMaxSignificantDigits , min ) ;
fMinSignificantDigits = min ;
fMaxSignificantDigits = max ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2004-03-25 17:42:28 +00:00
}
void DecimalFormat : : setMaximumSignificantDigits ( int32_t max ) {
if ( max < 1 ) {
max = 1 ;
}
2004-04-03 17:56:14 +00:00
// pin min sig dig to 1..max
U_ASSERT ( fMinSignificantDigits > = 1 ) ;
int32_t min = _min ( fMinSignificantDigits , max ) ;
fMinSignificantDigits = min ;
fMaxSignificantDigits = max ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2004-04-03 17:56:14 +00:00
}
2004-04-12 23:37:44 +00:00
UBool DecimalFormat : : areSignificantDigitsUsed ( ) const {
2004-04-03 17:56:14 +00:00
return fUseSignificantDigits ;
2004-03-25 17:42:28 +00:00
}
2004-04-12 23:37:44 +00:00
void DecimalFormat : : setSignificantDigitsUsed ( UBool useSignificantDigits ) {
2004-04-03 17:56:14 +00:00
fUseSignificantDigits = useSignificantDigits ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
1999-08-16 21:50:52 +00:00
}
2010-01-28 19:39:24 +00:00
void DecimalFormat : : setCurrencyInternally ( const UChar * theCurrency ,
2009-02-12 22:55:29 +00:00
UErrorCode & ec ) {
2002-05-13 19:33:05 +00:00
// If we are a currency format, then modify our affixes to
// encode the currency symbol for the given currency in our
// locale, and adjust the decimal digits and rounding for the
// given currency.
2004-02-13 01:53:12 +00:00
// Note: The code is ordered so that this object is *not changed*
// until we are sure we are going to succeed.
2010-01-28 19:39:24 +00:00
2004-02-13 01:53:12 +00:00
// NULL or empty currency is *legal* and indicates no currency.
UBool isCurr = ( theCurrency & & * theCurrency ) ;
double rounding = 0.0 ;
int32_t frac = 0 ;
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero & & isCurr ) {
2004-02-13 01:53:12 +00:00
rounding = ucurr_getRoundingIncrement ( theCurrency , & ec ) ;
frac = ucurr_getDefaultFractionDigits ( theCurrency , & ec ) ;
}
2010-01-28 19:39:24 +00:00
2004-02-13 01:53:12 +00:00
NumberFormat : : setCurrency ( theCurrency , ec ) ;
if ( U_FAILURE ( ec ) ) return ;
2002-05-13 19:33:05 +00:00
2009-02-12 22:55:29 +00:00
if ( fCurrencySignCount > fgCurrencySignCountZero ) {
2004-02-13 01:53:12 +00:00
// NULL or empty currency is *legal* and indicates no currency.
if ( isCurr ) {
setRoundingIncrement ( rounding ) ;
setMinimumFractionDigits ( frac ) ;
setMaximumFractionDigits ( frac ) ;
2003-04-24 22:58:04 +00:00
}
2009-02-12 22:55:29 +00:00
expandAffixes ( NULL ) ;
2002-05-13 19:33:05 +00:00
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2002-05-13 19:33:05 +00:00
}
2009-02-12 22:55:29 +00:00
void DecimalFormat : : setCurrency ( const UChar * theCurrency , UErrorCode & ec ) {
// set the currency before compute affixes to get the right currency names
NumberFormat : : setCurrency ( theCurrency , ec ) ;
2011-07-07 18:46:19 +00:00
if ( fFormatPattern . indexOf ( fgTripleCurrencySign , 3 , 0 ) ! = - 1 ) {
2009-02-12 22:55:29 +00:00
UnicodeString savedPtn = fFormatPattern ;
setupCurrencyAffixes ( fFormatPattern , TRUE , TRUE , ec ) ;
UParseError parseErr ;
applyPattern ( savedPtn , FALSE , parseErr , ec ) ;
}
// set the currency after apply pattern to get the correct rounding/fraction
setCurrencyInternally ( theCurrency , ec ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2009-02-12 22:55:29 +00:00
}
2004-05-27 22:03:26 +00:00
// Deprecated variant with no UErrorCode parameter
void DecimalFormat : : setCurrency ( const UChar * theCurrency ) {
UErrorCode ec = U_ZERO_ERROR ;
setCurrency ( theCurrency , ec ) ;
2012-05-30 00:41:57 +00:00
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
2004-05-27 22:03:26 +00:00
}
2008-01-11 18:44:41 +00:00
void DecimalFormat : : getEffectiveCurrency ( UChar * result , UErrorCode & ec ) const {
if ( fSymbols = = NULL ) {
2008-02-23 19:15:18 +00:00
ec = U_MEMORY_ALLOCATION_ERROR ;
return ;
2008-01-11 18:44:41 +00:00
}
ec = U_ZERO_ERROR ;
2008-02-23 19:15:18 +00:00
const UChar * c = getCurrency ( ) ;
2004-04-15 06:20:42 +00:00
if ( * c = = 0 ) {
const UnicodeString & intl =
fSymbols - > getConstSymbol ( DecimalFormatSymbols : : kIntlCurrencySymbol ) ;
c = intl . getBuffer ( ) ; // ok for intl to go out of scope
}
u_strncpy ( result , c , 3 ) ;
result [ 3 ] = 0 ;
}
2004-03-25 17:42:28 +00:00
/**
* Return the number of fraction digits to display , or the total
* number of digits for significant digit formats and exponential
* formats .
*/
2003-10-29 00:20:05 +00:00
int32_t
2010-02-26 02:29:00 +00:00
DecimalFormat : : precision ( ) const {
2004-04-12 23:37:44 +00:00
if ( areSignificantDigitsUsed ( ) ) {
2004-03-25 17:42:28 +00:00
return getMaximumSignificantDigits ( ) ;
} else if ( fUseExponentialNotation ) {
return getMinimumIntegerDigits ( ) + getMaximumFractionDigits ( ) ;
} else {
2010-02-26 02:29:00 +00:00
return getMaximumFractionDigits ( ) ;
2004-03-25 17:42:28 +00:00
}
2003-10-29 00:20:05 +00:00
}
2009-02-12 22:55:29 +00:00
// TODO: template algorithm
Hashtable *
DecimalFormat : : initHashForAffix ( UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return NULL ;
}
Hashtable * hTable ;
if ( ( hTable = new Hashtable ( TRUE , status ) ) = = NULL ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return NULL ;
}
2011-03-01 20:55:43 +00:00
if ( U_FAILURE ( status ) ) {
delete hTable ;
return NULL ;
}
2010-02-16 23:43:22 +00:00
hTable - > setValueComparator ( decimfmtAffixValueComparator ) ;
2009-02-12 22:55:29 +00:00
return hTable ;
}
Hashtable *
DecimalFormat : : initHashForAffixPattern ( UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return NULL ;
}
Hashtable * hTable ;
if ( ( hTable = new Hashtable ( TRUE , status ) ) = = NULL ) {
status = U_MEMORY_ALLOCATION_ERROR ;
return NULL ;
}
2011-03-01 20:55:43 +00:00
if ( U_FAILURE ( status ) ) {
delete hTable ;
return NULL ;
}
2010-02-16 23:43:22 +00:00
hTable - > setValueComparator ( decimfmtAffixPatternValueComparator ) ;
2009-02-12 22:55:29 +00:00
return hTable ;
}
void
2010-01-28 19:39:24 +00:00
DecimalFormat : : deleteHashForAffix ( Hashtable * & table )
2009-02-12 22:55:29 +00:00
{
if ( table = = NULL ) {
return ;
}
int32_t pos = - 1 ;
const UHashElement * element = NULL ;
while ( ( element = table - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok valueTok = element - > value ;
const AffixesForCurrency * value = ( AffixesForCurrency * ) valueTok . pointer ;
delete value ;
}
delete table ;
table = NULL ;
}
void
2010-01-28 19:39:24 +00:00
DecimalFormat : : deleteHashForAffixPattern ( )
2009-02-12 22:55:29 +00:00
{
if ( fAffixPatternsForCurrency = = NULL ) {
return ;
}
int32_t pos = - 1 ;
const UHashElement * element = NULL ;
while ( ( element = fAffixPatternsForCurrency - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok valueTok = element - > value ;
const AffixPatternsForCurrency * value = ( AffixPatternsForCurrency * ) valueTok . pointer ;
delete value ;
}
delete fAffixPatternsForCurrency ;
fAffixPatternsForCurrency = NULL ;
}
void
DecimalFormat : : copyHashForAffixPattern ( const Hashtable * source ,
Hashtable * target ,
UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return ;
}
int32_t pos = - 1 ;
const UHashElement * element = NULL ;
if ( source ) {
while ( ( element = source - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok keyTok = element - > key ;
const UnicodeString * key = ( UnicodeString * ) keyTok . pointer ;
const UHashTok valueTok = element - > value ;
const AffixPatternsForCurrency * value = ( AffixPatternsForCurrency * ) valueTok . pointer ;
AffixPatternsForCurrency * copy = new AffixPatternsForCurrency (
value - > negPrefixPatternForCurrency ,
value - > negSuffixPatternForCurrency ,
value - > posPrefixPatternForCurrency ,
2009-03-10 20:53:27 +00:00
value - > posSuffixPatternForCurrency ,
value - > patternType ) ;
2009-02-12 22:55:29 +00:00
target - > put ( UnicodeString ( * key ) , copy , status ) ;
if ( U_FAILURE ( status ) ) {
return ;
}
}
}
}
2012-10-12 19:52:43 +00:00
DecimalFormat & DecimalFormat : : setAttribute ( UNumberFormatAttribute attr ,
int32_t newValue ,
UErrorCode & status ) {
if ( U_FAILURE ( status ) ) return * this ;
switch ( attr ) {
case UNUM_LENIENT_PARSE :
setLenient ( newValue ! = 0 ) ;
break ;
case UNUM_PARSE_INT_ONLY :
setParseIntegerOnly ( newValue ! = 0 ) ;
break ;
case UNUM_GROUPING_USED :
setGroupingUsed ( newValue ! = 0 ) ;
break ;
case UNUM_DECIMAL_ALWAYS_SHOWN :
setDecimalSeparatorAlwaysShown ( newValue ! = 0 ) ;
break ;
case UNUM_MAX_INTEGER_DIGITS :
setMaximumIntegerDigits ( newValue ) ;
break ;
case UNUM_MIN_INTEGER_DIGITS :
setMinimumIntegerDigits ( newValue ) ;
break ;
case UNUM_INTEGER_DIGITS :
setMinimumIntegerDigits ( newValue ) ;
setMaximumIntegerDigits ( newValue ) ;
break ;
case UNUM_MAX_FRACTION_DIGITS :
setMaximumFractionDigits ( newValue ) ;
break ;
case UNUM_MIN_FRACTION_DIGITS :
setMinimumFractionDigits ( newValue ) ;
break ;
case UNUM_FRACTION_DIGITS :
setMinimumFractionDigits ( newValue ) ;
setMaximumFractionDigits ( newValue ) ;
break ;
case UNUM_SIGNIFICANT_DIGITS_USED :
setSignificantDigitsUsed ( newValue ! = 0 ) ;
break ;
case UNUM_MAX_SIGNIFICANT_DIGITS :
setMaximumSignificantDigits ( newValue ) ;
break ;
case UNUM_MIN_SIGNIFICANT_DIGITS :
setMinimumSignificantDigits ( newValue ) ;
break ;
case UNUM_MULTIPLIER :
setMultiplier ( newValue ) ;
break ;
case UNUM_GROUPING_SIZE :
setGroupingSize ( newValue ) ;
break ;
case UNUM_ROUNDING_MODE :
setRoundingMode ( ( DecimalFormat : : ERoundingMode ) newValue ) ;
break ;
case UNUM_FORMAT_WIDTH :
setFormatWidth ( newValue ) ;
break ;
case UNUM_PADDING_POSITION :
/** The position at which padding will take place. */
setPadPosition ( ( DecimalFormat : : EPadPosition ) newValue ) ;
break ;
case UNUM_SECONDARY_GROUPING_SIZE :
setSecondaryGroupingSize ( newValue ) ;
break ;
# if UCONFIG_HAVE_PARSEALLINPUT
case UNUM_PARSE_ALL_INPUT :
setParseAllInput ( ( UNumberFormatAttributeValue ) newValue ) ;
break ;
# endif
/* These are stored in fBoolFlags */
case UNUM_PARSE_NO_EXPONENT :
2012-10-12 21:53:41 +00:00
case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS :
2012-10-12 19:52:43 +00:00
if ( ! fBoolFlags . isValidValue ( newValue ) ) {
status = U_ILLEGAL_ARGUMENT_ERROR ;
} else {
fBoolFlags . set ( attr , newValue ) ;
}
break ;
default :
status = U_UNSUPPORTED_ERROR ;
break ;
}
return * this ;
}
int32_t DecimalFormat : : getAttribute ( UNumberFormatAttribute attr ,
UErrorCode & status ) const {
if ( U_FAILURE ( status ) ) return - 1 ;
switch ( attr ) {
case UNUM_LENIENT_PARSE :
return isLenient ( ) ;
case UNUM_PARSE_INT_ONLY :
return isParseIntegerOnly ( ) ;
case UNUM_GROUPING_USED :
return isGroupingUsed ( ) ;
case UNUM_DECIMAL_ALWAYS_SHOWN :
return isDecimalSeparatorAlwaysShown ( ) ;
case UNUM_MAX_INTEGER_DIGITS :
return getMaximumIntegerDigits ( ) ;
case UNUM_MIN_INTEGER_DIGITS :
return getMinimumIntegerDigits ( ) ;
case UNUM_INTEGER_DIGITS :
// TBD: what should this return?
return getMinimumIntegerDigits ( ) ;
case UNUM_MAX_FRACTION_DIGITS :
return getMaximumFractionDigits ( ) ;
case UNUM_MIN_FRACTION_DIGITS :
return getMinimumFractionDigits ( ) ;
case UNUM_FRACTION_DIGITS :
// TBD: what should this return?
return getMinimumFractionDigits ( ) ;
case UNUM_SIGNIFICANT_DIGITS_USED :
return areSignificantDigitsUsed ( ) ;
case UNUM_MAX_SIGNIFICANT_DIGITS :
return getMaximumSignificantDigits ( ) ;
case UNUM_MIN_SIGNIFICANT_DIGITS :
return getMinimumSignificantDigits ( ) ;
case UNUM_MULTIPLIER :
return getMultiplier ( ) ;
case UNUM_GROUPING_SIZE :
return getGroupingSize ( ) ;
case UNUM_ROUNDING_MODE :
return getRoundingMode ( ) ;
case UNUM_FORMAT_WIDTH :
return getFormatWidth ( ) ;
case UNUM_PADDING_POSITION :
return getPadPosition ( ) ;
case UNUM_SECONDARY_GROUPING_SIZE :
return getSecondaryGroupingSize ( ) ;
/* These are stored in fBoolFlags */
case UNUM_PARSE_NO_EXPONENT :
2012-10-12 21:53:41 +00:00
case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS :
2012-10-12 19:52:43 +00:00
return fBoolFlags . get ( attr ) ;
default :
status = U_UNSUPPORTED_ERROR ;
break ;
}
return - 1 ; /* undefined */
}
2012-05-30 00:41:57 +00:00
# if UCONFIG_HAVE_PARSEALLINPUT
void DecimalFormat : : setParseAllInput ( UNumberFormatAttributeValue value ) {
fParseAllInput = value ;
# if UCONFIG_FORMAT_FASTPATHS_49
handleChanged ( ) ;
# endif
}
# endif
2009-02-12 22:55:29 +00:00
void
DecimalFormat : : copyHashForAffix ( const Hashtable * source ,
Hashtable * target ,
UErrorCode & status ) {
if ( U_FAILURE ( status ) ) {
return ;
}
int32_t pos = - 1 ;
const UHashElement * element = NULL ;
if ( source ) {
while ( ( element = source - > nextElement ( pos ) ) ! = NULL ) {
const UHashTok keyTok = element - > key ;
const UnicodeString * key = ( UnicodeString * ) keyTok . pointer ;
const UHashTok valueTok = element - > value ;
const AffixesForCurrency * value = ( AffixesForCurrency * ) valueTok . pointer ;
AffixesForCurrency * copy = new AffixesForCurrency (
value - > negPrefixForCurrency ,
value - > negSuffixForCurrency ,
value - > posPrefixForCurrency ,
value - > posSuffixForCurrency ) ;
target - > put ( UnicodeString ( * key ) , copy , status ) ;
if ( U_FAILURE ( status ) ) {
return ;
}
}
}
}
2001-10-08 23:26:58 +00:00
U_NAMESPACE_END
2002-09-20 01:54:48 +00:00
# endif /* #if !UCONFIG_NO_FORMATTING */
1999-08-16 21:50:52 +00:00
//eof