/* ******************************************************************************* * Copyright (C) 2003, 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 "cstring.h" #include "uassert.h" static UTraceEntry *pTraceEntryFunc = NULL; static UTraceExit *pTraceExitFunc = NULL; static UTraceData *pTraceDataFunc = NULL; static const void *gTraceContext = NULL; U_EXPORT int32_t utrace_level; U_CAPI void U_EXPORT2 utrace_entry(int32_t fnNumber) { if (pTraceEntryFunc != NULL) { (*pTraceEntryFunc)(gTraceContext, fnNumber); } } U_CAPI void U_EXPORT2 utrace_exit(int32_t fnNumber, int32_t returnType, ...) { if (pTraceExitFunc != NULL) { va_list args; va_start(args, returnType); (*pTraceExitFunc)(gTraceContext, fnNumber, returnType, 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; 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)++; } /* Handle indenting at the start of lines */ if (c == '\n') { for(i=0; i= 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) { static const int16_t endianTestVal = (int16_t)0xabcd; 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 (*(uint8_t *)&endianTestVal == (uint8_t)0xcd) { /* Little Endian. Move p to most significant end of the value */ incVal = -1; p += sizeof(void *) - 1; } /* Loop through the bytes of the ptr as it sits in memory, from * most significant to least significant end */ for (i=0; i 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 void U_EXPORT2 utrace_formatExit(char *outBuf, int32_t capacity, int32_t indent, int32_t fnNumber, int32_t argType, va_list args) { int32_t outIx = 0; int32_t intVal; UBool boolVal; void *ptrVal; UErrorCode status; outputString(utrace_functionName(fnNumber), outBuf, &outIx, capacity, indent); outputString(" returns", outBuf, &outIx, capacity, indent); switch (argType & UTRACE_EXITV_MASK) { case UTRACE_EXITV_I32: outputChar(' ', outBuf, &outIx, capacity, indent); intVal = (int32_t)va_arg(args, int32_t); outputHexBytes(intVal, 8, outBuf, &outIx, capacity); break; case UTRACE_EXITV_PTR: outputChar(' ', outBuf, &outIx, capacity, indent); ptrVal = (void *)va_arg(args, void *); outputPtrBytes(ptrVal, outBuf, &outIx, capacity); break; case UTRACE_EXITV_BOOL: outputChar(' ', outBuf, &outIx, capacity, indent); boolVal = (UBool)va_arg(args, int32_t); /* gcc wants int, not UBool */ outputString(boolVal? "TRUE": "FALSE", outBuf, &outIx, capacity, indent); } outputString(".", outBuf, &outIx, capacity, indent); if (argType & UTRACE_EXITV_STATUS) { outputString(" Status = ", outBuf, &outIx, capacity, indent); status = (UErrorCode)va_arg(args, UErrorCode); outputString(u_errorName(status), outBuf, &outIx, capacity, indent); } outputChar(0, outBuf, &outIx, capacity, indent); } 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", 0}; static const char * const trConvNames[] = { "ucnv_open", "ucnv_close", "ucnv_flushCache", 0}; static const char * const trCollNames[] = { "ucol_open", "ucol_close", "ucol_strcoll", "ucol_getSortKey", "ucol_getLocale", "ucol_nextSortKeyPart", "ucol_strcollIter", 0}; 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]"; } }