/* ******************************************************************************* * Copyright (C) 1997-1999, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * * File MSGFMT.CPP * * Modification History: * * Date Name Description * 02/19/97 aliu Converted from java. * 03/20/97 helena Finished first cut of implementation. * 04/10/97 aliu Made to work on AIX. Added stoi to replace wtoi. * 06/11/97 helena Fixed addPattern to take the pattern correctly. * 06/17/97 helena Fixed the getPattern to return the correct pattern. * 07/09/97 helena Made ParsePosition into a class. * 02/22/99 stephen Removed character literals for EBCDIC safety ******************************************************************************** */ #include "unicode/msgfmt.h" #include "unicode/decimfmt.h" #include "unicode/datefmt.h" #include "unicode/smpdtfmt.h" #include "unicode/choicfmt.h" #include "mutex.h" // ***************************************************************************** // class MessageFormat // ***************************************************************************** // ------------------------------------- char MessageFormat::fgClassID = 0; // Value is irrelevant // This global NumberFormat instance is shared by all MessageFormat to // convert a number to(format)/from(parse) a string. NumberFormat* MessageFormat::fgNumberFormat = 0; // ------------------------------------- // Creates a MessageFormat instance based on the pattern. MessageFormat::MessageFormat(const UnicodeString& pattern, UErrorCode& success) : fOffsets(NULL), fArgumentNumbers(NULL), fLocale(Locale::getDefault()), // Uses the default locale fCount(0) { fCount = kMaxFormat; fOffsets = new int32_t[fCount]; fArgumentNumbers = new int32_t[fCount]; for (int32_t i = 0; i < fCount; i++) { fFormats[i] = NULL; // Format instances fOffsets[i] = 0; // Starting offset fArgumentNumbers[i] = 0; // Argument numbers. } applyPattern(pattern, success); } MessageFormat::MessageFormat(const UnicodeString& pattern, const Locale& newLocale, UErrorCode& success) : fOffsets(NULL), fArgumentNumbers(NULL), fLocale(newLocale), // Uses the default locale fCount(0) { fCount = kMaxFormat; fOffsets = new int32_t[fCount]; fArgumentNumbers = new int32_t[fCount]; for (int32_t i = 0; i < fCount; i++) { fFormats[i] = NULL; // Format instances fOffsets[i] = 0; // Starting offset fArgumentNumbers[i] = 0; // Argument numbers. } applyPattern(pattern, success); } MessageFormat::~MessageFormat() { for (int32_t i = 0; i < fCount; i++) delete fFormats[i]; delete [] fOffsets; delete [] fArgumentNumbers; fCount = 0; } // ------------------------------------- // copy constructor MessageFormat::MessageFormat(const MessageFormat& that) : Format(that), fOffsets(NULL), fCount(that.fCount), fLocale(that.fLocale), fMaxOffset(that.fMaxOffset), fArgumentNumbers(NULL), fPattern(that.fPattern) { fOffsets = new int32_t[fCount]; fArgumentNumbers = new int32_t[fCount]; // Sets up the format instance array, offsets and argument numbers. for (int32_t i = 0; i < fCount; i++) { fFormats[i] = NULL; // init since delete may be called if (that.fFormats[i] != NULL) { setFormat(i, *(that.fFormats[i]) ); // setFormat clones the format } fOffsets[i] = that.fOffsets[i]; fArgumentNumbers[i] = that.fArgumentNumbers[i]; } } // ------------------------------------- // assignment operator const MessageFormat& MessageFormat::operator=(const MessageFormat& that) { if (this != &that) { // Calls the super class for assignment first. Format::operator=(that); // Cleans up the format array and the offsets, argument numbers. for (int32_t j = 0; j < fCount; j++) { delete fFormats[j]; fFormats[j] = NULL; } delete [] fOffsets; fOffsets = NULL; delete [] fArgumentNumbers; fArgumentNumbers = NULL; fPattern = that.fPattern; fLocale = that.fLocale; fCount = that.fCount; fMaxOffset = that.fMaxOffset; fOffsets = new int32_t[fCount]; fArgumentNumbers = new int32_t[fCount]; // Sets up the format instance array, offsets and argument numbers. for (int32_t i = 0; i < fCount; i++) { if (that.fFormats[i] == NULL) { fFormats[i] = NULL; }else{ adoptFormat(i, that.fFormats[i]->clone()); } fOffsets[i] = that.fOffsets[i]; fArgumentNumbers[i] = that.fArgumentNumbers[i]; } } return *this; } UBool MessageFormat::operator==(const Format& that) const { if (this == &that) return TRUE; // Are the instances derived from the same Format class? if (getStaticClassID() != that.getDynamicClassID()) return FALSE; // not the same class // Calls the super class for equality check first. if (!Format::operator==(that)) return FALSE; MessageFormat& thatAlias = (MessageFormat&)that; // Checks the pattern, locale and array count of this MessageFormat object. if (fMaxOffset != thatAlias.fMaxOffset) return FALSE; if (fPattern != thatAlias.fPattern) return FALSE; if (fLocale != thatAlias.fLocale) return FALSE; if (fCount != thatAlias.fCount) return FALSE; // Checks each element in the arrays for equality last. for (int32_t i = 0; i < fCount; i++) { if ((fFormats[i] != thatAlias.fFormats[i]) || (fOffsets[i] != thatAlias.fOffsets[i]) || (fArgumentNumbers[i] != thatAlias.fArgumentNumbers[i])) return FALSE; } return TRUE; } // ------------------------------------- // Creates a copy of this MessageFormat, the caller owns the copy. Format* MessageFormat::clone() const { MessageFormat *aCopy = new MessageFormat(*this); return aCopy; } // ------------------------------------- // Sets the locale of this MessageFormat object to theLocale. void MessageFormat::setLocale(const Locale& theLocale) { fLocale = theLocale; } // ------------------------------------- // Gets the locale of this MessageFormat object. const Locale& MessageFormat::getLocale() const { return fLocale; } // ------------------------------------- // Applies the new pattern and returns an error if the pattern // is not correct. // For example, consider the pattern, // "There {0,choice,0#are no files|1#is one file|1getDynamicClassID() == DecimalFormat::getStaticClassID()) { UErrorCode status = U_ZERO_ERROR; NumberFormat& formatAlias = *(NumberFormat*)fFormats[i]; NumberFormat *numberTemplate = NumberFormat::createInstance(fLocale, status); NumberFormat *currencyTemplate = NumberFormat::createCurrencyInstance(fLocale, status); NumberFormat *percentTemplate = NumberFormat::createPercentInstance(fLocale, status); NumberFormat *integerTemplate = createIntegerFormat(fLocale, status); if (formatAlias == *numberTemplate) { result += ",number"; } else if (formatAlias == *currencyTemplate) { result += ",number,currency"; } else if (formatAlias == *percentTemplate) { result += ",number,percent"; } else if (formatAlias == *integerTemplate) { result += ",number,integer"; } else { UnicodeString buffer; result += ",number,"; result += ((DecimalFormat*)fFormats[i])->toPattern(buffer); } delete numberTemplate; delete currencyTemplate; delete percentTemplate; delete integerTemplate; } else if (fFormats[i]->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) { UErrorCode success = U_ZERO_ERROR; DateFormat& formatAlias = *(DateFormat*)fFormats[i]; DateFormat *defaultDateTemplate = DateFormat::createDateInstance(DateFormat::kDefault, fLocale); DateFormat *shortDateTemplate = DateFormat::createDateInstance(DateFormat::kShort, fLocale); DateFormat *longDateTemplate = DateFormat::createDateInstance(DateFormat::kLong, fLocale); DateFormat *fullDateTemplate = DateFormat::createDateInstance(DateFormat::kFull, fLocale); DateFormat *defaultTimeTemplate = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale); DateFormat *shortTimeTemplate = DateFormat::createTimeInstance(DateFormat::kShort, fLocale); DateFormat *longTimeTemplate = DateFormat::createTimeInstance(DateFormat::kLong, fLocale); DateFormat *fullTimeTemplate = DateFormat::createTimeInstance(DateFormat::kFull, fLocale); if (formatAlias == *defaultDateTemplate) { result += ",date"; } else if (formatAlias == *shortDateTemplate) { result += ",date,short"; } else if (formatAlias == *defaultDateTemplate) { result += ",date,medium"; } else if (formatAlias == *longDateTemplate) { result += ",date,long"; } else if (formatAlias == *fullDateTemplate) { result += ",date,full"; } else if (formatAlias == *defaultTimeTemplate) { result += ",time"; } else if (formatAlias == *shortTimeTemplate) { result += ",time,short"; } else if (formatAlias == *defaultTimeTemplate) { result += ",time,medium"; } else if (formatAlias == *longTimeTemplate) { result += ",time,long"; } else if (formatAlias == *fullTimeTemplate) { result += ",time,full"; } else { UnicodeString buffer; result += ",date,"; result += ((SimpleDateFormat*)fFormats[i])->toPattern(buffer); } delete defaultDateTemplate; delete shortDateTemplate; delete longDateTemplate; delete fullDateTemplate; delete defaultTimeTemplate; delete shortTimeTemplate; delete longTimeTemplate; delete fullTimeTemplate; // {sfb} there should be a more efficient way to do this! } else if (fFormats[i]->getDynamicClassID() == ChoiceFormat::getStaticClassID()) { UnicodeString buffer; result += ",choice,"; result += ((ChoiceFormat*)fFormats[i])->toPattern(buffer); } else { //result += ", unknown"; } result += (UChar)0x007D /*'}'*/; } copyAndFixQuotes(fPattern, lastOffset, fPattern.length(), result); return result; } // ------------------------------------- // Adopts the new formats array and updates the array count. // This MessageFormat instance owns the new formats. void MessageFormat::adoptFormats(Format** newFormats, int32_t cnt) { if(newFormats == NULL || cnt < 0) return; int32_t i; // Cleans up first. for (i = 0; i < fCount; i++) delete fFormats[i]; fCount = (cnt > kMaxFormat) ? kMaxFormat : cnt; for (i = 0; i < fCount; i++) fFormats[i] = newFormats[i]; for (i = kMaxFormat; i < cnt; i++) delete newFormats[i]; } // ------------------------------------- // Sets the new formats array and updates the array count. // This MessageFormat instance maks a copy of the new formats. void MessageFormat::setFormats(const Format** newFormats, int32_t cnt) { if(newFormats == NULL || cnt < 0) return; int32_t i; // Cleans up first. for (i = 0; i < fCount; i++) delete fFormats[i]; fCount = (cnt > kMaxFormat) ? kMaxFormat : cnt; for (i = 0; i < fCount; i++) if (newFormats[i] == NULL) { fFormats[i] = NULL; } else{ fFormats[i] = newFormats[i]->clone(); } } // ------------------------------------- // Adopts the first *variable* formats in the format array. // This MessageFormat instance owns the new formats. // Do nothing is the variable is not less than the array count. void MessageFormat::adoptFormat(int32_t variable, Format *newFormat) { if(variable < 0) return; if (variable < fCount) { // Deletes the old formats. delete fFormats[variable]; fFormats[variable] = newFormat; } } // ------------------------------------- // Sets the first *variable* formats in the format array, this // MessageFormat instance makes copies of the new formats. // Do nothing is the variable is not less than the array count. void MessageFormat::setFormat(int32_t variable, const Format& newFormat) { if (variable < fCount) { delete fFormats[variable]; if (&(newFormat) == NULL) { fFormats[variable] = NULL; } else{ fFormats[variable] = newFormat.clone(); } } } // ------------------------------------- // Gets the format array. const Format** MessageFormat::getFormats(int32_t& cnt) const { cnt = fCount; return (const Format**)fFormats; } // ------------------------------------- // Formats the source Formattable array and copy into the result buffer. // Ignore the FieldPosition result for error checking. UnicodeString& MessageFormat::format(const Formattable* source, int32_t cnt, UnicodeString& result, FieldPosition& ignore, UErrorCode& success) const { if (U_FAILURE(success)) return result; return format(source, cnt, result, ignore, 0, success); } // ------------------------------------- // Internally creates a MessageFormat instance based on the // pattern and formats the arguments Formattable array and // copy into the result buffer. UnicodeString& MessageFormat::format( const UnicodeString& pattern, const Formattable* arguments, int32_t cnt, UnicodeString& result, UErrorCode& success) { // {sfb} why does this use a local when so many other places use a static? MessageFormat *temp = new MessageFormat(pattern, success); if (U_FAILURE(success)) return result; FieldPosition ignore(0); temp->format(arguments, cnt, result, ignore, success); delete temp; return result; } // ------------------------------------- // Formats the source Formattable object and copy into the // result buffer. The Formattable object must be an array // of Formattable instances, returns error otherwise. UnicodeString& MessageFormat::format(const Formattable& source, UnicodeString& result, FieldPosition& ignore, UErrorCode& success) const { int32_t cnt; if (U_FAILURE(success)) return result; if (source.getType() != Formattable::kArray) { success = U_ILLEGAL_ARGUMENT_ERROR; return result; } const Formattable* tmpPtr = source.getArray(cnt); return format(tmpPtr, cnt, result, ignore, 0, success); } // ------------------------------------- // Formats the arguments Formattable array and copy into the result buffer. // Ignore the FieldPosition result for error checking. UnicodeString& MessageFormat::format(const Formattable* arguments, int32_t cnt, UnicodeString& result, FieldPosition& status, int32_t recursionProtection, UErrorCode& success) const { if(/*arguments == NULL ||*/ cnt < 0) { success = U_ILLEGAL_ARGUMENT_ERROR; return result; } UnicodeString buffer; int32_t lastOffset = 0; for (int32_t i = 0; i <= fMaxOffset;++i) { // Cleans up the temp buffer for each formattable arguments. buffer.remove(); // Append the prefix of current format element. fPattern.extract(lastOffset, fOffsets[i] - lastOffset, buffer); result += buffer; lastOffset = fOffsets[i]; int32_t argumentNumber = fArgumentNumbers[i]; // Checks the scope of the argument number. if (argumentNumber >= cnt) { /*success = U_ILLEGAL_ARGUMENT_ERROR; return result;*/ result += "{"; UnicodeString temp; result += itos(argumentNumber, temp); result += "}"; continue; } Formattable obj = arguments[argumentNumber]; UnicodeString arg; UBool tryRecursion = FALSE; // Recursively calling the format process only if the current format argument // refers to a ChoiceFormat object. if (fFormats[i] != NULL) { fFormats[i]->format(obj, arg, success); tryRecursion = (fFormats[i]->getDynamicClassID() == ChoiceFormat::getStaticClassID()); } // If the obj data type if a number, use a NumberFormat instance. else if ((obj.getType() == Formattable::kDouble) || (obj.getType() == Formattable::kLong)) { NumberFormat *numTemplate = NULL; numTemplate = NumberFormat::createInstance(fLocale, success); if (U_FAILURE(success)) { delete numTemplate; return result; } numTemplate->format((obj.getType() == Formattable::kDouble) ? obj.getDouble() : obj.getLong(), arg); delete numTemplate; if (U_FAILURE(success)) return result; } // If the obj data type is a Date instance, use a DateFormat instance. else if (obj.getType() == Formattable::kDate) { DateFormat *dateTemplate = NULL; dateTemplate = DateFormat::createDateTimeInstance(DateFormat::kShort, DateFormat::kShort, fLocale); dateTemplate->format(obj.getDate(), arg); delete dateTemplate; } else if (obj.getType() == Formattable::kString) { obj.getString(arg); } else { #ifdef LIUDEBUG cerr << "Unknown object of type:" << obj.getType() << endl; #endif success = U_ILLEGAL_ARGUMENT_ERROR; return result; } // Needs to reprocess the ChoiceFormat option by using the MessageFormat // pattern application. if (tryRecursion && arg.indexOf("{") >= 0) { MessageFormat *temp = NULL; temp = new MessageFormat(arg, fLocale, success); if (U_FAILURE(success)) return result; temp->format(arguments, cnt, result, status, recursionProtection, success); if (U_FAILURE(success)) { delete temp; return result; } delete temp; } else { result += arg; } } buffer.remove(); // Appends the rest of the pattern characters after the real last offset. fPattern.extract(lastOffset, fPattern.length(), buffer); result += buffer; return result; } // MessageFormat Type List Number, Date, Time or Choice const UnicodeString MessageFormat::fgTypeList[] = { UnicodeString(), UnicodeString(), UNICODE_STRING("number", 6), UnicodeString(), UNICODE_STRING("date", 4), UnicodeString(), UNICODE_STRING("time", 4), UnicodeString(), UNICODE_STRING("choice", 6) }; // NumberFormat modifier list, default, currency, percent or integer const UnicodeString MessageFormat::fgModifierList[] = { UnicodeString(), UnicodeString(), UNICODE_STRING("currency", 8), UnicodeString(), UNICODE_STRING("percent", 7), UnicodeString(), UNICODE_STRING("integer", 7), UnicodeString(), UnicodeString() }; // DateFormat modifier list, default, short, medium, long or full const UnicodeString MessageFormat::fgDateModifierList[] = { UnicodeString(), UnicodeString(), UNICODE_STRING("short", 5), UnicodeString(), UNICODE_STRING("medium", 6), UnicodeString(), UNICODE_STRING("long", 4), UnicodeString(), UNICODE_STRING("full", 4) }; const int32_t MessageFormat::fgListLength= 9; // ------------------------------------- // Parses the source pattern and returns the Formattable objects array, // the array count and the ending parse position. The caller of this method // owns the array. Formattable* MessageFormat::parse(const UnicodeString& source, ParsePosition& status, int32_t& count) const { Formattable *resultArray = new Formattable[kMaxFormat]; int32_t patternOffset = 0; int32_t sourceOffset = status.getIndex(); ParsePosition tempStatus(0); count = 0; // {sfb} reset to zero for (int32_t i = 0; i <= fMaxOffset; ++i) { // match up to format int32_t len = fOffsets[i] - patternOffset; if (len == 0 || fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) { sourceOffset += len; patternOffset += len; } else { status.setErrorIndex(sourceOffset); delete [] resultArray; count = 0; return NULL; // leave index as is to signal error } // now use format if (fFormats[i] == NULL) { // string format // if at end, use longest possible match // otherwise uses first match to intervening string // does NOT recursively try all possibilities int32_t tempLength = (i != fMaxOffset) ? fOffsets[i+1] : fPattern.length(); int32_t next; if (patternOffset >= tempLength) { next = source.length(); } else { UnicodeString buffer; fPattern.extract(patternOffset,tempLength - patternOffset, buffer); next = source.indexOf(buffer, sourceOffset); } if (next < 0) { status.setErrorIndex(sourceOffset); delete [] resultArray; count = 0; return NULL; // leave index as is to signal error } else { UnicodeString buffer; source.extract(sourceOffset,next - sourceOffset, buffer); UnicodeString strValue = buffer; UnicodeString temp("{"); // {sfb} check this later UnicodeString temp1; temp += itos(fArgumentNumbers[i], temp1); temp += "}"; if (strValue != temp) { source.extract(sourceOffset,next - sourceOffset, buffer); resultArray[fArgumentNumbers[i]].setString(buffer); // {sfb} not sure about this if ((fArgumentNumbers[i] + 1) > count) count = (fArgumentNumbers[i] + 1); } sourceOffset = next; } } else { tempStatus.setIndex(sourceOffset); fFormats[i]->parseObject(source, resultArray[fArgumentNumbers[i]], tempStatus); if (tempStatus.getIndex() == sourceOffset) { status.setErrorIndex(sourceOffset); delete [] resultArray; count = 0; return NULL; // leave index as is to signal error } if ((fArgumentNumbers[i] + 1) > count) count = (fArgumentNumbers[i] + 1); sourceOffset = tempStatus.getIndex(); // update } } int32_t len = fPattern.length() - patternOffset; if (len == 0 || fPattern.compare(patternOffset, len, source, sourceOffset, len) == 0) { status.setIndex(sourceOffset + len); } else { status.setErrorIndex(sourceOffset); delete [] resultArray; count = 0; return NULL; // leave index as is to signal error } return resultArray; } // ------------------------------------- // Parses the source string and returns the array of // Formattable objects and the array count. The caller // owns the returned array. Formattable* MessageFormat::parse(const UnicodeString& source, int32_t& cnt, UErrorCode& success) const { ParsePosition status(0); // Calls the actual implementation method and starts // from zero offset of the source text. Formattable* result = parse(source, status, cnt); if (status.getIndex() == 0) { success = U_MESSAGE_PARSE_ERROR; return NULL; } return result; } // ------------------------------------- // Parses the source text and copy into the result buffer. void MessageFormat::parseObject( const UnicodeString& source, Formattable& result, ParsePosition& status) const { int32_t cnt = 0; Formattable* tmpResult = parse(source, status, cnt); if (tmpResult != NULL) result.adoptArray(tmpResult, cnt); } // ------------------------------------- // NumberFormat cache management NumberFormat* MessageFormat::getNumberFormat(UErrorCode &status) { NumberFormat *theFormat = 0; if (fgNumberFormat != 0) // if there's something in the cache { Mutex lock; if (fgNumberFormat != 0) // Someone might have grabbed it. { theFormat = fgNumberFormat; fgNumberFormat = 0; // We have exclusive right to this formatter. } } if(theFormat == 0) // If we weren't able to pull it out of the cache, then we have to create it. { theFormat = NumberFormat::createInstance(Locale::US, status); if(U_FAILURE(status)) return 0; theFormat->setParseIntegerOnly(TRUE); } return theFormat; } void MessageFormat::releaseNumberFormat(NumberFormat *adopt) { if(fgNumberFormat == 0) // If the cache is empty we must add it back. { Mutex lock; if(fgNumberFormat == 0) { fgNumberFormat = adopt; adopt = 0; } } delete adopt; } /** * Converts a string to an integer value using a default NumberFormat object * which is static (shared by all MessageFormat instances). This replaces * a call to wtoi(). */ int32_t MessageFormat::stoi(const UnicodeString& string, UErrorCode& status) { NumberFormat *myFormat = getNumberFormat(status); if(U_FAILURE(status)) return -1; // OK? Formattable result; // Uses the global number formatter to parse the string. // Note: We assume here that parse() is thread-safe. myFormat->parse(string, result, status); releaseNumberFormat(myFormat); int32_t value = 0; if (U_SUCCESS(status) && result.getType() == Formattable::kLong) value = result.getLong(); return value; } // ------------------------------------- /** * Converts an integer value to a string using a default NumberFormat object * which is static (shared by all MessageFormat instances). This replaces * a call to wtoi(). */ UnicodeString& MessageFormat::itos(int32_t i, UnicodeString& string) { UErrorCode status = U_ZERO_ERROR; NumberFormat *myFormat = getNumberFormat(status); if(U_FAILURE(status)) return (string = ""); // _REVISIT_ maybe toPattern should take an errorcode. UnicodeString &retval = myFormat->format(i, string); releaseNumberFormat(myFormat); return retval; } // ------------------------------------- // Checks which format instance we are really using based on the segments. void MessageFormat::makeFormat(int32_t position, int32_t offsetNumber, UnicodeString* segments, UErrorCode& success) { if(U_FAILURE(success)) return; // get the number int32_t argumentNumber; int32_t oldMaxOffset = fMaxOffset; argumentNumber = stoi(segments[1], success); // always unlocalized! if (argumentNumber < 0 || argumentNumber > 9) { success = U_INVALID_FORMAT_ERROR; return; } fMaxOffset = offsetNumber; fOffsets[offsetNumber] = segments[0].length(); fArgumentNumbers[offsetNumber] = argumentNumber; // now get the format Format *newFormat = NULL; switch (findKeyword(segments[2], fgTypeList)) { case 0: break; case 1: case 2:// number switch (findKeyword(segments[3], fgModifierList)) { case 0: // default; newFormat = NumberFormat::createInstance(fLocale, success); break; case 1: case 2:// currency newFormat = NumberFormat::createCurrencyInstance(fLocale, success); break; case 3: case 4:// percent newFormat = NumberFormat::createPercentInstance(fLocale, success); break; case 5: case 6:// integer newFormat = createIntegerFormat(fLocale, success); break; default: // pattern newFormat = NumberFormat::createInstance(fLocale, success); if(U_FAILURE(success)) { newFormat = NULL; return; } if(newFormat->getDynamicClassID() == DecimalFormat::getStaticClassID()) ((DecimalFormat*)newFormat)->applyPattern(segments[3], success); if(U_FAILURE(success)) { fMaxOffset = oldMaxOffset; success = U_ILLEGAL_ARGUMENT_ERROR; return; } break; } break; case 3: case 4: // date switch (findKeyword(segments[3], fgDateModifierList)) { case 0: // default newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale); break; case 1: case 2: // short newFormat = DateFormat::createDateInstance(DateFormat::kShort, fLocale); break; case 3: case 4: // medium newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale); break; case 5: case 6: // long newFormat = DateFormat::createDateInstance(DateFormat::kLong, fLocale); break; case 7: case 8: // full newFormat = DateFormat::createDateInstance(DateFormat::kFull, fLocale); break; default: newFormat = DateFormat::createDateInstance(DateFormat::kDefault, fLocale); if(newFormat->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) ((SimpleDateFormat*)newFormat)->applyPattern(segments[3]); if(U_FAILURE(success)) { fMaxOffset = oldMaxOffset; success = U_ILLEGAL_ARGUMENT_ERROR; return; } break; } break; case 5: case 6:// time switch (findKeyword(segments[3], fgDateModifierList)) { case 0: // default newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale); break; case 1: case 2: // short newFormat = DateFormat::createTimeInstance(DateFormat::kShort, fLocale); break; case 3: case 4: // medium newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale); break; case 5: case 6: // long newFormat = DateFormat::createTimeInstance(DateFormat::kLong, fLocale); break; case 7: case 8: // full newFormat = DateFormat::createTimeInstance(DateFormat::kFull, fLocale); break; default: newFormat = DateFormat::createTimeInstance(DateFormat::kDefault, fLocale); if(newFormat->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) ((SimpleDateFormat*)newFormat)->applyPattern(segments[3]); if(U_FAILURE(success)) { fMaxOffset = oldMaxOffset; success = U_ILLEGAL_ARGUMENT_ERROR; return; } break; } break; case 7: case 8:// choice newFormat = new ChoiceFormat(segments[3], success); if(U_FAILURE(success)) { fMaxOffset = oldMaxOffset; success = U_ILLEGAL_ARGUMENT_ERROR; return; } break; default: fMaxOffset = oldMaxOffset; success = U_ILLEGAL_ARGUMENT_ERROR; return; } if(newFormat != NULL) { delete fFormats[offsetNumber]; fFormats[offsetNumber] = newFormat; } segments[1].remove(); // throw away other segments segments[2].remove(); segments[3].remove(); } // ------------------------------------- // Finds the string, s, in the string array, list. int32_t MessageFormat::findKeyword(const UnicodeString& s, const UnicodeString* list) { UnicodeString buffer = s; // Trims the space characters and turns all characters // in s to lower case. buffer.trim().toLower(); for (int32_t i = 0; i < fgListLength; ++i) { if (buffer == list[i]) return i; } return - 1; } // ------------------------------------- // Checks the range of the source text to quote the special // characters, { and ' and copy to target buffer. void MessageFormat::copyAndFixQuotes(const UnicodeString& source, int32_t start, int32_t end, UnicodeString& target) { UBool gotLB = FALSE; for (UTextOffset i = start; i < end; ++i) { UChar ch = source[i]; if (ch == 0x007B /*'{'*/) { target += "'{'"; gotLB = TRUE; } else if (ch == 0x007D /*'}'*/) { if(gotLB) { target += "}"; gotLB = FALSE; } else // orig code. target += "'}'"; } else if (ch == 0x0027 /*'\''*/) { target += "''"; } else { target += ch; } } } /** * Convenience method that ought to be in NumberFormat */ NumberFormat* MessageFormat::createIntegerFormat(const Locale& locale, UErrorCode& status) const { NumberFormat *temp = NumberFormat::createInstance(locale, status); if (temp->getDynamicClassID() == DecimalFormat::getStaticClassID()) { DecimalFormat *temp2 = (DecimalFormat*) temp; temp2->setMaximumFractionDigits(0); temp2->setDecimalSeparatorAlwaysShown(FALSE); temp2->setParseIntegerOnly(TRUE); } return temp; } //eof