diff --git a/icu4c/source/common/unicode/utrace.h b/icu4c/source/common/unicode/utrace.h index 8c924e7bc18..5349b2e9942 100644 --- a/icu4c/source/common/unicode/utrace.h +++ b/icu4c/source/common/unicode/utrace.h @@ -31,21 +31,20 @@ U_CDECL_BEGIN * @draft ICU 2.8 */ -enum UTraceLevel { - /** Disable all tracing */ +typedef enum UTraceLevel { + /** Disable all tracing @draft ICU 2.8*/ UTRACE_OFF=-1, - /** Trace error conditions only */ + /** Trace error conditions only @draft ICU 2.8*/ UTRACE_ERROR=0, - /** Trace errors and warnings */ + /** Trace errors and warnings @draft ICU 2.8*/ UTRACE_WARNING=3, - /** Trace opens and closes of ICU services */ + /** Trace opens and closes of ICU services @draft ICU 2.8*/ UTRACE_OPEN_CLOSE=5, - /** Trace an intermediate number of ICU operations */ + /** Trace an intermediate number of ICU operations @draft ICU 2.8*/ UTRACE_INFO=7, - /** Trace the maximum number of ICU operations */ + /** Trace the maximum number of ICU operations @draft ICU 2.8*/ UTRACE_VERBOSE=9 -}; -typedef enum UTraceLevel UTraceLevel; +} UTraceLevel; /** @@ -89,7 +88,7 @@ UTraceEntry(const void *context, int32_t fnNumber); */ typedef void U_CALLCONV UTraceExit(const void *context, int32_t fnNumber, - int32_t argType, va_list args); + const char *fmt, va_list args); /** * Type signature for the trace function to be called from within an ICU function @@ -109,6 +108,12 @@ UTraceData(const void *context, int32_t fnNumber, int32_t level, * of the use of ICU. Passing a NULL pointer for a tracing function * is allowed, and inhibits tracing action at points where that function * would be called. + *

+ * Tracing and Threads: Tracing functions are global to a process, and + * will be called in response to ICU operations performed by any + * thread. If tracing of an individual thread is desired, the + * tracing functions must themselves filter by checking that the + * current thread is the desired thread. * * @param context an uninterpretted pointer. Whatever is passed in * here will in turn be passed to each of the tracing @@ -244,8 +249,8 @@ utrace_getFunctions(const void **context, /** * Trace output Formatter. An application's UTraceData tracing functions may call * back to this function to format the trace output in a - * human readable form. Note that a UTraceData function is not - * required to format the data; it could, for example, save it in + * human readable form. Note that a UTraceData function may choose + * to not format the data; it could, for example, save it in * in the raw form it was received (more compact), leaving * formatting for a later trace analyis tool. * @param outBuf pointer to a buffer to receive the formatted output. Output @@ -264,56 +269,28 @@ U_CAPI int32_t U_EXPORT2 utrace_format(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args); - -/** - * Traced Function Exit return types. - * Flags indicating the number and types of varargs included in a call - * to a UTraceExit function. - * Bits 0-3: The function return type. First variable param. - * Bit 4: Flag for presence of U_ErrorCode status param. - * @draft ICU 2.8 - */ -enum UTraceExitVal { - /** The traced function returns no value */ - UTRACE_EXITV_NONE = 0, - /** The traced function returns an int32_t, or compatible, type. */ - UTRACE_EXITV_I32 = 1, - /** The traced function returns a pointer */ - UTRACE_EXITV_PTR = 2, - /** The traced function returns a UBool */ - UTRACE_EXITV_BOOL = 3, - /** Mask to extract the return type values from a UTraceExitVal */ - UTRACE_EXITV_MASK = 0xf, - /** Bit indicating that the traced function includes a UErrorCode parameter */ - UTRACE_EXITV_STATUS = 0x10 -}; -typedef enum UTraceExitVal UTraceExitVal; - - /** - * Trace formatter for UTraceExit, function exit tracing. - * UTraceExit may optionally receive two data items: a function return value - * and a UErrorCode status value. - * - * @param outBuf pointer to a buffer to receive the formatted output.Output + * Trace output Formatter. An application's UTraceData tracing functions may call + * this function to format any additional trace data, beyond that + * provided by default, in human readable form with the same + * formatting conventions used by utrace_format(). + * @param outBuf pointer to a buffer to receive the formatted output. Output * will be nul terminated if there is space in the buffer - * if the length of the requested output < the output buffer size. * @param capacity Length of the output buffer. * @param indent Number of spaces to indent the output. Intended to allow * data displayed from nested functions to be indented for readability. - * @param fnNumber An index specifying the function that is exiting. - * @param argType Flags specifying the number and types of data values. - * @param args Data to be formatted. If argType parameter indicates that a function - * return value exists, it will be the first varargs param. The - * function's UErrorCode status will be next, when applicable. + * @param fmt Format specification for the data to output + * @param ... Data to be formatted. * @return Length of formatted output, including the terminating NUL. * If buffer capacity is insufficient, the required capacity is returned. * @draft ICU 2.8 */ +U_CAPI int32_t U_EXPORT2 +utrace_formatA(char *outBuf, int32_t capacity, + int32_t indent, const char *fmt, ...); + -U_CAPI void U_EXPORT2 -utrace_formatExit(char *outBuf, int32_t capacity, int32_t indent, - int32_t fnNumber, int32_t argtype, va_list args); /* Trace function numbers --------------------------------------------------- */ @@ -331,8 +308,9 @@ utrace_functionName(int32_t fnNumber); /** * These are the ICU functions that will be traced when tracing is enabled. + * @draft ICU 2.8 */ -enum UTraceFunctionNumber { +typedef enum UTraceFunctionNumber { UTRACE_FUNCTION_START=0, UTRACE_U_INIT=UTRACE_FUNCTION_START, UTRACE_U_CLEANUP, @@ -353,8 +331,7 @@ enum UTraceFunctionNumber { UTRACE_UCOL_NEXTSORTKEYPART, UTRACE_UCOL_STRCOLLITER, UTRACE_COLLATION_LIMIT -}; -typedef enum UTraceFunctionNumber UTraceFunctionNumber; +} UTraceFunctionNumber; U_CDECL_END diff --git a/icu4c/source/common/utrace.c b/icu4c/source/common/utrace.c index c0a8f24c49b..272de197ec6 100644 --- a/icu4c/source/common/utrace.c +++ b/icu4c/source/common/utrace.c @@ -11,6 +11,7 @@ #define UTRACE_IMPL #include "unicode/utrace.h" +#include "utracimp.h" #include "cstring.h" #include "uassert.h" @@ -31,13 +32,41 @@ utrace_entry(int32_t 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; + 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, returnType, args); + (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args); va_end(args); } } @@ -57,6 +86,28 @@ utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) { 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; i0) { traceFnNestingDepth--; } - utrace_formatExit(buf, sizeof(buf), traceFnNestingDepth*3, fnNumber, type, args); - fprintf(stdout, "%s\n", buf); + utrace_formatA(buf, sizeof(buf), traceFnNestingDepth*3, "%s() ", utrace_functionName(fnNumber)); + fputs(buf, stdout); + utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args); + fputs(buf, stdout); + putc('\n', stdout); } void U_CALLCONV TraceData(const void *context, int32_t fnNumber, int32_t level, const char *fmt, va_list args) { - char buf[2000]; + char buf[500]; utrace_format(buf, sizeof(buf), traceFnNestingDepth*3, fmt, args); - fprintf(stdout, "%s\n", buf); + fputs(buf, stdout); + putc('\n', stdout); } diff --git a/icu4c/source/test/cintltst/tracetst.c b/icu4c/source/test/cintltst/tracetst.c index 97975be07eb..3cef2628c06 100644 --- a/icu4c/source/test/cintltst/tracetst.c +++ b/icu4c/source/test/cintltst/tracetst.c @@ -95,7 +95,7 @@ void testTraceEntry(const void *context, int32_t fnNumber) { } void testTraceExit(const void *context, int32_t fnNumber, - int32_t argType, va_list args) { + const char *fmt, va_list args) { } void testTraceData(const void *context, int32_t fnNumber, int32_t level, @@ -185,11 +185,12 @@ static void TestTraceAPI() { test_format("a 32 bit val %d...", 50, 0, "a 32 bit val 6789abcd...", __LINE__, 0x6789abcd); test_format("a 64 bit val %l", 50, 0, "a 64 bit val 123456780abcdef0" , __LINE__, INT64_C(0x123456780abcdef0)); + if (sizeof(ptr) == 4) { ptr = (void *)0xdeadbeef; test_format("a 32 bit ptr %p", 50, 0, "a 32 bit ptr deadbeef", __LINE__, ptr); - } else if (sizeof(ptr) == 8) { - ptr = (void *)0x1000200030004000; + } else if (sizeof(void *) == 8) { + ptr = (void *) INT64_C(0x1000200030004000); test_format("a 64 bit ptr %p", 50, 0, "a 64 bit ptr 1000200030004000", __LINE__, ptr); } else { TEST_ASSERT(FALSE); @@ -202,6 +203,12 @@ static void TestTraceAPI() { test_format("%vb", 100, 0, "41 42 43 [00000003]", __LINE__, "ABC", 3); + /* Null ptrs for strings, vectors */ + test_format("Null string - %s", 50, 0, "Null string - *NULL*", __LINE__, NULL); + test_format("Null string - %S", 50, 0, "Null string - *NULL*", __LINE__, NULL); + test_format("Null vector - %vc", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); + test_format("Null vector - %vC", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); + test_format("Null vector - %vd", 50, 0, "Null vector - *NULL* [00000002]", __LINE__, NULL, 2); }