michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 1997-2013, International Business Machines Corporation and * michael@0: * others. All Rights Reserved. * michael@0: ******************************************************************************* michael@0: * michael@0: * File FMTABLE.CPP michael@0: * michael@0: * Modification History: michael@0: * michael@0: * Date Name Description michael@0: * 03/25/97 clhuang Initial Implementation. michael@0: ******************************************************************************** michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: #include michael@0: #include "unicode/fmtable.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/measure.h" michael@0: #include "unicode/curramt.h" michael@0: #include "unicode/uformattable.h" michael@0: #include "charstr.h" michael@0: #include "cmemory.h" michael@0: #include "cstring.h" michael@0: #include "decNumber.h" michael@0: #include "digitlst.h" michael@0: michael@0: // ***************************************************************************** michael@0: // class Formattable michael@0: // ***************************************************************************** michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable) michael@0: michael@0: #include "fmtableimp.h" michael@0: michael@0: //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. michael@0: michael@0: // NOTE: As of 3.0, there are limitations to the UObject API. It does michael@0: // not (yet) support cloning, operator=, nor operator==. To michael@0: // work around this, I implement some simple inlines here. Later michael@0: // these can be modified or removed. [alan] michael@0: michael@0: // NOTE: These inlines assume that all fObjects are in fact instances michael@0: // of the Measure class, which is true as of 3.0. [alan] michael@0: michael@0: // Return TRUE if *a == *b. michael@0: static inline UBool objectEquals(const UObject* a, const UObject* b) { michael@0: // LATER: return *a == *b; michael@0: return *((const Measure*) a) == *((const Measure*) b); michael@0: } michael@0: michael@0: // Return a clone of *a. michael@0: static inline UObject* objectClone(const UObject* a) { michael@0: // LATER: return a->clone(); michael@0: return ((const Measure*) a)->clone(); michael@0: } michael@0: michael@0: // Return TRUE if *a is an instance of Measure. michael@0: static inline UBool instanceOfMeasure(const UObject* a) { michael@0: return dynamic_cast(a) != NULL; michael@0: } michael@0: michael@0: /** michael@0: * Creates a new Formattable array and copies the values from the specified michael@0: * original. michael@0: * @param array the original array michael@0: * @param count the original array count michael@0: * @return the new Formattable array. michael@0: */ michael@0: static Formattable* createArrayCopy(const Formattable* array, int32_t count) { michael@0: Formattable *result = new Formattable[count]; michael@0: if (result != NULL) { michael@0: for (int32_t i=0; istackDecimalNum)) { michael@0: delete fDecimalNum; michael@0: } else { michael@0: fDecimalNum->~DigitList(); // destruct, don't deallocate michael@0: } michael@0: fDecimalNum = NULL; michael@0: } michael@0: michael@0: Formattable * michael@0: Formattable::clone() const { michael@0: return new Formattable(*this); michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Gets the data type of this Formattable object. michael@0: Formattable::Type michael@0: Formattable::getType() const michael@0: { michael@0: return fType; michael@0: } michael@0: michael@0: UBool michael@0: Formattable::isNumeric() const { michael@0: switch (fType) { michael@0: case kDouble: michael@0: case kLong: michael@0: case kInt64: michael@0: return TRUE; michael@0: default: michael@0: return FALSE; michael@0: } michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: int32_t michael@0: //Formattable::getLong(UErrorCode* status) const michael@0: Formattable::getLong(UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return 0; michael@0: } michael@0: michael@0: switch (fType) { michael@0: case Formattable::kLong: michael@0: return (int32_t)fValue.fInt64; michael@0: case Formattable::kInt64: michael@0: if (fValue.fInt64 > INT32_MAX) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return INT32_MAX; michael@0: } else if (fValue.fInt64 < INT32_MIN) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return INT32_MIN; michael@0: } else { michael@0: return (int32_t)fValue.fInt64; michael@0: } michael@0: case Formattable::kDouble: michael@0: if (fValue.fDouble > INT32_MAX) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return INT32_MAX; michael@0: } else if (fValue.fDouble < INT32_MIN) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return INT32_MIN; michael@0: } else { michael@0: return (int32_t)fValue.fDouble; // loses fraction michael@0: } michael@0: case Formattable::kObject: michael@0: if (fValue.fObject == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: // TODO Later replace this with instanceof call michael@0: if (instanceOfMeasure(fValue.fObject)) { michael@0: return ((const Measure*) fValue.fObject)-> michael@0: getNumber().getLong(status); michael@0: } michael@0: default: michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Maximum int that can be represented exactly in a double. (53 bits) michael@0: // Larger ints may be rounded to a near-by value as not all are representable. michael@0: // TODO: move this constant elsewhere, possibly configure it for different michael@0: // floating point formats, if any non-standard ones are still in use. michael@0: static const int64_t U_DOUBLE_MAX_EXACT_INT = 9007199254740992LL; michael@0: michael@0: int64_t michael@0: Formattable::getInt64(UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return 0; michael@0: } michael@0: michael@0: switch (fType) { michael@0: case Formattable::kLong: michael@0: case Formattable::kInt64: michael@0: return fValue.fInt64; michael@0: case Formattable::kDouble: michael@0: if (fValue.fDouble > (double)U_INT64_MAX) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return U_INT64_MAX; michael@0: } else if (fValue.fDouble < (double)U_INT64_MIN) { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return U_INT64_MIN; michael@0: } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) { michael@0: int64_t val = fDecimalNum->getInt64(); michael@0: if (val != 0) { michael@0: return val; michael@0: } else { michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return fValue.fDouble > 0 ? U_INT64_MAX : U_INT64_MIN; michael@0: } michael@0: } else { michael@0: return (int64_t)fValue.fDouble; michael@0: } michael@0: case Formattable::kObject: michael@0: if (fValue.fObject == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: if (instanceOfMeasure(fValue.fObject)) { michael@0: return ((const Measure*) fValue.fObject)-> michael@0: getNumber().getInt64(status); michael@0: } michael@0: default: michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: double michael@0: Formattable::getDouble(UErrorCode& status) const michael@0: { michael@0: if (U_FAILURE(status)) { michael@0: return 0; michael@0: } michael@0: michael@0: switch (fType) { michael@0: case Formattable::kLong: michael@0: case Formattable::kInt64: // loses precision michael@0: return (double)fValue.fInt64; michael@0: case Formattable::kDouble: michael@0: return fValue.fDouble; michael@0: case Formattable::kObject: michael@0: if (fValue.fObject == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return 0; michael@0: } michael@0: // TODO Later replace this with instanceof call michael@0: if (instanceOfMeasure(fValue.fObject)) { michael@0: return ((const Measure*) fValue.fObject)-> michael@0: getNumber().getDouble(status); michael@0: } michael@0: default: michael@0: status = U_INVALID_FORMAT_ERROR; michael@0: return 0; michael@0: } michael@0: } michael@0: michael@0: const UObject* michael@0: Formattable::getObject() const { michael@0: return (fType == kObject) ? fValue.fObject : NULL; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to a double value d. michael@0: michael@0: void michael@0: Formattable::setDouble(double d) michael@0: { michael@0: dispose(); michael@0: fType = kDouble; michael@0: fValue.fDouble = d; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to a long value l. michael@0: michael@0: void michael@0: Formattable::setLong(int32_t l) michael@0: { michael@0: dispose(); michael@0: fType = kLong; michael@0: fValue.fInt64 = l; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to an int64 value ll. michael@0: michael@0: void michael@0: Formattable::setInt64(int64_t ll) michael@0: { michael@0: dispose(); michael@0: fType = kInt64; michael@0: fValue.fInt64 = ll; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to a Date instance d. michael@0: michael@0: void michael@0: Formattable::setDate(UDate d) michael@0: { michael@0: dispose(); michael@0: fType = kDate; michael@0: fValue.fDate = d; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to a string value stringToCopy. michael@0: michael@0: void michael@0: Formattable::setString(const UnicodeString& stringToCopy) michael@0: { michael@0: dispose(); michael@0: fType = kString; michael@0: fValue.fString = new UnicodeString(stringToCopy); michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Sets the value to an array of Formattable objects. michael@0: michael@0: void michael@0: Formattable::setArray(const Formattable* array, int32_t count) michael@0: { michael@0: dispose(); michael@0: fType = kArray; michael@0: fValue.fArrayAndCount.fArray = createArrayCopy(array, count); michael@0: fValue.fArrayAndCount.fCount = count; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Adopts the stringToAdopt value. michael@0: michael@0: void michael@0: Formattable::adoptString(UnicodeString* stringToAdopt) michael@0: { michael@0: dispose(); michael@0: fType = kString; michael@0: fValue.fString = stringToAdopt; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Adopts the array value and its count. michael@0: michael@0: void michael@0: Formattable::adoptArray(Formattable* array, int32_t count) michael@0: { michael@0: dispose(); michael@0: fType = kArray; michael@0: fValue.fArrayAndCount.fArray = array; michael@0: fValue.fArrayAndCount.fCount = count; michael@0: } michael@0: michael@0: void michael@0: Formattable::adoptObject(UObject* objectToAdopt) { michael@0: dispose(); michael@0: fType = kObject; michael@0: fValue.fObject = objectToAdopt; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: UnicodeString& michael@0: Formattable::getString(UnicodeString& result, UErrorCode& status) const michael@0: { michael@0: if (fType != kString) { michael@0: setError(status, U_INVALID_FORMAT_ERROR); michael@0: result.setToBogus(); michael@0: } else { michael@0: if (fValue.fString == NULL) { michael@0: setError(status, U_MEMORY_ALLOCATION_ERROR); michael@0: } else { michael@0: result = *fValue.fString; michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: const UnicodeString& michael@0: Formattable::getString(UErrorCode& status) const michael@0: { michael@0: if (fType != kString) { michael@0: setError(status, U_INVALID_FORMAT_ERROR); michael@0: return *getBogus(); michael@0: } michael@0: if (fValue.fString == NULL) { michael@0: setError(status, U_MEMORY_ALLOCATION_ERROR); michael@0: return *getBogus(); michael@0: } michael@0: return *fValue.fString; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: UnicodeString& michael@0: Formattable::getString(UErrorCode& status) michael@0: { michael@0: if (fType != kString) { michael@0: setError(status, U_INVALID_FORMAT_ERROR); michael@0: return *getBogus(); michael@0: } michael@0: if (fValue.fString == NULL) { michael@0: setError(status, U_MEMORY_ALLOCATION_ERROR); michael@0: return *getBogus(); michael@0: } michael@0: return *fValue.fString; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: const Formattable* michael@0: Formattable::getArray(int32_t& count, UErrorCode& status) const michael@0: { michael@0: if (fType != kArray) { michael@0: setError(status, U_INVALID_FORMAT_ERROR); michael@0: count = 0; michael@0: return NULL; michael@0: } michael@0: count = fValue.fArrayAndCount.fCount; michael@0: return fValue.fArrayAndCount.fArray; michael@0: } michael@0: michael@0: // ------------------------------------- michael@0: // Gets the bogus string, ensures mondo bogosity. michael@0: michael@0: UnicodeString* michael@0: Formattable::getBogus() const michael@0: { michael@0: return (UnicodeString*)&fBogus; /* cast away const :-( */ michael@0: } michael@0: michael@0: michael@0: // -------------------------------------- michael@0: StringPiece Formattable::getDecimalNumber(UErrorCode &status) { michael@0: if (U_FAILURE(status)) { michael@0: return ""; michael@0: } michael@0: if (fDecimalStr != NULL) { michael@0: return fDecimalStr->toStringPiece(); michael@0: } michael@0: michael@0: CharString *decimalStr = internalGetCharString(status); michael@0: if(decimalStr == NULL) { michael@0: return ""; // getDecimalNumber returns "" for error cases michael@0: } else { michael@0: return decimalStr->toStringPiece(); michael@0: } michael@0: } michael@0: michael@0: CharString *Formattable::internalGetCharString(UErrorCode &status) { michael@0: if(fDecimalStr == NULL) { michael@0: if (fDecimalNum == NULL) { michael@0: // No decimal number for the formattable yet. Which means the value was michael@0: // set directly by the user as an int, int64 or double. If the value came michael@0: // from parsing, or from the user setting a decimal number, fDecimalNum michael@0: // would already be set. michael@0: // michael@0: fDecimalNum = new DigitList; // TODO: use internal digit list michael@0: if (fDecimalNum == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: michael@0: switch (fType) { michael@0: case kDouble: michael@0: fDecimalNum->set(this->getDouble()); michael@0: break; michael@0: case kLong: michael@0: fDecimalNum->set(this->getLong()); michael@0: break; michael@0: case kInt64: michael@0: fDecimalNum->set(this->getInt64()); michael@0: break; michael@0: default: michael@0: // The formattable's value is not a numeric type. michael@0: status = U_INVALID_STATE_ERROR; michael@0: return NULL; michael@0: } michael@0: } michael@0: michael@0: fDecimalStr = new CharString; michael@0: if (fDecimalStr == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return NULL; michael@0: } michael@0: fDecimalNum->getDecimal(*fDecimalStr, status); michael@0: } michael@0: return fDecimalStr; michael@0: } michael@0: michael@0: michael@0: DigitList * michael@0: Formattable::getInternalDigitList() { michael@0: FmtStackData *stackData = (FmtStackData*)fStackData; michael@0: if(fDecimalNum != &(stackData->stackDecimalNum)) { michael@0: delete fDecimalNum; michael@0: fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList(); michael@0: } else { michael@0: fDecimalNum->clear(); michael@0: } michael@0: return fDecimalNum; michael@0: } michael@0: michael@0: // --------------------------------------- michael@0: void michael@0: Formattable::adoptDigitList(DigitList *dl) { michael@0: if(fDecimalNum==dl) { michael@0: fDecimalNum = NULL; // don't delete michael@0: } michael@0: dispose(); michael@0: michael@0: fDecimalNum = dl; michael@0: michael@0: if(dl==NULL) { // allow adoptDigitList(NULL) to clear michael@0: return; michael@0: } michael@0: michael@0: // Set the value into the Union of simple type values. michael@0: // Cannot use the set() functions because they would delete the fDecimalNum value, michael@0: michael@0: if (fDecimalNum->fitsIntoLong(FALSE)) { michael@0: fType = kLong; michael@0: fValue.fInt64 = fDecimalNum->getLong(); michael@0: } else if (fDecimalNum->fitsIntoInt64(FALSE)) { michael@0: fType = kInt64; michael@0: fValue.fInt64 = fDecimalNum->getInt64(); michael@0: } else { michael@0: fType = kDouble; michael@0: fValue.fDouble = fDecimalNum->getDouble(); michael@0: } michael@0: } michael@0: michael@0: michael@0: // --------------------------------------- michael@0: void michael@0: Formattable::setDecimalNumber(const StringPiece &numberString, UErrorCode &status) { michael@0: if (U_FAILURE(status)) { michael@0: return; michael@0: } michael@0: dispose(); michael@0: michael@0: // Copy the input string and nul-terminate it. michael@0: // The decNumber library requires nul-terminated input. StringPiece input michael@0: // is not guaranteed nul-terminated. Too bad. michael@0: // CharString automatically adds the nul. michael@0: DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList michael@0: if (dnum == NULL) { michael@0: status = U_MEMORY_ALLOCATION_ERROR; michael@0: return; michael@0: } michael@0: dnum->set(CharString(numberString, status).toStringPiece(), status); michael@0: if (U_FAILURE(status)) { michael@0: delete dnum; michael@0: return; // String didn't contain a decimal number. michael@0: } michael@0: adoptDigitList(dnum); michael@0: michael@0: // Note that we do not hang on to the caller's input string. michael@0: // If we are asked for the string, we will regenerate one from fDecimalNum. michael@0: } michael@0: michael@0: #if 0 michael@0: //---------------------------------------------------- michael@0: // console I/O michael@0: //---------------------------------------------------- michael@0: #ifdef _DEBUG michael@0: michael@0: #include michael@0: using namespace std; michael@0: michael@0: #include "unicode/datefmt.h" michael@0: #include "unistrm.h" michael@0: michael@0: class FormattableStreamer /* not : public UObject because all methods are static */ { michael@0: public: michael@0: static void streamOut(ostream& stream, const Formattable& obj); michael@0: michael@0: private: michael@0: FormattableStreamer() {} // private - forbid instantiation michael@0: }; michael@0: michael@0: // This is for debugging purposes only. This will send a displayable michael@0: // form of the Formattable object to the output stream. michael@0: michael@0: void michael@0: FormattableStreamer::streamOut(ostream& stream, const Formattable& obj) michael@0: { michael@0: static DateFormat *defDateFormat = 0; michael@0: michael@0: UnicodeString buffer; michael@0: switch(obj.getType()) { michael@0: case Formattable::kDate : michael@0: // Creates a DateFormat instance for formatting the michael@0: // Date instance. michael@0: if (defDateFormat == 0) { michael@0: defDateFormat = DateFormat::createInstance(); michael@0: } michael@0: defDateFormat->format(obj.getDate(), buffer); michael@0: stream << buffer; michael@0: break; michael@0: case Formattable::kDouble : michael@0: // Output the double as is. michael@0: stream << obj.getDouble() << 'D'; michael@0: break; michael@0: case Formattable::kLong : michael@0: // Output the double as is. michael@0: stream << obj.getLong() << 'L'; michael@0: break; michael@0: case Formattable::kString: michael@0: // Output the double as is. Please see UnicodeString console michael@0: // I/O routine for more details. michael@0: stream << '"' << obj.getString(buffer) << '"'; michael@0: break; michael@0: case Formattable::kArray: michael@0: int32_t i, count; michael@0: const Formattable* array; michael@0: array = obj.getArray(count); michael@0: stream << '['; michael@0: // Recursively calling the console I/O routine for each element in the array. michael@0: for (i=0; itoUFormattable(); michael@0: michael@0: if( fmt == NULL ) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: } michael@0: return fmt; michael@0: } michael@0: michael@0: U_DRAFT void U_EXPORT2 michael@0: ufmt_close(UFormattable *fmt) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: delete obj; michael@0: } michael@0: michael@0: U_INTERNAL UFormattableType U_EXPORT2 michael@0: ufmt_getType(const UFormattable *fmt, UErrorCode *status) { michael@0: if(U_FAILURE(*status)) { michael@0: return (UFormattableType)UFMT_COUNT; michael@0: } michael@0: const Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: return (UFormattableType)obj->getType(); michael@0: } michael@0: michael@0: michael@0: U_INTERNAL UBool U_EXPORT2 michael@0: ufmt_isNumeric(const UFormattable *fmt) { michael@0: const Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: return obj->isNumeric(); michael@0: } michael@0: michael@0: U_DRAFT UDate U_EXPORT2 michael@0: ufmt_getDate(const UFormattable *fmt, UErrorCode *status) { michael@0: const Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: return obj->getDate(*status); michael@0: } michael@0: michael@0: U_DRAFT double U_EXPORT2 michael@0: ufmt_getDouble(UFormattable *fmt, UErrorCode *status) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: return obj->getDouble(*status); michael@0: } michael@0: michael@0: U_DRAFT int32_t U_EXPORT2 michael@0: ufmt_getLong(UFormattable *fmt, UErrorCode *status) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: return obj->getLong(*status); michael@0: } michael@0: michael@0: michael@0: U_DRAFT const void *U_EXPORT2 michael@0: ufmt_getObject(const UFormattable *fmt, UErrorCode *status) { michael@0: const Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: const void *ret = obj->getObject(); michael@0: if( ret==NULL && michael@0: (obj->getType() != Formattable::kObject) && michael@0: U_SUCCESS( *status )) { michael@0: *status = U_INVALID_FORMAT_ERROR; michael@0: } michael@0: return ret; michael@0: } michael@0: michael@0: U_DRAFT const UChar* U_EXPORT2 michael@0: ufmt_getUChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: // avoid bogosity by checking the type first. michael@0: if( obj->getType() != Formattable::kString ) { michael@0: if( U_SUCCESS(*status) ){ michael@0: *status = U_INVALID_FORMAT_ERROR; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: // This should return a valid string michael@0: UnicodeString &str = obj->getString(*status); michael@0: if( U_SUCCESS(*status) && len != NULL ) { michael@0: *len = str.length(); michael@0: } michael@0: return str.getTerminatedBuffer(); michael@0: } michael@0: michael@0: U_DRAFT int32_t U_EXPORT2 michael@0: ufmt_getArrayLength(const UFormattable* fmt, UErrorCode *status) { michael@0: const Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: michael@0: int32_t count; michael@0: (void)obj->getArray(count, *status); michael@0: return count; michael@0: } michael@0: michael@0: U_DRAFT UFormattable * U_EXPORT2 michael@0: ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: int32_t count; michael@0: (void)obj->getArray(count, *status); michael@0: if(U_FAILURE(*status)) { michael@0: return NULL; michael@0: } else if(n<0 || n>=count) { michael@0: setError(*status, U_INDEX_OUTOFBOUNDS_ERROR); michael@0: return NULL; michael@0: } else { michael@0: return (*obj)[n].toUFormattable(); // returns non-const Formattable michael@0: } michael@0: } michael@0: michael@0: U_DRAFT const char * U_EXPORT2 michael@0: ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status) { michael@0: if(U_FAILURE(*status)) { michael@0: return ""; michael@0: } michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: CharString *charString = obj->internalGetCharString(*status); michael@0: if(U_FAILURE(*status)) { michael@0: return ""; michael@0: } michael@0: if(charString == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return ""; michael@0: } else { michael@0: if(len!=NULL) { michael@0: *len = charString->length(); michael@0: } michael@0: return charString->data(); michael@0: } michael@0: } michael@0: michael@0: U_DRAFT int64_t U_EXPORT2 michael@0: ufmt_getInt64(UFormattable *fmt, UErrorCode *status) { michael@0: Formattable *obj = Formattable::fromUFormattable(fmt); michael@0: return obj->getInt64(*status); michael@0: } michael@0: michael@0: #endif /* #if !UCONFIG_NO_FORMATTING */ michael@0: michael@0: //eof