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