intl/icu/source/i18n/choicfmt.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * Copyright (C) 1997-2013, International Business Machines Corporation and *
michael@0 4 * others. All Rights Reserved. *
michael@0 5 *******************************************************************************
michael@0 6 *
michael@0 7 * File CHOICFMT.CPP
michael@0 8 *
michael@0 9 * Modification History:
michael@0 10 *
michael@0 11 * Date Name Description
michael@0 12 * 02/19/97 aliu Converted from java.
michael@0 13 * 03/20/97 helena Finished first cut of implementation and got rid
michael@0 14 * of nextDouble/previousDouble and replaced with
michael@0 15 * boolean array.
michael@0 16 * 4/10/97 aliu Clean up. Modified to work on AIX.
michael@0 17 * 06/04/97 helena Fixed applyPattern(), toPattern() and not to include
michael@0 18 * wchar.h.
michael@0 19 * 07/09/97 helena Made ParsePosition into a class.
michael@0 20 * 08/06/97 nos removed overloaded constructor, fixed 'format(array)'
michael@0 21 * 07/22/98 stephen JDK 1.2 Sync - removed UBool array (doubleFlags)
michael@0 22 * 02/22/99 stephen Removed character literals for EBCDIC safety
michael@0 23 ********************************************************************************
michael@0 24 */
michael@0 25
michael@0 26 #include "unicode/utypes.h"
michael@0 27
michael@0 28 #if !UCONFIG_NO_FORMATTING
michael@0 29
michael@0 30 #include "unicode/choicfmt.h"
michael@0 31 #include "unicode/numfmt.h"
michael@0 32 #include "unicode/locid.h"
michael@0 33 #include "cpputils.h"
michael@0 34 #include "cstring.h"
michael@0 35 #include "messageimpl.h"
michael@0 36 #include "putilimp.h"
michael@0 37 #include "uassert.h"
michael@0 38 #include <stdio.h>
michael@0 39 #include <float.h>
michael@0 40
michael@0 41 // *****************************************************************************
michael@0 42 // class ChoiceFormat
michael@0 43 // *****************************************************************************
michael@0 44
michael@0 45 U_NAMESPACE_BEGIN
michael@0 46
michael@0 47 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChoiceFormat)
michael@0 48
michael@0 49 // Special characters used by ChoiceFormat. There are two characters
michael@0 50 // used interchangeably to indicate <=. Either is parsed, but only
michael@0 51 // LESS_EQUAL is generated by toPattern().
michael@0 52 #define SINGLE_QUOTE ((UChar)0x0027) /*'*/
michael@0 53 #define LESS_THAN ((UChar)0x003C) /*<*/
michael@0 54 #define LESS_EQUAL ((UChar)0x0023) /*#*/
michael@0 55 #define LESS_EQUAL2 ((UChar)0x2264)
michael@0 56 #define VERTICAL_BAR ((UChar)0x007C) /*|*/
michael@0 57 #define MINUS ((UChar)0x002D) /*-*/
michael@0 58
michael@0 59 static const UChar LEFT_CURLY_BRACE = 0x7B; /*{*/
michael@0 60 static const UChar RIGHT_CURLY_BRACE = 0x7D; /*}*/
michael@0 61
michael@0 62 #ifdef INFINITY
michael@0 63 #undef INFINITY
michael@0 64 #endif
michael@0 65 #define INFINITY ((UChar)0x221E)
michael@0 66
michael@0 67 //static const UChar gPositiveInfinity[] = {INFINITY, 0};
michael@0 68 //static const UChar gNegativeInfinity[] = {MINUS, INFINITY, 0};
michael@0 69 #define POSITIVE_INF_STRLEN 1
michael@0 70 #define NEGATIVE_INF_STRLEN 2
michael@0 71
michael@0 72 // -------------------------------------
michael@0 73 // Creates a ChoiceFormat instance based on the pattern.
michael@0 74
michael@0 75 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
michael@0 76 UErrorCode& status)
michael@0 77 : constructorErrorCode(status),
michael@0 78 msgPattern(status)
michael@0 79 {
michael@0 80 applyPattern(newPattern, status);
michael@0 81 }
michael@0 82
michael@0 83 // -------------------------------------
michael@0 84 // Creates a ChoiceFormat instance with the limit array and
michael@0 85 // format strings for each limit.
michael@0 86
michael@0 87 ChoiceFormat::ChoiceFormat(const double* limits,
michael@0 88 const UnicodeString* formats,
michael@0 89 int32_t cnt )
michael@0 90 : constructorErrorCode(U_ZERO_ERROR),
michael@0 91 msgPattern(constructorErrorCode)
michael@0 92 {
michael@0 93 setChoices(limits, NULL, formats, cnt, constructorErrorCode);
michael@0 94 }
michael@0 95
michael@0 96 // -------------------------------------
michael@0 97
michael@0 98 ChoiceFormat::ChoiceFormat(const double* limits,
michael@0 99 const UBool* closures,
michael@0 100 const UnicodeString* formats,
michael@0 101 int32_t cnt )
michael@0 102 : constructorErrorCode(U_ZERO_ERROR),
michael@0 103 msgPattern(constructorErrorCode)
michael@0 104 {
michael@0 105 setChoices(limits, closures, formats, cnt, constructorErrorCode);
michael@0 106 }
michael@0 107
michael@0 108 // -------------------------------------
michael@0 109 // copy constructor
michael@0 110
michael@0 111 ChoiceFormat::ChoiceFormat(const ChoiceFormat& that)
michael@0 112 : NumberFormat(that),
michael@0 113 constructorErrorCode(that.constructorErrorCode),
michael@0 114 msgPattern(that.msgPattern)
michael@0 115 {
michael@0 116 }
michael@0 117
michael@0 118 // -------------------------------------
michael@0 119 // Private constructor that creates a
michael@0 120 // ChoiceFormat instance based on the
michael@0 121 // pattern and populates UParseError
michael@0 122
michael@0 123 ChoiceFormat::ChoiceFormat(const UnicodeString& newPattern,
michael@0 124 UParseError& parseError,
michael@0 125 UErrorCode& status)
michael@0 126 : constructorErrorCode(status),
michael@0 127 msgPattern(status)
michael@0 128 {
michael@0 129 applyPattern(newPattern,parseError, status);
michael@0 130 }
michael@0 131 // -------------------------------------
michael@0 132
michael@0 133 UBool
michael@0 134 ChoiceFormat::operator==(const Format& that) const
michael@0 135 {
michael@0 136 if (this == &that) return TRUE;
michael@0 137 if (!NumberFormat::operator==(that)) return FALSE;
michael@0 138 ChoiceFormat& thatAlias = (ChoiceFormat&)that;
michael@0 139 return msgPattern == thatAlias.msgPattern;
michael@0 140 }
michael@0 141
michael@0 142 // -------------------------------------
michael@0 143 // copy constructor
michael@0 144
michael@0 145 const ChoiceFormat&
michael@0 146 ChoiceFormat::operator=(const ChoiceFormat& that)
michael@0 147 {
michael@0 148 if (this != &that) {
michael@0 149 NumberFormat::operator=(that);
michael@0 150 constructorErrorCode = that.constructorErrorCode;
michael@0 151 msgPattern = that.msgPattern;
michael@0 152 }
michael@0 153 return *this;
michael@0 154 }
michael@0 155
michael@0 156 // -------------------------------------
michael@0 157
michael@0 158 ChoiceFormat::~ChoiceFormat()
michael@0 159 {
michael@0 160 }
michael@0 161
michael@0 162 // -------------------------------------
michael@0 163
michael@0 164 /**
michael@0 165 * Convert a double value to a string without the overhead of NumberFormat.
michael@0 166 */
michael@0 167 UnicodeString&
michael@0 168 ChoiceFormat::dtos(double value,
michael@0 169 UnicodeString& string)
michael@0 170 {
michael@0 171 /* Buffer to contain the digits and any extra formatting stuff. */
michael@0 172 char temp[DBL_DIG + 16];
michael@0 173 char *itrPtr = temp;
michael@0 174 char *expPtr;
michael@0 175
michael@0 176 sprintf(temp, "%.*g", DBL_DIG, value);
michael@0 177
michael@0 178 /* Find and convert the decimal point.
michael@0 179 Using setlocale on some machines will cause sprintf to use a comma for certain locales.
michael@0 180 */
michael@0 181 while (*itrPtr && (*itrPtr == '-' || isdigit(*itrPtr))) {
michael@0 182 itrPtr++;
michael@0 183 }
michael@0 184 if (*itrPtr != 0 && *itrPtr != 'e') {
michael@0 185 /* We reached something that looks like a decimal point.
michael@0 186 In case someone used setlocale(), which changes the decimal point. */
michael@0 187 *itrPtr = '.';
michael@0 188 itrPtr++;
michael@0 189 }
michael@0 190 /* Search for the exponent */
michael@0 191 while (*itrPtr && *itrPtr != 'e') {
michael@0 192 itrPtr++;
michael@0 193 }
michael@0 194 if (*itrPtr == 'e') {
michael@0 195 itrPtr++;
michael@0 196 /* Verify the exponent sign */
michael@0 197 if (*itrPtr == '+' || *itrPtr == '-') {
michael@0 198 itrPtr++;
michael@0 199 }
michael@0 200 /* Remove leading zeros. You will see this on Windows machines. */
michael@0 201 expPtr = itrPtr;
michael@0 202 while (*itrPtr == '0') {
michael@0 203 itrPtr++;
michael@0 204 }
michael@0 205 if (*itrPtr && expPtr != itrPtr) {
michael@0 206 /* Shift the exponent without zeros. */
michael@0 207 while (*itrPtr) {
michael@0 208 *(expPtr++) = *(itrPtr++);
michael@0 209 }
michael@0 210 // NULL terminate
michael@0 211 *expPtr = 0;
michael@0 212 }
michael@0 213 }
michael@0 214
michael@0 215 string = UnicodeString(temp, -1, US_INV); /* invariant codepage */
michael@0 216 return string;
michael@0 217 }
michael@0 218
michael@0 219 // -------------------------------------
michael@0 220 // calls the overloaded applyPattern method.
michael@0 221
michael@0 222 void
michael@0 223 ChoiceFormat::applyPattern(const UnicodeString& pattern,
michael@0 224 UErrorCode& status)
michael@0 225 {
michael@0 226 msgPattern.parseChoiceStyle(pattern, NULL, status);
michael@0 227 constructorErrorCode = status;
michael@0 228 }
michael@0 229
michael@0 230 // -------------------------------------
michael@0 231 // Applies the pattern to this ChoiceFormat instance.
michael@0 232
michael@0 233 void
michael@0 234 ChoiceFormat::applyPattern(const UnicodeString& pattern,
michael@0 235 UParseError& parseError,
michael@0 236 UErrorCode& status)
michael@0 237 {
michael@0 238 msgPattern.parseChoiceStyle(pattern, &parseError, status);
michael@0 239 constructorErrorCode = status;
michael@0 240 }
michael@0 241 // -------------------------------------
michael@0 242 // Returns the input pattern string.
michael@0 243
michael@0 244 UnicodeString&
michael@0 245 ChoiceFormat::toPattern(UnicodeString& result) const
michael@0 246 {
michael@0 247 return result = msgPattern.getPatternString();
michael@0 248 }
michael@0 249
michael@0 250 // -------------------------------------
michael@0 251 // Sets the limit and format arrays.
michael@0 252 void
michael@0 253 ChoiceFormat::setChoices( const double* limits,
michael@0 254 const UnicodeString* formats,
michael@0 255 int32_t cnt )
michael@0 256 {
michael@0 257 UErrorCode errorCode = U_ZERO_ERROR;
michael@0 258 setChoices(limits, NULL, formats, cnt, errorCode);
michael@0 259 }
michael@0 260
michael@0 261 // -------------------------------------
michael@0 262 // Sets the limit and format arrays.
michael@0 263 void
michael@0 264 ChoiceFormat::setChoices( const double* limits,
michael@0 265 const UBool* closures,
michael@0 266 const UnicodeString* formats,
michael@0 267 int32_t cnt )
michael@0 268 {
michael@0 269 UErrorCode errorCode = U_ZERO_ERROR;
michael@0 270 setChoices(limits, closures, formats, cnt, errorCode);
michael@0 271 }
michael@0 272
michael@0 273 void
michael@0 274 ChoiceFormat::setChoices(const double* limits,
michael@0 275 const UBool* closures,
michael@0 276 const UnicodeString* formats,
michael@0 277 int32_t count,
michael@0 278 UErrorCode &errorCode) {
michael@0 279 if (U_FAILURE(errorCode)) {
michael@0 280 return;
michael@0 281 }
michael@0 282 if (limits == NULL || formats == NULL) {
michael@0 283 errorCode = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 284 return;
michael@0 285 }
michael@0 286 // Reconstruct the original input pattern.
michael@0 287 // Modified version of the pre-ICU 4.8 toPattern() implementation.
michael@0 288 UnicodeString result;
michael@0 289 for (int32_t i = 0; i < count; ++i) {
michael@0 290 if (i != 0) {
michael@0 291 result += VERTICAL_BAR;
michael@0 292 }
michael@0 293 UnicodeString buf;
michael@0 294 if (uprv_isPositiveInfinity(limits[i])) {
michael@0 295 result += INFINITY;
michael@0 296 } else if (uprv_isNegativeInfinity(limits[i])) {
michael@0 297 result += MINUS;
michael@0 298 result += INFINITY;
michael@0 299 } else {
michael@0 300 result += dtos(limits[i], buf);
michael@0 301 }
michael@0 302 if (closures != NULL && closures[i]) {
michael@0 303 result += LESS_THAN;
michael@0 304 } else {
michael@0 305 result += LESS_EQUAL;
michael@0 306 }
michael@0 307 // Append formats[i], using quotes if there are special
michael@0 308 // characters. Single quotes themselves must be escaped in
michael@0 309 // either case.
michael@0 310 const UnicodeString& text = formats[i];
michael@0 311 int32_t textLength = text.length();
michael@0 312 int32_t nestingLevel = 0;
michael@0 313 for (int32_t j = 0; j < textLength; ++j) {
michael@0 314 UChar c = text[j];
michael@0 315 if (c == SINGLE_QUOTE && nestingLevel == 0) {
michael@0 316 // Double each top-level apostrophe.
michael@0 317 result.append(c);
michael@0 318 } else if (c == VERTICAL_BAR && nestingLevel == 0) {
michael@0 319 // Surround each pipe symbol with apostrophes for quoting.
michael@0 320 // If the next character is an apostrophe, then that will be doubled,
michael@0 321 // and although the parser will see the apostrophe pairs beginning
michael@0 322 // and ending one character earlier than our doubling, the result
michael@0 323 // is as desired.
michael@0 324 // | -> '|'
michael@0 325 // |' -> '|'''
michael@0 326 // |'' -> '|''''' etc.
michael@0 327 result.append(SINGLE_QUOTE).append(c).append(SINGLE_QUOTE);
michael@0 328 continue; // Skip the append(c) at the end of the loop body.
michael@0 329 } else if (c == LEFT_CURLY_BRACE) {
michael@0 330 ++nestingLevel;
michael@0 331 } else if (c == RIGHT_CURLY_BRACE && nestingLevel > 0) {
michael@0 332 --nestingLevel;
michael@0 333 }
michael@0 334 result.append(c);
michael@0 335 }
michael@0 336 }
michael@0 337 // Apply the reconstructed pattern.
michael@0 338 applyPattern(result, errorCode);
michael@0 339 }
michael@0 340
michael@0 341 // -------------------------------------
michael@0 342 // Gets the limit array.
michael@0 343
michael@0 344 const double*
michael@0 345 ChoiceFormat::getLimits(int32_t& cnt) const
michael@0 346 {
michael@0 347 cnt = 0;
michael@0 348 return NULL;
michael@0 349 }
michael@0 350
michael@0 351 // -------------------------------------
michael@0 352 // Gets the closures array.
michael@0 353
michael@0 354 const UBool*
michael@0 355 ChoiceFormat::getClosures(int32_t& cnt) const
michael@0 356 {
michael@0 357 cnt = 0;
michael@0 358 return NULL;
michael@0 359 }
michael@0 360
michael@0 361 // -------------------------------------
michael@0 362 // Gets the format array.
michael@0 363
michael@0 364 const UnicodeString*
michael@0 365 ChoiceFormat::getFormats(int32_t& cnt) const
michael@0 366 {
michael@0 367 cnt = 0;
michael@0 368 return NULL;
michael@0 369 }
michael@0 370
michael@0 371 // -------------------------------------
michael@0 372 // Formats an int64 number, it's actually formatted as
michael@0 373 // a double. The returned format string may differ
michael@0 374 // from the input number because of this.
michael@0 375
michael@0 376 UnicodeString&
michael@0 377 ChoiceFormat::format(int64_t number,
michael@0 378 UnicodeString& appendTo,
michael@0 379 FieldPosition& status) const
michael@0 380 {
michael@0 381 return format((double) number, appendTo, status);
michael@0 382 }
michael@0 383
michael@0 384 // -------------------------------------
michael@0 385 // Formats an int32_t number, it's actually formatted as
michael@0 386 // a double.
michael@0 387
michael@0 388 UnicodeString&
michael@0 389 ChoiceFormat::format(int32_t number,
michael@0 390 UnicodeString& appendTo,
michael@0 391 FieldPosition& status) const
michael@0 392 {
michael@0 393 return format((double) number, appendTo, status);
michael@0 394 }
michael@0 395
michael@0 396 // -------------------------------------
michael@0 397 // Formats a double number.
michael@0 398
michael@0 399 UnicodeString&
michael@0 400 ChoiceFormat::format(double number,
michael@0 401 UnicodeString& appendTo,
michael@0 402 FieldPosition& /*pos*/) const
michael@0 403 {
michael@0 404 if (msgPattern.countParts() == 0) {
michael@0 405 // No pattern was applied, or it failed.
michael@0 406 return appendTo;
michael@0 407 }
michael@0 408 // Get the appropriate sub-message.
michael@0 409 int32_t msgStart = findSubMessage(msgPattern, 0, number);
michael@0 410 if (!MessageImpl::jdkAposMode(msgPattern)) {
michael@0 411 int32_t patternStart = msgPattern.getPart(msgStart).getLimit();
michael@0 412 int32_t msgLimit = msgPattern.getLimitPartIndex(msgStart);
michael@0 413 appendTo.append(msgPattern.getPatternString(),
michael@0 414 patternStart,
michael@0 415 msgPattern.getPatternIndex(msgLimit) - patternStart);
michael@0 416 return appendTo;
michael@0 417 }
michael@0 418 // JDK compatibility mode: Remove SKIP_SYNTAX.
michael@0 419 return MessageImpl::appendSubMessageWithoutSkipSyntax(msgPattern, msgStart, appendTo);
michael@0 420 }
michael@0 421
michael@0 422 int32_t
michael@0 423 ChoiceFormat::findSubMessage(const MessagePattern &pattern, int32_t partIndex, double number) {
michael@0 424 int32_t count = pattern.countParts();
michael@0 425 int32_t msgStart;
michael@0 426 // Iterate over (ARG_INT|DOUBLE, ARG_SELECTOR, message) tuples
michael@0 427 // until ARG_LIMIT or end of choice-only pattern.
michael@0 428 // Ignore the first number and selector and start the loop on the first message.
michael@0 429 partIndex += 2;
michael@0 430 for (;;) {
michael@0 431 // Skip but remember the current sub-message.
michael@0 432 msgStart = partIndex;
michael@0 433 partIndex = pattern.getLimitPartIndex(partIndex);
michael@0 434 if (++partIndex >= count) {
michael@0 435 // Reached the end of the choice-only pattern.
michael@0 436 // Return with the last sub-message.
michael@0 437 break;
michael@0 438 }
michael@0 439 const MessagePattern::Part &part = pattern.getPart(partIndex++);
michael@0 440 UMessagePatternPartType type = part.getType();
michael@0 441 if (type == UMSGPAT_PART_TYPE_ARG_LIMIT) {
michael@0 442 // Reached the end of the ChoiceFormat style.
michael@0 443 // Return with the last sub-message.
michael@0 444 break;
michael@0 445 }
michael@0 446 // part is an ARG_INT or ARG_DOUBLE
michael@0 447 U_ASSERT(MessagePattern::Part::hasNumericValue(type));
michael@0 448 double boundary = pattern.getNumericValue(part);
michael@0 449 // Fetch the ARG_SELECTOR character.
michael@0 450 int32_t selectorIndex = pattern.getPatternIndex(partIndex++);
michael@0 451 UChar boundaryChar = pattern.getPatternString().charAt(selectorIndex);
michael@0 452 if (boundaryChar == LESS_THAN ? !(number > boundary) : !(number >= boundary)) {
michael@0 453 // The number is in the interval between the previous boundary and the current one.
michael@0 454 // Return with the sub-message between them.
michael@0 455 // The !(a>b) and !(a>=b) comparisons are equivalent to
michael@0 456 // (a<=b) and (a<b) except they "catch" NaN.
michael@0 457 break;
michael@0 458 }
michael@0 459 }
michael@0 460 return msgStart;
michael@0 461 }
michael@0 462
michael@0 463 // -------------------------------------
michael@0 464 // Formats an array of objects. Checks if the data type of the objects
michael@0 465 // to get the right value for formatting.
michael@0 466
michael@0 467 UnicodeString&
michael@0 468 ChoiceFormat::format(const Formattable* objs,
michael@0 469 int32_t cnt,
michael@0 470 UnicodeString& appendTo,
michael@0 471 FieldPosition& pos,
michael@0 472 UErrorCode& status) const
michael@0 473 {
michael@0 474 if(cnt < 0) {
michael@0 475 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 476 return appendTo;
michael@0 477 }
michael@0 478 if (msgPattern.countParts() == 0) {
michael@0 479 status = U_INVALID_STATE_ERROR;
michael@0 480 return appendTo;
michael@0 481 }
michael@0 482
michael@0 483 for (int32_t i = 0; i < cnt; i++) {
michael@0 484 double objDouble = objs[i].getDouble(status);
michael@0 485 if (U_SUCCESS(status)) {
michael@0 486 format(objDouble, appendTo, pos);
michael@0 487 }
michael@0 488 }
michael@0 489
michael@0 490 return appendTo;
michael@0 491 }
michael@0 492
michael@0 493 // -------------------------------------
michael@0 494
michael@0 495 void
michael@0 496 ChoiceFormat::parse(const UnicodeString& text,
michael@0 497 Formattable& result,
michael@0 498 ParsePosition& pos) const
michael@0 499 {
michael@0 500 result.setDouble(parseArgument(msgPattern, 0, text, pos));
michael@0 501 }
michael@0 502
michael@0 503 double
michael@0 504 ChoiceFormat::parseArgument(
michael@0 505 const MessagePattern &pattern, int32_t partIndex,
michael@0 506 const UnicodeString &source, ParsePosition &pos) {
michael@0 507 // find the best number (defined as the one with the longest parse)
michael@0 508 int32_t start = pos.getIndex();
michael@0 509 int32_t furthest = start;
michael@0 510 double bestNumber = uprv_getNaN();
michael@0 511 double tempNumber = 0.0;
michael@0 512 int32_t count = pattern.countParts();
michael@0 513 while (partIndex < count && pattern.getPartType(partIndex) != UMSGPAT_PART_TYPE_ARG_LIMIT) {
michael@0 514 tempNumber = pattern.getNumericValue(pattern.getPart(partIndex));
michael@0 515 partIndex += 2; // skip the numeric part and ignore the ARG_SELECTOR
michael@0 516 int32_t msgLimit = pattern.getLimitPartIndex(partIndex);
michael@0 517 int32_t len = matchStringUntilLimitPart(pattern, partIndex, msgLimit, source, start);
michael@0 518 if (len >= 0) {
michael@0 519 int32_t newIndex = start + len;
michael@0 520 if (newIndex > furthest) {
michael@0 521 furthest = newIndex;
michael@0 522 bestNumber = tempNumber;
michael@0 523 if (furthest == source.length()) {
michael@0 524 break;
michael@0 525 }
michael@0 526 }
michael@0 527 }
michael@0 528 partIndex = msgLimit + 1;
michael@0 529 }
michael@0 530 if (furthest == start) {
michael@0 531 pos.setErrorIndex(start);
michael@0 532 } else {
michael@0 533 pos.setIndex(furthest);
michael@0 534 }
michael@0 535 return bestNumber;
michael@0 536 }
michael@0 537
michael@0 538 int32_t
michael@0 539 ChoiceFormat::matchStringUntilLimitPart(
michael@0 540 const MessagePattern &pattern, int32_t partIndex, int32_t limitPartIndex,
michael@0 541 const UnicodeString &source, int32_t sourceOffset) {
michael@0 542 int32_t matchingSourceLength = 0;
michael@0 543 const UnicodeString &msgString = pattern.getPatternString();
michael@0 544 int32_t prevIndex = pattern.getPart(partIndex).getLimit();
michael@0 545 for (;;) {
michael@0 546 const MessagePattern::Part &part = pattern.getPart(++partIndex);
michael@0 547 if (partIndex == limitPartIndex || part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
michael@0 548 int32_t index = part.getIndex();
michael@0 549 int32_t length = index - prevIndex;
michael@0 550 if (length != 0 && 0 != source.compare(sourceOffset, length, msgString, prevIndex, length)) {
michael@0 551 return -1; // mismatch
michael@0 552 }
michael@0 553 matchingSourceLength += length;
michael@0 554 if (partIndex == limitPartIndex) {
michael@0 555 return matchingSourceLength;
michael@0 556 }
michael@0 557 prevIndex = part.getLimit(); // SKIP_SYNTAX
michael@0 558 }
michael@0 559 }
michael@0 560 }
michael@0 561
michael@0 562 // -------------------------------------
michael@0 563
michael@0 564 Format*
michael@0 565 ChoiceFormat::clone() const
michael@0 566 {
michael@0 567 ChoiceFormat *aCopy = new ChoiceFormat(*this);
michael@0 568 return aCopy;
michael@0 569 }
michael@0 570
michael@0 571 U_NAMESPACE_END
michael@0 572
michael@0 573 #endif /* #if !UCONFIG_NO_FORMATTING */
michael@0 574
michael@0 575 //eof

mercurial