1 // Copyright (C) 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 20 static 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 27 struct Numberformattesttuple_EnumConversion { 28 const char *str; 29 int32_t value; 30 }; 31 32 static 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 42 static Numberformattesttuple_EnumConversion gCurrencyUsageEnum[] = { 43 {"standard", UCURR_USAGE_STANDARD}, 44 {"cash", UCURR_USAGE_CASH}}; 45 46 static Numberformattesttuple_EnumConversion gPadPositionEnum[] = { 47 {"beforePrefix", DecimalFormat::kPadBeforePrefix}, 48 {"afterPrefix", DecimalFormat::kPadAfterPrefix}, 49 {"beforeSuffix", DecimalFormat::kPadBeforeSuffix}, 50 {"afterSuffix", DecimalFormat::kPadAfterSuffix}}; 51 52 static 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 70 static 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 92 static 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 104 static void identVal( 105 const UnicodeString &str, void *strPtr, UErrorCode & /*status*/) { 106 *static_cast<UnicodeString *>(strPtr) = str; 107 } 108 109 static void identStr( 110 const void *strPtr, UnicodeString &appendTo) { 111 appendTo.append(*static_cast<const UnicodeString *>(strPtr)); 112 } 113 114 static 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 124 static void localeToStr( 125 const void *localePtr, UnicodeString &appendTo) { 126 appendTo.append( 127 UnicodeString( 128 static_cast<const Locale *>(localePtr)->getName())); 129 } 130 131 static 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 162 static 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 178 static 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 191 static 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 199 static 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 206 static 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 217 static 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 224 static 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 235 static 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 243 static 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 254 static 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 261 static 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 272 struct NumberFormatTestTupleFieldOps { 273 void (*toValue)(const UnicodeString &str, void *valPtr, UErrorCode &); 274 void (*toString)(const void *valPtr, UnicodeString &appendTo); 275 }; 276 277 const NumberFormatTestTupleFieldOps gStrOps = {identVal, identStr}; 278 const NumberFormatTestTupleFieldOps gIntOps = {strToInt, intToStr}; 279 const NumberFormatTestTupleFieldOps gLocaleOps = {strToLocale, localeToStr}; 280 const NumberFormatTestTupleFieldOps gDoubleOps = {strToDouble, doubleToStr}; 281 const NumberFormatTestTupleFieldOps gERoundingOps = {strToERounding, eRoundingToStr}; 282 const NumberFormatTestTupleFieldOps gCurrencyUsageOps = {strToCurrencyUsage, currencyUsageToStr}; 283 const NumberFormatTestTupleFieldOps gEPadPositionOps = {strToEPadPosition, ePadPositionToStr}; 284 const NumberFormatTestTupleFieldOps gFormatStyleOps = {strToFormatStyle, formatStyleToStr}; 285 286 struct 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 294 const 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(outputCurrency, &gStrOps) 339 }; 340 341 UBool 342 NumberFormatTestTuple::setField( 343 ENumberFormatTestTupleField fieldId, 344 const UnicodeString &fieldValue, 345 UErrorCode &status) { 346 if (U_FAILURE(status)) { 347 return FALSE; 348 } 349 if (fieldId == kNumberFormatTestTupleFieldCount) { 350 status = U_ILLEGAL_ARGUMENT_ERROR; 351 return FALSE; 352 } 353 gFieldData[fieldId].ops->toValue( 354 fieldValue, getMutableFieldAddress(fieldId), status); 355 if (U_FAILURE(status)) { 356 return FALSE; 357 } 358 setFlag(fieldId, TRUE); 359 return TRUE; 360 } 361 362 UBool 363 NumberFormatTestTuple::clearField( 364 ENumberFormatTestTupleField fieldId, 365 UErrorCode &status) { 366 if (U_FAILURE(status)) { 367 return FALSE; 368 } 369 if (fieldId == kNumberFormatTestTupleFieldCount) { 370 status = U_ILLEGAL_ARGUMENT_ERROR; 371 return FALSE; 372 } 373 setFlag(fieldId, FALSE); 374 return TRUE; 375 } 376 377 void 378 NumberFormatTestTuple::clear() { 379 for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) { 380 setFlag(i, FALSE); 381 } 382 } 383 384 UnicodeString & 385 NumberFormatTestTuple::toString( 386 UnicodeString &appendTo) const { 387 appendTo.append("{"); 388 UBool first = TRUE; 389 for (int32_t i = 0; i < kNumberFormatTestTupleFieldCount; ++i) { 390 if (!isFlag(i)) { 391 continue; 392 } 393 if (!first) { 394 appendTo.append(", "); 395 } 396 first = FALSE; 397 appendTo.append(gFieldData[i].name); 398 appendTo.append(": "); 399 gFieldData[i].ops->toString(getFieldAddress(i), appendTo); 400 } 401 appendTo.append("}"); 402 return appendTo; 403 } 404 405 ENumberFormatTestTupleField 406 NumberFormatTestTuple::getFieldByName( 407 const UnicodeString &name) { 408 CharString buffer; 409 UErrorCode status = U_ZERO_ERROR; 410 buffer.appendInvariantChars(name, status); 411 if (U_FAILURE(status)) { 412 return kNumberFormatTestTupleFieldCount; 413 } 414 int32_t result = -1; 415 for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) { 416 if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) { 417 result = i; 418 break; 419 } 420 } 421 if (result == -1) { 422 return kNumberFormatTestTupleFieldCount; 423 } 424 return (ENumberFormatTestTupleField) result; 425 } 426 427 const void * 428 NumberFormatTestTuple::getFieldAddress(int32_t fieldId) const { 429 return reinterpret_cast<const char *>(this) + gFieldData[fieldId].offset; 430 } 431 432 void * 433 NumberFormatTestTuple::getMutableFieldAddress(int32_t fieldId) { 434 return reinterpret_cast<char *>(this) + gFieldData[fieldId].offset; 435 } 436 437 void 438 NumberFormatTestTuple::setFlag(int32_t fieldId, UBool value) { 439 void *flagAddr = reinterpret_cast<char *>(this) + gFieldData[fieldId].flagOffset; 440 *static_cast<UBool *>(flagAddr) = value; 441 } 442 443 UBool 444 NumberFormatTestTuple::isFlag(int32_t fieldId) const { 445 const void *flagAddr = reinterpret_cast<const char *>(this) + gFieldData[fieldId].flagOffset; 446 return *static_cast<const UBool *>(flagAddr); 447 } 448 449 #endif /* !UCONFIG_NO_FORMATTING */ 450