16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*******************************************************************************
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org* Copyright (C) 1997-2013, International Business Machines Corporation and    *
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org* others. All Rights Reserved.                                                *
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*******************************************************************************
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org* File CHOICFMT.CPP
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org* Modification History:
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   Date        Name        Description
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   02/19/97    aliu        Converted from java.
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   03/20/97    helena      Finished first cut of implementation and got rid
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                           of nextDouble/previousDouble and replaced with
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                           boolean array.
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   4/10/97     aliu        Clean up.  Modified to work on AIX.
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   06/04/97    helena      Fixed applyPattern(), toPattern() and not to include
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*                           wchar.h.
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   07/09/97    helena      Made ParsePosition into a class.
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   08/06/97    nos         removed overloaded constructor, fixed 'format(array)'
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   07/22/98    stephen     JDK 1.2 Sync - removed UBool array (doubleFlags)
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*   02/22/99    stephen     Removed character literals for EBCDIC safety
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org********************************************************************************
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org*/
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utypes.h"
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_FORMATTING
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/choicfmt.h"
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/numfmt.h"
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/locid.h"
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cpputils.h"
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cstring.h"
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "messageimpl.h"
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "putilimp.h"
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <stdio.h>
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include <float.h>
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// *****************************************************************************
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// class ChoiceFormat
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// *****************************************************************************
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_BEGIN
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Special characters used by ChoiceFormat.  There are two characters
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// used interchangeably to indicate <=.  Either is parsed, but only
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// LESS_EQUAL is generated by toPattern().
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define SINGLE_QUOTE ((UChar)0x0027)   /*'*/
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define LESS_THAN    ((UChar)0x003C)   /*<*/
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define LESS_EQUAL   ((UChar)0x0023)   /*#*/
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define LESS_EQUAL2  ((UChar)0x2264)
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define VERTICAL_BAR ((UChar)0x007C)   /*|*/
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define MINUS        ((UChar)0x002D)   /*-*/
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar LEFT_CURLY_BRACE = 0x7B;     /*{*/
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic const UChar RIGHT_CURLY_BRACE = 0x7D;    /*}*/
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#ifdef INFINITY
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#undef INFINITY
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define INFINITY     ((UChar)0x221E)
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//static const UChar gPositiveInfinity[] = {INFINITY, 0};
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define POSITIVE_INF_STRLEN 1
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define NEGATIVE_INF_STRLEN 2
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Creates a ChoiceFormat instance based on the pattern.
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status)
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: constructorErrorCode(status),
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(status)
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(newPattern, status);
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Creates a ChoiceFormat instance with the limit array and
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// format strings for each limit.
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::ChoiceFormat(const double* limits,
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UnicodeString* formats,
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           int32_t cnt )
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: constructorErrorCode(U_ZERO_ERROR),
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(constructorErrorCode)
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setChoices(limits, NULL, formats, cnt, constructorErrorCode);
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::ChoiceFormat(const double* limits,
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UBool* closures,
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UnicodeString* formats,
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           int32_t cnt )
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: constructorErrorCode(U_ZERO_ERROR),
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(constructorErrorCode)
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setChoices(limits, closures, formats, cnt, constructorErrorCode);
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// copy constructor
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::ChoiceFormat(const    ChoiceFormat&   that)
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: NumberFormat(that),
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  constructorErrorCode(that.constructorErrorCode),
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(that.msgPattern)
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Private constructor that creates a
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// ChoiceFormat instance based on the
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// pattern and populates UParseError
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UParseError& parseError,
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status)
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org: constructorErrorCode(status),
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  msgPattern(status)
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(newPattern,parseError, status);
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::operator==(const Format& that) const
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this == &that) return TRUE;
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!NumberFormat::operator==(that)) return FALSE;
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ChoiceFormat& thatAlias = (ChoiceFormat&)that;
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgPattern == thatAlias.msgPattern;
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// copy constructor
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst ChoiceFormat&
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::operator=(const   ChoiceFormat& that)
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (this != &that) {
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        NumberFormat::operator=(that);
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        constructorErrorCode = that.constructorErrorCode;
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgPattern = that.msgPattern;
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return *this;
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::~ChoiceFormat()
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Convert a double value to a string without the overhead of NumberFormat.
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::dtos(double value,
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                   UnicodeString& string)
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* Buffer to contain the digits and any extra formatting stuff. */
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    char temp[DBL_DIG + 16];
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    char *itrPtr = temp;
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    char *expPtr;
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    sprintf(temp, "%.*g", DBL_DIG, value);
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* Find and convert the decimal point.
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org       Using setlocale on some machines will cause sprintf to use a comma for certain locales.
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    */
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        itrPtr++;
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (*itrPtr != 0 && *itrPtr != 'e') {
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        /* We reached something that looks like a decimal point.
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        In case someone used setlocale(), which changes the decimal point. */
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        *itrPtr = '.';
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        itrPtr++;
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    /* Search for the exponent */
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (*itrPtr && *itrPtr != 'e') {
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        itrPtr++;
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (*itrPtr == 'e') {
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        itrPtr++;
1966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        /* Verify the exponent sign */
1976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (*itrPtr == '+' || *itrPtr == '-') {
1986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            itrPtr++;
1996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        /* Remove leading zeros. You will see this on Windows machines. */
2016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        expPtr = itrPtr;
2026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        while (*itrPtr == '0') {
2036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            itrPtr++;
2046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (*itrPtr && expPtr != itrPtr) {
2066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            /* Shift the exponent without zeros. */
2076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            while (*itrPtr) {
2086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                *(expPtr++)  = *(itrPtr++);
2096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
2106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // NULL terminate
2116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            *expPtr = 0;
2126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    string = UnicodeString(temp, -1, US_INV);    /* invariant codepage */
2166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return string;
2176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// calls the overloaded applyPattern method.
2216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
2236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::applyPattern(const UnicodeString& pattern,
2246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status)
2256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    msgPattern.parseChoiceStyle(pattern, NULL, status);
2276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    constructorErrorCode = status;
2286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Applies the pattern to this ChoiceFormat instance.
2326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
2346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::applyPattern(const UnicodeString& pattern,
2356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UParseError& parseError,
2366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           UErrorCode& status)
2376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    msgPattern.parseChoiceStyle(pattern, &parseError, status);
2396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    constructorErrorCode = status;
2406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Returns the input pattern string.
2436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
2456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::toPattern(UnicodeString& result) const
2466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result = msgPattern.getPatternString();
2486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Sets the limit and format arrays.
2526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
2536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::setChoices(  const double* limits,
2546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UnicodeString* formats,
2556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           int32_t cnt )
2566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode errorCode = U_ZERO_ERROR;
2586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setChoices(limits, NULL, formats, cnt, errorCode);
2596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
2626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Sets the limit and format arrays.
2636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
2646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::setChoices(  const double* limits,
2656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UBool* closures,
2666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           const UnicodeString* formats,
2676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                           int32_t cnt )
2686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode errorCode = U_ZERO_ERROR;
2706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    setChoices(limits, closures, formats, cnt, errorCode);
2716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
2746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::setChoices(const double* limits,
2756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         const UBool* closures,
2766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         const UnicodeString* formats,
2776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         int32_t count,
2786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                         UErrorCode &errorCode) {
2796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (U_FAILURE(errorCode)) {
2806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
2816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (limits == NULL || formats == NULL) {
2836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
2846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return;
2856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Reconstruct the original input pattern.
2876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Modified version of the pre-ICU 4.8 toPattern() implementation.
2886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UnicodeString result;
2896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 0; i < count; ++i) {
2906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (i != 0) {
2916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += VERTICAL_BAR;
2926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UnicodeString buf;
2946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (uprv_isPositiveInfinity(limits[i])) {
2956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += INFINITY;
2966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else if (uprv_isNegativeInfinity(limits[i])) {
2976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += MINUS;
2986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += INFINITY;
2996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
3006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += dtos(limits[i], buf);
3016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
3026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (closures != NULL && closures[i]) {
3036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += LESS_THAN;
3046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        } else {
3056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result += LESS_EQUAL;
3066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
3076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Append formats[i], using quotes if there are special
3086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // characters.  Single quotes themselves must be escaped in
3096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // either case.
3106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UnicodeString& text = formats[i];
3116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t textLength = text.length();
3126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t nestingLevel = 0;
3136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for (int32_t j = 0; j < textLength; ++j) {
3146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UChar c = text[j];
3156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (c == SINGLE_QUOTE && nestingLevel == 0) {
3166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Double each top-level apostrophe.
3176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                result.append(c);
3186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else if (c == VERTICAL_BAR && nestingLevel == 0) {
3196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // Surround each pipe symbol with apostrophes for quoting.
3206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // If the next character is an apostrophe, then that will be doubled,
3216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // and although the parser will see the apostrophe pairs beginning
3226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // and ending one character earlier than our doubling, the result
3236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // is as desired.
3246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                //   | -> '|'
3256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                //   |' -> '|'''
3266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                //   |'' -> '|''''' etc.
3276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                result.append(SINGLE_QUOTE).append(c).append(SINGLE_QUOTE);
3286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                continue;  // Skip the append(c) at the end of the loop body.
3296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else if (c == LEFT_CURLY_BRACE) {
3306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                ++nestingLevel;
3316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else if (c == RIGHT_CURLY_BRACE && nestingLevel > 0) {
3326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                --nestingLevel;
3336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
3346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            result.append(c);
3356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
3366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
3376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Apply the reconstructed pattern.
3386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    applyPattern(result, errorCode);
3396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets the limit array.
3436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst double*
3456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::getLimits(int32_t& cnt) const
3466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cnt = 0;
3486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
3496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets the closures array.
3536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UBool*
3556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::getClosures(int32_t& cnt) const
3566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cnt = 0;
3586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
3596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Gets the format array.
3636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst UnicodeString*
3656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::getFormats(int32_t& cnt) const
3666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cnt = 0;
3686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return NULL;
3696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats an int64 number, it's actually formatted as
3736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// a double.  The returned format string may differ
3746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// from the input number because of this.
3756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
3776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::format(int64_t number,
3786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UnicodeString& appendTo,
3796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     FieldPosition& status) const
3806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return format((double) number, appendTo, status);
3826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats an int32_t number, it's actually formatted as
3866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// a double.
3876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
3896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::format(int32_t number,
3906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UnicodeString& appendTo,
3916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     FieldPosition& status) const
3926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
3936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return format((double) number, appendTo, status);
3946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
3956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
3976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats a double number.
3986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
3996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
4006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::format(double number,
4016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UnicodeString& appendTo,
4026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     FieldPosition& /*pos*/) const
4036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (msgPattern.countParts() == 0) {
4056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // No pattern was applied, or it failed.
4066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
4076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Get the appropriate sub-message.
4096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t msgStart = findSubMessage(msgPattern, 0, number);
4106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (!MessageImpl::jdkAposMode(msgPattern)) {
4116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
4126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
4136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        appendTo.append(msgPattern.getPatternString(),
4146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        patternStart,
4156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                        msgPattern.getPatternIndex(msgLimit) - patternStart);
4166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
4176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // JDK compatibility mode: Remove SKIP_SYNTAX.
4196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
4206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
4236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::findSubMessage(const MessagePattern &pattern, int32_t partIndex, double number) {
4246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t count = pattern.countParts();
4256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t msgStart;
4266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Iterate over (ARG_INT|DOUBLE, ARG_SELECTOR, message) tuples
4276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // until ARG_LIMIT or end of choice-only pattern.
4286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Ignore the first number and selector and start the loop on the first message.
4296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    partIndex += 2;
4306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (;;) {
4316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Skip but remember the current sub-message.
4326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        msgStart = partIndex;
4336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex = pattern.getLimitPartIndex(partIndex);
4346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (++partIndex >= count) {
4356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Reached the end of the choice-only pattern.
4366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Return with the last sub-message.
4376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
4386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part &part = pattern.getPart(partIndex++);
4406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UMessagePatternPartType type = part.getType();
4416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (type == UMSGPAT_PART_TYPE_ARG_LIMIT) {
4426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Reached the end of the ChoiceFormat style.
4436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Return with the last sub-message.
4446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
4456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // part is an ARG_INT or ARG_DOUBLE
4476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        U_ASSERT(MessagePattern::Part::hasNumericValue(type));
4486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        double boundary = pattern.getNumericValue(part);
4496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        // Fetch the ARG_SELECTOR character.
4506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t selectorIndex = pattern.getPatternIndex(partIndex++);
4516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        UChar boundaryChar = pattern.getPatternString().charAt(selectorIndex);
4526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (boundaryChar == LESS_THAN ? !(number > boundary) : !(number >= boundary)) {
4536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // The number is in the interval between the previous boundary and the current one.
4546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // Return with the sub-message between them.
4556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // The !(a>b) and !(a>=b) comparisons are equivalent to
4566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            // (a<=b) and (a<b) except they "catch" NaN.
4576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            break;
4586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return msgStart;
4616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// Formats an array of objects. Checks if the data type of the objects
4656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// to get the right value for formatting.
4666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
4686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::format(const Formattable* objs,
4696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     int32_t cnt,
4706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UnicodeString& appendTo,
4716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     FieldPosition& pos,
4726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                     UErrorCode& status) const
4736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
4746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if(cnt < 0) {
4756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_ILLEGAL_ARGUMENT_ERROR;
4766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
4776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (msgPattern.countParts() == 0) {
4796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        status = U_INVALID_STATE_ERROR;
4806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        return appendTo;
4816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (int32_t i = 0; i < cnt; i++) {
4846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        double objDouble = objs[i].getDouble(status);
4856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (U_SUCCESS(status)) {
4866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            format(objDouble, appendTo, pos);
4876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
4886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
4896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return appendTo;
4916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
4926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
4946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
4956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgvoid
4966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::parse(const UnicodeString& text,
4976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    Formattable& result,
4986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    ParsePosition& pos) const
4996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
5006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result.setDouble(parseArgument(msgPattern, 0, text, pos));
5016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgdouble
5046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::parseArgument(
5056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern &pattern, int32_t partIndex,
5066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UnicodeString &source, ParsePosition &pos) {
5076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // find the best number (defined as the one with the longest parse)
5086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t start = pos.getIndex();
5096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t furthest = start;
5106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    double bestNumber = uprv_getNaN();
5116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    double tempNumber = 0.0;
5126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t count = pattern.countParts();
5136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    while (partIndex < count && pattern.getPartType(partIndex) != UMSGPAT_PART_TYPE_ARG_LIMIT) {
5146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        tempNumber = pattern.getNumericValue(pattern.getPart(partIndex));
5156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex += 2;  // skip the numeric part and ignore the ARG_SELECTOR
5166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t msgLimit = pattern.getLimitPartIndex(partIndex);
5176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t len = matchStringUntilLimitPart(pattern, partIndex, msgLimit, source, start);
5186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (len >= 0) {
5196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t newIndex = start + len;
5206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (newIndex > furthest) {
5216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                furthest = newIndex;
5226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                bestNumber = tempNumber;
5236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (furthest == source.length()) {
5246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    break;
5256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
5266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
5276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        partIndex = msgLimit + 1;
5296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (furthest == start) {
5316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        pos.setErrorIndex(start);
5326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
5336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        pos.setIndex(furthest);
5346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return bestNumber;
5366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgint32_t
5396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::matchStringUntilLimitPart(
5406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern &pattern, int32_t partIndex, int32_t limitPartIndex,
5416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const UnicodeString &source, int32_t sourceOffset) {
5426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t matchingSourceLength = 0;
5436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    const UnicodeString &msgString = pattern.getPatternString();
5446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t prevIndex = pattern.getPart(partIndex).getLimit();
5456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (;;) {
5466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        const MessagePattern::Part &part = pattern.getPart(++partIndex);
5476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (partIndex == limitPartIndex || part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
5486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t index = part.getIndex();
5496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            int32_t length = index - prevIndex;
5506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (length != 0 && 0 != source.compare(sourceOffset, length, msgString, prevIndex, length)) {
5516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return -1;  // mismatch
5526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
5536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            matchingSourceLength += length;
5546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (partIndex == limitPartIndex) {
5556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return matchingSourceLength;
5566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
5576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            prevIndex = part.getLimit();  // SKIP_SYNTAX
5586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
5596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
5606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// -------------------------------------
5636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgFormat*
5656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgChoiceFormat::clone() const
5666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
5676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    ChoiceFormat *aCopy = new ChoiceFormat(*this);
5686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return aCopy;
5696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
5706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_END
5726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif /* #if !UCONFIG_NO_FORMATTING */
5746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
5756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org//eof
576