]>
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
;
73 va_start(args
, returnType
);
74 (*pTraceExitFunc
)(gTraceContext
, fnNumber
, fmt
, args
);
82 utrace_data(int32_t fnNumber
, int32_t level
, const char *fmt
, ...) {
83 if (pTraceDataFunc
!= NULL
) {
86 (*pTraceDataFunc
)(gTraceContext
, fnNumber
, level
, fmt
, args
);
92 static void outputChar(char c
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
94 /* Check whether a start of line indenting is needed. Three cases:
95 * 1. At the start of the first line (output index == 0).
96 * 2. At the start of subsequent lines (preceeding char in buffer == '\n')
97 * 3. When preflighting buffer len (buffer capacity is exceeded), when
98 * a \n is output. Ideally we wouldn't do the indent until the following char
99 * is received, but that won't work because there's no place to remember that
100 * the preceding char was \n. Meaning that we may overstimate the
101 * buffer size needed. No harm done.
103 if (*outIx
==0 || /* case 1. */
104 (c
!='\n' && c
!=0 && *outIx
< capacity
&& outBuf
[(*outIx
)-1]=='\n') || /* case 2. */
105 (c
=='\n' && *outIx
>=capacity
)) /* case 3 */
107 /* At the start of a line. Indent. */
108 for(i
=0; i
<indent
; i
++) {
109 if (*outIx
< capacity
) {
110 outBuf
[*outIx
] = ' ';
116 if (*outIx
< capacity
) {
120 /* Nulls only appear as end-of-string terminators. Move them to the output
121 * buffer, but do not update the length of the buffer, so that any
122 * following output will overwrite the null. */
127 static void outputHexBytes(int64_t val
, int32_t charsToOutput
,
128 char *outBuf
, int32_t *outIx
, int32_t capacity
) {
129 static const char gHexChars
[] = "0123456789abcdef";
131 for (shiftCount
=(charsToOutput
-1)*4; shiftCount
>= 0; shiftCount
-=4) {
132 char c
= gHexChars
[(val
>> shiftCount
) & 0xf];
133 outputChar(c
, outBuf
, outIx
, capacity
, 0);
137 /* Output a pointer value in hex. Work with any size of pointer */
138 static void outputPtrBytes(void *val
, char *outBuf
, int32_t *outIx
, int32_t capacity
) {
140 int32_t incVal
= 1; /* +1 for big endian, -1 for little endian */
141 char *p
= (char *)&val
; /* point to current byte to output in the ptr val */
144 /* Little Endian. Move p to most significant end of the value */
146 p
+= sizeof(void *) - 1;
149 /* Loop through the bytes of the ptr as it sits in memory, from
150 * most significant to least significant end */
151 for (i
=0; i
<sizeof(void *); i
++) {
152 outputHexBytes(*p
, 2, outBuf
, outIx
, capacity
);
157 static void outputString(const char *s
, char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
165 outputChar(c
, outBuf
, outIx
, capacity
, indent
);
171 static void outputUString(const UChar
*s
, int32_t len
,
172 char *outBuf
, int32_t *outIx
, int32_t capacity
, int32_t indent
) {
176 outputString(NULL
, outBuf
, outIx
, capacity
, indent
);
180 for (i
=0; i
<len
|| len
==-1; i
++) {
182 outputHexBytes(c
, 4, outBuf
, outIx
, capacity
);
183 outputChar(' ', outBuf
, outIx
, capacity
, indent
);
184 if (len
== -1 && c
==0) {
190 U_CAPI
int32_t U_EXPORT2
191 utrace_vformat(char *outBuf
, int32_t capacity
, int32_t indent
, const char *fmt
, va_list args
) {
200 /* Loop runs once for each character in the format string.
205 /* Literal character, not part of a %sequence. Just copy it to the output. */
206 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
208 /* We hit the null that terminates the format string.
209 * This is the normal (and only) exit from the loop that
210 * interprets the format
217 /* We encountered a '%'. Pick up the following format char */
222 /* single 8 bit char */
223 c
= (char)va_arg(args
, int32_t);
224 outputChar(c
, outBuf
, &outIx
, capacity
, indent
);
228 /* char * string, null terminated. */
229 ptrArg
= va_arg(args
, char *);
230 outputString((const char *)ptrArg
, outBuf
, &outIx
, capacity
, indent
);
234 /* UChar * string, with length, len==-1 for null terminated. */
235 ptrArg
= va_arg(args
, char *); /* Ptr */
236 intArg
=(int32_t)va_arg(args
, int32_t); /* Length */
237 outputUString((const UChar
*)ptrArg
, intArg
, outBuf
, &outIx
, capacity
, indent
);
242 intArg
= va_arg(args
, int);
243 outputHexBytes(intArg
, 2, outBuf
, &outIx
, capacity
);
248 intArg
= va_arg(args
, int);
249 outputHexBytes(intArg
, 4, outBuf
, &outIx
, capacity
);
254 intArg
= va_arg(args
, int);
255 outputHexBytes(intArg
, 8, outBuf
, &outIx
, capacity
);
260 longArg
= va_arg(args
, int64_t);
261 outputHexBytes(longArg
, 16, outBuf
, &outIx
, capacity
);
266 ptrArg
= va_arg(args
, char *);
267 outputPtrBytes(ptrArg
, outBuf
, &outIx
, capacity
);
271 /* Single '%' at end of fmt string. Output as literal '%'.
272 * Back up index into format string so that the terminating null will be
273 * re-fetched in the outer loop, causing it to terminate.
275 outputChar('%', outBuf
, &outIx
, capacity
, indent
);
281 /* Vector of values, e.g. %vh */
289 int32_t charsToOutput
= 0;
292 vectorType
= fmt
[fmtIx
]; /* b, h, d, l, p, etc. */
293 if (vectorType
!= 0) {
296 i8Ptr
= (const char *)va_arg(args
, void*);
297 i16Ptr
= (int16_t *)i8Ptr
;
298 i32Ptr
= (int32_t *)i8Ptr
;
299 i64Ptr
= (int64_t *)i8Ptr
;
300 ptrPtr
= (void **)i8Ptr
;
301 vectorLen
=(int32_t)va_arg(args
, int32_t);
302 if (ptrPtr
== NULL
) {
303 outputString("*NULL* ", outBuf
, &outIx
, capacity
, indent
);
305 for (i
=0; i
<vectorLen
|| vectorLen
==-1; i
++) {
306 switch (vectorType
) {
325 outputPtrBytes(*ptrPtr
, outBuf
, &outIx
, capacity
);
326 longArg
= *ptrPtr
==NULL
? 0: 1; /* test for null terminated array. */
331 outputChar(*i8Ptr
, outBuf
, &outIx
, capacity
, indent
);
332 longArg
= *i8Ptr
; /* for test for null terminated array. */
337 outputString((const char *)*ptrPtr
, outBuf
, &outIx
, capacity
, indent
);
338 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
339 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
345 outputUString((const UChar
*)*ptrPtr
, -1, outBuf
, &outIx
, capacity
, indent
);
346 outputChar('\n', outBuf
, &outIx
, capacity
, indent
);
347 longArg
= *ptrPtr
==NULL
? 0: 1; /* for test for null term. array. */
353 if (charsToOutput
> 0) {
354 outputHexBytes(longArg
, charsToOutput
, outBuf
, &outIx
, capacity
);
355 outputChar(' ', outBuf
, &outIx
, capacity
, indent
);
357 if (vectorLen
== -1 && longArg
== 0) {
362 outputChar('[', outBuf
, &outIx
, capacity
, indent
);
363 outputHexBytes(vectorLen
, 8, outBuf
, &outIx
, capacity
);
364 outputChar(']', outBuf
, &outIx
, capacity
, indent
);
370 /* %. in format string, where . is some character not in the set
371 * of recognized format chars. Just output it as if % wasn't there.
372 * (Covers "%%" outputing a single '%')
374 outputChar(fmtC
, outBuf
, &outIx
, capacity
, indent
);
377 outputChar(0, outBuf
, &outIx
, capacity
, indent
); /* Make sure that output is null terminated */
378 return outIx
+ 1; /* outIx + 1 because outIx does not increment when outputing final null. */
384 U_CAPI
int32_t U_EXPORT2
385 utrace_format(char *outBuf
, int32_t capacity
,
386 int32_t indent
, const char *fmt
, ...) {
389 va_start(args
, fmt
);
390 retVal
= utrace_vformat(outBuf
, capacity
, indent
, fmt
, args
);
396 U_CAPI
void U_EXPORT2
397 utrace_setFunctions(const void *context
,
398 UTraceEntry
*e
, UTraceExit
*x
, UTraceData
*d
) {
402 gTraceContext
= context
;
406 U_CAPI
void U_EXPORT2
407 utrace_getFunctions(const void **context
,
408 UTraceEntry
**e
, UTraceExit
**x
, UTraceData
**d
) {
409 *e
= pTraceEntryFunc
;
412 *context
= gTraceContext
;
415 U_CAPI
void U_EXPORT2
416 utrace_setLevel(int32_t level
) {
417 if (level
< UTRACE_OFF
) {
420 if (level
> UTRACE_VERBOSE
) {
421 level
= UTRACE_VERBOSE
;
423 utrace_level
= level
;
426 U_CAPI
int32_t U_EXPORT2
434 pTraceEntryFunc
= NULL
;
435 pTraceExitFunc
= NULL
;
436 pTraceDataFunc
= NULL
;
437 utrace_level
= UTRACE_OFF
;
438 gTraceContext
= NULL
;
443 static const char * const
451 static const char * const
455 "ucnv_openAlgorithmic",
465 static const char * const
472 "ucol_nextSortKeyPart",
474 "ucol_openFromShortString",
480 U_CAPI
const char * U_EXPORT2
481 utrace_functionName(int32_t fnNumber
) {
482 if(UTRACE_FUNCTION_START
<= fnNumber
&& fnNumber
< UTRACE_FUNCTION_LIMIT
) {
483 return trFnName
[fnNumber
];
484 } else if(UTRACE_CONVERSION_START
<= fnNumber
&& fnNumber
< UTRACE_CONVERSION_LIMIT
) {
485 return trConvNames
[fnNumber
- UTRACE_CONVERSION_START
];
486 } else if(UTRACE_COLLATION_START
<= fnNumber
&& fnNumber
< UTRACE_COLLATION_LIMIT
){
487 return trCollNames
[fnNumber
- UTRACE_COLLATION_START
];
489 return "[BOGUS Trace Function Number]";