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 18static 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 25struct Numberformattesttuple_EnumConversion { 26 const char *str; 27 int32_t value; 28}; 29 30static 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 40static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = { 41 {"standard", UCURR_USAGE_STANDARD}, 42 {"cash", UCURR_USAGE_CASH}}; 43 44static Numberformattesttuple_EnumConversion gPadPositionEnum[] = { 45 {"beforePrefix", DecimalFormat::kPadBeforePrefix}, 46 {"afterPrefix", DecimalFormat::kPadAfterPrefix}, 47 {"beforeSuffix", DecimalFormat::kPadBeforeSuffix}, 48 {"afterSuffix", DecimalFormat::kPadAfterSuffix}}; 49 50static 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 68static 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 90static 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 102static void identVal( 103 const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) { 104 *static_cast<UnicodeString *>(strPtr) = str; 105} 106 107static void identStr( 108 const void *strPtr, UnicodeString &appendTo) { 109 appendTo.append(*static_cast<const UnicodeString *>(strPtr)); 110} 111 112static 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 122static void localeToStr( 123 const void *localePtr, UnicodeString &appendTo) { 124 appendTo.append( 125 UnicodeString( 126 static_cast<const Locale *>(localePtr)->getName())); 127} 128 129static 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 160static 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 176static 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 189static 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 197static 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 204static 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 215static 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 222static 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 233static 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 241static 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 252static 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 259static 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 270struct NumberFormatTestTupleFieldOps { 271 void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &); 272 void (*toString)(const void *valPtr, UnicodeString &appendTo); 273}; 274 275const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr}; 276const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr}; 277const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr}; 278const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr}; 279const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr}; 280const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr}; 281const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr}; 282const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr}; 283 284struct 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 292const 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 339UBool 340NumberFormatTestTuple::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 360UBool 361NumberFormatTestTuple::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 375void 376NumberFormatTestTuple::clear() { 377 for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) { 378 setFlag(i, FALSE); 379 } 380} 381 382UnicodeString & 383NumberFormatTestTuple::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 403ENumberFormatTestTupleField 404NumberFormatTestTuple::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 425const void * 426NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const { 427 return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset; 428} 429 430void * 431NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) { 432 return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset; 433} 434 435void 436NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) { 437 void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset; 438 *static_cast<UBool *>(flagAddr) = value; 439} 440 441UBool 442NumberFormatTestTuple::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