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