diff options
Diffstat (limited to 'thirdparty/icu4c/common/utrace.cpp')
-rw-r--r-- | thirdparty/icu4c/common/utrace.cpp | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/thirdparty/icu4c/common/utrace.cpp b/thirdparty/icu4c/common/utrace.cpp new file mode 100644 index 0000000000..c981546594 --- /dev/null +++ b/thirdparty/icu4c/common/utrace.cpp @@ -0,0 +1,504 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/* +******************************************************************************* +* Copyright (C) 2003-2014, International Business Machines +* Corporation and others. All Rights Reserved. +******************************************************************************* +* file name: utrace.c +* encoding: UTF-8 +* tab size: 8 (not used) +* indentation:4 +*/ + +#include "unicode/utrace.h" +#include "utracimp.h" +#include "cstring.h" +#include "uassert.h" +#include "ucln_cmn.h" + + +static UTraceEntry *pTraceEntryFunc = NULL; +static UTraceExit *pTraceExitFunc = NULL; +static UTraceData *pTraceDataFunc = NULL; +static const void *gTraceContext = NULL; + +/** + * \var utrace_level + * Trace level variable. Negative for "off". + */ +static int32_t +utrace_level = UTRACE_ERROR; + +U_CAPI void U_EXPORT2 +utrace_entry(int32_t fnNumber) { + if (pTraceEntryFunc != NULL) { + (*pTraceEntryFunc)(gTraceContext, fnNumber); + } +} + + +static const char gExitFmt[] = "Returns."; +static const char gExitFmtValue[] = "Returns %d."; +static const char gExitFmtStatus[] = "Returns. Status = %d."; +static const char gExitFmtValueStatus[] = "Returns %d. Status = %d."; +static const char gExitFmtPtrStatus[] = "Returns %d. Status = %p."; + +U_CAPI void U_EXPORT2 +utrace_exit(int32_t fnNumber, int32_t returnType, ...) { + if (pTraceExitFunc != NULL) { + va_list args; + const char *fmt; + + switch (returnType) { + case 0: + fmt = gExitFmt; + break; + case UTRACE_EXITV_I32: + fmt = gExitFmtValue; + break; + case UTRACE_EXITV_STATUS: + fmt = gExitFmtStatus; + break; + case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS: + fmt = gExitFmtValueStatus; + break; + case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS: + fmt = gExitFmtPtrStatus; + break; + default: + UPRV_UNREACHABLE; + } + + va_start(args, returnType); + (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args); + va_end(args); + } +} + + + +U_CAPI void U_EXPORT2 +utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) { + if (pTraceDataFunc != NULL) { + va_list args; + va_start(args, fmt ); + (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args); + va_end(args); + } +} + + +static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { + int32_t i; + /* Check whether a start of line indenting is needed. Three cases: + * 1. At the start of the first line (output index == 0). + * 2. At the start of subsequent lines (preceeding char in buffer == '\n') + * 3. When preflighting buffer len (buffer capacity is exceeded), when + * a \n is output. Ideally we wouldn't do the indent until the following char + * is received, but that won't work because there's no place to remember that + * the preceding char was \n. Meaning that we may overstimate the + * buffer size needed. No harm done. + */ + if (*outIx==0 || /* case 1. */ + (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') || /* case 2. */ + (c=='\n' && *outIx>=capacity)) /* case 3 */ + { + /* At the start of a line. Indent. */ + for(i=0; i<indent; i++) { + if (*outIx < capacity) { + outBuf[*outIx] = ' '; + } + (*outIx)++; + } + } + + if (*outIx < capacity) { + outBuf[*outIx] = c; + } + if (c != 0) { + /* Nulls only appear as end-of-string terminators. Move them to the output + * buffer, but do not update the length of the buffer, so that any + * following output will overwrite the null. */ + (*outIx)++; + } +} + +static void outputHexBytes(int64_t val, int32_t charsToOutput, + char *outBuf, int32_t *outIx, int32_t capacity) { + static const char gHexChars[] = "0123456789abcdef"; + int32_t shiftCount; + for (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) { + char c = gHexChars[(val >> shiftCount) & 0xf]; + outputChar(c, outBuf, outIx, capacity, 0); + } +} + +/* Output a pointer value in hex. Work with any size of pointer */ +static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) { + uint32_t i; + int32_t incVal = 1; /* +1 for big endian, -1 for little endian */ + char *p = (char *)&val; /* point to current byte to output in the ptr val */ + +#if !U_IS_BIG_ENDIAN + /* Little Endian. Move p to most significant end of the value */ + incVal = -1; + p += sizeof(void *) - 1; +#endif + + /* Loop through the bytes of the ptr as it sits in memory, from + * most significant to least significant end */ + for (i=0; i<sizeof(void *); i++) { + outputHexBytes(*p, 2, outBuf, outIx, capacity); + p += incVal; + } +} + +static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { + int32_t i = 0; + char c; + if (s==NULL) { + s = "*NULL*"; + } + do { + c = s[i++]; + outputChar(c, outBuf, outIx, capacity, indent); + } while (c != 0); +} + + + +static void outputUString(const UChar *s, int32_t len, + char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { + int32_t i = 0; + UChar c; + if (s==NULL) { + outputString(NULL, outBuf, outIx, capacity, indent); + return; + } + + for (i=0; i<len || len==-1; i++) { + c = s[i]; + outputHexBytes(c, 4, outBuf, outIx, capacity); + outputChar(' ', outBuf, outIx, capacity, indent); + if (len == -1 && c==0) { + break; + } + } +} + +U_CAPI int32_t U_EXPORT2 +utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) { + int32_t outIx = 0; + int32_t fmtIx = 0; + char fmtC; + char c; + int32_t intArg; + int64_t longArg = 0; + char *ptrArg; + + /* Loop runs once for each character in the format string. + */ + for (;;) { + fmtC = fmt[fmtIx++]; + if (fmtC != '%') { + /* Literal character, not part of a %sequence. Just copy it to the output. */ + outputChar(fmtC, outBuf, &outIx, capacity, indent); + if (fmtC == 0) { + /* We hit the null that terminates the format string. + * This is the normal (and only) exit from the loop that + * interprets the format + */ + break; + } + continue; + } + + /* We encountered a '%'. Pick up the following format char */ + fmtC = fmt[fmtIx++]; + + switch (fmtC) { + case 'c': + /* single 8 bit char */ + c = (char)va_arg(args, int32_t); + outputChar(c, outBuf, &outIx, capacity, indent); + break; + + case 's': + /* char * string, null terminated. */ + ptrArg = va_arg(args, char *); + outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent); + break; + + case 'S': + /* UChar * string, with length, len==-1 for null terminated. */ + ptrArg = va_arg(args, char *); /* Ptr */ + intArg =(int32_t)va_arg(args, int32_t); /* Length */ + outputUString((const UChar *)ptrArg, intArg, outBuf, &outIx, capacity, indent); + break; + + case 'b': + /* 8 bit int */ + intArg = va_arg(args, int); + outputHexBytes(intArg, 2, outBuf, &outIx, capacity); + break; + + case 'h': + /* 16 bit int */ + intArg = va_arg(args, int); + outputHexBytes(intArg, 4, outBuf, &outIx, capacity); + break; + + case 'd': + /* 32 bit int */ + intArg = va_arg(args, int); + outputHexBytes(intArg, 8, outBuf, &outIx, capacity); + break; + + case 'l': + /* 64 bit long */ + longArg = va_arg(args, int64_t); + outputHexBytes(longArg, 16, outBuf, &outIx, capacity); + break; + + case 'p': + /* Pointers. */ + ptrArg = va_arg(args, char *); + outputPtrBytes(ptrArg, outBuf, &outIx, capacity); + break; + + case 0: + /* Single '%' at end of fmt string. Output as literal '%'. + * Back up index into format string so that the terminating null will be + * re-fetched in the outer loop, causing it to terminate. + */ + outputChar('%', outBuf, &outIx, capacity, indent); + fmtIx--; + break; + + case 'v': + { + /* Vector of values, e.g. %vh */ + char vectorType; + int32_t vectorLen; + const char *i8Ptr; + int16_t *i16Ptr; + int32_t *i32Ptr; + int64_t *i64Ptr; + void **ptrPtr; + int32_t charsToOutput = 0; + int32_t i; + + vectorType = fmt[fmtIx]; /* b, h, d, l, p, etc. */ + if (vectorType != 0) { + fmtIx++; + } + i8Ptr = (const char *)va_arg(args, void*); + i16Ptr = (int16_t *)i8Ptr; + i32Ptr = (int32_t *)i8Ptr; + i64Ptr = (int64_t *)i8Ptr; + ptrPtr = (void **)i8Ptr; + vectorLen =(int32_t)va_arg(args, int32_t); + if (ptrPtr == NULL) { + outputString("*NULL* ", outBuf, &outIx, capacity, indent); + } else { + for (i=0; i<vectorLen || vectorLen==-1; i++) { + switch (vectorType) { + case 'b': + charsToOutput = 2; + longArg = *i8Ptr++; + break; + case 'h': + charsToOutput = 4; + longArg = *i16Ptr++; + break; + case 'd': + charsToOutput = 8; + longArg = *i32Ptr++; + break; + case 'l': + charsToOutput = 16; + longArg = *i64Ptr++; + break; + case 'p': + charsToOutput = 0; + outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity); + longArg = *ptrPtr==NULL? 0: 1; /* test for null terminated array. */ + ptrPtr++; + break; + case 'c': + charsToOutput = 0; + outputChar(*i8Ptr, outBuf, &outIx, capacity, indent); + longArg = *i8Ptr; /* for test for null terminated array. */ + i8Ptr++; + break; + case 's': + charsToOutput = 0; + outputString((const char *)*ptrPtr, outBuf, &outIx, capacity, indent); + outputChar('\n', outBuf, &outIx, capacity, indent); + longArg = *ptrPtr==NULL? 0: 1; /* for test for null term. array. */ + ptrPtr++; + break; + + case 'S': + charsToOutput = 0; + outputUString((const UChar *)*ptrPtr, -1, outBuf, &outIx, capacity, indent); + outputChar('\n', outBuf, &outIx, capacity, indent); + longArg = *ptrPtr==NULL? 0: 1; /* for test for null term. array. */ + ptrPtr++; + break; + + + } + if (charsToOutput > 0) { + outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity); + outputChar(' ', outBuf, &outIx, capacity, indent); + } + if (vectorLen == -1 && longArg == 0) { + break; + } + } + } + outputChar('[', outBuf, &outIx, capacity, indent); + outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity); + outputChar(']', outBuf, &outIx, capacity, indent); + } + break; + + + default: + /* %. in format string, where . is some character not in the set + * of recognized format chars. Just output it as if % wasn't there. + * (Covers "%%" outputing a single '%') + */ + outputChar(fmtC, outBuf, &outIx, capacity, indent); + } + } + outputChar(0, outBuf, &outIx, capacity, indent); /* Make sure that output is null terminated */ + return outIx + 1; /* outIx + 1 because outIx does not increment when outputing final null. */ +} + + + + +U_CAPI int32_t U_EXPORT2 +utrace_format(char *outBuf, int32_t capacity, + int32_t indent, const char *fmt, ...) { + int32_t retVal; + va_list args; + va_start(args, fmt ); + retVal = utrace_vformat(outBuf, capacity, indent, fmt, args); + va_end(args); + return retVal; +} + + +U_CAPI void U_EXPORT2 +utrace_setFunctions(const void *context, + UTraceEntry *e, UTraceExit *x, UTraceData *d) { + pTraceEntryFunc = e; + pTraceExitFunc = x; + pTraceDataFunc = d; + gTraceContext = context; +} + + +U_CAPI void U_EXPORT2 +utrace_getFunctions(const void **context, + UTraceEntry **e, UTraceExit **x, UTraceData **d) { + *e = pTraceEntryFunc; + *x = pTraceExitFunc; + *d = pTraceDataFunc; + *context = gTraceContext; +} + +U_CAPI void U_EXPORT2 +utrace_setLevel(int32_t level) { + if (level < UTRACE_OFF) { + level = UTRACE_OFF; + } + if (level > UTRACE_VERBOSE) { + level = UTRACE_VERBOSE; + } + utrace_level = level; +} + +U_CAPI int32_t U_EXPORT2 +utrace_getLevel() { + return utrace_level; +} + + +U_CFUNC UBool +utrace_cleanup() { + pTraceEntryFunc = NULL; + pTraceExitFunc = NULL; + pTraceDataFunc = NULL; + utrace_level = UTRACE_OFF; + gTraceContext = NULL; + return TRUE; +} + + +static const char * const +trFnName[] = { + "u_init", + "u_cleanup", + NULL +}; + + +static const char * const +trConvNames[] = { + "ucnv_open", + "ucnv_openPackage", + "ucnv_openAlgorithmic", + "ucnv_clone", + "ucnv_close", + "ucnv_flushCache", + "ucnv_load", + "ucnv_unload", + NULL +}; + + +static const char * const +trCollNames[] = { + "ucol_open", + "ucol_close", + "ucol_strcoll", + "ucol_getSortKey", + "ucol_getLocale", + "ucol_nextSortKeyPart", + "ucol_strcollIter", + "ucol_openFromShortString", + "ucol_strcollUTF8", + NULL +}; + + +static const char* const +trResDataNames[] = { + "resc", + "bundle-open", + "file-open", + "res-open", + NULL +}; + + +U_CAPI const char * U_EXPORT2 +utrace_functionName(int32_t fnNumber) { + if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) { + return trFnName[fnNumber]; + } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) { + return trConvNames[fnNumber - UTRACE_CONVERSION_START]; + } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){ + return trCollNames[fnNumber - UTRACE_COLLATION_START]; + } else if(UTRACE_UDATA_START <= fnNumber && fnNumber < UTRACE_RES_DATA_LIMIT){ + return trResDataNames[fnNumber - UTRACE_UDATA_START]; + } else { + return "[BOGUS Trace Function Number]"; + } +} + |