intl/icu/source/common/utrace.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial