| /******************************************************************** | |
| * © 2016 and later: Unicode, Inc. and others. | |
| * License & terms of use: http://www.unicode.org/copyright.html | |
| ************************************************************************* | |
| ************************************************************************* | |
| * COPYRIGHT: | |
| * Copyright (c) 1999-2014, International Business Machines Corporation and | |
| * others. All Rights Reserved. | |
| *************************************************************************/ | |
| #include "unicode/utypes.h" | |
| #include "unicode/unistr.h" | |
| #include "unicode/numfmt.h" | |
| #include "unicode/dcfmtsym.h" | |
| #include "unicode/decimfmt.h" | |
| #include "unicode/locid.h" | |
| #include "unicode/uclean.h" | |
| #include "util.h" | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| extern "C" void capi(); | |
| void cppapi(); | |
| static void | |
| showCurrencyFormatting(UBool useICU26API); | |
| int main(int argc, char **argv) { | |
| printf("%s output is in UTF-8\n", argv[0]); | |
| printf("C++ API\n"); | |
| cppapi(); | |
| printf("C API\n"); | |
| capi(); | |
| showCurrencyFormatting(false); | |
| showCurrencyFormatting(true); | |
| u_cleanup(); // Release any additional storage held by ICU. | |
| printf("Exiting successfully\n"); | |
| return 0; | |
| } | |
| /** | |
| * Sample code for the C++ API to NumberFormat. | |
| */ | |
| void cppapi() { | |
| Locale us("en", "US"); | |
| UErrorCode status = U_ZERO_ERROR; | |
| // Create a number formatter for the US locale | |
| NumberFormat *fmt = NumberFormat::createInstance(us, status); | |
| check(status, "NumberFormat::createInstance"); | |
| // Parse a string. The string uses the digits '0' through '9' | |
| // and the decimal separator '.', standard in the US locale | |
| UnicodeString str("9876543210.123"); | |
| Formattable result; | |
| fmt->parse(str, result, status); | |
| check(status, "NumberFormat::parse"); | |
| printf("NumberFormat::parse(\""); // Display the result | |
| uprintf(str); | |
| printf("\") => "); | |
| uprintf(formattableToString(result)); | |
| printf("\n"); | |
| // Take the number parsed above, and use the formatter to | |
| // format it. | |
| str.remove(); // format() will APPEND to this string | |
| fmt->format(result, str, status); | |
| check(status, "NumberFormat::format"); | |
| printf("NumberFormat::format("); // Display the result | |
| uprintf(formattableToString(result)); | |
| printf(") => \""); | |
| uprintf(str); | |
| printf("\"\n"); | |
| delete fmt; // Release the storage used by the formatter | |
| } | |
| // currency formatting ----------------------------------------------------- *** | |
| /* | |
| * Set a currency on a NumberFormat with pre-ICU 2.6 APIs. | |
| * This is a "hack" that will not work properly for all cases because | |
| * only ICU 2.6 introduced a more complete framework and data for this. | |
| * | |
| * @param nf The NumberFormat on which to set the currency; takes effect on | |
| * currency-formatting NumberFormat instances. | |
| * This must actually be a DecimalFormat instance. | |
| * The display style of the output is controlled by nf (its pattern, | |
| * usually from the display locale ID used to create this instance) | |
| * while the currency symbol and number of decimals are set for | |
| * the currency. | |
| * @param currency The 3-letter ISO 4217 currency code, NUL-terminated. | |
| * @param errorCode ICU error code, must pass U_SUCCESS() on input. | |
| */ | |
| static void | |
| setNumberFormatCurrency_2_4(NumberFormat &nf, const char *currency, UErrorCode &errorCode) { | |
| // argument checking | |
| if(U_FAILURE(errorCode)) { | |
| return; | |
| } | |
| if(currency==NULL || strlen(currency)!=3) { | |
| errorCode=U_ILLEGAL_ARGUMENT_ERROR; | |
| return; | |
| } | |
| // check that the formatter is a DecimalFormat instance | |
| // necessary because we will cast to the DecimalFormat subclass to set | |
| // the currency symbol | |
| DecimalFormat *dnf=dynamic_cast<DecimalFormat *>(&nf); | |
| if(dnf==NULL) { | |
| errorCode=U_ILLEGAL_ARGUMENT_ERROR; | |
| return; | |
| } | |
| // map the currency code to a locale ID | |
| // only the currencies in this array are supported | |
| // it would be possible to map to a locale ID, instantiate a currency | |
| // formatter for that and copy its values, but that would be slower, | |
| // and we have to hardcode something here anyway | |
| static const struct { | |
| // ISO currency ID | |
| const char *currency; | |
| // fractionDigits==minimumFractionDigits==maximumFractionDigits | |
| // for these currencies | |
| int32_t fractionDigits; | |
| /* | |
| * Set the rounding increment to 0 if it is implied with the number of | |
| * fraction digits. Setting an explicit rounding increment makes | |
| * number formatting slower. | |
| * In other words, set it to something other than 0 only for unusual | |
| * cases like "nickel rounding" (0.05) when the increment differs from | |
| * 10^(-maximumFractionDigits). | |
| */ | |
| double roundingIncrement; | |
| // Unicode string with the desired currency display symbol or name | |
| UChar symbol[16]; | |
| } currencyMap[]={ | |
| { "USD", 2, 0.0, { 0x24, 0 } }, | |
| { "GBP", 2, 0.0, { 0xa3, 0 } }, | |
| { "EUR", 2, 0.0, { 0x20ac, 0 } }, | |
| { "JPY", 0, 0.0, { 0xa5, 0 } } | |
| }; | |
| int32_t i; | |
| for(i=0; i<UPRV_LENGTHOF(currencyMap); ++i) { | |
| if(strcmp(currency, currencyMap[i].currency)==0) { | |
| break; | |
| } | |
| } | |
| if(i==UPRV_LENGTHOF(currencyMap)) { | |
| // a more specific error code would be useful in a real application | |
| errorCode=U_UNSUPPORTED_ERROR; | |
| return; | |
| } | |
| // set the currency-related data into the caller's formatter | |
| nf.setMinimumFractionDigits(currencyMap[i].fractionDigits); | |
| nf.setMaximumFractionDigits(currencyMap[i].fractionDigits); | |
| dnf->setRoundingIncrement(currencyMap[i].roundingIncrement); | |
| DecimalFormatSymbols symbols(*dnf->getDecimalFormatSymbols()); | |
| symbols.setSymbol(DecimalFormatSymbols::kCurrencySymbol, currencyMap[i].symbol); | |
| dnf->setDecimalFormatSymbols(symbols); // do not adopt symbols: Jitterbug 2889 | |
| } | |
| /* | |
| * Set a currency on a NumberFormat with ICU 2.6 APIs. | |
| * | |
| * @param nf The NumberFormat on which to set the currency; takes effect on | |
| * currency-formatting NumberFormat instances. | |
| * The display style of the output is controlled by nf (its pattern, | |
| * usually from the display locale ID used to create this instance) | |
| * while the currency symbol and number of decimals are set for | |
| * the currency. | |
| * @param currency The 3-letter ISO 4217 currency code, NUL-terminated. | |
| * @param errorCode ICU error code, must pass U_SUCCESS() on input. | |
| */ | |
| static void | |
| setNumberFormatCurrency_2_6(NumberFormat &nf, const char *currency, UErrorCode &errorCode) { | |
| if(U_FAILURE(errorCode)) { | |
| return; | |
| } | |
| if(currency==NULL || strlen(currency)!=3) { | |
| errorCode=U_ILLEGAL_ARGUMENT_ERROR; | |
| return; | |
| } | |
| // invariant-character conversion to UChars (see utypes.h and putil.h) | |
| UChar uCurrency[4]; | |
| u_charsToUChars(currency, uCurrency, 4); | |
| // set the currency | |
| // in ICU 3.0 this API (which was @draft ICU 2.6) gained a UErrorCode& argument | |
| #if (U_ICU_VERSION_MAJOR_NUM < 3) | |
| nf.setCurrency(uCurrency); | |
| #else | |
| nf.setCurrency(uCurrency, errorCode); | |
| #endif | |
| } | |
| static const char *const | |
| sampleLocaleIDs[]={ | |
| // use locale IDs complete with country code to be sure to | |
| // pick up number/currency format patterns | |
| "en_US", "en_GB", "de_DE", "ja_JP", "fr_FR", "hi_IN" | |
| }; | |
| static const char *const | |
| sampleCurrencies[]={ | |
| "USD", "GBP", "EUR", "JPY" | |
| }; | |
| static void | |
| showCurrencyFormatting(UBool useICU26API) { | |
| NumberFormat *nf; | |
| int32_t i, j; | |
| UnicodeString output; | |
| UErrorCode errorCode; | |
| // TODO: Using printf() here assumes that the runtime encoding is ASCII-friendly | |
| // and can therefore be mixed with UTF-8 | |
| for(i=0; i<UPRV_LENGTHOF(sampleLocaleIDs); ++i) { | |
| printf("show currency formatting (method for %s) in the locale \"%s\"\n", | |
| useICU26API ? "ICU 2.6" : "before ICU 2.6", | |
| sampleLocaleIDs[i]); | |
| // get a currency formatter for this locale ID | |
| errorCode=U_ZERO_ERROR; | |
| nf=NumberFormat::createCurrencyInstance(sampleLocaleIDs[i], errorCode); | |
| if(U_FAILURE(errorCode)) { | |
| printf("NumberFormat::createCurrencyInstance(%s) failed - %s\n", | |
| sampleLocaleIDs[i], u_errorName(errorCode)); | |
| continue; | |
| } | |
| for(j=0; j<UPRV_LENGTHOF(sampleCurrencies); ++j) { | |
| printf(" - format currency \"%s\": ", sampleCurrencies[j]); | |
| // set the actual currency to be formatted | |
| if(useICU26API) { | |
| setNumberFormatCurrency_2_6(*nf, sampleCurrencies[j], errorCode); | |
| } else { | |
| setNumberFormatCurrency_2_4(*nf, sampleCurrencies[j], errorCode); | |
| } | |
| if(U_FAILURE(errorCode)) { | |
| printf("setNumberFormatCurrency(%s) failed - %s\n", | |
| sampleCurrencies[j], u_errorName(errorCode)); | |
| continue; | |
| } | |
| // output=formatted currency value | |
| output.remove(); | |
| nf->format(12345678.93, output); | |
| output+=(UChar)0x0a; // '\n' | |
| uprintf(output); | |
| } | |
| } | |
| } |