1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/utrace.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,486 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 2003-2008, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* file name: utrace.c 1.10 +* encoding: US-ASCII 1.11 +* tab size: 8 (not used) 1.12 +* indentation:4 1.13 +*/ 1.14 + 1.15 +#define UTRACE_IMPL 1.16 +#include "unicode/utrace.h" 1.17 +#include "utracimp.h" 1.18 +#include "cstring.h" 1.19 +#include "uassert.h" 1.20 +#include "ucln_cmn.h" 1.21 + 1.22 + 1.23 +static UTraceEntry *pTraceEntryFunc = NULL; 1.24 +static UTraceExit *pTraceExitFunc = NULL; 1.25 +static UTraceData *pTraceDataFunc = NULL; 1.26 +static const void *gTraceContext = NULL; 1.27 + 1.28 +U_EXPORT int32_t 1.29 +utrace_level = UTRACE_ERROR; 1.30 + 1.31 +U_CAPI void U_EXPORT2 1.32 +utrace_entry(int32_t fnNumber) { 1.33 + if (pTraceEntryFunc != NULL) { 1.34 + (*pTraceEntryFunc)(gTraceContext, fnNumber); 1.35 + } 1.36 +} 1.37 + 1.38 + 1.39 +static const char gExitFmt[] = "Returns."; 1.40 +static const char gExitFmtValue[] = "Returns %d."; 1.41 +static const char gExitFmtStatus[] = "Returns. Status = %d."; 1.42 +static const char gExitFmtValueStatus[] = "Returns %d. Status = %d."; 1.43 +static const char gExitFmtPtrStatus[] = "Returns %d. Status = %p."; 1.44 + 1.45 +U_CAPI void U_EXPORT2 1.46 +utrace_exit(int32_t fnNumber, int32_t returnType, ...) { 1.47 + if (pTraceExitFunc != NULL) { 1.48 + va_list args; 1.49 + const char *fmt; 1.50 + 1.51 + switch (returnType) { 1.52 + case 0: 1.53 + fmt = gExitFmt; 1.54 + break; 1.55 + case UTRACE_EXITV_I32: 1.56 + fmt = gExitFmtValue; 1.57 + break; 1.58 + case UTRACE_EXITV_STATUS: 1.59 + fmt = gExitFmtStatus; 1.60 + break; 1.61 + case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS: 1.62 + fmt = gExitFmtValueStatus; 1.63 + break; 1.64 + case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS: 1.65 + fmt = gExitFmtPtrStatus; 1.66 + break; 1.67 + default: 1.68 + U_ASSERT(FALSE); 1.69 + fmt = gExitFmt; 1.70 + } 1.71 + 1.72 + va_start(args, returnType); 1.73 + (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args); 1.74 + va_end(args); 1.75 + } 1.76 +} 1.77 + 1.78 + 1.79 + 1.80 +U_CAPI void U_EXPORT2 1.81 +utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) { 1.82 + if (pTraceDataFunc != NULL) { 1.83 + va_list args; 1.84 + va_start(args, fmt ); 1.85 + (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args); 1.86 + va_end(args); 1.87 + } 1.88 +} 1.89 + 1.90 + 1.91 +static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { 1.92 + int32_t i; 1.93 + /* Check whether a start of line indenting is needed. Three cases: 1.94 + * 1. At the start of the first line (output index == 0). 1.95 + * 2. At the start of subsequent lines (preceeding char in buffer == '\n') 1.96 + * 3. When preflighting buffer len (buffer capacity is exceeded), when 1.97 + * a \n is output. Ideally we wouldn't do the indent until the following char 1.98 + * is received, but that won't work because there's no place to remember that 1.99 + * the preceding char was \n. Meaning that we may overstimate the 1.100 + * buffer size needed. No harm done. 1.101 + */ 1.102 + if (*outIx==0 || /* case 1. */ 1.103 + (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') || /* case 2. */ 1.104 + (c=='\n' && *outIx>=capacity)) /* case 3 */ 1.105 + { 1.106 + /* At the start of a line. Indent. */ 1.107 + for(i=0; i<indent; i++) { 1.108 + if (*outIx < capacity) { 1.109 + outBuf[*outIx] = ' '; 1.110 + } 1.111 + (*outIx)++; 1.112 + } 1.113 + } 1.114 + 1.115 + if (*outIx < capacity) { 1.116 + outBuf[*outIx] = c; 1.117 + } 1.118 + if (c != 0) { 1.119 + /* Nulls only appear as end-of-string terminators. Move them to the output 1.120 + * buffer, but do not update the length of the buffer, so that any 1.121 + * following output will overwrite the null. */ 1.122 + (*outIx)++; 1.123 + } 1.124 +} 1.125 + 1.126 +static void outputHexBytes(int64_t val, int32_t charsToOutput, 1.127 + char *outBuf, int32_t *outIx, int32_t capacity) { 1.128 + static const char gHexChars[] = "0123456789abcdef"; 1.129 + int32_t shiftCount; 1.130 + for (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) { 1.131 + char c = gHexChars[(val >> shiftCount) & 0xf]; 1.132 + outputChar(c, outBuf, outIx, capacity, 0); 1.133 + } 1.134 +} 1.135 + 1.136 +/* Output a pointer value in hex. Work with any size of pointer */ 1.137 +static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) { 1.138 + int32_t i; 1.139 + int32_t incVal = 1; /* +1 for big endian, -1 for little endian */ 1.140 + char *p = (char *)&val; /* point to current byte to output in the ptr val */ 1.141 + 1.142 +#if !U_IS_BIG_ENDIAN 1.143 + /* Little Endian. Move p to most significant end of the value */ 1.144 + incVal = -1; 1.145 + p += sizeof(void *) - 1; 1.146 +#endif 1.147 + 1.148 + /* Loop through the bytes of the ptr as it sits in memory, from 1.149 + * most significant to least significant end */ 1.150 + for (i=0; i<sizeof(void *); i++) { 1.151 + outputHexBytes(*p, 2, outBuf, outIx, capacity); 1.152 + p += incVal; 1.153 + } 1.154 +} 1.155 + 1.156 +static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { 1.157 + int32_t i = 0; 1.158 + char c; 1.159 + if (s==NULL) { 1.160 + s = "*NULL*"; 1.161 + } 1.162 + do { 1.163 + c = s[i++]; 1.164 + outputChar(c, outBuf, outIx, capacity, indent); 1.165 + } while (c != 0); 1.166 +} 1.167 + 1.168 + 1.169 + 1.170 +static void outputUString(const UChar *s, int32_t len, 1.171 + char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { 1.172 + int32_t i = 0; 1.173 + UChar c; 1.174 + if (s==NULL) { 1.175 + outputString(NULL, outBuf, outIx, capacity, indent); 1.176 + return; 1.177 + } 1.178 + 1.179 + for (i=0; i<len || len==-1; i++) { 1.180 + c = s[i]; 1.181 + outputHexBytes(c, 4, outBuf, outIx, capacity); 1.182 + outputChar(' ', outBuf, outIx, capacity, indent); 1.183 + if (len == -1 && c==0) { 1.184 + break; 1.185 + } 1.186 + } 1.187 +} 1.188 + 1.189 +U_CAPI int32_t U_EXPORT2 1.190 +utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) { 1.191 + int32_t outIx = 0; 1.192 + int32_t fmtIx = 0; 1.193 + char fmtC; 1.194 + char c; 1.195 + int32_t intArg; 1.196 + int64_t longArg = 0; 1.197 + char *ptrArg; 1.198 + 1.199 + /* Loop runs once for each character in the format string. 1.200 + */ 1.201 + for (;;) { 1.202 + fmtC = fmt[fmtIx++]; 1.203 + if (fmtC != '%') { 1.204 + /* Literal character, not part of a %sequence. Just copy it to the output. */ 1.205 + outputChar(fmtC, outBuf, &outIx, capacity, indent); 1.206 + if (fmtC == 0) { 1.207 + /* We hit the null that terminates the format string. 1.208 + * This is the normal (and only) exit from the loop that 1.209 + * interprets the format 1.210 + */ 1.211 + break; 1.212 + } 1.213 + continue; 1.214 + } 1.215 + 1.216 + /* We encountered a '%'. Pick up the following format char */ 1.217 + fmtC = fmt[fmtIx++]; 1.218 + 1.219 + switch (fmtC) { 1.220 + case 'c': 1.221 + /* single 8 bit char */ 1.222 + c = (char)va_arg(args, int32_t); 1.223 + outputChar(c, outBuf, &outIx, capacity, indent); 1.224 + break; 1.225 + 1.226 + case 's': 1.227 + /* char * string, null terminated. */ 1.228 + ptrArg = va_arg(args, char *); 1.229 + outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent); 1.230 + break; 1.231 + 1.232 + case 'S': 1.233 + /* UChar * string, with length, len==-1 for null terminated. */ 1.234 + ptrArg = va_arg(args, void *); /* Ptr */ 1.235 + intArg =(int32_t)va_arg(args, int32_t); /* Length */ 1.236 + outputUString((const UChar *)ptrArg, intArg, outBuf, &outIx, capacity, indent); 1.237 + break; 1.238 + 1.239 + case 'b': 1.240 + /* 8 bit int */ 1.241 + intArg = va_arg(args, int); 1.242 + outputHexBytes(intArg, 2, outBuf, &outIx, capacity); 1.243 + break; 1.244 + 1.245 + case 'h': 1.246 + /* 16 bit int */ 1.247 + intArg = va_arg(args, int); 1.248 + outputHexBytes(intArg, 4, outBuf, &outIx, capacity); 1.249 + break; 1.250 + 1.251 + case 'd': 1.252 + /* 32 bit int */ 1.253 + intArg = va_arg(args, int); 1.254 + outputHexBytes(intArg, 8, outBuf, &outIx, capacity); 1.255 + break; 1.256 + 1.257 + case 'l': 1.258 + /* 64 bit long */ 1.259 + longArg = va_arg(args, int64_t); 1.260 + outputHexBytes(longArg, 16, outBuf, &outIx, capacity); 1.261 + break; 1.262 + 1.263 + case 'p': 1.264 + /* Pointers. */ 1.265 + ptrArg = va_arg(args, void *); 1.266 + outputPtrBytes(ptrArg, outBuf, &outIx, capacity); 1.267 + break; 1.268 + 1.269 + case 0: 1.270 + /* Single '%' at end of fmt string. Output as literal '%'. 1.271 + * Back up index into format string so that the terminating null will be 1.272 + * re-fetched in the outer loop, causing it to terminate. 1.273 + */ 1.274 + outputChar('%', outBuf, &outIx, capacity, indent); 1.275 + fmtIx--; 1.276 + break; 1.277 + 1.278 + case 'v': 1.279 + { 1.280 + /* Vector of values, e.g. %vh */ 1.281 + char vectorType; 1.282 + int32_t vectorLen; 1.283 + const char *i8Ptr; 1.284 + int16_t *i16Ptr; 1.285 + int32_t *i32Ptr; 1.286 + int64_t *i64Ptr; 1.287 + void **ptrPtr; 1.288 + int32_t charsToOutput = 0; 1.289 + int32_t i; 1.290 + 1.291 + vectorType = fmt[fmtIx]; /* b, h, d, l, p, etc. */ 1.292 + if (vectorType != 0) { 1.293 + fmtIx++; 1.294 + } 1.295 + i8Ptr = (const char *)va_arg(args, void*); 1.296 + i16Ptr = (int16_t *)i8Ptr; 1.297 + i32Ptr = (int32_t *)i8Ptr; 1.298 + i64Ptr = (int64_t *)i8Ptr; 1.299 + ptrPtr = (void **)i8Ptr; 1.300 + vectorLen =(int32_t)va_arg(args, int32_t); 1.301 + if (ptrPtr == NULL) { 1.302 + outputString("*NULL* ", outBuf, &outIx, capacity, indent); 1.303 + } else { 1.304 + for (i=0; i<vectorLen || vectorLen==-1; i++) { 1.305 + switch (vectorType) { 1.306 + case 'b': 1.307 + charsToOutput = 2; 1.308 + longArg = *i8Ptr++; 1.309 + break; 1.310 + case 'h': 1.311 + charsToOutput = 4; 1.312 + longArg = *i16Ptr++; 1.313 + break; 1.314 + case 'd': 1.315 + charsToOutput = 8; 1.316 + longArg = *i32Ptr++; 1.317 + break; 1.318 + case 'l': 1.319 + charsToOutput = 16; 1.320 + longArg = *i64Ptr++; 1.321 + break; 1.322 + case 'p': 1.323 + charsToOutput = 0; 1.324 + outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity); 1.325 + longArg = *ptrPtr==NULL? 0: 1; /* test for null terminated array. */ 1.326 + ptrPtr++; 1.327 + break; 1.328 + case 'c': 1.329 + charsToOutput = 0; 1.330 + outputChar(*i8Ptr, outBuf, &outIx, capacity, indent); 1.331 + longArg = *i8Ptr; /* for test for null terminated array. */ 1.332 + i8Ptr++; 1.333 + break; 1.334 + case 's': 1.335 + charsToOutput = 0; 1.336 + outputString(*ptrPtr, outBuf, &outIx, capacity, indent); 1.337 + outputChar('\n', outBuf, &outIx, capacity, indent); 1.338 + longArg = *ptrPtr==NULL? 0: 1; /* for test for null term. array. */ 1.339 + ptrPtr++; 1.340 + break; 1.341 + 1.342 + case 'S': 1.343 + charsToOutput = 0; 1.344 + outputUString((const UChar *)*ptrPtr, -1, outBuf, &outIx, capacity, indent); 1.345 + outputChar('\n', outBuf, &outIx, capacity, indent); 1.346 + longArg = *ptrPtr==NULL? 0: 1; /* for test for null term. array. */ 1.347 + ptrPtr++; 1.348 + break; 1.349 + 1.350 + 1.351 + } 1.352 + if (charsToOutput > 0) { 1.353 + outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity); 1.354 + outputChar(' ', outBuf, &outIx, capacity, indent); 1.355 + } 1.356 + if (vectorLen == -1 && longArg == 0) { 1.357 + break; 1.358 + } 1.359 + } 1.360 + } 1.361 + outputChar('[', outBuf, &outIx, capacity, indent); 1.362 + outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity); 1.363 + outputChar(']', outBuf, &outIx, capacity, indent); 1.364 + } 1.365 + break; 1.366 + 1.367 + 1.368 + default: 1.369 + /* %. in format string, where . is some character not in the set 1.370 + * of recognized format chars. Just output it as if % wasn't there. 1.371 + * (Covers "%%" outputing a single '%') 1.372 + */ 1.373 + outputChar(fmtC, outBuf, &outIx, capacity, indent); 1.374 + } 1.375 + } 1.376 + outputChar(0, outBuf, &outIx, capacity, indent); /* Make sure that output is null terminated */ 1.377 + return outIx + 1; /* outIx + 1 because outIx does not increment when outputing final null. */ 1.378 +} 1.379 + 1.380 + 1.381 + 1.382 + 1.383 +U_CAPI int32_t U_EXPORT2 1.384 +utrace_format(char *outBuf, int32_t capacity, 1.385 + int32_t indent, const char *fmt, ...) { 1.386 + int32_t retVal; 1.387 + va_list args; 1.388 + va_start(args, fmt ); 1.389 + retVal = utrace_vformat(outBuf, capacity, indent, fmt, args); 1.390 + va_end(args); 1.391 + return retVal; 1.392 +} 1.393 + 1.394 + 1.395 +U_CAPI void U_EXPORT2 1.396 +utrace_setFunctions(const void *context, 1.397 + UTraceEntry *e, UTraceExit *x, UTraceData *d) { 1.398 + pTraceEntryFunc = e; 1.399 + pTraceExitFunc = x; 1.400 + pTraceDataFunc = d; 1.401 + gTraceContext = context; 1.402 +} 1.403 + 1.404 + 1.405 +U_CAPI void U_EXPORT2 1.406 +utrace_getFunctions(const void **context, 1.407 + UTraceEntry **e, UTraceExit **x, UTraceData **d) { 1.408 + *e = pTraceEntryFunc; 1.409 + *x = pTraceExitFunc; 1.410 + *d = pTraceDataFunc; 1.411 + *context = gTraceContext; 1.412 +} 1.413 + 1.414 +U_CAPI void U_EXPORT2 1.415 +utrace_setLevel(int32_t level) { 1.416 + if (level < UTRACE_OFF) { 1.417 + level = UTRACE_OFF; 1.418 + } 1.419 + if (level > UTRACE_VERBOSE) { 1.420 + level = UTRACE_VERBOSE; 1.421 + } 1.422 + utrace_level = level; 1.423 +} 1.424 + 1.425 +U_CAPI int32_t U_EXPORT2 1.426 +utrace_getLevel() { 1.427 + return utrace_level; 1.428 +} 1.429 + 1.430 + 1.431 +U_CFUNC UBool 1.432 +utrace_cleanup() { 1.433 + pTraceEntryFunc = NULL; 1.434 + pTraceExitFunc = NULL; 1.435 + pTraceDataFunc = NULL; 1.436 + utrace_level = UTRACE_OFF; 1.437 + gTraceContext = NULL; 1.438 + return TRUE; 1.439 +} 1.440 + 1.441 + 1.442 +static const char * const 1.443 +trFnName[] = { 1.444 + "u_init", 1.445 + "u_cleanup", 1.446 + NULL 1.447 +}; 1.448 + 1.449 + 1.450 +static const char * const 1.451 +trConvNames[] = { 1.452 + "ucnv_open", 1.453 + "ucnv_openPackage", 1.454 + "ucnv_openAlgorithmic", 1.455 + "ucnv_clone", 1.456 + "ucnv_close", 1.457 + "ucnv_flushCache", 1.458 + "ucnv_load", 1.459 + "ucnv_unload", 1.460 + NULL 1.461 +}; 1.462 + 1.463 + 1.464 +static const char * const 1.465 +trCollNames[] = { 1.466 + "ucol_open", 1.467 + "ucol_close", 1.468 + "ucol_strcoll", 1.469 + "ucol_getSortKey", 1.470 + "ucol_getLocale", 1.471 + "ucol_nextSortKeyPart", 1.472 + "ucol_strcollIter", 1.473 + NULL 1.474 +}; 1.475 + 1.476 + 1.477 +U_CAPI const char * U_EXPORT2 1.478 +utrace_functionName(int32_t fnNumber) { 1.479 + if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) { 1.480 + return trFnName[fnNumber]; 1.481 + } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) { 1.482 + return trConvNames[fnNumber - UTRACE_CONVERSION_START]; 1.483 + } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){ 1.484 + return trCollNames[fnNumber - UTRACE_COLLATION_START]; 1.485 + } else { 1.486 + return "[BOGUS Trace Function Number]"; 1.487 + } 1.488 +} 1.489 +