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