1 /*
2 *******************************************************************************
3 * Copyright (C) 2015, International Business Machines Corporation and         *
4 * others. All Rights Reserved.                                                *
5 *******************************************************************************
6 */
7 
8 #include "numberformattesttuple.h"
9 
10 #if !UCONFIG_NO_FORMATTING
11 
12 #include "ustrfmt.h"
13 #include "charstr.h"
14 #include "cstring.h"
15 #include "cmemory.h"
16 #include "digitlst.h"
17 
18 static NumberFormatTestTuple *gNullPtr = NULL;
19 
20 #define FIELD_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName) - ((char *) gNullPtr)))
21 #define FIELD_FLAG_OFFSET(fieldName) ((int32_t) (((char *) &gNullPtr->fieldName##Flag) - ((char *) gNullPtr)))
22 
23 #define FIELD_INIT(fieldName, fieldType) {#fieldName, FIELD_OFFSET(fieldName), FIELD_FLAG_OFFSET(fieldName), fieldType}
24 
25 struct Numberformattesttuple_EnumConversion {
26     const char *str;
27     int32_t value;
28 };
29 
30 static Numberformattesttuple_EnumConversion gRoundingEnum[] = {
31     {"ceiling", DecimalFormat::kRoundCeiling},
32     {"floor", DecimalFormat::kRoundFloor},
33     {"down", DecimalFormat::kRoundDown},
34     {"up", DecimalFormat::kRoundUp},
35     {"halfEven", DecimalFormat::kRoundHalfEven},
36     {"halfDown", DecimalFormat::kRoundHalfDown},
37     {"halfUp", DecimalFormat::kRoundHalfUp},
38     {"unnecessary", DecimalFormat::kRoundUnnecessary}};
39 
40 static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = {
41     {"standard", UCURR_USAGE_STANDARD},
42     {"cash", UCURR_USAGE_CASH}};
43 
44 static Numberformattesttuple_EnumConversion gPadPositionEnum[] = {
45     {"beforePrefix", DecimalFormat::kPadBeforePrefix},
46     {"afterPrefix", DecimalFormat::kPadAfterPrefix},
47     {"beforeSuffix", DecimalFormat::kPadBeforeSuffix},
48     {"afterSuffix", DecimalFormat::kPadAfterSuffix}};
49 
50 static Numberformattesttuple_EnumConversion gFormatStyleEnum[] = {
51     {"patternDecimal", UNUM_PATTERN_DECIMAL},
52     {"decimal", UNUM_DECIMAL},
53     {"currency", UNUM_CURRENCY},
54     {"percent", UNUM_PERCENT},
55     {"scientific", UNUM_SCIENTIFIC},
56     {"spellout", UNUM_SPELLOUT},
57     {"ordinal", UNUM_ORDINAL},
58     {"duration", UNUM_DURATION},
59     {"numberingSystem", UNUM_NUMBERING_SYSTEM},
60     {"patternRuleBased", UNUM_PATTERN_RULEBASED},
61     {"currencyIso", UNUM_CURRENCY_ISO},
62     {"currencyPlural", UNUM_CURRENCY_PLURAL},
63     {"currencyAccounting", UNUM_CURRENCY_ACCOUNTING},
64     {"cashCurrency", UNUM_CASH_CURRENCY},
65     {"default", UNUM_DEFAULT},
66     {"ignore", UNUM_IGNORE}};
67 
toEnum(const Numberformattesttuple_EnumConversion * table,int32_t tableLength,const UnicodeString & str,UErrorCode & status)68 static int32_t toEnum(
69         const Numberformattesttuple_EnumConversion *table,
70         int32_t tableLength,
71         const UnicodeString &str,
72         UErrorCode &status) {
73     if (U_FAILURE(status)) {
74         return 0;
75     }
76     CharString cstr;
77     cstr.appendInvariantChars(str, status);
78     if (U_FAILURE(status)) {
79         return 0;
80     }
81     for (int32_t i = 0; i < tableLength; ++i) {
82         if (uprv_strcmp(cstr.data(), table[i].str) == 0) {
83             return table[i].value;
84         }
85     }
86     status = U_ILLEGAL_ARGUMENT_ERROR;
87     return 0;
88 }
89 
fromEnum(const Numberformattesttuple_EnumConversion * table,int32_t tableLength,int32_t val,UnicodeString & appendTo)90 static void fromEnum(
91         const Numberformattesttuple_EnumConversion *table,
92         int32_t tableLength,
93         int32_t val,
94         UnicodeString &appendTo) {
95     for (int32_t i = 0; i < tableLength; ++i) {
96         if (table[i].value == val) {
97             appendTo.append(table[i].str);
98         }
99     }
100 }
101 
identVal(const UnicodeString & str,void * strPtr,UErrorCode &)102 static void identVal(
103         const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) {
104     *static_cast<UnicodeString *>(strPtr) = str;
105 }
106 
identStr(const void * strPtr,UnicodeString & appendTo)107 static void identStr(
108         const void *strPtr, UnicodeString &appendTo) {
109     appendTo.append(*static_cast<const UnicodeString *>(strPtr));
110 }
111 
strToLocale(const UnicodeString & str,void * localePtr,UErrorCode & status)112 static void strToLocale(
113         const UnicodeString &str, void *localePtr, UErrorCode &status) {
114     if (U_FAILURE(status)) {
115         return;
116     }
117     CharString localeStr;
118     localeStr.appendInvariantChars(str, status);
119     *static_cast<Locale *>(localePtr) = Locale(localeStr.data());
120 }
121 
localeToStr(const void * localePtr,UnicodeString & appendTo)122 static void localeToStr(
123         const void *localePtr, UnicodeString &appendTo) {
124     appendTo.append(
125             UnicodeString(
126                     static_cast<const Locale *>(localePtr)->getName()));
127 }
128 
strToInt(const UnicodeString & str,void * intPtr,UErrorCode & status)129 static void strToInt(
130         const UnicodeString &str, void *intPtr, UErrorCode &status) {
131     if (U_FAILURE(status)) {
132         return;
133     }
134     int32_t len = str.length();
135     int32_t start = 0;
136     UBool neg = FALSE;
137     if (len > 0 && str[0] == 0x2D) { // negative
138         neg = TRUE;
139         start = 1;
140     }
141     if (start == len) {
142         status = U_ILLEGAL_ARGUMENT_ERROR;
143         return;
144     }
145     int32_t value = 0;
146     for (int32_t i = start; i < len; ++i) {
147         UChar ch = str[i];
148         if (ch < 0x30 || ch > 0x39) {
149             status = U_ILLEGAL_ARGUMENT_ERROR;
150             return;
151         }
152         value = value * 10 - 0x30 + (int32_t) ch;
153     }
154     if (neg) {
155         value = -value;
156     }
157     *static_cast<int32_t *>(intPtr) = value;
158 }
159 
intToStr(const void * intPtr,UnicodeString & appendTo)160 static void intToStr(
161         const void *intPtr, UnicodeString &appendTo) {
162     UChar buffer[20];
163     int32_t x = *static_cast<const int32_t *>(intPtr);
164     UBool neg = FALSE;
165     if (x < 0) {
166         neg = TRUE;
167         x = -x;
168     }
169     if (neg) {
170         appendTo.append(0x2D);
171     }
172     int32_t len = uprv_itou(buffer, UPRV_LENGTHOF(buffer), (uint32_t) x, 10, 1);
173     appendTo.append(buffer, 0, len);
174 }
175 
strToDouble(const UnicodeString & str,void * doublePtr,UErrorCode & status)176 static void strToDouble(
177         const UnicodeString &str, void *doublePtr, UErrorCode &status) {
178     if (U_FAILURE(status)) {
179         return;
180     }
181     CharString buffer;
182     buffer.appendInvariantChars(str, status);
183     if (U_FAILURE(status)) {
184         return;
185     }
186     *static_cast<double *>(doublePtr) = atof(buffer.data());
187 }
188 
doubleToStr(const void * doublePtr,UnicodeString & appendTo)189 static void doubleToStr(
190         const void *doublePtr, UnicodeString &appendTo) {
191     char buffer[256];
192     double x = *static_cast<const double *>(doublePtr);
193     sprintf(buffer, "%f", x);
194     appendTo.append(buffer);
195 }
196 
strToERounding(const UnicodeString & str,void * roundPtr,UErrorCode & status)197 static void strToERounding(
198         const UnicodeString &str, void *roundPtr, UErrorCode &status) {
199     int32_t val = toEnum(
200             gRoundingEnum, UPRV_LENGTHOF(gRoundingEnum), str, status);
201     *static_cast<DecimalFormat::ERoundingMode *>(roundPtr) = (DecimalFormat::ERoundingMode) val;
202 }
203 
eRoundingToStr(const void * roundPtr,UnicodeString & appendTo)204 static void eRoundingToStr(
205         const void *roundPtr, UnicodeString &appendTo) {
206     DecimalFormat::ERoundingMode rounding =
207             *static_cast<const DecimalFormat::ERoundingMode *>(roundPtr);
208     fromEnum(
209             gRoundingEnum,
210             UPRV_LENGTHOF(gRoundingEnum),
211             rounding,
212             appendTo);
213 }
214 
strToCurrencyUsage(const UnicodeString & str,void * currencyUsagePtr,UErrorCode & status)215 static void strToCurrencyUsage(
216         const UnicodeString &str, void *currencyUsagePtr, UErrorCode &status) {
217     int32_t val = toEnum(
218             gCurrencyUsageEnum, UPRV_LENGTHOF(gCurrencyUsageEnum), str, status);
219     *static_cast<UCurrencyUsage *>(currencyUsagePtr) = (UCurrencyUsage) val;
220 }
221 
currencyUsageToStr(const void * currencyUsagePtr,UnicodeString & appendTo)222 static void currencyUsageToStr(
223         const void *currencyUsagePtr, UnicodeString &appendTo) {
224     UCurrencyUsage currencyUsage =
225             *static_cast<const UCurrencyUsage *>(currencyUsagePtr);
226     fromEnum(
227             gCurrencyUsageEnum,
228             UPRV_LENGTHOF(gCurrencyUsageEnum),
229             currencyUsage,
230             appendTo);
231 }
232 
strToEPadPosition(const UnicodeString & str,void * padPositionPtr,UErrorCode & status)233 static void strToEPadPosition(
234         const UnicodeString &str, void *padPositionPtr, UErrorCode &status) {
235     int32_t val = toEnum(
236             gPadPositionEnum, UPRV_LENGTHOF(gPadPositionEnum), str, status);
237     *static_cast<DecimalFormat::EPadPosition *>(padPositionPtr) =
238             (DecimalFormat::EPadPosition) val;
239 }
240 
ePadPositionToStr(const void * padPositionPtr,UnicodeString & appendTo)241 static void ePadPositionToStr(
242         const void *padPositionPtr, UnicodeString &appendTo) {
243     DecimalFormat::EPadPosition padPosition =
244             *static_cast<const DecimalFormat::EPadPosition *>(padPositionPtr);
245     fromEnum(
246             gPadPositionEnum,
247             UPRV_LENGTHOF(gPadPositionEnum),
248             padPosition,
249             appendTo);
250 }
251 
strToFormatStyle(const UnicodeString & str,void * formatStylePtr,UErrorCode & status)252 static void strToFormatStyle(
253         const UnicodeString &str, void *formatStylePtr, UErrorCode &status) {
254     int32_t val = toEnum(
255             gFormatStyleEnum, UPRV_LENGTHOF(gFormatStyleEnum), str, status);
256     *static_cast<UNumberFormatStyle *>(formatStylePtr) = (UNumberFormatStyle) val;
257 }
258 
formatStyleToStr(const void * formatStylePtr,UnicodeString & appendTo)259 static void formatStyleToStr(
260         const void *formatStylePtr, UnicodeString &appendTo) {
261     UNumberFormatStyle formatStyle =
262             *static_cast<const UNumberFormatStyle *>(formatStylePtr);
263     fromEnum(
264             gFormatStyleEnum,
265             UPRV_LENGTHOF(gFormatStyleEnum),
266             formatStyle,
267             appendTo);
268 }
269 
270 struct NumberFormatTestTupleFieldOps {
271     void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &);
272     void (*toString)(const void *valPtr, UnicodeString &appendTo);
273 };
274 
275 const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr};
276 const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr};
277 const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr};
278 const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr};
279 const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr};
280 const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr};
281 const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr};
282 const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr};
283 
284 struct NumberFormatTestTupleFieldData {
285     const char *name;
286     int32_t offset;
287     int32_t flagOffset;
288     const NumberFormatTestTupleFieldOps *ops;
289 };
290 
291 // Order must correspond to ENumberFormatTestTupleField
292 const NumberFormatTestTupleFieldData gFieldData[] = {
293     FIELD_INIT(locale, &gLocaleOps),
294     FIELD_INIT(currency, &gStrOps),
295     FIELD_INIT(pattern, &gStrOps),
296     FIELD_INIT(format, &gStrOps),
297     FIELD_INIT(output, &gStrOps),
298     FIELD_INIT(comment, &gStrOps),
299     FIELD_INIT(minIntegerDigits, &gIntOps),
300     FIELD_INIT(maxIntegerDigits, &gIntOps),
301     FIELD_INIT(minFractionDigits, &gIntOps),
302     FIELD_INIT(maxFractionDigits, &gIntOps),
303     FIELD_INIT(minGroupingDigits, &gIntOps),
304     FIELD_INIT(breaks, &gStrOps),
305     FIELD_INIT(useSigDigits, &gIntOps),
306     FIELD_INIT(minSigDigits, &gIntOps),
307     FIELD_INIT(maxSigDigits, &gIntOps),
308     FIELD_INIT(useGrouping, &gIntOps),
309     FIELD_INIT(multiplier, &gIntOps),
310     FIELD_INIT(roundingIncrement, &gDoubleOps),
311     FIELD_INIT(formatWidth, &gIntOps),
312     FIELD_INIT(padCharacter, &gStrOps),
313     FIELD_INIT(useScientific, &gIntOps),
314     FIELD_INIT(grouping, &gIntOps),
315     FIELD_INIT(grouping2, &gIntOps),
316     FIELD_INIT(roundingMode, &gERoundingOps),
317     FIELD_INIT(currencyUsage, &gCurrencyUsageOps),
318     FIELD_INIT(minimumExponentDigits, &gIntOps),
319     FIELD_INIT(exponentSignAlwaysShown, &gIntOps),
320     FIELD_INIT(decimalSeparatorAlwaysShown, &gIntOps),
321     FIELD_INIT(padPosition, &gEPadPositionOps),
322     FIELD_INIT(positivePrefix, &gStrOps),
323     FIELD_INIT(positiveSuffix, &gStrOps),
324     FIELD_INIT(negativePrefix, &gStrOps),
325     FIELD_INIT(negativeSuffix, &gStrOps),
326     FIELD_INIT(localizedPattern, &gStrOps),
327     FIELD_INIT(toPattern, &gStrOps),
328     FIELD_INIT(toLocalizedPattern, &gStrOps),
329     FIELD_INIT(style, &gFormatStyleOps),
330     FIELD_INIT(parse, &gStrOps),
331     FIELD_INIT(lenient, &gIntOps),
332     FIELD_INIT(plural, &gStrOps),
333     FIELD_INIT(parseIntegerOnly, &gIntOps),
334     FIELD_INIT(decimalPatternMatchRequired, &gIntOps),
335     FIELD_INIT(parseNoExponent, &gIntOps),
336     FIELD_INIT(outputCurrency, &gStrOps)
337 };
338 
339 UBool
setField(ENumberFormatTestTupleField fieldId,const UnicodeString & fieldValue,UErrorCode & status)340 NumberFormatTestTuple::setField(
341         ENumberFormatTestTupleField fieldId,
342         const UnicodeString &fieldValue,
343         UErrorCode &status) {
344     if (U_FAILURE(status)) {
345         return FALSE;
346     }
347     if (fieldId == kNumberFormatTestTupleFieldCount) {
348         status = U_ILLEGAL_ARGUMENT_ERROR;
349         return FALSE;
350     }
351     gFieldData[fieldId].ops->toValue(
352             fieldValue, getMutableFieldAddress(fieldId), status);
353     if (U_FAILURE(status)) {
354         return FALSE;
355     }
356     setFlag(fieldId, TRUE);
357     return TRUE;
358 }
359 
360 UBool
clearField(ENumberFormatTestTupleField fieldId,UErrorCode & status)361 NumberFormatTestTuple::clearField(
362         ENumberFormatTestTupleField fieldId,
363         UErrorCode &status) {
364     if (U_FAILURE(status)) {
365         return FALSE;
366     }
367     if (fieldId == kNumberFormatTestTupleFieldCount) {
368         status = U_ILLEGAL_ARGUMENT_ERROR;
369         return FALSE;
370     }
371     setFlag(fieldId, FALSE);
372     return TRUE;
373 }
374 
375 void
clear()376 NumberFormatTestTuple::clear() {
377     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
378         setFlag(i, FALSE);
379     }
380 }
381 
382 UnicodeString &
toString(UnicodeString & appendTo) const383 NumberFormatTestTuple::toString(
384         UnicodeString &appendTo) const {
385     appendTo.append("{");
386     UBool first = TRUE;
387     for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) {
388         if (!isFlag(i)) {
389             continue;
390         }
391         if (!first) {
392             appendTo.append(", ");
393         }
394         first = FALSE;
395         appendTo.append(gFieldData[i].name);
396         appendTo.append(": ");
397         gFieldData[i].ops->toString(getFieldAddress(i), appendTo);
398     }
399     appendTo.append("}");
400     return appendTo;
401 }
402 
403 ENumberFormatTestTupleField
getFieldByName(const UnicodeString & name)404 NumberFormatTestTuple::getFieldByName(
405         const UnicodeString &name) {
406     CharString buffer;
407     UErrorCode status = U_ZERO_ERROR;
408     buffer.appendInvariantChars(name, status);
409     if (U_FAILURE(status)) {
410         return kNumberFormatTestTupleFieldCount;
411     }
412     int32_t result = -1;
413     for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) {
414         if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) {
415             result = i;
416             break;
417         }
418     }
419     if (result == -1) {
420         return kNumberFormatTestTupleFieldCount;
421     }
422     return (ENumberFormatTestTupleField) result;
423 }
424 
425 const void *
getFieldAddress(int32_t fieldId) const426 NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const {
427     return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset;
428 }
429 
430 void *
getMutableFieldAddress(int32_t fieldId)431 NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) {
432     return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset;
433 }
434 
435 void
setFlag(int32_t fieldId,UBool value)436 NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) {
437     void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset;
438     *static_cast<UBool *>(flagAddr) = value;
439 }
440 
441 UBool
isFlag(int32_t fieldId) const442 NumberFormatTestTuple::isFlag(int32_t fieldId) const {
443     const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset;
444     return *static_cast<const UBool *>(flagAddr);
445 }
446 
447 #endif /* !UCONFIG_NO_FORMATTING */
448