udbgutil.cpp (25157B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * COPYRIGHT: 5 * Copyright (c) 2007-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ********************************************************************/ 8 9 #include "udbgutil.h" 10 #include <string.h> 11 #include "ustr_imp.h" 12 #include "cmemory.h" 13 #include "cstring.h" 14 #include "putilimp.h" 15 #include "unicode/ulocdata.h" 16 #include "unicode/ucnv.h" 17 #include "unicode/unistr.h" 18 #include "cstr.h" 19 #include "mutex.h" 20 #include "umutex.h" 21 22 /* 23 To add a new enum type 24 (For example: UShoeSize with values USHOE_WIDE=0, USHOE_REGULAR, USHOE_NARROW, USHOE_COUNT) 25 26 0. Make sure that all lines you add are protected with appropriate uconfig guards, 27 such as '#if !UCONFIG_NO_SHOES'. 28 1. udbgutil.h: add UDBG_UShoeSize to the UDebugEnumType enum before UDBG_ENUM_COUNT 29 ( The subsequent steps involve this file, udbgutil.cpp ) 30 2. Find the marker "Add new enum types above this line" 31 3. Before that marker, add a #include of any header file you need. 32 4. Each enum type has three things in this section: a #define, a count_, and an array of Fields. 33 It may help to copy and paste a previous definition. 34 5. In the case of the USHOE_... strings above, "USHOE_" is common to all values- six characters 35 " #define LEN_USHOE 6 " 36 6 characters will strip off "USHOE_" leaving enum values of WIDE, REGULAR, and NARROW. 37 6. Define the 'count_' variable, with the number of enum values. If the enum has a _MAX or _COUNT value, 38 that can be helpful for automatically defining the count. Otherwise define it manually. 39 " static const int32_t count_UShoeSize = USHOE_COUNT; " 40 7. Define the field names, in order. 41 " static const Field names_UShoeSize[] = { 42 " FIELD_NAME_STR( LEN_USHOE, USHOE_WIDE ), 43 " FIELD_NAME_STR( LEN_USHOE, USHOE_REGULAR ), 44 " FIELD_NAME_STR( LEN_USHOE, USHOE_NARROW ), 45 " }; 46 ( The following command was usedfor converting ucol.h into partially correct entities ) 47 grep "^[ ]*UCOL" < unicode/ucol.h | 48 sed -e 's%^[ ]*\([A-Z]*\)_\([A-Z_]*\).*% FIELD_NAME_STR( LEN_\1, \1_\2 ),%g' 49 8. Now, a bit farther down, add the name of the enum itself to the end of names_UDebugEnumType 50 ( UDebugEnumType is an enum, too!) 51 names_UDebugEnumType[] { ... 52 " FIELD_NAME_STR( LEN_UDBG, UDBG_UShoeSize ), " 53 9. Find the function _udbg_enumCount and add the count macro: 54 " COUNT_CASE(UShoeSize) 55 10. Find the function _udbg_enumFields and add the field macro: 56 " FIELD_CASE(UShoeSize) 57 11. verify that your test code, and Java data generation, works properly. 58 */ 59 60 /** 61 * Structure representing an enum value 62 */ 63 struct Field { 64 int32_t prefix; /**< how many characters to remove in the prefix - i.e. UCHAR_ = 5 */ 65 const char *str; /**< The actual string value */ 66 int32_t num; /**< The numeric value */ 67 }; 68 69 /** 70 * Define another field name. Used in an array of Field s 71 * @param y the common prefix length (i.e. 6 for "USHOE_" ) 72 * @param x the actual enum value - it will be copied in both string and symbolic form. 73 * @see Field 74 */ 75 #define FIELD_NAME_STR(y,x) { y, #x, x } 76 77 78 // TODO: Currently, this whole functionality goes away with UCONFIG_NO_FORMATTING. Should be split up. 79 #if !UCONFIG_NO_FORMATTING 80 81 // Calendar 82 #include "unicode/ucal.h" 83 84 // 'UCAL_' = 5 85 #define LEN_UCAL 5 /* UCAL_ */ 86 static const int32_t count_UCalendarDateFields = UCAL_FIELD_COUNT; 87 static const Field names_UCalendarDateFields[] = 88 { 89 FIELD_NAME_STR( LEN_UCAL, UCAL_ERA ), 90 FIELD_NAME_STR( LEN_UCAL, UCAL_YEAR ), 91 FIELD_NAME_STR( LEN_UCAL, UCAL_MONTH ), 92 FIELD_NAME_STR( LEN_UCAL, UCAL_WEEK_OF_YEAR ), 93 FIELD_NAME_STR( LEN_UCAL, UCAL_WEEK_OF_MONTH ), 94 FIELD_NAME_STR( LEN_UCAL, UCAL_DATE ), 95 FIELD_NAME_STR( LEN_UCAL, UCAL_DAY_OF_YEAR ), 96 FIELD_NAME_STR( LEN_UCAL, UCAL_DAY_OF_WEEK ), 97 FIELD_NAME_STR( LEN_UCAL, UCAL_DAY_OF_WEEK_IN_MONTH ), 98 FIELD_NAME_STR( LEN_UCAL, UCAL_AM_PM ), 99 FIELD_NAME_STR( LEN_UCAL, UCAL_HOUR ), 100 FIELD_NAME_STR( LEN_UCAL, UCAL_HOUR_OF_DAY ), 101 FIELD_NAME_STR( LEN_UCAL, UCAL_MINUTE ), 102 FIELD_NAME_STR( LEN_UCAL, UCAL_SECOND ), 103 FIELD_NAME_STR( LEN_UCAL, UCAL_MILLISECOND ), 104 FIELD_NAME_STR( LEN_UCAL, UCAL_ZONE_OFFSET ), 105 FIELD_NAME_STR( LEN_UCAL, UCAL_DST_OFFSET ), 106 FIELD_NAME_STR( LEN_UCAL, UCAL_YEAR_WOY ), 107 FIELD_NAME_STR( LEN_UCAL, UCAL_DOW_LOCAL ), 108 FIELD_NAME_STR( LEN_UCAL, UCAL_EXTENDED_YEAR ), 109 FIELD_NAME_STR( LEN_UCAL, UCAL_JULIAN_DAY ), 110 FIELD_NAME_STR( LEN_UCAL, UCAL_MILLISECONDS_IN_DAY ), 111 FIELD_NAME_STR( LEN_UCAL, UCAL_IS_LEAP_MONTH ), 112 FIELD_NAME_STR( LEN_UCAL, UCAL_ORDINAL_MONTH ), 113 }; 114 115 116 static const int32_t count_UCalendarMonths = UCAL_UNDECIMBER+1; 117 static const Field names_UCalendarMonths[] = 118 { 119 FIELD_NAME_STR( LEN_UCAL, UCAL_JANUARY ), 120 FIELD_NAME_STR( LEN_UCAL, UCAL_FEBRUARY ), 121 FIELD_NAME_STR( LEN_UCAL, UCAL_MARCH ), 122 FIELD_NAME_STR( LEN_UCAL, UCAL_APRIL ), 123 FIELD_NAME_STR( LEN_UCAL, UCAL_MAY ), 124 FIELD_NAME_STR( LEN_UCAL, UCAL_JUNE ), 125 FIELD_NAME_STR( LEN_UCAL, UCAL_JULY ), 126 FIELD_NAME_STR( LEN_UCAL, UCAL_AUGUST ), 127 FIELD_NAME_STR( LEN_UCAL, UCAL_SEPTEMBER ), 128 FIELD_NAME_STR( LEN_UCAL, UCAL_OCTOBER ), 129 FIELD_NAME_STR( LEN_UCAL, UCAL_NOVEMBER ), 130 FIELD_NAME_STR( LEN_UCAL, UCAL_DECEMBER ), 131 FIELD_NAME_STR( LEN_UCAL, UCAL_UNDECIMBER) 132 }; 133 134 #include "unicode/udat.h" 135 136 #define LEN_UDAT 5 /* "UDAT_" */ 137 static const int32_t count_UDateFormatStyle = UDAT_SHORT+1; 138 static const Field names_UDateFormatStyle[] = 139 { 140 FIELD_NAME_STR( LEN_UDAT, UDAT_FULL ), 141 FIELD_NAME_STR( LEN_UDAT, UDAT_LONG ), 142 FIELD_NAME_STR( LEN_UDAT, UDAT_MEDIUM ), 143 FIELD_NAME_STR( LEN_UDAT, UDAT_SHORT ), 144 /* end regular */ 145 /* 146 * negative enums.. leave out for now. 147 FIELD_NAME_STR( LEN_UDAT, UDAT_NONE ), 148 FIELD_NAME_STR( LEN_UDAT, UDAT_PATTERN ), 149 */ 150 }; 151 152 #endif 153 154 #include "unicode/uloc.h" 155 156 #define LEN_UAR 12 /* "ULOC_ACCEPT_" */ 157 static const int32_t count_UAcceptResult = 3; 158 static const Field names_UAcceptResult[] = 159 { 160 FIELD_NAME_STR( LEN_UAR, ULOC_ACCEPT_FAILED ), 161 FIELD_NAME_STR( LEN_UAR, ULOC_ACCEPT_VALID ), 162 FIELD_NAME_STR( LEN_UAR, ULOC_ACCEPT_FALLBACK ), 163 }; 164 165 #if !UCONFIG_NO_COLLATION 166 #include "unicode/ucol.h" 167 #define LEN_UCOL 5 /* UCOL_ */ 168 static const int32_t count_UColAttributeValue = UCOL_ATTRIBUTE_VALUE_COUNT; 169 static const Field names_UColAttributeValue[] = { 170 FIELD_NAME_STR( LEN_UCOL, UCOL_PRIMARY ), 171 FIELD_NAME_STR( LEN_UCOL, UCOL_SECONDARY ), 172 FIELD_NAME_STR( LEN_UCOL, UCOL_TERTIARY ), 173 // FIELD_NAME_STR( LEN_UCOL, UCOL_CE_STRENGTH_LIMIT ), 174 FIELD_NAME_STR( LEN_UCOL, UCOL_QUATERNARY ), 175 // gap 176 FIELD_NAME_STR( LEN_UCOL, UCOL_IDENTICAL ), 177 // FIELD_NAME_STR( LEN_UCOL, UCOL_STRENGTH_LIMIT ), 178 FIELD_NAME_STR( LEN_UCOL, UCOL_OFF ), 179 FIELD_NAME_STR( LEN_UCOL, UCOL_ON ), 180 // gap 181 FIELD_NAME_STR( LEN_UCOL, UCOL_SHIFTED ), 182 FIELD_NAME_STR( LEN_UCOL, UCOL_NON_IGNORABLE ), 183 // gap 184 FIELD_NAME_STR( LEN_UCOL, UCOL_LOWER_FIRST ), 185 FIELD_NAME_STR( LEN_UCOL, UCOL_UPPER_FIRST ), 186 }; 187 188 #endif 189 190 191 #if UCONFIG_ENABLE_PLUGINS 192 #include "unicode/icuplug.h" 193 194 #define LEN_UPLUG_REASON 13 /* UPLUG_REASON_ */ 195 static const int32_t count_UPlugReason = UPLUG_REASON_COUNT; 196 static const Field names_UPlugReason[] = { 197 FIELD_NAME_STR( LEN_UPLUG_REASON, UPLUG_REASON_QUERY ), 198 FIELD_NAME_STR( LEN_UPLUG_REASON, UPLUG_REASON_LOAD ), 199 FIELD_NAME_STR( LEN_UPLUG_REASON, UPLUG_REASON_UNLOAD ), 200 }; 201 202 #define LEN_UPLUG_LEVEL 12 /* UPLUG_LEVEL_ */ 203 static const int32_t count_UPlugLevel = UPLUG_LEVEL_COUNT; 204 static const Field names_UPlugLevel[] = { 205 FIELD_NAME_STR( LEN_UPLUG_LEVEL, UPLUG_LEVEL_INVALID ), 206 FIELD_NAME_STR( LEN_UPLUG_LEVEL, UPLUG_LEVEL_UNKNOWN ), 207 FIELD_NAME_STR( LEN_UPLUG_LEVEL, UPLUG_LEVEL_LOW ), 208 FIELD_NAME_STR( LEN_UPLUG_LEVEL, UPLUG_LEVEL_HIGH ), 209 }; 210 #endif 211 212 #define LEN_UDBG 5 /* "UDBG_" */ 213 static const int32_t count_UDebugEnumType = UDBG_ENUM_COUNT; 214 static const Field names_UDebugEnumType[] = 215 { 216 FIELD_NAME_STR( LEN_UDBG, UDBG_UDebugEnumType ), 217 #if !UCONFIG_NO_FORMATTING 218 FIELD_NAME_STR( LEN_UDBG, UDBG_UCalendarDateFields ), 219 FIELD_NAME_STR( LEN_UDBG, UDBG_UCalendarMonths ), 220 FIELD_NAME_STR( LEN_UDBG, UDBG_UDateFormatStyle ), 221 #endif 222 #if UCONFIG_ENABLE_PLUGINS 223 FIELD_NAME_STR( LEN_UDBG, UDBG_UPlugReason ), 224 FIELD_NAME_STR( LEN_UDBG, UDBG_UPlugLevel ), 225 #endif 226 FIELD_NAME_STR( LEN_UDBG, UDBG_UAcceptResult ), 227 #if !UCONFIG_NO_COLLATION 228 FIELD_NAME_STR( LEN_UDBG, UDBG_UColAttributeValue ), 229 #endif 230 }; 231 232 233 // --- Add new enum types above this line --- 234 235 #define COUNT_CASE(x) case UDBG_##x: return (actual?count_##x:UPRV_LENGTHOF(names_##x)); 236 #define COUNT_FAIL_CASE(x) case UDBG_##x: return -1; 237 238 #define FIELD_CASE(x) case UDBG_##x: return names_##x; 239 #define FIELD_FAIL_CASE(x) case UDBG_##x: return nullptr; 240 241 // low level 242 243 /** 244 * @param type type of item 245 * @param actual true: for the actual enum's type (UCAL_FIELD_COUNT, etc), or false for the string count 246 */ 247 static int32_t _udbg_enumCount(UDebugEnumType type, UBool actual) { 248 switch(type) { 249 COUNT_CASE(UDebugEnumType) 250 #if !UCONFIG_NO_FORMATTING 251 COUNT_CASE(UCalendarDateFields) 252 COUNT_CASE(UCalendarMonths) 253 COUNT_CASE(UDateFormatStyle) 254 #endif 255 #if UCONFIG_ENABLE_PLUGINS 256 COUNT_CASE(UPlugReason) 257 COUNT_CASE(UPlugLevel) 258 #endif 259 COUNT_CASE(UAcceptResult) 260 #if !UCONFIG_NO_COLLATION 261 COUNT_CASE(UColAttributeValue) 262 #endif 263 // COUNT_FAIL_CASE(UNonExistentEnum) 264 default: 265 return -1; 266 } 267 } 268 269 static const Field* _udbg_enumFields(UDebugEnumType type) { 270 switch(type) { 271 FIELD_CASE(UDebugEnumType) 272 #if !UCONFIG_NO_FORMATTING 273 FIELD_CASE(UCalendarDateFields) 274 FIELD_CASE(UCalendarMonths) 275 FIELD_CASE(UDateFormatStyle) 276 #endif 277 #if UCONFIG_ENABLE_PLUGINS 278 FIELD_CASE(UPlugReason) 279 FIELD_CASE(UPlugLevel) 280 #endif 281 FIELD_CASE(UAcceptResult) 282 // FIELD_FAIL_CASE(UNonExistentEnum) 283 #if !UCONFIG_NO_COLLATION 284 FIELD_CASE(UColAttributeValue) 285 #endif 286 default: 287 return nullptr; 288 } 289 } 290 291 // implementation 292 293 int32_t udbg_enumCount(UDebugEnumType type) { 294 return _udbg_enumCount(type, false); 295 } 296 297 int32_t udbg_enumExpectedCount(UDebugEnumType type) { 298 return _udbg_enumCount(type, true); 299 } 300 301 const char * udbg_enumName(UDebugEnumType type, int32_t field) { 302 if(field<0 || 303 field>=_udbg_enumCount(type,false)) { // also will catch unsupported items 304 return nullptr; 305 } else { 306 const Field *fields = _udbg_enumFields(type); 307 if(fields == nullptr) { 308 return nullptr; 309 } else { 310 return fields[field].str + fields[field].prefix; 311 } 312 } 313 } 314 315 int32_t udbg_enumArrayValue(UDebugEnumType type, int32_t field) { 316 if(field<0 || 317 field>=_udbg_enumCount(type,false)) { // also will catch unsupported items 318 return -1; 319 } else { 320 const Field *fields = _udbg_enumFields(type); 321 if(fields == nullptr) { 322 return -1; 323 } else { 324 return fields[field].num; 325 } 326 } 327 } 328 329 int32_t udbg_enumByName(UDebugEnumType type, const char *value) { 330 if(type<0||type>=_udbg_enumCount(UDBG_UDebugEnumType, true)) { 331 return -1; // type out of range 332 } 333 const Field *fields = _udbg_enumFields(type); 334 if (fields != nullptr) { 335 for(int32_t field = 0;field<_udbg_enumCount(type, false);field++) { 336 if(!strcmp(value, fields[field].str + fields[field].prefix)) { 337 return fields[field].num; 338 } 339 } 340 // try with the prefix 341 for(int32_t field = 0;field<_udbg_enumCount(type, false);field++) { 342 if(!strcmp(value, fields[field].str)) { 343 return fields[field].num; 344 } 345 } 346 } 347 // fail 348 return -1; 349 } 350 351 /* platform info */ 352 /** 353 * Print the current platform 354 */ 355 U_CAPI const char *udbg_getPlatform() 356 { 357 #if U_PLATFORM_USES_ONLY_WIN32_API 358 return "Windows"; 359 #elif U_PLATFORM == U_PF_CYGWIN 360 return "Cygwin"; 361 #elif U_PLATFORM == U_PF_UNKNOWN 362 return "unknown"; 363 #elif U_PLATFORM == U_PF_DARWIN 364 return "Darwin"; 365 #elif U_PLATFORM == U_PF_BSD 366 return "BSD"; 367 #elif U_PLATFORM == U_PF_QNX 368 return "QNX"; 369 #elif U_PLATFORM == U_PF_LINUX 370 return "Linux"; 371 #elif U_PLATFORM == U_PF_ANDROID 372 return "Android"; 373 #elif U_PLATFORM == U_PF_CLASSIC_MACOS 374 return "MacOS (Classic)"; 375 #elif U_PLATFORM == U_PF_OS390 376 return "IBM z"; 377 #elif U_PLATFORM == U_PF_OS400 378 return "IBM i"; 379 #else 380 return "Other (POSIX-like)"; 381 #endif 382 } 383 384 struct USystemParams; 385 386 typedef int32_t U_CALLCONV USystemParameterCallback(const USystemParams *param, char *target, int32_t targetCapacity, UErrorCode *status); 387 388 struct USystemParams { 389 const char *paramName; 390 USystemParameterCallback *paramFunction; 391 const char *paramStr; 392 int32_t paramInt; 393 }; 394 395 /* parameter types */ 396 U_CAPI int32_t 397 paramEmpty(const USystemParams * /* param */, char *target, int32_t targetCapacity, UErrorCode *status) { 398 if(U_FAILURE(*status))return 0; 399 return u_terminateChars(target, targetCapacity, 0, status); 400 } 401 402 U_CAPI int32_t 403 paramStatic(const USystemParams *param, char *target, int32_t targetCapacity, UErrorCode *status) { 404 if(param->paramStr==nullptr) return paramEmpty(param,target,targetCapacity,status); 405 if(U_FAILURE(*status))return 0; 406 int32_t len = static_cast<int32_t>(uprv_strlen(param->paramStr)); 407 if(target!=nullptr) { 408 uprv_strncpy(target,param->paramStr,uprv_min(len,targetCapacity)); 409 } 410 return u_terminateChars(target, targetCapacity, len, status); 411 } 412 413 static const char *nullString = "(null)"; 414 415 static int32_t stringToStringBuffer(char *target, int32_t targetCapacity, const char *str, UErrorCode *status) { 416 if(str==nullptr) str=nullString; 417 418 int32_t len = static_cast<int32_t>(uprv_strlen(str)); 419 if (U_SUCCESS(*status)) { 420 if(target!=nullptr) { 421 uprv_strncpy(target,str,uprv_min(len,targetCapacity)); 422 } 423 } else { 424 const char *s = u_errorName(*status); 425 len = static_cast<int32_t>(uprv_strlen(s)); 426 if(target!=nullptr) { 427 uprv_strncpy(target,s,uprv_min(len,targetCapacity)); 428 } 429 } 430 return u_terminateChars(target, targetCapacity, len, status); 431 } 432 433 static int32_t integerToStringBuffer(char *target, int32_t targetCapacity, int32_t n, int32_t radix, UErrorCode *status) { 434 if(U_FAILURE(*status)) return 0; 435 char str[300]; 436 T_CString_integerToString(str,n,radix); 437 return stringToStringBuffer(target,targetCapacity,str,status); 438 } 439 440 U_CAPI int32_t 441 paramInteger(const USystemParams *param, char *target, int32_t targetCapacity, UErrorCode *status) { 442 if(U_FAILURE(*status))return 0; 443 if(param->paramStr==nullptr || param->paramStr[0]=='d') { 444 return integerToStringBuffer(target,targetCapacity,param->paramInt, 10,status); 445 } else if(param->paramStr[0]=='x') { 446 return integerToStringBuffer(target,targetCapacity,param->paramInt, 16,status); 447 } else if(param->paramStr[0]=='o') { 448 return integerToStringBuffer(target,targetCapacity,param->paramInt, 8,status); 449 } else if(param->paramStr[0]=='b') { 450 return integerToStringBuffer(target,targetCapacity,param->paramInt, 2,status); 451 } else { 452 *status = U_INTERNAL_PROGRAM_ERROR; 453 return 0; 454 } 455 } 456 457 458 U_CAPI int32_t 459 paramCldrVersion(const USystemParams * /* param */, char *target, int32_t targetCapacity, UErrorCode *status) { 460 if(U_FAILURE(*status))return 0; 461 char str[200]=""; 462 UVersionInfo icu; 463 464 ulocdata_getCLDRVersion(icu, status); 465 if(U_SUCCESS(*status)) { 466 u_versionToString(icu, str); 467 return stringToStringBuffer(target,targetCapacity,str,status); 468 } else { 469 return 0; 470 } 471 } 472 473 474 #if !UCONFIG_NO_FORMATTING 475 U_CAPI int32_t 476 paramTimezoneDefault(const USystemParams * /* param */, char *target, int32_t targetCapacity, UErrorCode *status) { 477 if(U_FAILURE(*status))return 0; 478 char16_t buf[100]; 479 char buf2[100]; 480 int32_t len; 481 482 len = ucal_getDefaultTimeZone(buf, 100, status); 483 if(U_SUCCESS(*status)&&len>0) { 484 u_UCharsToChars(buf, buf2, len+1); 485 return stringToStringBuffer(target,targetCapacity, buf2,status); 486 } else { 487 return 0; 488 } 489 } 490 #endif 491 492 U_CAPI int32_t 493 paramLocaleDefaultBcp47(const USystemParams * /* param */, char *target, int32_t targetCapacity, UErrorCode *status) { 494 if(U_FAILURE(*status))return 0; 495 const char *def = uloc_getDefault(); 496 return uloc_toLanguageTag(def,target,targetCapacity,false,status); 497 } 498 499 500 /* simple 1-liner param functions */ 501 #define STRING_PARAM(func, str) U_CAPI int32_t \ 502 func(const USystemParams *, char *target, int32_t targetCapacity, UErrorCode *status) \ 503 { return stringToStringBuffer(target,targetCapacity,(str),status); } 504 505 STRING_PARAM(paramIcudataPath, u_getDataDirectory()) 506 STRING_PARAM(paramPlatform, udbg_getPlatform()) 507 STRING_PARAM(paramLocaleDefault, uloc_getDefault()) 508 #if !UCONFIG_NO_CONVERSION 509 STRING_PARAM(paramConverterDefault, ucnv_getDefaultName()) 510 #endif 511 512 #if !UCONFIG_NO_FORMATTING 513 STRING_PARAM(paramTimezoneVersion, ucal_getTZDataVersion(status)) 514 #endif 515 516 static const USystemParams systemParams[] = { 517 { "copyright", paramStatic, U_COPYRIGHT_STRING,0 }, 518 { "product", paramStatic, "icu4c",0 }, 519 { "product.full", paramStatic, "International Components for Unicode for C/C++",0 }, 520 { "version", paramStatic, U_ICU_VERSION,0 }, 521 { "version.unicode", paramStatic, U_UNICODE_VERSION,0 }, 522 { "platform.number", paramInteger, "d",U_PLATFORM}, 523 { "platform.type", paramPlatform, nullptr ,0}, 524 { "locale.default", paramLocaleDefault, nullptr, 0}, 525 { "locale.default.bcp47", paramLocaleDefaultBcp47, nullptr, 0}, 526 #if !UCONFIG_NO_CONVERSION 527 { "converter.default", paramConverterDefault, nullptr, 0}, 528 #endif 529 { "icudata.name", paramStatic, U_ICUDATA_NAME, 0}, 530 { "icudata.path", paramIcudataPath, nullptr, 0}, 531 532 { "cldr.version", paramCldrVersion, nullptr, 0}, 533 534 #if !UCONFIG_NO_FORMATTING 535 { "tz.version", paramTimezoneVersion, nullptr, 0}, 536 { "tz.default", paramTimezoneDefault, nullptr, 0}, 537 #endif 538 539 { "cpu.bits", paramInteger, "d", (sizeof(void*))*8}, 540 { "cpu.big_endian", paramInteger, "b", U_IS_BIG_ENDIAN}, 541 { "os.wchar_width", paramInteger, "d", U_SIZEOF_WCHAR_T}, 542 { "os.charset_family", paramInteger, "d", U_CHARSET_FAMILY}, 543 #if defined (U_HOST) 544 { "os.host", paramStatic, U_HOST, 0}, 545 #endif 546 #if defined (U_BUILD) 547 { "build.build", paramStatic, U_BUILD, 0}, 548 #endif 549 #if defined (U_CC) 550 { "build.cc", paramStatic, U_CC, 0}, 551 #endif 552 #if defined (U_CXX) 553 { "build.cxx", paramStatic, U_CXX, 0}, 554 #endif 555 #if defined (CYGWINMSVC) 556 { "build.cygwinmsvc", paramInteger, "b", 1}, 557 #endif 558 { "uconfig.internal_digitlist", paramInteger, "b", 1}, /* always 1 */ 559 { "uconfig.have_parseallinput", paramInteger, "b", UCONFIG_HAVE_PARSEALLINPUT}, 560 561 562 }; 563 564 #define U_SYSPARAM_COUNT UPRV_LENGTHOF(systemParams) 565 566 U_CAPI const char *udbg_getSystemParameterNameByIndex(int32_t i) { 567 if (i >= 0 && i < U_SYSPARAM_COUNT) { 568 return systemParams[i].paramName; 569 } else { 570 return nullptr; 571 } 572 } 573 574 575 U_CAPI int32_t udbg_getSystemParameterValueByIndex(int32_t i, char *buffer, int32_t bufferCapacity, UErrorCode *status) { 576 if (i >= 0 && i < U_SYSPARAM_COUNT) { 577 return systemParams[i].paramFunction(&(systemParams[i]),buffer,bufferCapacity,status); 578 } else { 579 return 0; 580 } 581 } 582 583 U_CAPI void udbg_writeIcuInfo(FILE *out) { 584 char str[2000]; 585 /* todo: API for writing DTD? */ 586 fprintf(out, " <icuSystemParams type=\"icu4c\">\n"); 587 const char *paramName; 588 for(int32_t i=0;(paramName=udbg_getSystemParameterNameByIndex(i))!=nullptr;i++) { 589 UErrorCode status2 = U_ZERO_ERROR; 590 udbg_getSystemParameterValueByIndex(i, str,2000,&status2); 591 if(U_SUCCESS(status2)) { 592 fprintf(out," <param name=\"%s\">%s</param>\n", paramName,str); 593 } else { 594 fprintf(out," <!-- n=\"%s\" ERROR: %s -->\n", paramName, u_errorName(status2)); 595 } 596 } 597 fprintf(out, " </icuSystemParams>\n"); 598 } 599 600 #define UNICODE_BUG_URL "https://unicode-org.atlassian.net/browse/" 601 #define OLD_CLDR_PREFIX "cldrbug:" 602 #define CLDR_BUG_PREFIX "CLDR-" 603 #define ICU_BUG_PREFIX "ICU-" 604 605 606 607 #include <set> 608 #include <map> 609 #include <string> 610 #include <ostream> 611 #include <iostream> 612 613 static icu::UMutex gKnownIssuesLock; 614 615 class KnownIssues { 616 public: 617 KnownIssues(); 618 ~KnownIssues(); 619 void add(const char *ticket, const char *where, const char16_t *msg, UBool *firstForTicket, UBool *firstForWhere); 620 void add(const char *ticket, const char *where, const char *msg, UBool *firstForTicket, UBool *firstForWhere); 621 UBool print(); 622 private: 623 std::map< std::string, 624 std::map < std::string, std::set < std::string > > > fTable; 625 }; 626 627 KnownIssues::KnownIssues() 628 : fTable() 629 { 630 } 631 632 KnownIssues::~KnownIssues() 633 { 634 } 635 636 /** 637 * Map cldr:1234 to CLDR-1234 638 * Map 1234 to ICU-1234 639 */ 640 static std::string mapTicketId(const char *ticketStr) { 641 std::string ticket(ticketStr); 642 // TODO: Can remove this function once all logKnownIssue calls are switched over 643 // to the ICU-1234 and CLDR-1234 format. 644 if(ticket.rfind(OLD_CLDR_PREFIX) == 0) { 645 // map cldrbug:1234 to CLDR-1234 646 ticket.replace(0, uprv_strlen(OLD_CLDR_PREFIX), CLDR_BUG_PREFIX); 647 } else if(::isdigit(ticket[0])) { 648 // map 1234 to ICU-1234 649 ticket.insert(0, ICU_BUG_PREFIX); 650 } 651 return ticket; 652 } 653 654 void KnownIssues::add(const char *ticketStr, const char *where, const char16_t *msg, UBool *firstForTicket, UBool *firstForWhere) 655 { 656 const std::string ticket = mapTicketId(ticketStr); 657 icu::Mutex mutex(&gKnownIssuesLock); 658 if(fTable.find(ticket) == fTable.end()) { 659 if(firstForTicket!=nullptr) *firstForTicket = true; 660 fTable[ticket] = std::map < std::string, std::set < std::string > >(); 661 } else { 662 if(firstForTicket!=nullptr) *firstForTicket = false; 663 } 664 if(where==nullptr) return; 665 666 if(fTable[ticket].find(where) == fTable[ticket].end()) { 667 if(firstForWhere!=nullptr) *firstForWhere = true; 668 fTable[ticket][where] = std::set < std::string >(); 669 } else { 670 if(firstForWhere!=nullptr) *firstForWhere = false; 671 } 672 if(msg==nullptr || !*msg) return; 673 674 const icu::UnicodeString ustr(msg); 675 676 fTable[ticket][where].insert(std::string(icu::CStr(ustr)())); 677 } 678 679 void KnownIssues::add(const char *ticketStr, const char *where, const char *msg, UBool *firstForTicket, UBool *firstForWhere) 680 { 681 const std::string ticket = mapTicketId(ticketStr); 682 icu::Mutex mutex(&gKnownIssuesLock); 683 if(fTable.find(ticket) == fTable.end()) { 684 if(firstForTicket!=nullptr) *firstForTicket = true; 685 fTable[ticket] = std::map < std::string, std::set < std::string > >(); 686 } else { 687 if(firstForTicket!=nullptr) *firstForTicket = false; 688 } 689 if(where==nullptr) return; 690 691 if(fTable[ticket].find(where) == fTable[ticket].end()) { 692 if(firstForWhere!=nullptr) *firstForWhere = true; 693 fTable[ticket][where] = std::set < std::string >(); 694 } else { 695 if(firstForWhere!=nullptr) *firstForWhere = false; 696 } 697 if(msg==nullptr || !*msg) return; 698 699 std::string str(msg); 700 fTable[ticket][where].insert(str); 701 } 702 703 UBool KnownIssues::print() 704 { 705 icu::Mutex mutex(&gKnownIssuesLock); 706 if(fTable.empty()) { 707 return false; 708 } 709 710 std::cout << "KNOWN ISSUES" << std::endl; 711 for( std::map< std::string, 712 std::map < std::string, std::set < std::string > > >::iterator i = fTable.begin(); 713 i != fTable.end(); 714 i++ ) { 715 const std::string ticketid = (*i).first; 716 std::cout << "[" << ticketid << "] "; 717 if(ticketid.rfind(ICU_BUG_PREFIX) == 0 || ticketid.rfind(CLDR_BUG_PREFIX) == 0) { 718 // If it's a unicode.org bug. 719 std::cout << UNICODE_BUG_URL << ticketid; 720 } // Else: some other kind of bug. Allow this, but without a URL. 721 std::cout << std::endl; 722 723 for( std::map< std::string, std::set < std::string > >::iterator ii = (*i).second.begin(); 724 ii != (*i).second.end(); 725 ii++ ) { 726 std::cout << " " << (*ii).first << std::endl; 727 for ( std::set < std::string >::iterator iii = (*ii).second.begin(); 728 iii != (*ii).second.end(); 729 iii++ ) { 730 std::cout << " " << '"' << (*iii) << '"' << std::endl; 731 } 732 } 733 } 734 return true; 735 } 736 737 U_CAPI void *udbg_knownIssue_openU(void *ptr, const char *ticket, char *where, const char16_t *msg, UBool *firstForTicket, 738 UBool *firstForWhere) { 739 KnownIssues *t = static_cast<KnownIssues*>(ptr); 740 if(t==nullptr) { 741 t = new KnownIssues(); 742 } 743 744 t->add(ticket, where, msg, firstForTicket, firstForWhere); 745 746 return static_cast<void*>(t); 747 } 748 749 U_CAPI void *udbg_knownIssue_open(void *ptr, const char *ticket, char *where, const char *msg, UBool *firstForTicket, 750 UBool *firstForWhere) { 751 KnownIssues *t = static_cast<KnownIssues*>(ptr); 752 if(t==nullptr) { 753 t = new KnownIssues(); 754 } 755 756 t->add(ticket, where, msg, firstForTicket, firstForWhere); 757 758 return static_cast<void*>(t); 759 } 760 761 U_CAPI UBool udbg_knownIssue_print(void *ptr) { 762 KnownIssues *t = static_cast<KnownIssues*>(ptr); 763 if(t==nullptr) { 764 return false; 765 } else { 766 t->print(); 767 return true; 768 } 769 } 770 771 U_CAPI void udbg_knownIssue_close(void *ptr) { 772 KnownIssues *t = static_cast<KnownIssues*>(ptr); 773 delete t; 774 }