Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 1997-2009, International Business Machines Corporation and    *
      4 * others. All Rights Reserved.                                                *
      5 *******************************************************************************
      6 *
      7 * File CHOICFMT.CPP
      8 *
      9 * Modification History:
     10 *
     11 *   Date        Name        Description
     12 *   02/19/97    aliu        Converted from java.
     13 *   03/20/97    helena      Finished first cut of implementation and got rid
     14 *                           of nextDouble/previousDouble and replaced with
     15 *                           boolean array.
     16 *   4/10/97     aliu        Clean up.  Modified to work on AIX.
     17 *   06/04/97    helena      Fixed applyPattern(), toPattern() and not to include
     18 *                           wchar.h.
     19 *   07/09/97    helena      Made ParsePosition into a class.
     20 *   08/06/97    nos         removed overloaded constructor, fixed 'format(array)'
     21 *   07/22/98    stephen     JDK 1.2 Sync - removed UBool array (doubleFlags)
     22 *   02/22/99    stephen     Removed character literals for EBCDIC safety
     23 ********************************************************************************
     24 */
     25 
     26 #include "unicode/utypes.h"
     27 
     28 #if !UCONFIG_NO_FORMATTING
     29 
     30 #include "unicode/choicfmt.h"
     31 #include "unicode/numfmt.h"
     32 #include "unicode/locid.h"
     33 #include "cpputils.h"
     34 #include "cstring.h"
     35 #include "putilimp.h"
     36 #include <stdio.h>
     37 #include <float.h>
     38 
     39 // *****************************************************************************
     40 // class ChoiceFormat
     41 // *****************************************************************************
     42 
     43 U_NAMESPACE_BEGIN
     44 
     45 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
     46 
     47 // Special characters used by ChoiceFormat.  There are two characters
     48 // used interchangeably to indicate <=.  Either is parsed, but only
     49 // LESS_EQUAL is generated by toPattern().
     50 #define SINGLE_QUOTE ((UChar)0x0027)   /*'*/
     51 #define LESS_THAN    ((UChar)0x003C)   /*<*/
     52 #define LESS_EQUAL   ((UChar)0x0023)   /*#*/
     53 #define LESS_EQUAL2  ((UChar)0x2264)
     54 #define VERTICAL_BAR ((UChar)0x007C)   /*|*/
     55 #define MINUS        ((UChar)0x002D)   /*-*/
     56 
     57 #ifdef INFINITY
     58 #undef INFINITY
     59 #endif
     60 #define INFINITY     ((UChar)0x221E)
     61 
     62 static const UChar gPositiveInfinity[] = {INFINITY, 0};
     63 static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
     64 #define POSITIVE_INF_STRLEN 1
     65 #define NEGATIVE_INF_STRLEN 2
     66 
     67 // -------------------------------------
     68 // Creates a ChoiceFormat instance based on the pattern.
     69 
     70 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
     71                            UErrorCode& status)
     72 : fChoiceLimits(0),
     73   fClosures(0),
     74   fChoiceFormats(0),
     75   fCount(0)
     76 {
     77     applyPattern(newPattern, status);
     78 }
     79 
     80 // -------------------------------------
     81 // Creates a ChoiceFormat instance with the limit array and
     82 // format strings for each limit.
     83 
     84 ChoiceFormat::ChoiceFormat(const double* limits,
     85                            const UnicodeString* formats,
     86                            int32_t cnt )
     87 : fChoiceLimits(0),
     88   fClosures(0),
     89   fChoiceFormats(0),
     90   fCount(0)
     91 {
     92     setChoices(limits, formats, cnt );
     93 }
     94 
     95 // -------------------------------------
     96 
     97 ChoiceFormat::ChoiceFormat(const double* limits,
     98                            const UBool* closures,
     99                            const UnicodeString* formats,
    100                            int32_t cnt )
    101 : fChoiceLimits(0),
    102   fClosures(0),
    103   fChoiceFormats(0),
    104   fCount(0)
    105 {
    106     setChoices(limits, closures, formats, cnt );
    107 }
    108 
    109 // -------------------------------------
    110 // copy constructor
    111 
    112 ChoiceFormat::ChoiceFormat(const    ChoiceFormat&   that)
    113 : NumberFormat(that),
    114   fChoiceLimits(0),
    115   fClosures(0),
    116   fChoiceFormats(0)
    117 {
    118     *this = that;
    119 }
    120 
    121 // -------------------------------------
    122 // Private constructor that creates a
    123 // ChoiceFormat instance based on the
    124 // pattern and populates UParseError
    125 
    126 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
    127                            UParseError& parseError,
    128                            UErrorCode& status)
    129 : fChoiceLimits(0),
    130   fClosures(0),
    131   fChoiceFormats(0),
    132   fCount(0)
    133 {
    134     applyPattern(newPattern,parseError, status);
    135 }
    136 // -------------------------------------
    137 
    138 UBool
    139 ChoiceFormat::operator==(const Format& that) const
    140 {
    141     if (this == &that) return TRUE;
    142     if (!NumberFormat::operator==(that)) return FALSE;
    143     ChoiceFormat& thatAlias = (ChoiceFormat&)that;
    144     if (fCount != thatAlias.fCount) return FALSE;
    145     // Checks the limits, the corresponding format string and LE or LT flags.
    146     // LE means less than and equal to, LT means less than.
    147     for (int32_t i = 0; i < fCount; i++) {
    148         if ((fChoiceLimits[i] != thatAlias.fChoiceLimits[i]) ||
    149             (fClosures[i] != thatAlias.fClosures[i]) ||
    150             (fChoiceFormats[i] != thatAlias.fChoiceFormats[i]))
    151             return FALSE;
    152     }
    153     return TRUE;
    154 }
    155 
    156 // -------------------------------------
    157 // copy constructor
    158 
    159 const ChoiceFormat&
    160 ChoiceFormat::operator=(const   ChoiceFormat& that)
    161 {
    162     if (this != &that) {
    163         NumberFormat::operator=(that);
    164         fCount = that.fCount;
    165         uprv_free(fChoiceLimits);
    166         fChoiceLimits = NULL;
    167         uprv_free(fClosures);
    168         fClosures = NULL;
    169         delete [] fChoiceFormats;
    170         fChoiceFormats = NULL;
    171 
    172         fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
    173         fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
    174         fChoiceFormats = new UnicodeString[fCount];
    175 
    176         // check for memory allocation error
    177         if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
    178             if (fChoiceLimits) {
    179                 uprv_free(fChoiceLimits);
    180                 fChoiceLimits = NULL;
    181             }
    182             if (fClosures) {
    183                 uprv_free(fClosures);
    184                 fClosures = NULL;
    185             }
    186             if (fChoiceFormats) {
    187                 delete[] fChoiceFormats;
    188                 fChoiceFormats = NULL;
    189             }
    190         } else {
    191             uprv_arrayCopy(that.fChoiceLimits, fChoiceLimits, fCount);
    192             uprv_arrayCopy(that.fClosures, fClosures, fCount);
    193             uprv_arrayCopy(that.fChoiceFormats, fChoiceFormats, fCount);
    194         }
    195     }
    196     return *this;
    197 }
    198 
    199 // -------------------------------------
    200 
    201 ChoiceFormat::~ChoiceFormat()
    202 {
    203     uprv_free(fChoiceLimits);
    204     fChoiceLimits = NULL;
    205     uprv_free(fClosures);
    206     fClosures = NULL;
    207     delete [] fChoiceFormats;
    208     fChoiceFormats = NULL;
    209     fCount = 0;
    210 }
    211 
    212 /**
    213  * Convert a string to a double value
    214  */
    215 double
    216 ChoiceFormat::stod(const UnicodeString& string)
    217 {
    218     char source[256];
    219     char* end;
    220 
    221     string.extract(0, string.length(), source, (int32_t)sizeof(source), US_INV);    /* invariant codepage */
    222     return uprv_strtod(source,&end);
    223 }
    224 
    225 // -------------------------------------
    226 
    227 /**
    228  * Convert a double value to a string without the overhead of ICU.
    229  */
    230 UnicodeString&
    231 ChoiceFormat::dtos(double value,
    232                    UnicodeString& string)
    233 {
    234     /* Buffer to contain the digits and any extra formatting stuff. */
    235     char temp[DBL_DIG + 16];
    236     char *itrPtr = temp;
    237     char *expPtr;
    238 
    239     sprintf(temp, "%.*g", DBL_DIG, value);
    240 
    241     /* Find and convert the decimal point.
    242        Using setlocale on some machines will cause sprintf to use a comma for certain locales.
    243     */
    244     while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
    245         itrPtr++;
    246     }
    247     if (*itrPtr != 0 && *itrPtr != 'e') {
    248         /* We reached something that looks like a decimal point.
    249         In case someone used setlocale(), which changes the decimal point. */
    250         *itrPtr = '.';
    251         itrPtr++;
    252     }
    253     /* Search for the exponent */
    254     while (*itrPtr && *itrPtr != 'e') {
    255         itrPtr++;
    256     }
    257     if (*itrPtr == 'e') {
    258         itrPtr++;
    259         /* Verify the exponent sign */
    260         if (*itrPtr == '+' || *itrPtr == '-') {
    261             itrPtr++;
    262         }
    263         /* Remove leading zeros. You will see this on Windows machines. */
    264         expPtr = itrPtr;
    265         while (*itrPtr == '0') {
    266             itrPtr++;
    267         }
    268         if (*itrPtr && expPtr != itrPtr) {
    269             /* Shift the exponent without zeros. */
    270             while (*itrPtr) {
    271                 *(expPtr++)  = *(itrPtr++);
    272             }
    273             // NULL terminate
    274             *expPtr = 0;
    275         }
    276     }
    277 
    278     string = UnicodeString(temp, -1, US_INV);    /* invariant codepage */
    279     return string;
    280 }
    281 
    282 // -------------------------------------
    283 // calls the overloaded applyPattern method.
    284 
    285 void
    286 ChoiceFormat::applyPattern(const UnicodeString& pattern,
    287                            UErrorCode& status)
    288 {
    289     UParseError parseError;
    290     applyPattern(pattern, parseError, status);
    291 }
    292 
    293 // -------------------------------------
    294 // Applies the pattern to this ChoiceFormat instance.
    295 
    296 void
    297 ChoiceFormat::applyPattern(const UnicodeString& pattern,
    298                            UParseError& parseError,
    299                            UErrorCode& status)
    300 {
    301     if (U_FAILURE(status))
    302     {
    303         return;
    304     }
    305 
    306     // Clear error struct
    307     parseError.offset = -1;
    308     parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
    309 
    310     // Perform 2 passes.  The first computes the number of limits in
    311     // this pattern (fCount), which is 1 more than the number of
    312     // literal VERTICAL_BAR characters.
    313     int32_t count = 1;
    314     int32_t i;
    315     for (i=0; i<pattern.length(); ++i) {
    316         UChar c = pattern[i];
    317         if (c == SINGLE_QUOTE) {
    318             // Skip over the entire quote, including embedded
    319             // contiguous pairs of SINGLE_QUOTE.
    320             for (;;) {
    321                 do {
    322                     ++i;
    323                 } while (i<pattern.length() &&
    324                          pattern[i] != SINGLE_QUOTE);
    325                 if ((i+1)<pattern.length() &&
    326                     pattern[i+1] == SINGLE_QUOTE) {
    327                     // SINGLE_QUOTE pair; skip over it
    328                     ++i;
    329                 } else {
    330                     break;
    331                 }
    332             }
    333         } else if (c == VERTICAL_BAR) {
    334             ++count;
    335         }
    336     }
    337 
    338     // Allocate the required storage.
    339     double *newLimits = (double*) uprv_malloc( sizeof(double) * count);
    340     /* test for NULL */
    341     if (newLimits == 0) {
    342         status = U_MEMORY_ALLOCATION_ERROR;
    343         return;
    344     }
    345     UBool *newClosures = (UBool*) uprv_malloc( sizeof(UBool) * count);
    346     /* test for NULL */
    347     if (newClosures == 0) {
    348         status = U_MEMORY_ALLOCATION_ERROR;
    349         uprv_free(newLimits);
    350         return;
    351     }
    352     UnicodeString *newFormats = new UnicodeString[count];
    353     /* test for NULL */
    354     if (newFormats == 0) {
    355         status = U_MEMORY_ALLOCATION_ERROR;
    356         uprv_free(newLimits);
    357         uprv_free(newClosures);
    358         return;
    359     }
    360 
    361     // Perform the second pass
    362     int32_t k = 0; // index into newXxx[] arrays
    363     UnicodeString buf; // scratch buffer
    364     UBool inQuote = FALSE;
    365     UBool inNumber = TRUE; // TRUE before < or #, FALSE after
    366 
    367     for (i=0; i<pattern.length(); ++i) {
    368         UChar c = pattern[i];
    369         if (c == SINGLE_QUOTE) {
    370             // Check for SINGLE_QUOTE pair indicating a literal quote
    371             if ((i+1) < pattern.length() &&
    372                 pattern[i+1] == SINGLE_QUOTE) {
    373                 buf += SINGLE_QUOTE;
    374                 ++i;
    375             } else {
    376                 inQuote = !inQuote;
    377             }
    378         } else if (inQuote) {
    379             buf += c;
    380         } else if (c == LESS_THAN || c == LESS_EQUAL || c == LESS_EQUAL2) {
    381             if (!inNumber || buf.length() == 0) {
    382                 goto error;
    383             }
    384             inNumber = FALSE;
    385 
    386             double limit;
    387             buf.trim();
    388             if (!buf.compare(gPositiveInfinity, POSITIVE_INF_STRLEN)) {
    389                 limit = uprv_getInfinity();
    390             } else if (!buf.compare(gNegativeInfinity, NEGATIVE_INF_STRLEN)) {
    391                 limit = -uprv_getInfinity();
    392             } else {
    393                 limit = stod(buf);
    394             }
    395 
    396             if (k == count) {
    397                 // This shouldn't happen.  If it does, it means that
    398                 // the count determined in the first pass did not
    399                 // match the number of elements found in the second
    400                 // pass.
    401                 goto error;
    402             }
    403             newLimits[k] = limit;
    404             newClosures[k] = (c == LESS_THAN);
    405 
    406             if (k > 0 && limit <= newLimits[k-1]) {
    407                 // Each limit must be strictly > than the previous
    408                 // limit.  One exception: Two subsequent limits may be
    409                 // == if the first closure is FALSE and the second
    410                 // closure is TRUE.  This places the limit value in
    411                 // the second interval.
    412                 if (!(limit == newLimits[k-1] &&
    413                       !newClosures[k-1] &&
    414                       newClosures[k])) {
    415                     goto error;
    416                 }
    417             }
    418 
    419             buf.truncate(0);
    420         } else if (c == VERTICAL_BAR) {
    421             if (inNumber) {
    422                 goto error;
    423             }
    424             inNumber = TRUE;
    425 
    426             newFormats[k] = buf;
    427             ++k;
    428             buf.truncate(0);
    429         } else {
    430             buf += c;
    431         }
    432     }
    433 
    434     if (k != (count-1) || inNumber || inQuote) {
    435         goto error;
    436     }
    437     newFormats[k] = buf;
    438 
    439     // Don't modify this object until the parse succeeds
    440     uprv_free(fChoiceLimits);
    441     uprv_free(fClosures);
    442     delete[] fChoiceFormats;
    443     fCount = count;
    444     fChoiceLimits  = newLimits;
    445     fClosures      = newClosures;
    446     fChoiceFormats = newFormats;
    447     return;
    448 
    449 error:
    450     status = U_ILLEGAL_ARGUMENT_ERROR;
    451     syntaxError(pattern,i,parseError);
    452     uprv_free(newLimits);
    453     uprv_free(newClosures);
    454     delete[] newFormats;
    455     return;
    456 
    457 }
    458 // -------------------------------------
    459 // Reconstruct the original input pattern.
    460 
    461 UnicodeString&
    462 ChoiceFormat::toPattern(UnicodeString& result) const
    463 {
    464     result.remove();
    465     for (int32_t i = 0; i < fCount; ++i) {
    466         if (i != 0) {
    467             result += VERTICAL_BAR;
    468         }
    469         UnicodeString buf;
    470         if (uprv_isPositiveInfinity(fChoiceLimits[i])) {
    471             result += INFINITY;
    472         } else if (uprv_isNegativeInfinity(fChoiceLimits[i])) {
    473             result += MINUS;
    474             result += INFINITY;
    475         } else {
    476             result += dtos(fChoiceLimits[i], buf);
    477         }
    478         if (fClosures[i]) {
    479             result += LESS_THAN;
    480         } else {
    481             result += LESS_EQUAL;
    482         }
    483         // Append fChoiceFormats[i], using quotes if there are special
    484         // characters.  Single quotes themselves must be escaped in
    485         // either case.
    486         const UnicodeString& text = fChoiceFormats[i];
    487         UBool needQuote = text.indexOf(LESS_THAN) >= 0
    488             || text.indexOf(LESS_EQUAL) >= 0
    489             || text.indexOf(LESS_EQUAL2) >= 0
    490             || text.indexOf(VERTICAL_BAR) >= 0;
    491         if (needQuote) {
    492             result += SINGLE_QUOTE;
    493         }
    494         if (text.indexOf(SINGLE_QUOTE) < 0) {
    495             result += text;
    496         }
    497         else {
    498             for (int32_t j = 0; j < text.length(); ++j) {
    499                 UChar c = text[j];
    500                 result += c;
    501                 if (c == SINGLE_QUOTE) {
    502                     result += c;
    503                 }
    504             }
    505         }
    506         if (needQuote) {
    507             result += SINGLE_QUOTE;
    508         }
    509     }
    510 
    511     return result;
    512 }
    513 
    514 // -------------------------------------
    515 // Sets the limit and format arrays.
    516 void
    517 ChoiceFormat::setChoices(  const double* limits,
    518                            const UnicodeString* formats,
    519                            int32_t cnt )
    520 {
    521     setChoices(limits, 0, formats, cnt);
    522 }
    523 
    524 // -------------------------------------
    525 // Sets the limit and format arrays.
    526 void
    527 ChoiceFormat::setChoices(  const double* limits,
    528                            const UBool* closures,
    529                            const UnicodeString* formats,
    530                            int32_t cnt )
    531 {
    532     if(limits == 0 || formats == 0)
    533         return;
    534 
    535     if (fChoiceLimits) {
    536         uprv_free(fChoiceLimits);
    537     }
    538     if (fClosures) {
    539         uprv_free(fClosures);
    540     }
    541     if (fChoiceFormats) {
    542         delete [] fChoiceFormats;
    543     }
    544 
    545     // Note that the old arrays are deleted and this owns
    546     // the created array.
    547     fCount = cnt;
    548     fChoiceLimits = (double*) uprv_malloc( sizeof(double) * fCount);
    549     fClosures = (UBool*) uprv_malloc( sizeof(UBool) * fCount);
    550     fChoiceFormats = new UnicodeString[fCount];
    551 
    552     //check for memory allocation error
    553     if (!fChoiceLimits || !fClosures || !fChoiceFormats) {
    554         if (fChoiceLimits) {
    555             uprv_free(fChoiceLimits);
    556             fChoiceLimits = NULL;
    557         }
    558         if (fClosures) {
    559             uprv_free(fClosures);
    560             fClosures = NULL;
    561         }
    562         if (fChoiceFormats) {
    563             delete[] fChoiceFormats;
    564             fChoiceFormats = NULL;
    565         }
    566         return;
    567     }
    568 
    569     uprv_arrayCopy(limits, fChoiceLimits, fCount);
    570     uprv_arrayCopy(formats, fChoiceFormats, fCount);
    571 
    572     if (closures != 0) {
    573         uprv_arrayCopy(closures, fClosures, fCount);
    574     } else {
    575         int32_t i;
    576         for (i=0; i<fCount; ++i) {
    577             fClosures[i] = FALSE;
    578         }
    579     }
    580 }
    581 
    582 // -------------------------------------
    583 // Gets the limit array.
    584 
    585 const double*
    586 ChoiceFormat::getLimits(int32_t& cnt) const
    587 {
    588     cnt = fCount;
    589     return fChoiceLimits;
    590 }
    591 
    592 // -------------------------------------
    593 // Gets the closures array.
    594 
    595 const UBool*
    596 ChoiceFormat::getClosures(int32_t& cnt) const
    597 {
    598     cnt = fCount;
    599     return fClosures;
    600 }
    601 
    602 // -------------------------------------
    603 // Gets the format array.
    604 
    605 const UnicodeString*
    606 ChoiceFormat::getFormats(int32_t& cnt) const
    607 {
    608     cnt = fCount;
    609     return fChoiceFormats;
    610 }
    611 
    612 // -------------------------------------
    613 // Formats an int64 number, it's actually formatted as
    614 // a double.  The returned format string may differ
    615 // from the input number because of this.
    616 
    617 UnicodeString&
    618 ChoiceFormat::format(int64_t number,
    619                      UnicodeString& appendTo,
    620                      FieldPosition& status) const
    621 {
    622     return format((double) number, appendTo, status);
    623 }
    624 
    625 // -------------------------------------
    626 // Formats a long number, it's actually formatted as
    627 // a double.  The returned format string may differ
    628 // from the input number because of this.
    629 
    630 UnicodeString&
    631 ChoiceFormat::format(int32_t number,
    632                      UnicodeString& appendTo,
    633                      FieldPosition& status) const
    634 {
    635     return format((double) number, appendTo, status);
    636 }
    637 
    638 // -------------------------------------
    639 // Formats a double number.
    640 
    641 UnicodeString&
    642 ChoiceFormat::format(double number,
    643                      UnicodeString& appendTo,
    644                      FieldPosition& /*pos*/) const
    645 {
    646     // find the number
    647     int32_t i;
    648     for (i = 0; i < fCount; ++i) {
    649         if (fClosures[i]) {
    650             if (!(number > fChoiceLimits[i])) {
    651                 // same as number <= fChoiceLimits, except catches NaN
    652                 break;
    653             }
    654         } else if (!(number >= fChoiceLimits[i])) {
    655             // same as number < fChoiceLimits, except catches NaN
    656             break;
    657         }
    658     }
    659     --i;
    660     if (i < 0) {
    661         i = 0;
    662     }
    663     // return either a formatted number, or a string
    664     appendTo += fChoiceFormats[i];
    665     return appendTo;
    666 }
    667 
    668 // -------------------------------------
    669 // Formats an array of objects. Checks if the data type of the objects
    670 // to get the right value for formatting.
    671 
    672 UnicodeString&
    673 ChoiceFormat::format(const Formattable* objs,
    674                      int32_t cnt,
    675                      UnicodeString& appendTo,
    676                      FieldPosition& pos,
    677                      UErrorCode& status) const
    678 {
    679     if(cnt < 0) {
    680         status = U_ILLEGAL_ARGUMENT_ERROR;
    681         return appendTo;
    682     }
    683 
    684     UnicodeString buffer;
    685     for (int32_t i = 0; i < cnt; i++) {
    686         double objDouble = objs[i].getDouble(status);
    687         if (U_SUCCESS(status)) {
    688             buffer.remove();
    689             appendTo += format(objDouble, buffer, pos);
    690         }
    691     }
    692 
    693     return appendTo;
    694 }
    695 
    696 // -------------------------------------
    697 // Formats an array of objects. Checks if the data type of the objects
    698 // to get the right value for formatting.
    699 
    700 UnicodeString&
    701 ChoiceFormat::format(const Formattable& obj,
    702                      UnicodeString& appendTo,
    703                      FieldPosition& pos,
    704                      UErrorCode& status) const
    705 {
    706     return NumberFormat::format(obj, appendTo, pos, status);
    707 }
    708 // -------------------------------------
    709 
    710 void
    711 ChoiceFormat::parse(const UnicodeString& text,
    712                     Formattable& result,
    713                     ParsePosition& status) const
    714 {
    715     // find the best number (defined as the one with the longest parse)
    716     int32_t start = status.getIndex();
    717     int32_t furthest = start;
    718     double bestNumber = uprv_getNaN();
    719     double tempNumber = 0.0;
    720     for (int i = 0; i < fCount; ++i) {
    721         int32_t len = fChoiceFormats[i].length();
    722         if (text.compare(start, len, fChoiceFormats[i]) == 0) {
    723             status.setIndex(start + len);
    724             tempNumber = fChoiceLimits[i];
    725             if (status.getIndex() > furthest) {
    726                 furthest = status.getIndex();
    727                 bestNumber = tempNumber;
    728                 if (furthest == text.length())
    729                     break;
    730             }
    731         }
    732     }
    733     status.setIndex(furthest);
    734     if (status.getIndex() == start) {
    735         status.setErrorIndex(furthest);
    736     }
    737     result.setDouble(bestNumber);
    738 }
    739 
    740 // -------------------------------------
    741 // Parses the text and return the Formattable object.
    742 
    743 void
    744 ChoiceFormat::parse(const UnicodeString& text,
    745                     Formattable& result,
    746                     UErrorCode& status) const
    747 {
    748     NumberFormat::parse(text, result, status);
    749 }
    750 
    751 // -------------------------------------
    752 
    753 Format*
    754 ChoiceFormat::clone() const
    755 {
    756     ChoiceFormat *aCopy = new ChoiceFormat(*this);
    757     return aCopy;
    758 }
    759 
    760 U_NAMESPACE_END
    761 
    762 #endif /* #if !UCONFIG_NO_FORMATTING */
    763 
    764 //eof
    765