intl/icu/source/common/utrace.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/common/utrace.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,486 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +*   Copyright (C) 2003-2008, International Business Machines
     1.7 +*   Corporation and others.  All Rights Reserved.
     1.8 +*******************************************************************************
     1.9 +*   file name:  utrace.c
    1.10 +*   encoding:   US-ASCII
    1.11 +*   tab size:   8 (not used)
    1.12 +*   indentation:4
    1.13 +*/
    1.14 +
    1.15 +#define   UTRACE_IMPL
    1.16 +#include "unicode/utrace.h"
    1.17 +#include "utracimp.h"
    1.18 +#include "cstring.h"
    1.19 +#include "uassert.h"
    1.20 +#include "ucln_cmn.h"
    1.21 +
    1.22 +
    1.23 +static UTraceEntry     *pTraceEntryFunc = NULL;
    1.24 +static UTraceExit      *pTraceExitFunc  = NULL;
    1.25 +static UTraceData      *pTraceDataFunc  = NULL;
    1.26 +static const void      *gTraceContext   = NULL;
    1.27 +
    1.28 +U_EXPORT int32_t
    1.29 +utrace_level = UTRACE_ERROR;
    1.30 +
    1.31 +U_CAPI void U_EXPORT2
    1.32 +utrace_entry(int32_t fnNumber) {
    1.33 +    if (pTraceEntryFunc != NULL) {
    1.34 +        (*pTraceEntryFunc)(gTraceContext, fnNumber);
    1.35 +    }
    1.36 +}
    1.37 +
    1.38 +
    1.39 +static const char gExitFmt[]             = "Returns.";
    1.40 +static const char gExitFmtValue[]        = "Returns %d.";
    1.41 +static const char gExitFmtStatus[]       = "Returns.  Status = %d.";
    1.42 +static const char gExitFmtValueStatus[]  = "Returns %d.  Status = %d.";
    1.43 +static const char gExitFmtPtrStatus[]    = "Returns %d.  Status = %p.";
    1.44 +
    1.45 +U_CAPI void U_EXPORT2
    1.46 +utrace_exit(int32_t fnNumber, int32_t returnType, ...) {
    1.47 +    if (pTraceExitFunc != NULL) {
    1.48 +        va_list     args;
    1.49 +        const char *fmt;
    1.50 +
    1.51 +        switch (returnType) {
    1.52 +        case 0:
    1.53 +            fmt = gExitFmt;
    1.54 +            break;
    1.55 +        case UTRACE_EXITV_I32:
    1.56 +            fmt = gExitFmtValue;
    1.57 +            break;
    1.58 +        case UTRACE_EXITV_STATUS:
    1.59 +            fmt = gExitFmtStatus;
    1.60 +            break;
    1.61 +        case UTRACE_EXITV_I32 | UTRACE_EXITV_STATUS:
    1.62 +            fmt = gExitFmtValueStatus;
    1.63 +            break;
    1.64 +        case UTRACE_EXITV_PTR | UTRACE_EXITV_STATUS:
    1.65 +            fmt = gExitFmtPtrStatus;
    1.66 +            break;
    1.67 +        default:
    1.68 +            U_ASSERT(FALSE);
    1.69 +            fmt = gExitFmt;
    1.70 +        }
    1.71 +
    1.72 +        va_start(args, returnType);
    1.73 +        (*pTraceExitFunc)(gTraceContext, fnNumber, fmt, args);
    1.74 +        va_end(args);
    1.75 +    }
    1.76 +}
    1.77 + 
    1.78 +
    1.79 + 
    1.80 +U_CAPI void U_EXPORT2 
    1.81 +utrace_data(int32_t fnNumber, int32_t level, const char *fmt, ...) {
    1.82 +    if (pTraceDataFunc != NULL) {
    1.83 +           va_list args;
    1.84 +           va_start(args, fmt ); 
    1.85 +           (*pTraceDataFunc)(gTraceContext, fnNumber, level, fmt, args);
    1.86 +           va_end(args);
    1.87 +    }
    1.88 +}
    1.89 +
    1.90 +
    1.91 +static void outputChar(char c, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
    1.92 +    int32_t i;
    1.93 +    /* Check whether a start of line indenting is needed.  Three cases:
    1.94 +     *   1.  At the start of the first line  (output index == 0).
    1.95 +     *   2.  At the start of subsequent lines  (preceeding char in buffer == '\n')
    1.96 +     *   3.  When preflighting buffer len (buffer capacity is exceeded), when
    1.97 +     *       a \n is output.  Ideally we wouldn't do the indent until the following char
    1.98 +     *       is received, but that won't work because there's no place to remember that
    1.99 +     *       the preceding char was \n.  Meaning that we may overstimate the
   1.100 +     *       buffer size needed.  No harm done.
   1.101 +     */
   1.102 +    if (*outIx==0 ||   /* case 1. */
   1.103 +        (c!='\n' && c!=0 && *outIx < capacity && outBuf[(*outIx)-1]=='\n') ||  /* case 2. */
   1.104 +        (c=='\n' && *outIx>=capacity))    /* case 3 */
   1.105 +    {
   1.106 +        /* At the start of a line.  Indent. */
   1.107 +        for(i=0; i<indent; i++) {
   1.108 +            if (*outIx < capacity) {
   1.109 +                outBuf[*outIx] = ' ';
   1.110 +            }
   1.111 +            (*outIx)++;
   1.112 +        }
   1.113 +    }
   1.114 +
   1.115 +    if (*outIx < capacity) {
   1.116 +        outBuf[*outIx] = c;
   1.117 +    }
   1.118 +    if (c != 0) {
   1.119 +        /* Nulls only appear as end-of-string terminators.  Move them to the output
   1.120 +         *  buffer, but do not update the length of the buffer, so that any
   1.121 +         *  following output will overwrite the null. */
   1.122 +        (*outIx)++;
   1.123 +    }
   1.124 +}
   1.125 +
   1.126 +static void outputHexBytes(int64_t val, int32_t charsToOutput,
   1.127 +                           char *outBuf, int32_t *outIx, int32_t capacity) {
   1.128 +    static const char gHexChars[] = "0123456789abcdef";
   1.129 +    int32_t shiftCount;
   1.130 +    for  (shiftCount=(charsToOutput-1)*4; shiftCount >= 0; shiftCount-=4) {
   1.131 +        char c = gHexChars[(val >> shiftCount) & 0xf];
   1.132 +        outputChar(c, outBuf, outIx, capacity, 0);
   1.133 +    }
   1.134 +}
   1.135 +
   1.136 +/* Output a pointer value in hex.  Work with any size of pointer   */
   1.137 +static void outputPtrBytes(void *val, char *outBuf, int32_t *outIx, int32_t capacity) {
   1.138 +    int32_t  i;
   1.139 +    int32_t  incVal = 1;              /* +1 for big endian, -1 for little endian          */
   1.140 +    char     *p     = (char *)&val;   /* point to current byte to output in the ptr val  */
   1.141 +
   1.142 +#if !U_IS_BIG_ENDIAN
   1.143 +    /* Little Endian.  Move p to most significant end of the value      */
   1.144 +    incVal = -1;
   1.145 +    p += sizeof(void *) - 1;
   1.146 +#endif
   1.147 +
   1.148 +    /* Loop through the bytes of the ptr as it sits in memory, from 
   1.149 +     * most significant to least significant end                    */
   1.150 +    for (i=0; i<sizeof(void *); i++) {
   1.151 +        outputHexBytes(*p, 2, outBuf, outIx, capacity);
   1.152 +        p += incVal;
   1.153 +    }
   1.154 +}
   1.155 +
   1.156 +static void outputString(const char *s, char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
   1.157 +    int32_t i = 0;
   1.158 +    char    c;
   1.159 +    if (s==NULL) {
   1.160 +        s = "*NULL*";
   1.161 +    }
   1.162 +    do {
   1.163 +        c = s[i++];
   1.164 +        outputChar(c, outBuf, outIx, capacity, indent);
   1.165 +    } while (c != 0);
   1.166 +}
   1.167 +        
   1.168 +
   1.169 +
   1.170 +static void outputUString(const UChar *s, int32_t len, 
   1.171 +                          char *outBuf, int32_t *outIx, int32_t capacity, int32_t indent) {
   1.172 +    int32_t i = 0;
   1.173 +    UChar   c;
   1.174 +    if (s==NULL) {
   1.175 +        outputString(NULL, outBuf, outIx, capacity, indent);
   1.176 +        return;
   1.177 +    }
   1.178 +
   1.179 +    for (i=0; i<len || len==-1; i++) {
   1.180 +        c = s[i];
   1.181 +        outputHexBytes(c, 4, outBuf, outIx, capacity);
   1.182 +        outputChar(' ', outBuf, outIx, capacity, indent);
   1.183 +        if (len == -1 && c==0) {
   1.184 +            break;
   1.185 +        }
   1.186 +    }
   1.187 +}
   1.188 +        
   1.189 +U_CAPI int32_t U_EXPORT2
   1.190 +utrace_vformat(char *outBuf, int32_t capacity, int32_t indent, const char *fmt, va_list args) {
   1.191 +    int32_t   outIx  = 0;
   1.192 +    int32_t   fmtIx  = 0;
   1.193 +    char      fmtC;
   1.194 +    char      c;
   1.195 +    int32_t   intArg;
   1.196 +    int64_t   longArg = 0;
   1.197 +    char      *ptrArg;
   1.198 +
   1.199 +    /*   Loop runs once for each character in the format string.
   1.200 +     */
   1.201 +    for (;;) {
   1.202 +        fmtC = fmt[fmtIx++];
   1.203 +        if (fmtC != '%') {
   1.204 +            /* Literal character, not part of a %sequence.  Just copy it to the output. */
   1.205 +            outputChar(fmtC, outBuf, &outIx, capacity, indent);
   1.206 +            if (fmtC == 0) {
   1.207 +                /* We hit the null that terminates the format string.
   1.208 +                 * This is the normal (and only) exit from the loop that
   1.209 +                 * interprets the format
   1.210 +                 */
   1.211 +                break;
   1.212 +            }
   1.213 +            continue;
   1.214 +        }
   1.215 +
   1.216 +        /* We encountered a '%'.  Pick up the following format char */
   1.217 +        fmtC = fmt[fmtIx++];
   1.218 +
   1.219 +        switch (fmtC) {
   1.220 +        case 'c':
   1.221 +            /* single 8 bit char   */
   1.222 +            c = (char)va_arg(args, int32_t);
   1.223 +            outputChar(c, outBuf, &outIx, capacity, indent);
   1.224 +            break;
   1.225 +
   1.226 +        case 's':
   1.227 +            /* char * string, null terminated.  */
   1.228 +            ptrArg = va_arg(args, char *);
   1.229 +            outputString((const char *)ptrArg, outBuf, &outIx, capacity, indent);
   1.230 +            break;
   1.231 +
   1.232 +        case 'S':
   1.233 +            /* UChar * string, with length, len==-1 for null terminated. */
   1.234 +            ptrArg = va_arg(args, void *);             /* Ptr    */
   1.235 +            intArg =(int32_t)va_arg(args, int32_t);    /* Length */
   1.236 +            outputUString((const UChar *)ptrArg, intArg, outBuf, &outIx, capacity, indent);
   1.237 +            break;
   1.238 +
   1.239 +        case 'b':
   1.240 +            /*  8 bit int  */
   1.241 +            intArg = va_arg(args, int);
   1.242 +            outputHexBytes(intArg, 2, outBuf, &outIx, capacity);
   1.243 +            break;
   1.244 +
   1.245 +        case 'h':
   1.246 +            /*  16 bit int  */
   1.247 +            intArg = va_arg(args, int);
   1.248 +            outputHexBytes(intArg, 4, outBuf, &outIx, capacity);
   1.249 +            break;
   1.250 +
   1.251 +        case 'd':
   1.252 +            /*  32 bit int  */
   1.253 +            intArg = va_arg(args, int);
   1.254 +            outputHexBytes(intArg, 8, outBuf, &outIx, capacity);
   1.255 +            break;
   1.256 +
   1.257 +        case 'l':
   1.258 +            /*  64 bit long  */
   1.259 +            longArg = va_arg(args, int64_t);
   1.260 +            outputHexBytes(longArg, 16, outBuf, &outIx, capacity);
   1.261 +            break;
   1.262 +            
   1.263 +        case 'p':
   1.264 +            /*  Pointers.   */
   1.265 +            ptrArg = va_arg(args, void *);
   1.266 +            outputPtrBytes(ptrArg, outBuf, &outIx, capacity);
   1.267 +            break;
   1.268 +
   1.269 +        case 0:
   1.270 +            /* Single '%' at end of fmt string.  Output as literal '%'.   
   1.271 +             * Back up index into format string so that the terminating null will be
   1.272 +             * re-fetched in the outer loop, causing it to terminate.
   1.273 +             */
   1.274 +            outputChar('%', outBuf, &outIx, capacity, indent);
   1.275 +            fmtIx--;
   1.276 +            break;
   1.277 +
   1.278 +        case 'v':
   1.279 +            {
   1.280 +                /* Vector of values, e.g. %vh */
   1.281 +                char     vectorType;
   1.282 +                int32_t  vectorLen;
   1.283 +                const char   *i8Ptr;
   1.284 +                int16_t  *i16Ptr;
   1.285 +                int32_t  *i32Ptr;
   1.286 +                int64_t  *i64Ptr;
   1.287 +                void     **ptrPtr;
   1.288 +                int32_t   charsToOutput = 0;
   1.289 +                int32_t   i;
   1.290 +                
   1.291 +                vectorType = fmt[fmtIx];    /* b, h, d, l, p, etc. */
   1.292 +                if (vectorType != 0) {
   1.293 +                    fmtIx++;
   1.294 +                }
   1.295 +                i8Ptr = (const char *)va_arg(args, void*);
   1.296 +                i16Ptr = (int16_t *)i8Ptr;
   1.297 +                i32Ptr = (int32_t *)i8Ptr;
   1.298 +                i64Ptr = (int64_t *)i8Ptr;
   1.299 +                ptrPtr = (void **)i8Ptr;
   1.300 +                vectorLen =(int32_t)va_arg(args, int32_t);
   1.301 +                if (ptrPtr == NULL) {
   1.302 +                    outputString("*NULL* ", outBuf, &outIx, capacity, indent);
   1.303 +                } else {
   1.304 +                    for (i=0; i<vectorLen || vectorLen==-1; i++) { 
   1.305 +                        switch (vectorType) {
   1.306 +                        case 'b':
   1.307 +                            charsToOutput = 2;
   1.308 +                            longArg = *i8Ptr++;
   1.309 +                            break;
   1.310 +                        case 'h':
   1.311 +                            charsToOutput = 4;
   1.312 +                            longArg = *i16Ptr++;
   1.313 +                            break;
   1.314 +                        case 'd':
   1.315 +                            charsToOutput = 8;
   1.316 +                            longArg = *i32Ptr++;
   1.317 +                            break;
   1.318 +                        case 'l':
   1.319 +                            charsToOutput = 16;
   1.320 +                            longArg = *i64Ptr++;
   1.321 +                            break;
   1.322 +                        case 'p':
   1.323 +                            charsToOutput = 0;
   1.324 +                            outputPtrBytes(*ptrPtr, outBuf, &outIx, capacity);
   1.325 +                            longArg = *ptrPtr==NULL? 0: 1;    /* test for null terminated array. */
   1.326 +                            ptrPtr++;
   1.327 +                            break;
   1.328 +                        case 'c':
   1.329 +                            charsToOutput = 0;
   1.330 +                            outputChar(*i8Ptr, outBuf, &outIx, capacity, indent);
   1.331 +                            longArg = *i8Ptr;    /* for test for null terminated array. */
   1.332 +                            i8Ptr++;
   1.333 +                            break;
   1.334 +                        case 's':
   1.335 +                            charsToOutput = 0;
   1.336 +                            outputString(*ptrPtr, outBuf, &outIx, capacity, indent);
   1.337 +                            outputChar('\n', outBuf, &outIx, capacity, indent);
   1.338 +                            longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */
   1.339 +                            ptrPtr++;
   1.340 +                            break;
   1.341 +
   1.342 +                        case 'S':
   1.343 +                            charsToOutput = 0;
   1.344 +                            outputUString((const UChar *)*ptrPtr, -1, outBuf, &outIx, capacity, indent);
   1.345 +                            outputChar('\n', outBuf, &outIx, capacity, indent);
   1.346 +                            longArg = *ptrPtr==NULL? 0: 1;   /* for test for null term. array. */
   1.347 +                            ptrPtr++;
   1.348 +                            break;
   1.349 +
   1.350 +                            
   1.351 +                        }
   1.352 +                        if (charsToOutput > 0) {
   1.353 +                            outputHexBytes(longArg, charsToOutput, outBuf, &outIx, capacity);
   1.354 +                            outputChar(' ', outBuf, &outIx, capacity, indent);
   1.355 +                        }
   1.356 +                        if (vectorLen == -1 && longArg == 0) {
   1.357 +                            break;
   1.358 +                        }
   1.359 +                    }
   1.360 +                }
   1.361 +                outputChar('[', outBuf, &outIx, capacity, indent);
   1.362 +                outputHexBytes(vectorLen, 8, outBuf, &outIx, capacity);
   1.363 +                outputChar(']', outBuf, &outIx, capacity, indent);
   1.364 +            }
   1.365 +            break;
   1.366 +
   1.367 +
   1.368 +        default:
   1.369 +            /* %. in format string, where . is some character not in the set
   1.370 +             *    of recognized format chars.  Just output it as if % wasn't there.
   1.371 +             *    (Covers "%%" outputing a single '%')
   1.372 +             */
   1.373 +             outputChar(fmtC, outBuf, &outIx, capacity, indent);
   1.374 +        }
   1.375 +    }
   1.376 +    outputChar(0, outBuf, &outIx, capacity, indent);  /* Make sure that output is null terminated  */
   1.377 +    return outIx + 1;     /* outIx + 1 because outIx does not increment when outputing final null. */
   1.378 +}
   1.379 +
   1.380 +
   1.381 +
   1.382 +
   1.383 +U_CAPI int32_t U_EXPORT2
   1.384 +utrace_format(char *outBuf, int32_t capacity,
   1.385 +                int32_t indent, const char *fmt,  ...) {
   1.386 +    int32_t retVal;
   1.387 +    va_list args;
   1.388 +    va_start(args, fmt ); 
   1.389 +    retVal = utrace_vformat(outBuf, capacity, indent, fmt, args);
   1.390 +    va_end(args);
   1.391 +    return retVal;
   1.392 +}
   1.393 +
   1.394 +
   1.395 +U_CAPI void U_EXPORT2
   1.396 +utrace_setFunctions(const void *context,
   1.397 +                    UTraceEntry *e, UTraceExit *x, UTraceData *d) {
   1.398 +    pTraceEntryFunc = e;
   1.399 +    pTraceExitFunc  = x;
   1.400 +    pTraceDataFunc  = d;
   1.401 +    gTraceContext   = context;
   1.402 +}
   1.403 +
   1.404 +
   1.405 +U_CAPI void U_EXPORT2
   1.406 +utrace_getFunctions(const void **context,
   1.407 +                    UTraceEntry **e, UTraceExit **x, UTraceData **d) {
   1.408 +    *e = pTraceEntryFunc;
   1.409 +    *x = pTraceExitFunc;
   1.410 +    *d = pTraceDataFunc;
   1.411 +    *context = gTraceContext;
   1.412 +}
   1.413 +
   1.414 +U_CAPI void U_EXPORT2
   1.415 +utrace_setLevel(int32_t level) {
   1.416 +    if (level < UTRACE_OFF) {
   1.417 +        level = UTRACE_OFF;
   1.418 +    }
   1.419 +    if (level > UTRACE_VERBOSE) {
   1.420 +        level = UTRACE_VERBOSE;
   1.421 +    }
   1.422 +    utrace_level = level;
   1.423 +}
   1.424 +
   1.425 +U_CAPI int32_t U_EXPORT2
   1.426 +utrace_getLevel() {
   1.427 +    return utrace_level;
   1.428 +}
   1.429 +
   1.430 +
   1.431 +U_CFUNC UBool 
   1.432 +utrace_cleanup() {
   1.433 +    pTraceEntryFunc = NULL;
   1.434 +    pTraceExitFunc  = NULL;
   1.435 +    pTraceDataFunc  = NULL;
   1.436 +    utrace_level    = UTRACE_OFF;
   1.437 +    gTraceContext   = NULL;
   1.438 +    return TRUE;
   1.439 +}
   1.440 +
   1.441 +
   1.442 +static const char * const
   1.443 +trFnName[] = {
   1.444 +    "u_init",
   1.445 +    "u_cleanup",
   1.446 +    NULL
   1.447 +};
   1.448 +
   1.449 +
   1.450 +static const char * const
   1.451 +trConvNames[] = {
   1.452 +    "ucnv_open",
   1.453 +    "ucnv_openPackage",
   1.454 +    "ucnv_openAlgorithmic",
   1.455 +    "ucnv_clone",
   1.456 +    "ucnv_close",
   1.457 +    "ucnv_flushCache",
   1.458 +    "ucnv_load",
   1.459 +    "ucnv_unload",
   1.460 +    NULL
   1.461 +};
   1.462 +
   1.463 +    
   1.464 +static const char * const
   1.465 +trCollNames[] = {
   1.466 +    "ucol_open",
   1.467 +    "ucol_close",
   1.468 +    "ucol_strcoll",
   1.469 +    "ucol_getSortKey",
   1.470 +    "ucol_getLocale",
   1.471 +    "ucol_nextSortKeyPart",
   1.472 +    "ucol_strcollIter",
   1.473 +    NULL
   1.474 +};
   1.475 +
   1.476 +                
   1.477 +U_CAPI const char * U_EXPORT2
   1.478 +utrace_functionName(int32_t fnNumber) {
   1.479 +    if(UTRACE_FUNCTION_START <= fnNumber && fnNumber < UTRACE_FUNCTION_LIMIT) {
   1.480 +        return trFnName[fnNumber];
   1.481 +    } else if(UTRACE_CONVERSION_START <= fnNumber && fnNumber < UTRACE_CONVERSION_LIMIT) {
   1.482 +        return trConvNames[fnNumber - UTRACE_CONVERSION_START];
   1.483 +    } else if(UTRACE_COLLATION_START <= fnNumber && fnNumber < UTRACE_COLLATION_LIMIT){
   1.484 +        return trCollNames[fnNumber - UTRACE_COLLATION_START];
   1.485 +    } else {
   1.486 +        return "[BOGUS Trace Function Number]";
   1.487 +    }
   1.488 +}
   1.489 +

mercurial