| 1 | // © 2016 and later: Unicode, Inc. and others. | 
|---|
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | 
|---|
| 3 | /* | 
|---|
| 4 | ******************************************************************************* | 
|---|
| 5 | *   Copyright (C) 2003-2014, International Business Machines | 
|---|
| 6 | *   Corporation and others.  All Rights Reserved. | 
|---|
| 7 | ******************************************************************************* | 
|---|
| 8 | *   file name:  utrace.c | 
|---|
| 9 | *   encoding:   UTF-8 | 
|---|
| 10 | *   tab size:   8 (not used) | 
|---|
| 11 | *   indentation:4 | 
|---|
| 12 | */ | 
|---|
| 13 |  | 
|---|
| 14 | #include "unicode/utrace.h" | 
|---|
| 15 | #include "utracimp.h" | 
|---|
| 16 | #include "cstring.h" | 
|---|
| 17 | #include "uassert.h" | 
|---|
| 18 | #include "ucln_cmn.h" | 
|---|
| 19 |  | 
|---|
| 20 |  | 
|---|
| 21 | static UTraceEntry     *pTraceEntryFunc = NULL; | 
|---|
| 22 | static UTraceExit      *pTraceExitFunc  = NULL; | 
|---|
| 23 | static UTraceData      *pTraceDataFunc  = NULL; | 
|---|
| 24 | static const void      *gTraceContext   = NULL; | 
|---|
| 25 |  | 
|---|
| 26 | /** | 
|---|
| 27 | * \var utrace_level | 
|---|
| 28 | * Trace level variable. Negative for "off". | 
|---|
| 29 | */ | 
|---|
| 30 | static int32_t | 
|---|
| 31 | utrace_level = UTRACE_ERROR; | 
|---|
| 32 |  | 
|---|
| 33 | U_CAPI void U_EXPORT2 | 
|---|
| 34 | utrace_entry(int32_t fnNumber) { | 
|---|
| 35 | if (pTraceEntryFunc != NULL) { | 
|---|
| 36 | (*pTraceEntryFunc)(gTraceContext, fnNumber); | 
|---|
| 37 | } | 
|---|
| 38 | } | 
|---|
| 39 |  | 
|---|
| 40 |  | 
|---|
| 41 | static const char gExitFmt[]             = "Returns."; | 
|---|
| 42 | static const char gExitFmtValue[]        = "Returns %d."; | 
|---|
| 43 | static const char gExitFmtStatus[]       = "Returns.  Status = %d."; | 
|---|
| 44 | static const char gExitFmtValueStatus[]  = "Returns %d.  Status = %d."; | 
|---|
| 45 | static const char gExitFmtPtrStatus[]    = "Returns %d.  Status = %p."; | 
|---|
| 46 |  | 
|---|
| 47 | U_CAPI void U_EXPORT2 | 
|---|
| 48 | utrace_exit(int32_t fnNumber, int32_t returnType, ...) { | 
|---|
| 49 | if (pTraceExitFunc != NULL) { | 
|---|
| 50 | va_list     args; | 
|---|
| 51 | const char *fmt; | 
|---|
| 52 |  | 
|---|
| 53 | switch (returnType) { | 
|---|
| 54 | case 0: | 
|---|
| 55 | fmt = gExitFmt; | 
|---|
| 56 | break; | 
|---|
| 57 | case UTRACE_EXITV_I32: | 
|---|
| 58 | fmt = gExitFmtValue; | 
|---|
| 59 | break; | 
|---|
| 60 | case UTRACE_EXITV_STATUS: | 
|---|
| 61 | fmt = gExitFmtStatus; | 
|---|
| 62 | break; | 
|---|
| 63 | case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS: | 
|---|
| 64 | fmt = gExitFmtValueStatus; | 
|---|
| 65 | break; | 
|---|
| 66 | case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS: | 
|---|
| 67 | fmt = gExitFmtPtrStatus; | 
|---|
| 68 | break; | 
|---|
| 69 | default: | 
|---|
| 70 | UPRV_UNREACHABLE; | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|
| 73 | va_start(args, returnType); | 
|---|
| 74 | (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args); | 
|---|
| 75 | va_end(args); | 
|---|
| 76 | } | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 |  | 
|---|
| 80 |  | 
|---|
| 81 | U_CAPI void U_EXPORT2 | 
|---|
| 82 | utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) { | 
|---|
| 83 | if (pTraceDataFunc != NULL) { | 
|---|
| 84 | va_list args; | 
|---|
| 85 | va_start(args, fmt ); | 
|---|
| 86 | (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args); | 
|---|
| 87 | va_end(args); | 
|---|
| 88 | } | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 |  | 
|---|
| 92 | static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { | 
|---|
| 93 | int32_t i; | 
|---|
| 94 | /* Check whether a start of line indenting is needed.  Three cases: | 
|---|
| 95 | *   1.  At the start of the first line  (output index == 0). | 
|---|
| 96 | *   2.  At the start of subsequent lines  (preceeding char in buffer == '\n') | 
|---|
| 97 | *   3.  When preflighting buffer len (buffer capacity is exceeded), when | 
|---|
| 98 | *       a \n is output.  Ideally we wouldn't do the indent until the following char | 
|---|
| 99 | *       is received, but that won't work because there's no place to remember that | 
|---|
| 100 | *       the preceding char was \n.  Meaning that we may overstimate the | 
|---|
| 101 | *       buffer size needed.  No harm done. | 
|---|
| 102 | */ | 
|---|
| 103 | if (*outIx==0 ||   /* case 1. */ | 
|---|
| 104 | (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') ||  /* case 2. */ | 
|---|
| 105 | (c=='\n' && *outIx>=capacity))    /* case 3 */ | 
|---|
| 106 | { | 
|---|
| 107 | /* At the start of a line.  Indent. */ | 
|---|
| 108 | for(i=0; i<indent; i++) { | 
|---|
| 109 | if (*outIx < capacity) { | 
|---|
| 110 | outBuf[*outIx] = ' '; | 
|---|
| 111 | } | 
|---|
| 112 | (*outIx)++; | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | if (*outIx < capacity) { | 
|---|
| 117 | outBuf[*outIx] = c; | 
|---|
| 118 | } | 
|---|
| 119 | if (c != 0) { | 
|---|
| 120 | /* Nulls only appear as end-of-string terminators.  Move them to the output | 
|---|
| 121 | *  buffer, but do not update the length of the buffer, so that any | 
|---|
| 122 | *  following output will overwrite the null. */ | 
|---|
| 123 | (*outIx)++; | 
|---|
| 124 | } | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | static void outputHexBytes(int64_t val, int32_t charsToOutput, | 
|---|
| 128 | char *outBuf, int32_t *outIx, int32_t capacity) { | 
|---|
| 129 | static const char gHexChars[] = "0123456789abcdef"; | 
|---|
| 130 | int32_t shiftCount; | 
|---|
| 131 | for  (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) { | 
|---|
| 132 | char c = gHexChars[(val >> shiftCount) & 0xf]; | 
|---|
| 133 | outputChar(c, outBuf, outIx, capacity, 0); | 
|---|
| 134 | } | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | /* Output a pointer value in hex.  Work with any size of pointer   */ | 
|---|
| 138 | static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) { | 
|---|
| 139 | uint32_t  i; | 
|---|
| 140 | int32_t  incVal = 1;              /* +1 for big endian, -1 for little endian          */ | 
|---|
| 141 | char     *p     = (char *)&val;   /* point to current byte to output in the ptr val  */ | 
|---|
| 142 |  | 
|---|
| 143 | #if !U_IS_BIG_ENDIAN | 
|---|
| 144 | /* Little Endian.  Move p to most significant end of the value      */ | 
|---|
| 145 | incVal = -1; | 
|---|
| 146 | p += sizeof(void *) - 1; | 
|---|
| 147 | #endif | 
|---|
| 148 |  | 
|---|
| 149 | /* Loop through the bytes of the ptr as it sits in memory, from | 
|---|
| 150 | * most significant to least significant end                    */ | 
|---|
| 151 | for (i=0; i<sizeof(void *); i++) { | 
|---|
| 152 | outputHexBytes(*p, 2, outBuf, outIx, capacity); | 
|---|
| 153 | p += incVal; | 
|---|
| 154 | } | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { | 
|---|
| 158 | int32_t i = 0; | 
|---|
| 159 | char    c; | 
|---|
| 160 | if (s==NULL) { | 
|---|
| 161 | s = "*NULL*"; | 
|---|
| 162 | } | 
|---|
| 163 | do { | 
|---|
| 164 | c = s[i++]; | 
|---|
| 165 | outputChar(c, outBuf, outIx, capacity, indent); | 
|---|
| 166 | } while (c != 0); | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 |  | 
|---|
| 170 |  | 
|---|
| 171 | static void outputUString(const UChar *s, int32_t len, | 
|---|
| 172 | char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { | 
|---|
| 173 | int32_t i = 0; | 
|---|
| 174 | UChar   c; | 
|---|
| 175 | if (s==NULL) { | 
|---|
| 176 | outputString(NULL, outBuf, outIx, capacity, indent); | 
|---|
| 177 | return; | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | for (i=0; i<len || len==-1; i++) { | 
|---|
| 181 | c = s[i]; | 
|---|
| 182 | outputHexBytes(c, 4, outBuf, outIx, capacity); | 
|---|
| 183 | outputChar(' ', outBuf, outIx, capacity, indent); | 
|---|
| 184 | if (len == -1 && c==0) { | 
|---|
| 185 | break; | 
|---|
| 186 | } | 
|---|
| 187 | } | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | U_CAPI int32_t U_EXPORT2 | 
|---|
| 191 | utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) { | 
|---|
| 192 | int32_t   outIx  = 0; | 
|---|
| 193 | int32_t   fmtIx  = 0; | 
|---|
| 194 | char      fmtC; | 
|---|
| 195 | char      c; | 
|---|
| 196 | int32_t   intArg; | 
|---|
| 197 | int64_t   longArg = 0; | 
|---|
| 198 | char      *ptrArg; | 
|---|
| 199 |  | 
|---|
| 200 | /*   Loop runs once for each character in the format string. | 
|---|
| 201 | */ | 
|---|
| 202 | for (;;) { | 
|---|
| 203 | fmtC = fmt[fmtIx++]; | 
|---|
| 204 | if (fmtC != '%') { | 
|---|
| 205 | /* Literal character, not part of a %sequence.  Just copy it to the output. */ | 
|---|
| 206 | outputChar(fmtC, outBuf, &outIx, capacity, indent); | 
|---|
| 207 | if (fmtC == 0) { | 
|---|
| 208 | /* We hit the null that terminates the format string. | 
|---|
| 209 | * This is the normal (and only) exit from the loop that | 
|---|
| 210 | * interprets the format | 
|---|
| 211 | */ | 
|---|
| 212 | break; | 
|---|
| 213 | } | 
|---|
| 214 | continue; | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | /* We encountered a '%'.  Pick up the following format char */ | 
|---|
| 218 | fmtC = fmt[fmtIx++]; | 
|---|
| 219 |  | 
|---|
| 220 | switch (fmtC) { | 
|---|
| 221 | case 'c': | 
|---|
| 222 | /* single 8 bit char   */ | 
|---|
| 223 | c = (char)va_arg(args, int32_t); | 
|---|
| 224 | outputChar(c, outBuf, &outIx, capacity, indent); | 
|---|
| 225 | break; | 
|---|
| 226 |  | 
|---|
| 227 | case 's': | 
|---|
| 228 | /* char * string, null terminated.  */ | 
|---|
| 229 | ptrArg = va_arg(args, char *); | 
|---|
| 230 | outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent); | 
|---|
| 231 | break; | 
|---|
| 232 |  | 
|---|
| 233 | case 'S': | 
|---|
| 234 | /* UChar * string, with length, len==-1 for null terminated. */ | 
|---|
| 235 | ptrArg = va_arg(args, char *);             /* Ptr    */ | 
|---|
| 236 | intArg =(int32_t)va_arg(args, int32_t);    /* Length */ | 
|---|
| 237 | outputUString((const UChar *)ptrArg, intArg, outBuf, &outIx, capacity, indent); | 
|---|
| 238 | break; | 
|---|
| 239 |  | 
|---|
| 240 | case 'b': | 
|---|
| 241 | /*  8 bit int  */ | 
|---|
| 242 | intArg = va_arg(args, int); | 
|---|
| 243 | outputHexBytes(intArg, 2, outBuf, &outIx, capacity); | 
|---|
| 244 | break; | 
|---|
| 245 |  | 
|---|
| 246 | case 'h': | 
|---|
| 247 | /*  16 bit int  */ | 
|---|
| 248 | intArg = va_arg(args, int); | 
|---|
| 249 | outputHexBytes(intArg, 4, outBuf, &outIx, capacity); | 
|---|
| 250 | break; | 
|---|
| 251 |  | 
|---|
| 252 | case 'd': | 
|---|
| 253 | /*  32 bit int  */ | 
|---|
| 254 | intArg = va_arg(args, int); | 
|---|
| 255 | outputHexBytes(intArg, 8, outBuf, &outIx, capacity); | 
|---|
| 256 | break; | 
|---|
| 257 |  | 
|---|
| 258 | case 'l': | 
|---|
| 259 | /*  64 bit long  */ | 
|---|
| 260 | longArg = va_arg(args, int64_t); | 
|---|
| 261 | outputHexBytes(longArg, 16, outBuf, &outIx, capacity); | 
|---|
| 262 | break; | 
|---|
| 263 |  | 
|---|
| 264 | case 'p': | 
|---|
| 265 | /*  Pointers.   */ | 
|---|
| 266 | ptrArg = va_arg(args, char *); | 
|---|
| 267 | outputPtrBytes(ptrArg, outBuf, &outIx, capacity); | 
|---|
| 268 | break; | 
|---|
| 269 |  | 
|---|
| 270 | case 0: | 
|---|
| 271 | /* Single '%' at end of fmt string.  Output as literal '%'. | 
|---|
| 272 | * Back up index into format string so that the terminating null will be | 
|---|
| 273 | * re-fetched in the outer loop, causing it to terminate. | 
|---|
| 274 | */ | 
|---|
| 275 | outputChar('%', outBuf, &outIx, capacity, indent); | 
|---|
| 276 | fmtIx--; | 
|---|
| 277 | break; | 
|---|
| 278 |  | 
|---|
| 279 | case 'v': | 
|---|
| 280 | { | 
|---|
| 281 | /* Vector of values, e.g. %vh */ | 
|---|
| 282 | char     vectorType; | 
|---|
| 283 | int32_t  vectorLen; | 
|---|
| 284 | const char   *i8Ptr; | 
|---|
| 285 | int16_t  *i16Ptr; | 
|---|
| 286 | int32_t  *i32Ptr; | 
|---|
| 287 | int64_t  *i64Ptr; | 
|---|
| 288 | void     **ptrPtr; | 
|---|
| 289 | int32_t   charsToOutput = 0; | 
|---|
| 290 | int32_t   i; | 
|---|
| 291 |  | 
|---|
| 292 | vectorType = fmt[fmtIx];    /* b, h, d, l, p, etc. */ | 
|---|
| 293 | if (vectorType != 0) { | 
|---|
| 294 | fmtIx++; | 
|---|
| 295 | } | 
|---|
| 296 | i8Ptr = (const char *)va_arg(args, void*); | 
|---|
| 297 | i16Ptr = (int16_t *)i8Ptr; | 
|---|
| 298 | i32Ptr = (int32_t *)i8Ptr; | 
|---|
| 299 | i64Ptr = (int64_t *)i8Ptr; | 
|---|
| 300 | ptrPtr = (void **)i8Ptr; | 
|---|
| 301 | vectorLen =(int32_t)va_arg(args, int32_t); | 
|---|
| 302 | if (ptrPtr == NULL) { | 
|---|
| 303 | outputString( "*NULL* ", outBuf, &outIx, capacity, indent); | 
|---|
| 304 | } else { | 
|---|
| 305 | for (i=0; i<vectorLen || vectorLen==-1; i++) { | 
|---|
| 306 | switch (vectorType) { | 
|---|
| 307 | case 'b': | 
|---|
| 308 | charsToOutput = 2; | 
|---|
| 309 | longArg = *i8Ptr++; | 
|---|
| 310 | break; | 
|---|
| 311 | case 'h': | 
|---|
| 312 | charsToOutput = 4; | 
|---|
| 313 | longArg = *i16Ptr++; | 
|---|
| 314 | break; | 
|---|
| 315 | case 'd': | 
|---|
| 316 | charsToOutput = 8; | 
|---|
| 317 | longArg = *i32Ptr++; | 
|---|
| 318 | break; | 
|---|
| 319 | case 'l': | 
|---|
| 320 | charsToOutput = 16; | 
|---|
| 321 | longArg = *i64Ptr++; | 
|---|
| 322 | break; | 
|---|
| 323 | case 'p': | 
|---|
| 324 | charsToOutput = 0; | 
|---|
| 325 | outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity); | 
|---|
| 326 | longArg = *ptrPtr==NULL? 0: 1;    /* test for null terminated array. */ | 
|---|
| 327 | ptrPtr++; | 
|---|
| 328 | break; | 
|---|
| 329 | case 'c': | 
|---|
| 330 | charsToOutput = 0; | 
|---|
| 331 | outputChar(*i8Ptr, outBuf, &outIx, capacity, indent); | 
|---|
| 332 | longArg = *i8Ptr;    /* for test for null terminated array. */ | 
|---|
| 333 | i8Ptr++; | 
|---|
| 334 | break; | 
|---|
| 335 | case 's': | 
|---|
| 336 | charsToOutput = 0; | 
|---|
| 337 | outputString((const char *)*ptrPtr, outBuf, &outIx, capacity, indent); | 
|---|
| 338 | outputChar('\n', outBuf, &outIx, capacity, indent); | 
|---|
| 339 | longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */ | 
|---|
| 340 | ptrPtr++; | 
|---|
| 341 | break; | 
|---|
| 342 |  | 
|---|
| 343 | case 'S': | 
|---|
| 344 | charsToOutput = 0; | 
|---|
| 345 | outputUString((const UChar *)*ptrPtr, -1, outBuf, &outIx, capacity, indent); | 
|---|
| 346 | outputChar('\n', outBuf, &outIx, capacity, indent); | 
|---|
| 347 | longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */ | 
|---|
| 348 | ptrPtr++; | 
|---|
| 349 | break; | 
|---|
| 350 |  | 
|---|
| 351 |  | 
|---|
| 352 | } | 
|---|
| 353 | if (charsToOutput > 0) { | 
|---|
| 354 | outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity); | 
|---|
| 355 | outputChar(' ', outBuf, &outIx, capacity, indent); | 
|---|
| 356 | } | 
|---|
| 357 | if (vectorLen == -1 && longArg == 0) { | 
|---|
| 358 | break; | 
|---|
| 359 | } | 
|---|
| 360 | } | 
|---|
| 361 | } | 
|---|
| 362 | outputChar('[', outBuf, &outIx, capacity, indent); | 
|---|
| 363 | outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity); | 
|---|
| 364 | outputChar(']', outBuf, &outIx, capacity, indent); | 
|---|
| 365 | } | 
|---|
| 366 | break; | 
|---|
| 367 |  | 
|---|
| 368 |  | 
|---|
| 369 | default: | 
|---|
| 370 | /* %. in format string, where . is some character not in the set | 
|---|
| 371 | *    of recognized format chars.  Just output it as if % wasn't there. | 
|---|
| 372 | *    (Covers "%%" outputing a single '%') | 
|---|
| 373 | */ | 
|---|
| 374 | outputChar(fmtC, outBuf, &outIx, capacity, indent); | 
|---|
| 375 | } | 
|---|
| 376 | } | 
|---|
| 377 | outputChar(0, outBuf, &outIx, capacity, indent);  /* Make sure that output is null terminated  */ | 
|---|
| 378 | return outIx + 1;     /* outIx + 1 because outIx does not increment when outputing final null. */ | 
|---|
| 379 | } | 
|---|
| 380 |  | 
|---|
| 381 |  | 
|---|
| 382 |  | 
|---|
| 383 |  | 
|---|
| 384 | U_CAPI int32_t U_EXPORT2 | 
|---|
| 385 | utrace_format(char *outBuf, int32_t capacity, | 
|---|
| 386 | int32_t indent, const char *fmt,  ...) { | 
|---|
| 387 | int32_t retVal; | 
|---|
| 388 | va_list args; | 
|---|
| 389 | va_start(args, fmt ); | 
|---|
| 390 | retVal = utrace_vformat(outBuf, capacity, indent, fmt, args); | 
|---|
| 391 | va_end(args); | 
|---|
| 392 | return retVal; | 
|---|
| 393 | } | 
|---|
| 394 |  | 
|---|
| 395 |  | 
|---|
| 396 | U_CAPI void U_EXPORT2 | 
|---|
| 397 | utrace_setFunctions(const void *context, | 
|---|
| 398 | UTraceEntry *e, UTraceExit *x, UTraceData *d) { | 
|---|
| 399 | pTraceEntryFunc = e; | 
|---|
| 400 | pTraceExitFunc  = x; | 
|---|
| 401 | pTraceDataFunc  = d; | 
|---|
| 402 | gTraceContext   = context; | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 |  | 
|---|
| 406 | U_CAPI void U_EXPORT2 | 
|---|
| 407 | utrace_getFunctions(const void **context, | 
|---|
| 408 | UTraceEntry **e, UTraceExit **x, UTraceData **d) { | 
|---|
| 409 | *e = pTraceEntryFunc; | 
|---|
| 410 | *x = pTraceExitFunc; | 
|---|
| 411 | *d = pTraceDataFunc; | 
|---|
| 412 | *context = gTraceContext; | 
|---|
| 413 | } | 
|---|
| 414 |  | 
|---|
| 415 | U_CAPI void U_EXPORT2 | 
|---|
| 416 | utrace_setLevel(int32_t level) { | 
|---|
| 417 | if (level < UTRACE_OFF) { | 
|---|
| 418 | level = UTRACE_OFF; | 
|---|
| 419 | } | 
|---|
| 420 | if (level > UTRACE_VERBOSE) { | 
|---|
| 421 | level = UTRACE_VERBOSE; | 
|---|
| 422 | } | 
|---|
| 423 | utrace_level = level; | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | U_CAPI int32_t U_EXPORT2 | 
|---|
| 427 | utrace_getLevel() { | 
|---|
| 428 | return utrace_level; | 
|---|
| 429 | } | 
|---|
| 430 |  | 
|---|
| 431 |  | 
|---|
| 432 | U_CFUNC UBool | 
|---|
| 433 | utrace_cleanup() { | 
|---|
| 434 | pTraceEntryFunc = NULL; | 
|---|
| 435 | pTraceExitFunc  = NULL; | 
|---|
| 436 | pTraceDataFunc  = NULL; | 
|---|
| 437 | utrace_level    = UTRACE_OFF; | 
|---|
| 438 | gTraceContext   = NULL; | 
|---|
| 439 | return TRUE; | 
|---|
| 440 | } | 
|---|
| 441 |  | 
|---|
| 442 |  | 
|---|
| 443 | static const char * const | 
|---|
| 444 | trFnName[] = { | 
|---|
| 445 | "u_init", | 
|---|
| 446 | "u_cleanup", | 
|---|
| 447 | NULL | 
|---|
| 448 | }; | 
|---|
| 449 |  | 
|---|
| 450 |  | 
|---|
| 451 | static const char * const | 
|---|
| 452 | trConvNames[] = { | 
|---|
| 453 | "ucnv_open", | 
|---|
| 454 | "ucnv_openPackage", | 
|---|
| 455 | "ucnv_openAlgorithmic", | 
|---|
| 456 | "ucnv_clone", | 
|---|
| 457 | "ucnv_close", | 
|---|
| 458 | "ucnv_flushCache", | 
|---|
| 459 | "ucnv_load", | 
|---|
| 460 | "ucnv_unload", | 
|---|
| 461 | NULL | 
|---|
| 462 | }; | 
|---|
| 463 |  | 
|---|
| 464 |  | 
|---|
| 465 | static const char * const | 
|---|
| 466 | trCollNames[] = { | 
|---|
| 467 | "ucol_open", | 
|---|
| 468 | "ucol_close", | 
|---|
| 469 | "ucol_strcoll", | 
|---|
| 470 | "ucol_getSortKey", | 
|---|
| 471 | "ucol_getLocale", | 
|---|
| 472 | "ucol_nextSortKeyPart", | 
|---|
| 473 | "ucol_strcollIter", | 
|---|
| 474 | "ucol_openFromShortString", | 
|---|
| 475 | "ucol_strcollUTF8", | 
|---|
| 476 | NULL | 
|---|
| 477 | }; | 
|---|
| 478 |  | 
|---|
| 479 |  | 
|---|
| 480 | static const char* const | 
|---|
| 481 | trResDataNames[] = { | 
|---|
| 482 | "resc", | 
|---|
| 483 | "bundle-open", | 
|---|
| 484 | "file-open", | 
|---|
| 485 | "res-open", | 
|---|
| 486 | NULL | 
|---|
| 487 | }; | 
|---|
| 488 |  | 
|---|
| 489 |  | 
|---|
| 490 | U_CAPI const char * U_EXPORT2 | 
|---|
| 491 | utrace_functionName(int32_t fnNumber) { | 
|---|
| 492 | if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) { | 
|---|
| 493 | return trFnName[fnNumber]; | 
|---|
| 494 | } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) { | 
|---|
| 495 | return trConvNames[fnNumber - UTRACE_CONVERSION_START]; | 
|---|
| 496 | } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){ | 
|---|
| 497 | return trCollNames[fnNumber - UTRACE_COLLATION_START]; | 
|---|
| 498 | } else if(UTRACE_UDATA_START <= fnNumber && fnNumber < UTRACE_RES_DATA_LIMIT){ | 
|---|
| 499 | return trResDataNames[fnNumber - UTRACE_UDATA_START]; | 
|---|
| 500 | } else { | 
|---|
| 501 | return "[BOGUS Trace Function Number]"; | 
|---|
| 502 | } | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 |  | 
|---|