]>
git.saurik.com Git - apple/icu.git/blob - icuSources/common/utrace.c
2 *******************************************************************************
3 * Copyright (C) 2003-2008, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
8 * tab size: 8 (not used)
13 #include "unicode/utrace.h"
20 static UTraceEntry
*pTraceEntryFunc
= NULL
;
21 static UTraceExit
*pTraceExitFunc
= NULL
;
22 static UTraceData
*pTraceDataFunc
= NULL
;
23 static const void *gTraceContext
= NULL
;
26 utrace_level
= UTRACE_ERROR
;
29 utrace_entry(int32_t fnNumber
) {
30 if (pTraceEntryFunc
!= NULL
) {
31 (*pTraceEntryFunc
)(gTraceContext
, fnNumber
);
36 static const char gExitFmt
[] = "Returns.";
37 static const char gExitFmtValue
[] = "Returns %d.";
38 static const char gExitFmtStatus
[] = "Returns. Status = %d.";
39 static const char gExitFmtValueStatus
[] = "Returns %d. Status = %d.";
40 static const char gExitFmtPtrStatus
[] = "Returns %d. Status = %p.";
43 utrace_exit(int32_t fnNumber
, int32_t returnType
, ...) {
44 if (pTraceExitFunc
!= NULL
) {
52 case UTRACE_EXITV_I32
:
55 case UTRACE_EXITV_STATUS
:
58 case UTRACE_EXITV_I32
| UTRACE_EXITV_STATUS
:
59 fmt
= gExitFmtValueStatus
;
61 case UTRACE_EXITV_PTR
| UTRACE_EXITV_STATUS
:
62 fmt
= gExitFmtPtrStatus
;
69 va_start(args
, returnType
);
70 (*pTraceExitFunc
)(gTraceContext
, fnNumber
, fmt
, args
);
78 utrace_data(int32_t fnNumber
, int32_t level
, const char *fmt
, ...) {
79 if (pTraceDataFunc
!= NULL
) {
82 (*pTraceDataFunc
)(gTraceContext
, fnNumber
, level
, fmt
, args
);
88 static void outputChar(char c
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
90 /* Check whether a start of line indenting is needed. Three cases:
91 * 1. At the start of the first line (output index == 0).
92 * 2. At the start of subsequent lines (preceeding char in buffer == '\n')
93 * 3. When preflighting buffer len (buffer capacity is exceeded), when
94 * a \n is output. Ideally we wouldn't do the indent until the following char
95 * is received, but that won't work because there's no place to remember that
96 * the preceding char was \n. Meaning that we may overstimate the
97 * buffer size needed. No harm done.
99 if (*outIx
==0 || /* case 1. */
100 (c
!='\n' && c
!=0 && *outIx
< capacity
&& outBuf
[(*outIx
)-1]=='\n') || /* case 2. */
101 (c
=='\n' && *outIx
>=capacity
)) /* case 3 */
103 /* At the start of a line. Indent. */
104 for(i
=0; i
<indent
; i
++) {
105 if (*outIx
< capacity
) {
106 outBuf
[*outIx
] = ' ';
112 if (*outIx
< capacity
) {
116 /* Nulls only appear as end-of-string terminators. Move them to the output
117 * buffer, but do not update the length of the buffer, so that any
118 * following output will overwrite the null. */
123 static void outputHexBytes(int64_t val
, int32_t charsToOutput
,
124 char *outBuf
, int32_t *outIx
, int32_t capacity
) {
125 static const char gHexChars
[] = "0123456789abcdef";
127 for (shiftCount
=(charsToOutput
-1)*4; shiftCount
>= 0; shiftCount
-=4) {
128 char c
= gHexChars
[(val
>> shiftCount
) & 0xf];
129 outputChar(c
, outBuf
, outIx
, capacity
, 0);
133 /* Output a pointer value in hex. Work with any size of pointer */
134 static void outputPtrBytes(void *val
, char *outBuf
, int32_t *outIx
, int32_t capacity
) {
136 int32_t incVal
= 1; /* +1 for big endian, -1 for little endian */
137 char *p
= (char *)&val
; /* point to current byte to output in the ptr val */
140 /* Little Endian. Move p to most significant end of the value */
142 p
+= sizeof(void *) - 1;
145 /* Loop through the bytes of the ptr as it sits in memory, from
146 * most significant to least significant end */
147 for (i
=0; i
<sizeof(void *); i
++) {
148 outputHexBytes(*p
, 2, outBuf
, outIx
, capacity
);
153 static void outputString(const char *s
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
161 outputChar(c
, outBuf
, outIx
, capacity
, indent
);
167 static void outputUString(const UChar
*s
, int32_t len
,
168 char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
172 outputString(NULL
, outBuf
, outIx
, capacity
, indent
);
176 for (i
=0; i
<len
|| len
==-1; i
++) {
178 outputHexBytes(c
, 4, outBuf
, outIx
, capacity
);
179 outputChar(' ', outBuf
, outIx
, capacity
, indent
);
180 if (len
== -1 && c
==0) {
186 U_CAPI
int32_t U_EXPORT2
187 utrace_vformat(char *outBuf
, int32_t capacity
, int32_t indent
, const char *fmt
, va_list args
) {
196 /* Loop runs once for each character in the format string.
201 /* Literal character, not part of a %sequence. Just copy it to the output. */
202 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
204 /* We hit the null that terminates the format string.
205 * This is the normal (and only) exit from the loop that
206 * interprets the format
213 /* We encountered a '%'. Pick up the following format char */
218 /* single 8 bit char */
219 c
= (char)va_arg(args
, int32_t);
220 outputChar(c
, outBuf
, &outIx
, capacity
, indent
);
224 /* char * string, null terminated. */
225 ptrArg
= va_arg(args
, char *);
226 outputString((const char *)ptrArg
, outBuf
, &outIx
, capacity
, indent
);
230 /* UChar * string, with length, len==-1 for null terminated. */
231 ptrArg
= va_arg(args
, void *); /* Ptr */
232 intArg
=(int32_t)va_arg(args
, int32_t); /* Length */
233 outputUString((const UChar
*)ptrArg
, intArg
, outBuf
, &outIx
, capacity
, indent
);
238 intArg
= va_arg(args
, int);
239 outputHexBytes(intArg
, 2, outBuf
, &outIx
, capacity
);
244 intArg
= va_arg(args
, int);
245 outputHexBytes(intArg
, 4, outBuf
, &outIx
, capacity
);
250 intArg
= va_arg(args
, int);
251 outputHexBytes(intArg
, 8, outBuf
, &outIx
, capacity
);
256 longArg
= va_arg(args
, int64_t);
257 outputHexBytes(longArg
, 16, outBuf
, &outIx
, capacity
);
262 ptrArg
= va_arg(args
, void *);
263 outputPtrBytes(ptrArg
, outBuf
, &outIx
, capacity
);
267 /* Single '%' at end of fmt string. Output as literal '%'.
268 * Back up index into format string so that the terminating null will be
269 * re-fetched in the outer loop, causing it to terminate.
271 outputChar('%', outBuf
, &outIx
, capacity
, indent
);
277 /* Vector of values, e.g. %vh */
285 int32_t charsToOutput
= 0;
288 vectorType
= fmt
[fmtIx
]; /* b, h, d, l, p, etc. */
289 if (vectorType
!= 0) {
292 i8Ptr
= (const char *)va_arg(args
, void*);
293 i16Ptr
= (int16_t *)i8Ptr
;
294 i32Ptr
= (int32_t *)i8Ptr
;
295 i64Ptr
= (int64_t *)i8Ptr
;
296 ptrPtr
= (void **)i8Ptr
;
297 vectorLen
=(int32_t)va_arg(args
, int32_t);
298 if (ptrPtr
== NULL
) {
299 outputString("*NULL* ", outBuf
, &outIx
, capacity
, indent
);
301 for (i
=0; i
<vectorLen
|| vectorLen
==-1; i
++) {
302 switch (vectorType
) {
321 outputPtrBytes(*ptrPtr
, outBuf
, &outIx
, capacity
);
322 longArg
= *ptrPtr
==NULL
? 0: 1; /* test for null terminated array. */
327 outputChar(*i8Ptr
, outBuf
, &outIx
, capacity
, indent
);
328 longArg
= *i8Ptr
; /* for test for null terminated array. */
333 outputString(*ptrPtr
, outBuf
, &outIx
, capacity
, indent
);
334 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
335 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
341 outputUString((const UChar
*)*ptrPtr
, -1, outBuf
, &outIx
, capacity
, indent
);
342 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
343 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
349 if (charsToOutput
> 0) {
350 outputHexBytes(longArg
, charsToOutput
, outBuf
, &outIx
, capacity
);
351 outputChar(' ', outBuf
, &outIx
, capacity
, indent
);
353 if (vectorLen
== -1 && longArg
== 0) {
358 outputChar('[', outBuf
, &outIx
, capacity
, indent
);
359 outputHexBytes(vectorLen
, 8, outBuf
, &outIx
, capacity
);
360 outputChar(']', outBuf
, &outIx
, capacity
, indent
);
366 /* %. in format string, where . is some character not in the set
367 * of recognized format chars. Just output it as if % wasn't there.
368 * (Covers "%%" outputing a single '%')
370 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
373 outputChar(0, outBuf
, &outIx
, capacity
, indent
); /* Make sure that output is null terminated */
374 return outIx
+ 1; /* outIx + 1 because outIx does not increment when outputing final null. */
380 U_CAPI
int32_t U_EXPORT2
381 utrace_format(char *outBuf
, int32_t capacity
,
382 int32_t indent
, const char *fmt
, ...) {
385 va_start(args
, fmt
);
386 retVal
= utrace_vformat(outBuf
, capacity
, indent
, fmt
, args
);
392 U_CAPI
void U_EXPORT2
393 utrace_setFunctions(const void *context
,
394 UTraceEntry
*e
, UTraceExit
*x
, UTraceData
*d
) {
398 gTraceContext
= context
;
402 U_CAPI
void U_EXPORT2
403 utrace_getFunctions(const void **context
,
404 UTraceEntry
**e
, UTraceExit
**x
, UTraceData
**d
) {
405 *e
= pTraceEntryFunc
;
408 *context
= gTraceContext
;
411 U_CAPI
void U_EXPORT2
412 utrace_setLevel(int32_t level
) {
413 if (level
< UTRACE_OFF
) {
416 if (level
> UTRACE_VERBOSE
) {
417 level
= UTRACE_VERBOSE
;
419 utrace_level
= level
;
422 U_CAPI
int32_t U_EXPORT2
430 pTraceEntryFunc
= NULL
;
431 pTraceExitFunc
= NULL
;
432 pTraceDataFunc
= NULL
;
433 utrace_level
= UTRACE_OFF
;
434 gTraceContext
= NULL
;
439 static const char * const
447 static const char * const
451 "ucnv_openAlgorithmic",
461 static const char * const
468 "ucol_nextSortKeyPart",
474 U_CAPI
const char * U_EXPORT2
475 utrace_functionName(int32_t fnNumber
) {
476 if(UTRACE_FUNCTION_START
<= fnNumber
&& fnNumber
< UTRACE_FUNCTION_LIMIT
) {
477 return trFnName
[fnNumber
];
478 } else if(UTRACE_CONVERSION_START
<= fnNumber
&& fnNumber
< UTRACE_CONVERSION_LIMIT
) {
479 return trConvNames
[fnNumber
- UTRACE_CONVERSION_START
];
480 } else if(UTRACE_COLLATION_START
<= fnNumber
&& fnNumber
< UTRACE_COLLATION_LIMIT
){
481 return trCollNames
[fnNumber
- UTRACE_COLLATION_START
];
483 return "[BOGUS Trace Function Number]";