| 1 | // © 2018 and later: Unicode, Inc. and others. | 
|---|
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | 
|---|
| 3 |  | 
|---|
| 4 | #include "unicode/utypes.h" | 
|---|
| 5 |  | 
|---|
| 6 | #if !UCONFIG_NO_FORMATTING | 
|---|
| 7 |  | 
|---|
| 8 | // Allow implicit conversion from char16_t* to UnicodeString for this file: | 
|---|
| 9 | // Helpful in toString methods and elsewhere. | 
|---|
| 10 | #define UNISTR_FROM_STRING_EXPLICIT | 
|---|
| 11 |  | 
|---|
| 12 | #include "fphdlimp.h" | 
|---|
| 13 | #include "number_utypes.h" | 
|---|
| 14 | #include "numparse_types.h" | 
|---|
| 15 | #include "formattedval_impl.h" | 
|---|
| 16 | #include "unicode/numberformatter.h" | 
|---|
| 17 | #include "unicode/unumberformatter.h" | 
|---|
| 18 |  | 
|---|
| 19 | using namespace icu; | 
|---|
| 20 | using namespace icu::number; | 
|---|
| 21 | using namespace icu::number::impl; | 
|---|
| 22 |  | 
|---|
| 23 |  | 
|---|
| 24 | U_NAMESPACE_BEGIN | 
|---|
| 25 | namespace number { | 
|---|
| 26 | namespace impl { | 
|---|
| 27 |  | 
|---|
| 28 | /** | 
|---|
| 29 | * Implementation class for UNumberFormatter. Wraps a LocalizedNumberFormatter. | 
|---|
| 30 | */ | 
|---|
| 31 | struct UNumberFormatterData : public UMemory, | 
|---|
| 32 | // Magic number as ASCII == "NFR" (NumberFormatteR) | 
|---|
| 33 | public IcuCApiHelper<UNumberFormatter, UNumberFormatterData, 0x4E465200> { | 
|---|
| 34 | LocalizedNumberFormatter fFormatter; | 
|---|
| 35 | }; | 
|---|
| 36 |  | 
|---|
| 37 | struct UFormattedNumberImpl; | 
|---|
| 38 |  | 
|---|
| 39 | // Magic number as ASCII == "FDN" (FormatteDNumber) | 
|---|
| 40 | typedef IcuCApiHelper<UFormattedNumber, UFormattedNumberImpl, 0x46444E00> UFormattedNumberApiHelper; | 
|---|
| 41 |  | 
|---|
| 42 | struct UFormattedNumberImpl : public UFormattedValueImpl, public UFormattedNumberApiHelper { | 
|---|
| 43 | UFormattedNumberImpl(); | 
|---|
| 44 | ~UFormattedNumberImpl(); | 
|---|
| 45 |  | 
|---|
| 46 | FormattedNumber fImpl; | 
|---|
| 47 | UFormattedNumberData fData; | 
|---|
| 48 | }; | 
|---|
| 49 |  | 
|---|
| 50 | UFormattedNumberImpl::UFormattedNumberImpl() | 
|---|
| 51 | : fImpl(&fData) { | 
|---|
| 52 | fFormattedValue = &fImpl; | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | UFormattedNumberImpl::~UFormattedNumberImpl() { | 
|---|
| 56 | // Disown the data from fImpl so it doesn't get deleted twice | 
|---|
| 57 | fImpl.fData = nullptr; | 
|---|
| 58 | } | 
|---|
| 59 |  | 
|---|
| 60 | } | 
|---|
| 61 | } | 
|---|
| 62 | U_NAMESPACE_END | 
|---|
| 63 |  | 
|---|
| 64 |  | 
|---|
| 65 | UPRV_FORMATTED_VALUE_CAPI_NO_IMPLTYPE_AUTO_IMPL( | 
|---|
| 66 | UFormattedNumber, | 
|---|
| 67 | UFormattedNumberImpl, | 
|---|
| 68 | UFormattedNumberApiHelper, | 
|---|
| 69 | unumf) | 
|---|
| 70 |  | 
|---|
| 71 |  | 
|---|
| 72 | const DecimalQuantity* icu::number::impl::validateUFormattedNumberToDecimalQuantity( | 
|---|
| 73 | const UFormattedNumber* uresult, UErrorCode& status) { | 
|---|
| 74 | auto* result = UFormattedNumberApiHelper::validate(uresult, status); | 
|---|
| 75 | if (U_FAILURE(status)) { | 
|---|
| 76 | return nullptr; | 
|---|
| 77 | } | 
|---|
| 78 | return &result->fData.quantity; | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 |  | 
|---|
| 82 |  | 
|---|
| 83 | U_CAPI UNumberFormatter* U_EXPORT2 | 
|---|
| 84 | unumf_openForSkeletonAndLocale(const UChar* skeleton, int32_t skeletonLen, const char* locale, | 
|---|
| 85 | UErrorCode* ec) { | 
|---|
| 86 | auto* impl = new UNumberFormatterData(); | 
|---|
| 87 | if (impl == nullptr) { | 
|---|
| 88 | *ec = U_MEMORY_ALLOCATION_ERROR; | 
|---|
| 89 | return nullptr; | 
|---|
| 90 | } | 
|---|
| 91 | // Readonly-alias constructor (first argument is whether we are NUL-terminated) | 
|---|
| 92 | UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); | 
|---|
| 93 | impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *ec).locale(locale); | 
|---|
| 94 | return impl->exportForC(); | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | U_CAPI UNumberFormatter* U_EXPORT2 | 
|---|
| 98 | unumf_openForSkeletonAndLocaleWithError(const UChar* skeleton, int32_t skeletonLen, const char* locale, | 
|---|
| 99 | UParseError* perror, UErrorCode* ec) { | 
|---|
| 100 | auto* impl = new UNumberFormatterData(); | 
|---|
| 101 | if (impl == nullptr) { | 
|---|
| 102 | *ec = U_MEMORY_ALLOCATION_ERROR; | 
|---|
| 103 | return nullptr; | 
|---|
| 104 | } | 
|---|
| 105 | // Readonly-alias constructor (first argument is whether we are NUL-terminated) | 
|---|
| 106 | UnicodeString skeletonString(skeletonLen == -1, skeleton, skeletonLen); | 
|---|
| 107 | impl->fFormatter = NumberFormatter::forSkeleton(skeletonString, *perror, *ec).locale(locale); | 
|---|
| 108 | return impl->exportForC(); | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | U_CAPI void U_EXPORT2 | 
|---|
| 112 | unumf_formatInt(const UNumberFormatter* uformatter, int64_t value, UFormattedNumber* uresult, | 
|---|
| 113 | UErrorCode* ec) { | 
|---|
| 114 | const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); | 
|---|
| 115 | auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 116 | if (U_FAILURE(*ec)) { return; } | 
|---|
| 117 |  | 
|---|
| 118 | result->fData.getStringRef().clear(); | 
|---|
| 119 | result->fData.quantity.setToLong(value); | 
|---|
| 120 | formatter->fFormatter.formatImpl(&result->fData, *ec); | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | U_CAPI void U_EXPORT2 | 
|---|
| 124 | unumf_formatDouble(const UNumberFormatter* uformatter, double value, UFormattedNumber* uresult, | 
|---|
| 125 | UErrorCode* ec) { | 
|---|
| 126 | const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); | 
|---|
| 127 | auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 128 | if (U_FAILURE(*ec)) { return; } | 
|---|
| 129 |  | 
|---|
| 130 | result->fData.getStringRef().clear(); | 
|---|
| 131 | result->fData.quantity.setToDouble(value); | 
|---|
| 132 | formatter->fFormatter.formatImpl(&result->fData, *ec); | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | U_CAPI void U_EXPORT2 | 
|---|
| 136 | unumf_formatDecimal(const UNumberFormatter* uformatter, const char* value, int32_t valueLen, | 
|---|
| 137 | UFormattedNumber* uresult, UErrorCode* ec) { | 
|---|
| 138 | const UNumberFormatterData* formatter = UNumberFormatterData::validate(uformatter, *ec); | 
|---|
| 139 | auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 140 | if (U_FAILURE(*ec)) { return; } | 
|---|
| 141 |  | 
|---|
| 142 | result->fData.getStringRef().clear(); | 
|---|
| 143 | result->fData.quantity.setToDecNumber({value, valueLen}, *ec); | 
|---|
| 144 | if (U_FAILURE(*ec)) { return; } | 
|---|
| 145 | formatter->fFormatter.formatImpl(&result->fData, *ec); | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | U_CAPI int32_t U_EXPORT2 | 
|---|
| 149 | unumf_resultToString(const UFormattedNumber* uresult, UChar* buffer, int32_t bufferCapacity, | 
|---|
| 150 | UErrorCode* ec) { | 
|---|
| 151 | const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 152 | if (U_FAILURE(*ec)) { return 0; } | 
|---|
| 153 |  | 
|---|
| 154 | if (buffer == nullptr ? bufferCapacity != 0 : bufferCapacity < 0) { | 
|---|
| 155 | *ec = U_ILLEGAL_ARGUMENT_ERROR; | 
|---|
| 156 | return 0; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | return result->fImpl.toTempString(*ec).extract(buffer, bufferCapacity, *ec); | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | U_CAPI UBool U_EXPORT2 | 
|---|
| 163 | unumf_resultNextFieldPosition(const UFormattedNumber* uresult, UFieldPosition* ufpos, UErrorCode* ec) { | 
|---|
| 164 | const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 165 | if (U_FAILURE(*ec)) { return FALSE; } | 
|---|
| 166 |  | 
|---|
| 167 | if (ufpos == nullptr) { | 
|---|
| 168 | *ec = U_ILLEGAL_ARGUMENT_ERROR; | 
|---|
| 169 | return FALSE; | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | FieldPosition fp; | 
|---|
| 173 | fp.setField(ufpos->field); | 
|---|
| 174 | fp.setBeginIndex(ufpos->beginIndex); | 
|---|
| 175 | fp.setEndIndex(ufpos->endIndex); | 
|---|
| 176 | bool retval = result->fImpl.nextFieldPosition(fp, *ec); | 
|---|
| 177 | ufpos->beginIndex = fp.getBeginIndex(); | 
|---|
| 178 | ufpos->endIndex = fp.getEndIndex(); | 
|---|
| 179 | // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool | 
|---|
| 180 | return retval ? TRUE : FALSE; | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | U_CAPI void U_EXPORT2 | 
|---|
| 184 | unumf_resultGetAllFieldPositions(const UFormattedNumber* uresult, UFieldPositionIterator* ufpositer, | 
|---|
| 185 | UErrorCode* ec) { | 
|---|
| 186 | const auto* result = UFormattedNumberApiHelper::validate(uresult, *ec); | 
|---|
| 187 | if (U_FAILURE(*ec)) { return; } | 
|---|
| 188 |  | 
|---|
| 189 | if (ufpositer == nullptr) { | 
|---|
| 190 | *ec = U_ILLEGAL_ARGUMENT_ERROR; | 
|---|
| 191 | return; | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | auto* fpi = reinterpret_cast<FieldPositionIterator*>(ufpositer); | 
|---|
| 195 | result->fImpl.getAllFieldPositions(*fpi, *ec); | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | U_CAPI void U_EXPORT2 | 
|---|
| 199 | unumf_close(UNumberFormatter* f) { | 
|---|
| 200 | UErrorCode localStatus = U_ZERO_ERROR; | 
|---|
| 201 | const UNumberFormatterData* impl = UNumberFormatterData::validate(f, localStatus); | 
|---|
| 202 | delete impl; | 
|---|
| 203 | } | 
|---|
| 204 |  | 
|---|
| 205 |  | 
|---|
| 206 | #endif /* #if !UCONFIG_NO_FORMATTING */ | 
|---|
| 207 |  | 
|---|
| 208 |  | 
|---|
| 209 |  | 
|---|
| 210 |  | 
|---|
| 211 |  | 
|---|
| 212 |  | 
|---|
| 213 |  | 
|---|
| 214 |  | 
|---|
| 215 |  | 
|---|
| 216 |  | 
|---|
| 217 |  | 
|---|
| 218 |  | 
|---|
| 219 |  | 
|---|
| 220 |  | 
|---|
| 221 |  | 
|---|
| 222 |  | 
|---|
| 223 |  | 
|---|
| 224 |  | 
|---|
| 225 |  | 
|---|
| 226 |  | 
|---|
| 227 |  | 
|---|
| 228 |  | 
|---|
| 229 |  | 
|---|
| 230 |  | 
|---|
| 231 |  | 
|---|
| 232 |  | 
|---|
| 233 |  | 
|---|
| 234 |  | 
|---|