1/******************************************************************** 2 * Copyright (C) 2016 and later: Unicode, Inc. and others. 3 * License & terms of use: http://www.unicode.org/copyright.html#License 4 ************************************************************************* 5 ************************************************************************* 6 * COPYRIGHT: 7 * Copyright (c) 1999-2014, International Business Machines Corporation and 8 * others. All Rights Reserved. 9 *************************************************************************/ 10 11#include "unicode/utypes.h" 12#include "unicode/unistr.h" 13#include "unicode/numfmt.h" 14#include "unicode/dcfmtsym.h" 15#include "unicode/decimfmt.h" 16#include "unicode/locid.h" 17#include "unicode/uclean.h" 18#include "util.h" 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22 23extern "C" void capi(); 24void cppapi(); 25 26static void 27showCurrencyFormatting(UBool useICU26API); 28 29int main(int argc, char **argv) { 30 printf("%s output is in UTF-8\n", argv[0]); 31 32 printf("C++ API\n"); 33 cppapi(); 34 35 printf("C API\n"); 36 capi(); 37 38 showCurrencyFormatting(FALSE); 39 showCurrencyFormatting(TRUE); 40 41 u_cleanup(); // Release any additional storage held by ICU. 42 43 printf("Exiting successfully\n"); 44 return 0; 45} 46 47/** 48 * Sample code for the C++ API to NumberFormat. 49 */ 50void cppapi() { 51 Locale us("en", "US"); 52 UErrorCode status = U_ZERO_ERROR; 53 54 // Create a number formatter for the US locale 55 NumberFormat *fmt = NumberFormat::createInstance(us, status); 56 check(status, "NumberFormat::createInstance"); 57 58 // Parse a string. The string uses the digits '0' through '9' 59 // and the decimal separator '.', standard in the US locale 60 UnicodeString str("9876543210.123"); 61 Formattable result; 62 fmt->parse(str, result, status); 63 check(status, "NumberFormat::parse"); 64 65 printf("NumberFormat::parse(\""); // Display the result 66 uprintf(str); 67 printf("\") => "); 68 uprintf(formattableToString(result)); 69 printf("\n"); 70 71 // Take the number parsed above, and use the formatter to 72 // format it. 73 str.remove(); // format() will APPEND to this string 74 fmt->format(result, str, status); 75 check(status, "NumberFormat::format"); 76 77 printf("NumberFormat::format("); // Display the result 78 uprintf(formattableToString(result)); 79 printf(") => \""); 80 uprintf(str); 81 printf("\"\n"); 82 83 delete fmt; // Release the storage used by the formatter 84 85} 86 87// currency formatting ----------------------------------------------------- *** 88 89/* 90 * Set a currency on a NumberFormat with pre-ICU 2.6 APIs. 91 * This is a "hack" that will not work properly for all cases because 92 * only ICU 2.6 introduced a more complete framework and data for this. 93 * 94 * @param nf The NumberFormat on which to set the currency; takes effect on 95 * currency-formatting NumberFormat instances. 96 * This must actually be a DecimalFormat instance. 97 * The display style of the output is controlled by nf (its pattern, 98 * usually from the display locale ID used to create this instance) 99 * while the currency symbol and number of decimals are set for 100 * the currency. 101 * @param currency The 3-letter ISO 4217 currency code, NUL-terminated. 102 * @param errorCode ICU error code, must pass U_SUCCESS() on input. 103 */ 104static void 105setNumberFormatCurrency_2_4(NumberFormat &nf, const char *currency, UErrorCode &errorCode) { 106 // argument checking 107 if(U_FAILURE(errorCode)) { 108 return; 109 } 110 if(currency==NULL || strlen(currency)!=3) { 111 errorCode=U_ILLEGAL_ARGUMENT_ERROR; 112 return; 113 } 114 115 // check that the formatter is a DecimalFormat instance 116 // necessary because we will cast to the DecimalFormat subclass to set 117 // the currency symbol 118 DecimalFormat *dnf=dynamic_cast<DecimalFormat *>(&nf); 119 if(dnf==NULL) { 120 errorCode=U_ILLEGAL_ARGUMENT_ERROR; 121 return; 122 } 123 124 // map the currency code to a locale ID 125 // only the currencies in this array are supported 126 // it would be possible to map to a locale ID, instantiate a currency 127 // formatter for that and copy its values, but that would be slower, 128 // and we have to hardcode something here anyway 129 static const struct { 130 // ISO currency ID 131 const char *currency; 132 133 // fractionDigits==minimumFractionDigits==maximumFractionDigits 134 // for these currencies 135 int32_t fractionDigits; 136 137 /* 138 * Set the rounding increment to 0 if it is implied with the number of 139 * fraction digits. Setting an explicit rounding increment makes 140 * number formatting slower. 141 * In other words, set it to something other than 0 only for unusual 142 * cases like "nickel rounding" (0.05) when the increment differs from 143 * 10^(-maximumFractionDigits). 144 */ 145 double roundingIncrement; 146 147 // Unicode string with the desired currency display symbol or name 148 UChar symbol[16]; 149 } currencyMap[]={ 150 { "USD", 2, 0.0, { 0x24, 0 } }, 151 { "GBP", 2, 0.0, { 0xa3, 0 } }, 152 { "EUR", 2, 0.0, { 0x20ac, 0 } }, 153 { "JPY", 0, 0.0, { 0xa5, 0 } } 154 }; 155 156 int32_t i; 157 158 for(i=0; i<UPRV_LENGTHOF(currencyMap); ++i) { 159 if(strcmp(currency, currencyMap[i].currency)==0) { 160 break; 161 } 162 } 163 if(i==UPRV_LENGTHOF(currencyMap)) { 164 // a more specific error code would be useful in a real application 165 errorCode=U_UNSUPPORTED_ERROR; 166 return; 167 } 168 169 // set the currency-related data into the caller's formatter 170 171 nf.setMinimumFractionDigits(currencyMap[i].fractionDigits); 172 nf.setMaximumFractionDigits(currencyMap[i].fractionDigits); 173 174 dnf->setRoundingIncrement(currencyMap[i].roundingIncrement); 175 176 DecimalFormatSymbols symbols(*dnf->getDecimalFormatSymbols()); 177 symbols.setSymbol(DecimalFormatSymbols::kCurrencySymbol, currencyMap[i].symbol); 178 dnf->setDecimalFormatSymbols(symbols); // do not adopt symbols: Jitterbug 2889 179} 180 181/* 182 * Set a currency on a NumberFormat with ICU 2.6 APIs. 183 * 184 * @param nf The NumberFormat on which to set the currency; takes effect on 185 * currency-formatting NumberFormat instances. 186 * The display style of the output is controlled by nf (its pattern, 187 * usually from the display locale ID used to create this instance) 188 * while the currency symbol and number of decimals are set for 189 * the currency. 190 * @param currency The 3-letter ISO 4217 currency code, NUL-terminated. 191 * @param errorCode ICU error code, must pass U_SUCCESS() on input. 192 */ 193static void 194setNumberFormatCurrency_2_6(NumberFormat &nf, const char *currency, UErrorCode &errorCode) { 195 if(U_FAILURE(errorCode)) { 196 return; 197 } 198 if(currency==NULL || strlen(currency)!=3) { 199 errorCode=U_ILLEGAL_ARGUMENT_ERROR; 200 return; 201 } 202 203 // invariant-character conversion to UChars (see utypes.h and putil.h) 204 UChar uCurrency[4]; 205 u_charsToUChars(currency, uCurrency, 4); 206 207 // set the currency 208 // in ICU 3.0 this API (which was @draft ICU 2.6) gained a UErrorCode& argument 209#if (U_ICU_VERSION_MAJOR_NUM < 3) 210 nf.setCurrency(uCurrency); 211#else 212 nf.setCurrency(uCurrency, errorCode); 213#endif 214} 215 216static const char *const 217sampleLocaleIDs[]={ 218 // use locale IDs complete with country code to be sure to 219 // pick up number/currency format patterns 220 "en_US", "en_GB", "de_DE", "ja_JP", "fr_FR", "hi_IN" 221}; 222 223static const char *const 224sampleCurrencies[]={ 225 "USD", "GBP", "EUR", "JPY" 226}; 227 228static void 229showCurrencyFormatting(UBool useICU26API) { 230 NumberFormat *nf; 231 int32_t i, j; 232 233 UnicodeString output; 234 235 UErrorCode errorCode; 236 237 // TODO: Using printf() here assumes that the runtime encoding is ASCII-friendly 238 // and can therefore be mixed with UTF-8 239 240 for(i=0; i<UPRV_LENGTHOF(sampleLocaleIDs); ++i) { 241 printf("show currency formatting (method for %s) in the locale \"%s\"\n", 242 useICU26API ? "ICU 2.6" : "before ICU 2.6", 243 sampleLocaleIDs[i]); 244 245 // get a currency formatter for this locale ID 246 errorCode=U_ZERO_ERROR; 247 nf=NumberFormat::createCurrencyInstance(sampleLocaleIDs[i], errorCode); 248 if(U_FAILURE(errorCode)) { 249 printf("NumberFormat::createCurrencyInstance(%s) failed - %s\n", 250 sampleLocaleIDs[i], u_errorName(errorCode)); 251 continue; 252 } 253 254 for(j=0; j<UPRV_LENGTHOF(sampleCurrencies); ++j) { 255 printf(" - format currency \"%s\": ", sampleCurrencies[j]); 256 257 // set the actual currency to be formatted 258 if(useICU26API) { 259 setNumberFormatCurrency_2_6(*nf, sampleCurrencies[j], errorCode); 260 } else { 261 setNumberFormatCurrency_2_4(*nf, sampleCurrencies[j], errorCode); 262 } 263 if(U_FAILURE(errorCode)) { 264 printf("setNumberFormatCurrency(%s) failed - %s\n", 265 sampleCurrencies[j], u_errorName(errorCode)); 266 continue; 267 } 268 269 // output=formatted currency value 270 output.remove(); 271 nf->format(12345678.93, output); 272 output+=(UChar)0x0a; // '\n' 273 uprintf(output); 274 } 275 } 276} 277