• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
main(int argc,char ** argv)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  */
cppapi()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
setNumberFormatCurrency_2_4(NumberFormat & nf,const char * currency,UErrorCode & errorCode)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
setNumberFormatCurrency_2_6(NumberFormat & nf,const char * currency,UErrorCode & errorCode)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
showCurrencyFormatting(UBool useICU26API)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