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