michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 2003-2008, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: ******************************************************************************* michael@0: * file name: utrace.c michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:4 michael@0: */ michael@0: michael@0: #define UTRACE_IMPL michael@0: #include "unicode/utrace.h" michael@0: #include "utracimp.h" michael@0: #include "cstring.h" michael@0: #include "uassert.h" michael@0: #include "ucln_cmn.h" michael@0: michael@0: michael@0: static UTraceEntry *pTraceEntryFunc = NULL; michael@0: static UTraceExit *pTraceExitFunc = NULL; michael@0: static UTraceData *pTraceDataFunc = NULL; michael@0: static const void *gTraceContext = NULL; michael@0: michael@0: U_EXPORT int32_t michael@0: utrace_level = UTRACE_ERROR; michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_entry(int32_t fnNumber) { michael@0: if (pTraceEntryFunc != NULL) { michael@0: (*pTraceEntryFunc)(gTraceContext, fnNumber); michael@0: } michael@0: } michael@0: michael@0: michael@0: static const char gExitFmt[] = "Returns."; michael@0: static const char gExitFmtValue[] = "Returns %d."; michael@0: static const char gExitFmtStatus[] = "Returns. Status = %d."; michael@0: static const char gExitFmtValueStatus[] = "Returns %d. Status = %d."; michael@0: static const char gExitFmtPtrStatus[] = "Returns %d. Status = %p."; michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_exit(int32_t fnNumber, int32_t returnType, ...) { michael@0: if (pTraceExitFunc != NULL) { michael@0: va_list args; michael@0: const char *fmt; michael@0: michael@0: switch (returnType) { michael@0: case 0: michael@0: fmt = gExitFmt; michael@0: break; michael@0: case UTRACE_EXITV_I32: michael@0: fmt = gExitFmtValue; michael@0: break; michael@0: case UTRACE_EXITV_STATUS: michael@0: fmt = gExitFmtStatus; michael@0: break; michael@0: case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS: michael@0: fmt = gExitFmtValueStatus; michael@0: break; michael@0: case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS: michael@0: fmt = gExitFmtPtrStatus; michael@0: break; michael@0: default: michael@0: U_ASSERT(FALSE); michael@0: fmt = gExitFmt; michael@0: } michael@0: michael@0: va_start(args, returnType); michael@0: (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args); michael@0: va_end(args); michael@0: } michael@0: } michael@0: michael@0: michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) { michael@0: if (pTraceDataFunc != NULL) { michael@0: va_list args; michael@0: va_start(args, fmt ); michael@0: (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args); michael@0: va_end(args); michael@0: } michael@0: } michael@0: michael@0: michael@0: static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) { michael@0: int32_t i; michael@0: /* Check whether a start of line indenting is needed. Three cases: michael@0: * 1. At the start of the first line (output index == 0). michael@0: * 2. At the start of subsequent lines (preceeding char in buffer == '\n') michael@0: * 3. When preflighting buffer len (buffer capacity is exceeded), when michael@0: * a \n is output. Ideally we wouldn't do the indent until the following char michael@0: * is received, but that won't work because there's no place to remember that michael@0: * the preceding char was \n. Meaning that we may overstimate the michael@0: * buffer size needed. No harm done. michael@0: */ michael@0: if (*outIx==0 || /* case 1. */ michael@0: (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') || /* case 2. */ michael@0: (c=='\n' && *outIx>=capacity)) /* case 3 */ michael@0: { michael@0: /* At the start of a line. Indent. */ michael@0: for(i=0; i= 0; shiftCount-=4) { michael@0: char c = gHexChars[(val >> shiftCount) & 0xf]; michael@0: outputChar(c, outBuf, outIx, capacity, 0); michael@0: } michael@0: } michael@0: michael@0: /* Output a pointer value in hex. Work with any size of pointer */ michael@0: static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) { michael@0: int32_t i; michael@0: int32_t incVal = 1; /* +1 for big endian, -1 for little endian */ michael@0: char *p = (char *)&val; /* point to current byte to output in the ptr val */ michael@0: michael@0: #if !U_IS_BIG_ENDIAN michael@0: /* Little Endian. Move p to most significant end of the value */ michael@0: incVal = -1; michael@0: p += sizeof(void *) - 1; michael@0: #endif michael@0: michael@0: /* Loop through the bytes of the ptr as it sits in memory, from michael@0: * most significant to least significant end */ michael@0: for (i=0; i 0) { michael@0: outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity); michael@0: outputChar(' ', outBuf, &outIx, capacity, indent); michael@0: } michael@0: if (vectorLen == -1 && longArg == 0) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: outputChar('[', outBuf, &outIx, capacity, indent); michael@0: outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity); michael@0: outputChar(']', outBuf, &outIx, capacity, indent); michael@0: } michael@0: break; michael@0: michael@0: michael@0: default: michael@0: /* %. in format string, where . is some character not in the set michael@0: * of recognized format chars. Just output it as if % wasn't there. michael@0: * (Covers "%%" outputing a single '%') michael@0: */ michael@0: outputChar(fmtC, outBuf, &outIx, capacity, indent); michael@0: } michael@0: } michael@0: outputChar(0, outBuf, &outIx, capacity, indent); /* Make sure that output is null terminated */ michael@0: return outIx + 1; /* outIx + 1 because outIx does not increment when outputing final null. */ michael@0: } michael@0: michael@0: michael@0: michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: utrace_format(char *outBuf, int32_t capacity, michael@0: int32_t indent, const char *fmt, ...) { michael@0: int32_t retVal; michael@0: va_list args; michael@0: va_start(args, fmt ); michael@0: retVal = utrace_vformat(outBuf, capacity, indent, fmt, args); michael@0: va_end(args); michael@0: return retVal; michael@0: } michael@0: michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_setFunctions(const void *context, michael@0: UTraceEntry *e, UTraceExit *x, UTraceData *d) { michael@0: pTraceEntryFunc = e; michael@0: pTraceExitFunc = x; michael@0: pTraceDataFunc = d; michael@0: gTraceContext = context; michael@0: } michael@0: michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_getFunctions(const void **context, michael@0: UTraceEntry **e, UTraceExit **x, UTraceData **d) { michael@0: *e = pTraceEntryFunc; michael@0: *x = pTraceExitFunc; michael@0: *d = pTraceDataFunc; michael@0: *context = gTraceContext; michael@0: } michael@0: michael@0: U_CAPI void U_EXPORT2 michael@0: utrace_setLevel(int32_t level) { michael@0: if (level < UTRACE_OFF) { michael@0: level = UTRACE_OFF; michael@0: } michael@0: if (level > UTRACE_VERBOSE) { michael@0: level = UTRACE_VERBOSE; michael@0: } michael@0: utrace_level = level; michael@0: } michael@0: michael@0: U_CAPI int32_t U_EXPORT2 michael@0: utrace_getLevel() { michael@0: return utrace_level; michael@0: } michael@0: michael@0: michael@0: U_CFUNC UBool michael@0: utrace_cleanup() { michael@0: pTraceEntryFunc = NULL; michael@0: pTraceExitFunc = NULL; michael@0: pTraceDataFunc = NULL; michael@0: utrace_level = UTRACE_OFF; michael@0: gTraceContext = NULL; michael@0: return TRUE; michael@0: } michael@0: michael@0: michael@0: static const char * const michael@0: trFnName[] = { michael@0: "u_init", michael@0: "u_cleanup", michael@0: NULL michael@0: }; michael@0: michael@0: michael@0: static const char * const michael@0: trConvNames[] = { michael@0: "ucnv_open", michael@0: "ucnv_openPackage", michael@0: "ucnv_openAlgorithmic", michael@0: "ucnv_clone", michael@0: "ucnv_close", michael@0: "ucnv_flushCache", michael@0: "ucnv_load", michael@0: "ucnv_unload", michael@0: NULL michael@0: }; michael@0: michael@0: michael@0: static const char * const michael@0: trCollNames[] = { michael@0: "ucol_open", michael@0: "ucol_close", michael@0: "ucol_strcoll", michael@0: "ucol_getSortKey", michael@0: "ucol_getLocale", michael@0: "ucol_nextSortKeyPart", michael@0: "ucol_strcollIter", michael@0: NULL michael@0: }; michael@0: michael@0: michael@0: U_CAPI const char * U_EXPORT2 michael@0: utrace_functionName(int32_t fnNumber) { michael@0: if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) { michael@0: return trFnName[fnNumber]; michael@0: } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) { michael@0: return trConvNames[fnNumber - UTRACE_CONVERSION_START]; michael@0: } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){ michael@0: return trCollNames[fnNumber - UTRACE_COLLATION_START]; michael@0: } else { michael@0: return "[BOGUS Trace Function Number]"; michael@0: } michael@0: } michael@0: