| 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 | |