]>
git.saurik.com Git - apple/icu.git/blob - icuSources/common/utrace.cpp
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2003-2014, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
10 * tab size: 8 (not used)
14 #include "unicode/utrace.h"
21 static UTraceEntry
*pTraceEntryFunc
= NULL
;
22 static UTraceExit
*pTraceExitFunc
= NULL
;
23 static UTraceData
*pTraceDataFunc
= NULL
;
24 static const void *gTraceContext
= NULL
;
28 * Trace level variable. Negative for "off".
31 utrace_level
= UTRACE_ERROR
;
34 utrace_entry(int32_t fnNumber
) {
35 if (pTraceEntryFunc
!= NULL
) {
36 (*pTraceEntryFunc
)(gTraceContext
, fnNumber
);
41 static const char gExitFmt
[] = "Returns.";
42 static const char gExitFmtValue
[] = "Returns %d.";
43 static const char gExitFmtStatus
[] = "Returns. Status = %d.";
44 static const char gExitFmtValueStatus
[] = "Returns %d. Status = %d.";
45 static const char gExitFmtPtrStatus
[] = "Returns %d. Status = %p.";
48 utrace_exit(int32_t fnNumber
, int32_t returnType
, ...) {
49 if (pTraceExitFunc
!= NULL
) {
57 case UTRACE_EXITV_I32
:
60 case UTRACE_EXITV_STATUS
:
63 case UTRACE_EXITV_I32
| UTRACE_EXITV_STATUS
:
64 fmt
= gExitFmtValueStatus
;
66 case UTRACE_EXITV_PTR
| UTRACE_EXITV_STATUS
:
67 fmt
= gExitFmtPtrStatus
;
74 va_start(args
, returnType
);
75 (*pTraceExitFunc
)(gTraceContext
, fnNumber
, fmt
, args
);
83 utrace_data(int32_t fnNumber
, int32_t level
, const char *fmt
, ...) {
84 if (pTraceDataFunc
!= NULL
) {
87 (*pTraceDataFunc
)(gTraceContext
, fnNumber
, level
, fmt
, args
);
93 static void outputChar(char c
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
95 /* Check whether a start of line indenting is needed. Three cases:
96 * 1. At the start of the first line (output index == 0).
97 * 2. At the start of subsequent lines (preceeding char in buffer == '\n')
98 * 3. When preflighting buffer len (buffer capacity is exceeded), when
99 * a \n is output. Ideally we wouldn't do the indent until the following char
100 * is received, but that won't work because there's no place to remember that
101 * the preceding char was \n. Meaning that we may overstimate the
102 * buffer size needed. No harm done.
104 if (*outIx
==0 || /* case 1. */
105 (c
!='\n' && c
!=0 && *outIx
< capacity
&& outBuf
[(*outIx
)-1]=='\n') || /* case 2. */
106 (c
=='\n' && *outIx
>=capacity
)) /* case 3 */
108 /* At the start of a line. Indent. */
109 for(i
=0; i
<indent
; i
++) {
110 if (*outIx
< capacity
) {
111 outBuf
[*outIx
] = ' ';
117 if (*outIx
< capacity
) {
121 /* Nulls only appear as end-of-string terminators. Move them to the output
122 * buffer, but do not update the length of the buffer, so that any
123 * following output will overwrite the null. */
128 static void outputHexBytes(int64_t val
, int32_t charsToOutput
,
129 char *outBuf
, int32_t *outIx
, int32_t capacity
) {
130 static const char gHexChars
[] = "0123456789abcdef";
132 for (shiftCount
=(charsToOutput
-1)*4; shiftCount
>= 0; shiftCount
-=4) {
133 char c
= gHexChars
[(val
>> shiftCount
) & 0xf];
134 outputChar(c
, outBuf
, outIx
, capacity
, 0);
138 /* Output a pointer value in hex. Work with any size of pointer */
139 static void outputPtrBytes(void *val
, char *outBuf
, int32_t *outIx
, int32_t capacity
) {
141 int32_t incVal
= 1; /* +1 for big endian, -1 for little endian */
142 char *p
= (char *)&val
; /* point to current byte to output in the ptr val */
145 /* Little Endian. Move p to most significant end of the value */
147 p
+= sizeof(void *) - 1;
150 /* Loop through the bytes of the ptr as it sits in memory, from
151 * most significant to least significant end */
152 for (i
=0; i
<sizeof(void *); i
++) {
153 outputHexBytes(*p
, 2, outBuf
, outIx
, capacity
);
158 static void outputString(const char *s
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
166 outputChar(c
, outBuf
, outIx
, capacity
, indent
);
172 static void outputUString(const UChar
*s
, int32_t len
,
173 char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
177 outputString(NULL
, outBuf
, outIx
, capacity
, indent
);
181 for (i
=0; i
<len
|| len
==-1; i
++) {
183 outputHexBytes(c
, 4, outBuf
, outIx
, capacity
);
184 outputChar(' ', outBuf
, outIx
, capacity
, indent
);
185 if (len
== -1 && c
==0) {
191 U_CAPI
int32_t U_EXPORT2
192 utrace_vformat(char *outBuf
, int32_t capacity
, int32_t indent
, const char *fmt
, va_list args
) {
201 /* Loop runs once for each character in the format string.
206 /* Literal character, not part of a %sequence. Just copy it to the output. */
207 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
209 /* We hit the null that terminates the format string.
210 * This is the normal (and only) exit from the loop that
211 * interprets the format
218 /* We encountered a '%'. Pick up the following format char */
223 /* single 8 bit char */
224 c
= (char)va_arg(args
, int32_t);
225 outputChar(c
, outBuf
, &outIx
, capacity
, indent
);
229 /* char * string, null terminated. */
230 ptrArg
= va_arg(args
, char *);
231 outputString((const char *)ptrArg
, outBuf
, &outIx
, capacity
, indent
);
235 /* UChar * string, with length, len==-1 for null terminated. */
236 ptrArg
= va_arg(args
, char *); /* Ptr */
237 intArg
=(int32_t)va_arg(args
, int32_t); /* Length */
238 outputUString((const UChar
*)ptrArg
, intArg
, outBuf
, &outIx
, capacity
, indent
);
243 intArg
= va_arg(args
, int);
244 outputHexBytes(intArg
, 2, outBuf
, &outIx
, capacity
);
249 intArg
= va_arg(args
, int);
250 outputHexBytes(intArg
, 4, outBuf
, &outIx
, capacity
);
255 intArg
= va_arg(args
, int);
256 outputHexBytes(intArg
, 8, outBuf
, &outIx
, capacity
);
261 longArg
= va_arg(args
, int64_t);
262 outputHexBytes(longArg
, 16, outBuf
, &outIx
, capacity
);
267 ptrArg
= va_arg(args
, char *);
268 outputPtrBytes(ptrArg
, outBuf
, &outIx
, capacity
);
272 /* Single '%' at end of fmt string. Output as literal '%'.
273 * Back up index into format string so that the terminating null will be
274 * re-fetched in the outer loop, causing it to terminate.
276 outputChar('%', outBuf
, &outIx
, capacity
, indent
);
282 /* Vector of values, e.g. %vh */
290 int32_t charsToOutput
= 0;
293 vectorType
= fmt
[fmtIx
]; /* b, h, d, l, p, etc. */
294 if (vectorType
!= 0) {
297 i8Ptr
= (const char *)va_arg(args
, void*);
298 i16Ptr
= (int16_t *)i8Ptr
;
299 i32Ptr
= (int32_t *)i8Ptr
;
300 i64Ptr
= (int64_t *)i8Ptr
;
301 ptrPtr
= (void **)i8Ptr
;
302 vectorLen
=(int32_t)va_arg(args
, int32_t);
303 if (ptrPtr
== NULL
) {
304 outputString("*NULL* ", outBuf
, &outIx
, capacity
, indent
);
306 for (i
=0; i
<vectorLen
|| vectorLen
==-1; i
++) {
307 switch (vectorType
) {
326 outputPtrBytes(*ptrPtr
, outBuf
, &outIx
, capacity
);
327 longArg
= *ptrPtr
==NULL
? 0: 1; /* test for null terminated array. */
332 outputChar(*i8Ptr
, outBuf
, &outIx
, capacity
, indent
);
333 longArg
= *i8Ptr
; /* for test for null terminated array. */
338 outputString((const char *)*ptrPtr
, outBuf
, &outIx
, capacity
, indent
);
339 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
340 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
346 outputUString((const UChar
*)*ptrPtr
, -1, outBuf
, &outIx
, capacity
, indent
);
347 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
348 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
354 if (charsToOutput
> 0) {
355 outputHexBytes(longArg
, charsToOutput
, outBuf
, &outIx
, capacity
);
356 outputChar(' ', outBuf
, &outIx
, capacity
, indent
);
358 if (vectorLen
== -1 && longArg
== 0) {
363 outputChar('[', outBuf
, &outIx
, capacity
, indent
);
364 outputHexBytes(vectorLen
, 8, outBuf
, &outIx
, capacity
);
365 outputChar(']', outBuf
, &outIx
, capacity
, indent
);
371 /* %. in format string, where . is some character not in the set
372 * of recognized format chars. Just output it as if % wasn't there.
373 * (Covers "%%" outputing a single '%')
375 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
378 outputChar(0, outBuf
, &outIx
, capacity
, indent
); /* Make sure that output is null terminated */
379 return outIx
+ 1; /* outIx + 1 because outIx does not increment when outputing final null. */
385 U_CAPI
int32_t U_EXPORT2
386 utrace_format(char *outBuf
, int32_t capacity
,
387 int32_t indent
, const char *fmt
, ...) {
390 va_start(args
, fmt
);
391 retVal
= utrace_vformat(outBuf
, capacity
, indent
, fmt
, args
);
397 U_CAPI
void U_EXPORT2
398 utrace_setFunctions(const void *context
,
399 UTraceEntry
*e
, UTraceExit
*x
, UTraceData
*d
) {
403 gTraceContext
= context
;
407 U_CAPI
void U_EXPORT2
408 utrace_getFunctions(const void **context
,
409 UTraceEntry
**e
, UTraceExit
**x
, UTraceData
**d
) {
410 *e
= pTraceEntryFunc
;
413 *context
= gTraceContext
;
416 U_CAPI
void U_EXPORT2
417 utrace_setLevel(int32_t level
) {
418 if (level
< UTRACE_OFF
) {
421 if (level
> UTRACE_VERBOSE
) {
422 level
= UTRACE_VERBOSE
;
424 utrace_level
= level
;
427 U_CAPI
int32_t U_EXPORT2
435 pTraceEntryFunc
= NULL
;
436 pTraceExitFunc
= NULL
;
437 pTraceDataFunc
= NULL
;
438 utrace_level
= UTRACE_OFF
;
439 gTraceContext
= NULL
;
444 static const char * const
452 static const char * const
456 "ucnv_openAlgorithmic",
466 static const char * const
473 "ucol_nextSortKeyPart",
475 "ucol_openFromShortString",
481 U_CAPI
const char * U_EXPORT2
482 utrace_functionName(int32_t fnNumber
) {
483 if(UTRACE_FUNCTION_START
<= fnNumber
&& fnNumber
< UTRACE_FUNCTION_LIMIT
) {
484 return trFnName
[fnNumber
];
485 } else if(UTRACE_CONVERSION_START
<= fnNumber
&& fnNumber
< UTRACE_CONVERSION_LIMIT
) {
486 return trConvNames
[fnNumber
- UTRACE_CONVERSION_START
];
487 } else if(UTRACE_COLLATION_START
<= fnNumber
&& fnNumber
< UTRACE_COLLATION_LIMIT
){
488 return trCollNames
[fnNumber
- UTRACE_COLLATION_START
];
490 return "[BOGUS Trace Function Number]";