Index: icu46/source/common/utrace.c |
=================================================================== |
--- icu46/source/common/utrace.c (revision 0) |
+++ icu46/source/common/utrace.c (revision 0) |
@@ -0,0 +1,486 @@ |
+/* |
+******************************************************************************* |
+* Copyright (C) 2003-2008, International Business Machines |
+* Corporation and others. All Rights Reserved. |
+******************************************************************************* |
+* file name: utrace.c |
+* encoding: US-ASCII |
+* tab size: 8 (not used) |
+* indentation:4 |
+*/ |
+ |
+#define UTRACE_IMPL |
+#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; |
+ |
+U_EXPORT 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: |
+ U_ASSERT(FALSE); |
+ fmt = gExitFmt; |
+ } |
+ |
+ 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) { |
+ int32_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, void *); /* 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, void *); |
+ 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(*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", |
+ 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 { |
+ return "[BOGUS Trace Function Number]"; |
+ } |
+} |
+ |
Property changes on: icu46/source/common/utrace.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |