intl/icu/source/io/uprntf_p.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/io/uprntf_p.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1589 @@
     1.4 +/*
     1.5 +******************************************************************************
     1.6 +*
     1.7 +*   Copyright (C) 1998-2011, International Business Machines
     1.8 +*   Corporation and others.  All Rights Reserved.
     1.9 +*
    1.10 +******************************************************************************
    1.11 +*
    1.12 +* File uprntf_p.c
    1.13 +*
    1.14 +* Modification History:
    1.15 +*
    1.16 +*   Date        Name        Description
    1.17 +*   11/23/98    stephen     Creation.
    1.18 +*   03/12/99    stephen     Modified for new C API.
    1.19 +*   08/07/2003  george      Reunify printf implementations
    1.20 +******************************************************************************
    1.21 +*/
    1.22 +
    1.23 +#include "unicode/utypes.h"
    1.24 +
    1.25 +#if !UCONFIG_NO_FORMATTING
    1.26 +
    1.27 +#include "unicode/ustring.h"
    1.28 +#include "unicode/utf16.h"
    1.29 +#include "uprintf.h"
    1.30 +#include "ufmt_cmn.h"
    1.31 +#include "cmemory.h"
    1.32 +#include "putilimp.h"
    1.33 +
    1.34 +/* ANSI style formatting */
    1.35 +/* Use US-ASCII characters only for formatting */
    1.36 +
    1.37 +/* % */
    1.38 +#define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
    1.39 +/* s */
    1.40 +#define UFMT_STRING         {ufmt_string, u_printf_string_handler}
    1.41 +/* c */
    1.42 +#define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
    1.43 +/* d, i */
    1.44 +#define UFMT_INT            {ufmt_int, u_printf_integer_handler}
    1.45 +/* u */
    1.46 +#define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
    1.47 +/* o */
    1.48 +#define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
    1.49 +/* x, X */
    1.50 +#define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
    1.51 +/* f */
    1.52 +#define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
    1.53 +/* e, E */
    1.54 +#define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
    1.55 +/* g, G */
    1.56 +#define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
    1.57 +/* n */
    1.58 +#define UFMT_COUNT          {ufmt_count, u_printf_count_handler}
    1.59 +
    1.60 +/* non-ANSI extensions */
    1.61 +/* Use US-ASCII characters only for formatting */
    1.62 +
    1.63 +/* p */
    1.64 +#define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
    1.65 +/* V */
    1.66 +#define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
    1.67 +/* P */
    1.68 +#define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
    1.69 +/* C  K is old format */
    1.70 +#define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
    1.71 +/* S  U is old format */
    1.72 +#define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}
    1.73 +
    1.74 +
    1.75 +#define UFMT_EMPTY {ufmt_empty, NULL}
    1.76 +
    1.77 +/**
    1.78 + * A u_printf handler function.  
    1.79 + * A u_printf handler is responsible for handling a single u_printf 
    1.80 + * format specification, for example 'd' or 's'.
    1.81 + * @param stream The UFILE to which to write output.
    1.82 + * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
    1.83 + * information on the format specification.
    1.84 + * @param args A pointer to the argument data
    1.85 + * @return The number of Unicode characters written to <TT>stream</TT>.
    1.86 + */
    1.87 +typedef int32_t U_EXPORT2
    1.88 +u_printf_handler(const u_printf_stream_handler  *handler,
    1.89 +
    1.90 +                 void                           *context,
    1.91 +                 ULocaleBundle                  *formatBundle,
    1.92 +                 const u_printf_spec_info       *info,
    1.93 +                 const ufmt_args                *args);
    1.94 +
    1.95 +typedef struct u_printf_info {
    1.96 +    ufmt_type_info info;
    1.97 +    u_printf_handler *handler;
    1.98 +} u_printf_info;
    1.99 +
   1.100 +/**
   1.101 + * Struct encapsulating a single uprintf format specification.
   1.102 + */
   1.103 +typedef struct u_printf_spec {
   1.104 +  u_printf_spec_info    fInfo;        /* Information on this spec */
   1.105 +  int32_t        fWidthPos;     /* Position of width in arg list */
   1.106 +  int32_t        fPrecisionPos;    /* Position of precision in arg list */
   1.107 +  int32_t        fArgPos;    /* Position of data in arg list */
   1.108 +} u_printf_spec;
   1.109 +
   1.110 +#define UPRINTF_NUM_FMT_HANDLERS 108
   1.111 +
   1.112 +/* We do not use handlers for 0-0x1f */
   1.113 +#define UPRINTF_BASE_FMT_HANDLERS 0x20
   1.114 +
   1.115 +/* buffer size for formatting */
   1.116 +#define UPRINTF_BUFFER_SIZE 1024
   1.117 +#define UPRINTF_SYMBOL_BUFFER_SIZE 8
   1.118 +
   1.119 +static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
   1.120 +static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
   1.121 +
   1.122 +/* Sets the sign of a format based on u_printf_spec_info */
   1.123 +/* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
   1.124 +static void
   1.125 +u_printf_set_sign(UNumberFormat        *format,
   1.126 +                   const u_printf_spec_info     *info,
   1.127 +                   UChar *prefixBuffer,
   1.128 +                   int32_t *prefixBufLen,
   1.129 +                   UErrorCode *status)
   1.130 +{
   1.131 +    if(info->fShowSign) {
   1.132 +        *prefixBufLen = unum_getTextAttribute(format,
   1.133 +                                              UNUM_POSITIVE_PREFIX,
   1.134 +                                              prefixBuffer,
   1.135 +                                              *prefixBufLen,
   1.136 +                                              status);
   1.137 +        if (info->fSpace) {
   1.138 +            /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
   1.139 +            /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
   1.140 +            unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
   1.141 +        }
   1.142 +        else {
   1.143 +            UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
   1.144 +            int32_t symbolLen;
   1.145 +
   1.146 +            symbolLen = unum_getSymbol(format,
   1.147 +                UNUM_PLUS_SIGN_SYMBOL,
   1.148 +                plusSymbol,
   1.149 +                sizeof(plusSymbol)/sizeof(*plusSymbol),
   1.150 +                status);
   1.151 +            unum_setTextAttribute(format,
   1.152 +                UNUM_POSITIVE_PREFIX,
   1.153 +                plusSymbol,
   1.154 +                symbolLen,
   1.155 +                status);
   1.156 +        }
   1.157 +    }
   1.158 +    else {
   1.159 +        *prefixBufLen = 0;
   1.160 +    }
   1.161 +}
   1.162 +
   1.163 +static void
   1.164 +u_printf_reset_sign(UNumberFormat        *format,
   1.165 +                   const u_printf_spec_info     *info,
   1.166 +                   UChar *prefixBuffer,
   1.167 +                   int32_t *prefixBufLen,
   1.168 +                   UErrorCode *status)
   1.169 +{
   1.170 +    if(info->fShowSign) {
   1.171 +        unum_setTextAttribute(format,
   1.172 +                              UNUM_POSITIVE_PREFIX,
   1.173 +                              prefixBuffer,
   1.174 +                              *prefixBufLen,
   1.175 +                              status);
   1.176 +    }
   1.177 +}
   1.178 +
   1.179 +
   1.180 +/* handle a '%' */
   1.181 +static int32_t
   1.182 +u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
   1.183 +                                void                           *context,
   1.184 +                                ULocaleBundle                  *formatBundle,
   1.185 +                                const u_printf_spec_info       *info,
   1.186 +                                const ufmt_args                *args)
   1.187 +{
   1.188 +    static const UChar PERCENT[] = { UP_PERCENT };
   1.189 +
   1.190 +    /* put a single '%' onto the output */
   1.191 +    return handler->write(context, PERCENT, 1);
   1.192 +}
   1.193 +
   1.194 +/* handle 's' */
   1.195 +static int32_t
   1.196 +u_printf_string_handler(const u_printf_stream_handler  *handler,
   1.197 +                        void                           *context,
   1.198 +                        ULocaleBundle                  *formatBundle,
   1.199 +                        const u_printf_spec_info       *info,
   1.200 +                        const ufmt_args                *args)
   1.201 +{
   1.202 +    UChar *s;
   1.203 +    UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
   1.204 +    int32_t len, written;
   1.205 +    int32_t argSize;
   1.206 +    const char *arg = (const char*)(args[0].ptrValue);
   1.207 +
   1.208 +    /* convert from the default codepage to Unicode */
   1.209 +    if (arg) {
   1.210 +        argSize = (int32_t)strlen(arg) + 1;
   1.211 +        if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
   1.212 +            s = ufmt_defaultCPToUnicode(arg, argSize,
   1.213 +                    (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
   1.214 +                    MAX_UCHAR_BUFFER_NEEDED(argSize));
   1.215 +            if(s == NULL) {
   1.216 +                return 0;
   1.217 +            }
   1.218 +        }
   1.219 +        else {
   1.220 +            s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
   1.221 +                    sizeof(buffer)/sizeof(UChar));
   1.222 +        }
   1.223 +    }
   1.224 +    else {
   1.225 +        s = (UChar *)gNullStr;
   1.226 +    }
   1.227 +    len = u_strlen(s);
   1.228 +
   1.229 +    /* width = minimum # of characters to write */
   1.230 +    /* precision = maximum # of characters to write */
   1.231 +    if (info->fPrecision != -1 && info->fPrecision < len) {
   1.232 +        len = info->fPrecision;
   1.233 +    }
   1.234 +
   1.235 +    written = handler->pad_and_justify(context, info, s, len);
   1.236 +
   1.237 +    /* clean up */
   1.238 +    if (gNullStr != s && buffer != s) {
   1.239 +        uprv_free(s);
   1.240 +    }
   1.241 +
   1.242 +    return written;
   1.243 +}
   1.244 +
   1.245 +static int32_t
   1.246 +u_printf_char_handler(const u_printf_stream_handler  *handler,
   1.247 +                      void                           *context,
   1.248 +                      ULocaleBundle                  *formatBundle,
   1.249 +                      const u_printf_spec_info       *info,
   1.250 +                      const ufmt_args                *args)
   1.251 +{
   1.252 +    UChar s[U16_MAX_LENGTH+1];
   1.253 +    int32_t len = 1, written;
   1.254 +    unsigned char arg = (unsigned char)(args[0].int64Value);
   1.255 +
   1.256 +    /* convert from default codepage to Unicode */
   1.257 +    ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
   1.258 +
   1.259 +    /* Remember that this may be an MBCS character */
   1.260 +    if (arg != 0) {
   1.261 +        len = u_strlen(s);
   1.262 +    }
   1.263 +
   1.264 +    /* width = minimum # of characters to write */
   1.265 +    /* precision = maximum # of characters to write */
   1.266 +    /* precision is ignored when handling a char */
   1.267 +
   1.268 +    written = handler->pad_and_justify(context, info, s, len);
   1.269 +
   1.270 +    return written;
   1.271 +}
   1.272 +
   1.273 +static int32_t
   1.274 +u_printf_double_handler(const u_printf_stream_handler  *handler,
   1.275 +                        void                           *context,
   1.276 +                        ULocaleBundle                  *formatBundle,
   1.277 +                        const u_printf_spec_info       *info,
   1.278 +                        const ufmt_args                *args)
   1.279 +{
   1.280 +    double        num         = (double) (args[0].doubleValue);
   1.281 +    UNumberFormat  *format;
   1.282 +    UChar          result[UPRINTF_BUFFER_SIZE];
   1.283 +    UChar          prefixBuffer[UPRINTF_BUFFER_SIZE];
   1.284 +    int32_t        prefixBufferLen = sizeof(prefixBuffer);
   1.285 +    int32_t        minDecimalDigits;
   1.286 +    int32_t        maxDecimalDigits;
   1.287 +    int32_t        resultLen;
   1.288 +    UErrorCode     status        = U_ZERO_ERROR;
   1.289 +
   1.290 +    prefixBuffer[0] = 0;
   1.291 +
   1.292 +    /* mask off any necessary bits */
   1.293 +    /*  if(! info->fIsLongDouble)
   1.294 +    num &= DBL_MAX;*/
   1.295 +
   1.296 +    /* get the formatter */
   1.297 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
   1.298 +
   1.299 +    /* handle error */
   1.300 +    if(format == 0)
   1.301 +        return 0;
   1.302 +
   1.303 +    /* save the formatter's state */
   1.304 +    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
   1.305 +    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
   1.306 +
   1.307 +    /* set the appropriate flags and number of decimal digits on the formatter */
   1.308 +    if(info->fPrecision != -1) {
   1.309 +        /* set the # of decimal digits */
   1.310 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
   1.311 +    }
   1.312 +    else if(info->fAlt) {
   1.313 +        /* '#' means always show decimal point */
   1.314 +        /* copy of printf behavior on Solaris - '#' shows 6 digits */
   1.315 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.316 +    }
   1.317 +    else {
   1.318 +        /* # of decimal digits is 6 if precision not specified regardless of locale */
   1.319 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.320 +    }
   1.321 +
   1.322 +    /* set whether to show the sign */
   1.323 +    if (info->fShowSign) {
   1.324 +        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
   1.325 +    }
   1.326 +
   1.327 +    /* format the number */
   1.328 +    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.329 +
   1.330 +    if (U_FAILURE(status)) {
   1.331 +        resultLen = 0;
   1.332 +    }
   1.333 +
   1.334 +    /* restore the number format */
   1.335 +    /* TODO: Is this needed? */
   1.336 +    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
   1.337 +    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
   1.338 +
   1.339 +    if (info->fShowSign) {
   1.340 +        /* Reset back to original value regardless of what the error was */
   1.341 +        UErrorCode localStatus = U_ZERO_ERROR;
   1.342 +        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
   1.343 +    }
   1.344 +
   1.345 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.346 +}
   1.347 +
   1.348 +/* HSYS */
   1.349 +static int32_t
   1.350 +u_printf_integer_handler(const u_printf_stream_handler  *handler,
   1.351 +                         void                           *context,
   1.352 +                         ULocaleBundle                  *formatBundle,
   1.353 +                         const u_printf_spec_info       *info,
   1.354 +                         const ufmt_args                *args)
   1.355 +{
   1.356 +    int64_t         num        = args[0].int64Value;
   1.357 +    UNumberFormat   *format;
   1.358 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.359 +    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
   1.360 +    int32_t         prefixBufferLen = sizeof(prefixBuffer);
   1.361 +    int32_t         minDigits     = -1;
   1.362 +    int32_t         resultLen;
   1.363 +    UErrorCode      status        = U_ZERO_ERROR;
   1.364 +
   1.365 +    prefixBuffer[0] = 0;
   1.366 +
   1.367 +    /* mask off any necessary bits */
   1.368 +    if (info->fIsShort)
   1.369 +        num = (int16_t)num;
   1.370 +    else if (!info->fIsLongLong)
   1.371 +        num = (int32_t)num;
   1.372 +
   1.373 +    /* get the formatter */
   1.374 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
   1.375 +
   1.376 +    /* handle error */
   1.377 +    if(format == 0)
   1.378 +        return 0;
   1.379 +
   1.380 +    /* set the appropriate flags on the formatter */
   1.381 +
   1.382 +    /* set the minimum integer digits */
   1.383 +    if(info->fPrecision != -1) {
   1.384 +        /* set the minimum # of digits */
   1.385 +        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
   1.386 +        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
   1.387 +    }
   1.388 +
   1.389 +    /* set whether to show the sign */
   1.390 +    if(info->fShowSign) {
   1.391 +        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
   1.392 +    }
   1.393 +
   1.394 +    /* format the number */
   1.395 +    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.396 +
   1.397 +    if (U_FAILURE(status)) {
   1.398 +        resultLen = 0;
   1.399 +    }
   1.400 +
   1.401 +    /* restore the number format */
   1.402 +    if (minDigits != -1) {
   1.403 +        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
   1.404 +    }
   1.405 +
   1.406 +    if (info->fShowSign) {
   1.407 +        /* Reset back to original value regardless of what the error was */
   1.408 +        UErrorCode localStatus = U_ZERO_ERROR;
   1.409 +        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
   1.410 +    }
   1.411 +
   1.412 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.413 +}
   1.414 +
   1.415 +static int32_t
   1.416 +u_printf_hex_handler(const u_printf_stream_handler  *handler,
   1.417 +                     void                           *context,
   1.418 +                     ULocaleBundle                  *formatBundle,
   1.419 +                     const u_printf_spec_info       *info,
   1.420 +                     const ufmt_args                *args)
   1.421 +{
   1.422 +    int64_t         num        = args[0].int64Value;
   1.423 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.424 +    int32_t         len        = UPRINTF_BUFFER_SIZE;
   1.425 +
   1.426 +
   1.427 +    /* mask off any necessary bits */
   1.428 +    if (info->fIsShort)
   1.429 +        num &= UINT16_MAX;
   1.430 +    else if (!info->fIsLongLong)
   1.431 +        num &= UINT32_MAX;
   1.432 +
   1.433 +    /* format the number, preserving the minimum # of digits */
   1.434 +    ufmt_64tou(result, &len, num, 16,
   1.435 +        (UBool)(info->fSpec == 0x0078),
   1.436 +        (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
   1.437 +
   1.438 +    /* convert to alt form, if desired */
   1.439 +    if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
   1.440 +        /* shift the formatted string right by 2 chars */
   1.441 +        memmove(result + 2, result, len * sizeof(UChar));
   1.442 +        result[0] = 0x0030;
   1.443 +        result[1] = info->fSpec;
   1.444 +        len += 2;
   1.445 +    }
   1.446 +
   1.447 +    return handler->pad_and_justify(context, info, result, len);
   1.448 +}
   1.449 +
   1.450 +static int32_t
   1.451 +u_printf_octal_handler(const u_printf_stream_handler  *handler,
   1.452 +                       void                           *context,
   1.453 +                       ULocaleBundle                  *formatBundle,
   1.454 +                       const u_printf_spec_info       *info,
   1.455 +                       const ufmt_args                *args)
   1.456 +{
   1.457 +    int64_t         num        = args[0].int64Value;
   1.458 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.459 +    int32_t         len        = UPRINTF_BUFFER_SIZE;
   1.460 +
   1.461 +
   1.462 +    /* mask off any necessary bits */
   1.463 +    if (info->fIsShort)
   1.464 +        num &= UINT16_MAX;
   1.465 +    else if (!info->fIsLongLong)
   1.466 +        num &= UINT32_MAX;
   1.467 +
   1.468 +    /* format the number, preserving the minimum # of digits */
   1.469 +    ufmt_64tou(result, &len, num, 8,
   1.470 +        FALSE, /* doesn't matter for octal */
   1.471 +        info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
   1.472 +
   1.473 +    /* convert to alt form, if desired */
   1.474 +    if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
   1.475 +        /* shift the formatted string right by 1 char */
   1.476 +        memmove(result + 1, result, len * sizeof(UChar));
   1.477 +        result[0] = 0x0030;
   1.478 +        len += 1;
   1.479 +    }
   1.480 +
   1.481 +    return handler->pad_and_justify(context, info, result, len);
   1.482 +}
   1.483 +
   1.484 +static int32_t
   1.485 +u_printf_uinteger_handler(const u_printf_stream_handler *handler,
   1.486 +                          void                          *context,
   1.487 +                          ULocaleBundle                 *formatBundle,
   1.488 +                          const u_printf_spec_info      *info,
   1.489 +                          const ufmt_args               *args)
   1.490 +{
   1.491 +    int64_t         num        = args[0].int64Value;
   1.492 +    UNumberFormat   *format;
   1.493 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.494 +    int32_t         minDigits     = -1;
   1.495 +    int32_t         resultLen;
   1.496 +    UErrorCode      status        = U_ZERO_ERROR;
   1.497 +
   1.498 +    /* TODO: Fix this once uint64_t can be formatted. */
   1.499 +    if (info->fIsShort)
   1.500 +        num &= UINT16_MAX;
   1.501 +    else if (!info->fIsLongLong)
   1.502 +        num &= UINT32_MAX;
   1.503 +
   1.504 +    /* get the formatter */
   1.505 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
   1.506 +
   1.507 +    /* handle error */
   1.508 +    if(format == 0)
   1.509 +        return 0;
   1.510 +
   1.511 +    /* set the appropriate flags on the formatter */
   1.512 +
   1.513 +    /* set the minimum integer digits */
   1.514 +    if(info->fPrecision != -1) {
   1.515 +        /* set the minimum # of digits */
   1.516 +        minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
   1.517 +        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
   1.518 +    }
   1.519 +
   1.520 +    /* To mirror other stdio implementations, we ignore the sign argument */
   1.521 +
   1.522 +    /* format the number */
   1.523 +    resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.524 +
   1.525 +    if (U_FAILURE(status)) {
   1.526 +        resultLen = 0;
   1.527 +    }
   1.528 +
   1.529 +    /* restore the number format */
   1.530 +    if (minDigits != -1) {
   1.531 +        unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
   1.532 +    }
   1.533 +
   1.534 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.535 +}
   1.536 +
   1.537 +static int32_t
   1.538 +u_printf_pointer_handler(const u_printf_stream_handler  *handler,
   1.539 +                         void                           *context,
   1.540 +                         ULocaleBundle                  *formatBundle,
   1.541 +                         const u_printf_spec_info       *info,
   1.542 +                         const ufmt_args                *args)
   1.543 +{
   1.544 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.545 +    int32_t         len  = UPRINTF_BUFFER_SIZE;
   1.546 +
   1.547 +    /* format the pointer in hex */
   1.548 +    ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
   1.549 +
   1.550 +    return handler->pad_and_justify(context, info, result, len);
   1.551 +}
   1.552 +
   1.553 +static int32_t
   1.554 +u_printf_scientific_handler(const u_printf_stream_handler  *handler,
   1.555 +                            void                           *context,
   1.556 +                            ULocaleBundle                  *formatBundle,
   1.557 +                            const u_printf_spec_info       *info,
   1.558 +                            const ufmt_args                *args)
   1.559 +{
   1.560 +    double          num         = (double) (args[0].doubleValue);
   1.561 +    UNumberFormat   *format;
   1.562 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.563 +    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
   1.564 +    int32_t         prefixBufferLen = sizeof(prefixBuffer);
   1.565 +    int32_t         minDecimalDigits;
   1.566 +    int32_t         maxDecimalDigits;
   1.567 +    UErrorCode      status        = U_ZERO_ERROR;
   1.568 +    UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
   1.569 +    int32_t srcLen, expLen;
   1.570 +    int32_t resultLen;
   1.571 +    UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
   1.572 +
   1.573 +    prefixBuffer[0] = 0;
   1.574 +
   1.575 +    /* mask off any necessary bits */
   1.576 +    /*  if(! info->fIsLongDouble)
   1.577 +    num &= DBL_MAX;*/
   1.578 +
   1.579 +    /* get the formatter */
   1.580 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
   1.581 +
   1.582 +    /* handle error */
   1.583 +    if(format == 0)
   1.584 +        return 0;
   1.585 +
   1.586 +    /* set the appropriate flags on the formatter */
   1.587 +
   1.588 +    srcLen = unum_getSymbol(format,
   1.589 +        UNUM_EXPONENTIAL_SYMBOL,
   1.590 +        srcExpBuf,
   1.591 +        sizeof(srcExpBuf),
   1.592 +        &status);
   1.593 +
   1.594 +    /* Upper/lower case the e */
   1.595 +    if (info->fSpec == (UChar)0x65 /* e */) {
   1.596 +        expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
   1.597 +            srcExpBuf, srcLen,
   1.598 +            formatBundle->fLocale,
   1.599 +            &status);
   1.600 +    }
   1.601 +    else {
   1.602 +        expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
   1.603 +            srcExpBuf, srcLen,
   1.604 +            formatBundle->fLocale,
   1.605 +            &status);
   1.606 +    }
   1.607 +
   1.608 +    unum_setSymbol(format,
   1.609 +        UNUM_EXPONENTIAL_SYMBOL,
   1.610 +        expBuf,
   1.611 +        expLen,
   1.612 +        &status);
   1.613 +
   1.614 +    /* save the formatter's state */
   1.615 +    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
   1.616 +    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
   1.617 +
   1.618 +    /* set the appropriate flags and number of decimal digits on the formatter */
   1.619 +    if(info->fPrecision != -1) {
   1.620 +        /* set the # of decimal digits */
   1.621 +        if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
   1.622 +            unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
   1.623 +        }
   1.624 +        else {
   1.625 +            unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
   1.626 +            unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
   1.627 +        }
   1.628 +    }
   1.629 +    else if(info->fAlt) {
   1.630 +        /* '#' means always show decimal point */
   1.631 +        /* copy of printf behavior on Solaris - '#' shows 6 digits */
   1.632 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.633 +    }
   1.634 +    else {
   1.635 +        /* # of decimal digits is 6 if precision not specified */
   1.636 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.637 +    }
   1.638 +
   1.639 +    /* set whether to show the sign */
   1.640 +    if (info->fShowSign) {
   1.641 +        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
   1.642 +    }
   1.643 +
   1.644 +    /* format the number */
   1.645 +    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.646 +
   1.647 +    if (U_FAILURE(status)) {
   1.648 +        resultLen = 0;
   1.649 +    }
   1.650 +
   1.651 +    /* restore the number format */
   1.652 +    /* TODO: Is this needed? */
   1.653 +    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
   1.654 +    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
   1.655 +
   1.656 +    /* Since we're the only one using the scientific
   1.657 +       format, we don't need to save the old exponent value. */
   1.658 +    /*unum_setSymbol(format,
   1.659 +        UNUM_EXPONENTIAL_SYMBOL,
   1.660 +        srcExpBuf,
   1.661 +        srcLen,
   1.662 +        &status);*/
   1.663 +
   1.664 +    if (info->fShowSign) {
   1.665 +        /* Reset back to original value regardless of what the error was */
   1.666 +        UErrorCode localStatus = U_ZERO_ERROR;
   1.667 +        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
   1.668 +    }
   1.669 +
   1.670 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.671 +}
   1.672 +
   1.673 +static int32_t
   1.674 +u_printf_percent_handler(const u_printf_stream_handler  *handler,
   1.675 +                         void                           *context,
   1.676 +                         ULocaleBundle                  *formatBundle,
   1.677 +                         const u_printf_spec_info       *info,
   1.678 +                         const ufmt_args                *args)
   1.679 +{
   1.680 +    double          num         = (double) (args[0].doubleValue);
   1.681 +    UNumberFormat   *format;
   1.682 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.683 +    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
   1.684 +    int32_t         prefixBufferLen = sizeof(prefixBuffer);
   1.685 +    int32_t         minDecimalDigits;
   1.686 +    int32_t         maxDecimalDigits;
   1.687 +    int32_t         resultLen;
   1.688 +    UErrorCode      status        = U_ZERO_ERROR;
   1.689 +
   1.690 +    prefixBuffer[0] = 0;
   1.691 +
   1.692 +    /* mask off any necessary bits */
   1.693 +    /*  if(! info->fIsLongDouble)
   1.694 +    num &= DBL_MAX;*/
   1.695 +
   1.696 +    /* get the formatter */
   1.697 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
   1.698 +
   1.699 +    /* handle error */
   1.700 +    if(format == 0)
   1.701 +        return 0;
   1.702 +
   1.703 +    /* save the formatter's state */
   1.704 +    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
   1.705 +    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
   1.706 +
   1.707 +    /* set the appropriate flags and number of decimal digits on the formatter */
   1.708 +    if(info->fPrecision != -1) {
   1.709 +        /* set the # of decimal digits */
   1.710 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
   1.711 +    }
   1.712 +    else if(info->fAlt) {
   1.713 +        /* '#' means always show decimal point */
   1.714 +        /* copy of printf behavior on Solaris - '#' shows 6 digits */
   1.715 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.716 +    }
   1.717 +    else {
   1.718 +        /* # of decimal digits is 6 if precision not specified */
   1.719 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.720 +    }
   1.721 +
   1.722 +    /* set whether to show the sign */
   1.723 +    if (info->fShowSign) {
   1.724 +        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
   1.725 +    }
   1.726 +
   1.727 +    /* format the number */
   1.728 +    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.729 +
   1.730 +    if (U_FAILURE(status)) {
   1.731 +        resultLen = 0;
   1.732 +    }
   1.733 +
   1.734 +    /* restore the number format */
   1.735 +    /* TODO: Is this needed? */
   1.736 +    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
   1.737 +    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
   1.738 +
   1.739 +    if (info->fShowSign) {
   1.740 +        /* Reset back to original value regardless of what the error was */
   1.741 +        UErrorCode localStatus = U_ZERO_ERROR;
   1.742 +        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
   1.743 +    }
   1.744 +
   1.745 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.746 +}
   1.747 +
   1.748 +static int32_t
   1.749 +u_printf_ustring_handler(const u_printf_stream_handler  *handler,
   1.750 +                         void                           *context,
   1.751 +                         ULocaleBundle                  *formatBundle,
   1.752 +                         const u_printf_spec_info       *info,
   1.753 +                         const ufmt_args                *args)
   1.754 +{
   1.755 +    int32_t len, written;
   1.756 +    const UChar *arg = (const UChar*)(args[0].ptrValue);
   1.757 +
   1.758 +    /* allocate enough space for the buffer */
   1.759 +    if (arg == NULL) {
   1.760 +        arg = gNullStr;
   1.761 +    }
   1.762 +    len = u_strlen(arg);
   1.763 +
   1.764 +    /* width = minimum # of characters to write */
   1.765 +    /* precision = maximum # of characters to write */
   1.766 +    if (info->fPrecision != -1 && info->fPrecision < len) {
   1.767 +        len = info->fPrecision;
   1.768 +    }
   1.769 +
   1.770 +    /* determine if the string should be padded */
   1.771 +    written = handler->pad_and_justify(context, info, arg, len);
   1.772 +
   1.773 +    return written;
   1.774 +}
   1.775 +
   1.776 +static int32_t
   1.777 +u_printf_uchar_handler(const u_printf_stream_handler  *handler,
   1.778 +                       void                           *context,
   1.779 +                       ULocaleBundle                  *formatBundle,
   1.780 +                       const u_printf_spec_info       *info,
   1.781 +                       const ufmt_args                *args)
   1.782 +{
   1.783 +    int32_t written = 0;
   1.784 +    UChar arg = (UChar)(args[0].int64Value);
   1.785 +
   1.786 +    /* width = minimum # of characters to write */
   1.787 +    /* precision = maximum # of characters to write */
   1.788 +    /* precision is ignored when handling a uchar */
   1.789 +
   1.790 +    /* determine if the string should be padded */
   1.791 +    written = handler->pad_and_justify(context, info, &arg, 1);
   1.792 +
   1.793 +    return written;
   1.794 +}
   1.795 +
   1.796 +static int32_t
   1.797 +u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
   1.798 +                        void                           *context,
   1.799 +                        ULocaleBundle                  *formatBundle,
   1.800 +                        const u_printf_spec_info       *info,
   1.801 +                        const ufmt_args                *args)
   1.802 +{
   1.803 +    u_printf_spec_info scidbl_info;
   1.804 +    double      num = args[0].doubleValue;
   1.805 +    int32_t     retVal;
   1.806 +    UNumberFormat *format;
   1.807 +    int32_t maxSigDecimalDigits, significantDigits;
   1.808 +
   1.809 +    memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
   1.810 +
   1.811 +    /* determine whether to use 'd', 'e' or 'f' notation */
   1.812 +    if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
   1.813 +    {
   1.814 +        /* use 'f' notation */
   1.815 +        scidbl_info.fSpec = 0x0066;
   1.816 +        scidbl_info.fPrecision = 0;
   1.817 +        /* call the double handler */
   1.818 +        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
   1.819 +    }
   1.820 +    else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
   1.821 +        || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
   1.822 +    {
   1.823 +        /* use 'e' or 'E' notation */
   1.824 +        scidbl_info.fSpec = scidbl_info.fSpec - 2;
   1.825 +        if (scidbl_info.fPrecision == -1) {
   1.826 +            scidbl_info.fPrecision = 5;
   1.827 +        }
   1.828 +        /* call the scientific handler */
   1.829 +        retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
   1.830 +    }
   1.831 +    else {
   1.832 +        format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
   1.833 +        /* Check for null pointer */
   1.834 +        if (format == NULL) {
   1.835 +            return 0;
   1.836 +        }
   1.837 +        maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
   1.838 +        significantDigits = scidbl_info.fPrecision;
   1.839 +
   1.840 +        /* use 'f' notation */
   1.841 +        scidbl_info.fSpec = 0x0066;
   1.842 +        if (significantDigits == -1) {
   1.843 +            significantDigits = 6;
   1.844 +        }
   1.845 +        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
   1.846 +        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
   1.847 +        /* call the double handler */
   1.848 +        retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
   1.849 +        unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
   1.850 +        unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
   1.851 +    }
   1.852 +    return retVal;
   1.853 +}
   1.854 +
   1.855 +static int32_t
   1.856 +u_printf_count_handler(const u_printf_stream_handler  *handler,
   1.857 +                       void                           *context,
   1.858 +                       ULocaleBundle                  *formatBundle,
   1.859 +                       const u_printf_spec_info       *info,
   1.860 +                       const ufmt_args                *args)
   1.861 +{
   1.862 +    int32_t *count = (int32_t*)(args[0].ptrValue);
   1.863 +
   1.864 +    /* in the special case of count, the u_printf_spec_info's width */
   1.865 +    /* will contain the # of chars written thus far */
   1.866 +    *count = info->fWidth;
   1.867 +
   1.868 +    return 0;
   1.869 +}
   1.870 +
   1.871 +static int32_t
   1.872 +u_printf_spellout_handler(const u_printf_stream_handler *handler,
   1.873 +                          void                          *context,
   1.874 +                          ULocaleBundle                 *formatBundle,
   1.875 +                          const u_printf_spec_info      *info,
   1.876 +                          const ufmt_args               *args)
   1.877 +{
   1.878 +    double          num         = (double) (args[0].doubleValue);
   1.879 +    UNumberFormat   *format;
   1.880 +    UChar           result[UPRINTF_BUFFER_SIZE];
   1.881 +    UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
   1.882 +    int32_t         prefixBufferLen = sizeof(prefixBuffer);
   1.883 +    int32_t         minDecimalDigits;
   1.884 +    int32_t         maxDecimalDigits;
   1.885 +    int32_t         resultLen;
   1.886 +    UErrorCode      status        = U_ZERO_ERROR;
   1.887 +
   1.888 +    prefixBuffer[0] = 0;
   1.889 +
   1.890 +    /* mask off any necessary bits */
   1.891 +    /*  if(! info->fIsLongDouble)
   1.892 +    num &= DBL_MAX;*/
   1.893 +
   1.894 +    /* get the formatter */
   1.895 +    format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
   1.896 +
   1.897 +    /* handle error */
   1.898 +    if(format == 0)
   1.899 +        return 0;
   1.900 +
   1.901 +    /* save the formatter's state */
   1.902 +    minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
   1.903 +    maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
   1.904 +
   1.905 +    /* set the appropriate flags and number of decimal digits on the formatter */
   1.906 +    if(info->fPrecision != -1) {
   1.907 +        /* set the # of decimal digits */
   1.908 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
   1.909 +    }
   1.910 +    else if(info->fAlt) {
   1.911 +        /* '#' means always show decimal point */
   1.912 +        /* copy of printf behavior on Solaris - '#' shows 6 digits */
   1.913 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.914 +    }
   1.915 +    else {
   1.916 +        /* # of decimal digits is 6 if precision not specified */
   1.917 +        unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
   1.918 +    }
   1.919 +
   1.920 +    /* set whether to show the sign */
   1.921 +    if (info->fShowSign) {
   1.922 +        u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
   1.923 +    }
   1.924 +
   1.925 +    /* format the number */
   1.926 +    resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
   1.927 +
   1.928 +    if (U_FAILURE(status)) {
   1.929 +        resultLen = 0;
   1.930 +    }
   1.931 +
   1.932 +    /* restore the number format */
   1.933 +    /* TODO: Is this needed? */
   1.934 +    unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
   1.935 +    unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
   1.936 +
   1.937 +    if (info->fShowSign) {
   1.938 +        /* Reset back to original value regardless of what the error was */
   1.939 +        UErrorCode localStatus = U_ZERO_ERROR;
   1.940 +        u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
   1.941 +    }
   1.942 +
   1.943 +    return handler->pad_and_justify(context, info, result, resultLen);
   1.944 +}
   1.945 +
   1.946 +/* Use US-ASCII characters only for formatting. Most codepages have
   1.947 + characters 20-7F from Unicode. Using any other codepage specific
   1.948 + characters will make it very difficult to format the string on
   1.949 + non-Unicode machines */
   1.950 +static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
   1.951 +/* 0x20 */
   1.952 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.953 +    UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
   1.954 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.955 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.956 +
   1.957 +/* 0x30 */
   1.958 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.959 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.960 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.961 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.962 +
   1.963 +/* 0x40 */
   1.964 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
   1.965 +    UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
   1.966 +#ifdef U_USE_OBSOLETE_IO_FORMATTING
   1.967 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
   1.968 +#else
   1.969 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.970 +#endif
   1.971 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.972 +
   1.973 +/* 0x50 */
   1.974 +    UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
   1.975 +#ifdef U_USE_OBSOLETE_IO_FORMATTING
   1.976 +    UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
   1.977 +#else
   1.978 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
   1.979 +#endif
   1.980 +    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.981 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.982 +
   1.983 +/* 0x60 */
   1.984 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
   1.985 +    UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
   1.986 +    UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
   1.987 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
   1.988 +
   1.989 +/* 0x70 */
   1.990 +    UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
   1.991 +    UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
   1.992 +    UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.993 +    UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
   1.994 +};
   1.995 +
   1.996 +/* flag characters for uprintf */
   1.997 +#define FLAG_MINUS 0x002D
   1.998 +#define FLAG_PLUS 0x002B
   1.999 +#define FLAG_SPACE 0x0020
  1.1000 +#define FLAG_POUND 0x0023
  1.1001 +#define FLAG_ZERO  0x0030
  1.1002 +#define FLAG_PAREN 0x0028
  1.1003 +
  1.1004 +#define ISFLAG(s)    (s) == FLAG_MINUS || \
  1.1005 +            (s) == FLAG_PLUS || \
  1.1006 +            (s) == FLAG_SPACE || \
  1.1007 +            (s) == FLAG_POUND || \
  1.1008 +            (s) == FLAG_ZERO || \
  1.1009 +            (s) == FLAG_PAREN
  1.1010 +
  1.1011 +/* special characters for uprintf */
  1.1012 +#define SPEC_ASTERISK 0x002A
  1.1013 +#define SPEC_DOLLARSIGN 0x0024
  1.1014 +#define SPEC_PERIOD 0x002E
  1.1015 +#define SPEC_PERCENT 0x0025
  1.1016 +
  1.1017 +/* unicode digits */
  1.1018 +#define DIGIT_ZERO 0x0030
  1.1019 +#define DIGIT_ONE 0x0031
  1.1020 +#define DIGIT_TWO 0x0032
  1.1021 +#define DIGIT_THREE 0x0033
  1.1022 +#define DIGIT_FOUR 0x0034
  1.1023 +#define DIGIT_FIVE 0x0035
  1.1024 +#define DIGIT_SIX 0x0036
  1.1025 +#define DIGIT_SEVEN 0x0037
  1.1026 +#define DIGIT_EIGHT 0x0038
  1.1027 +#define DIGIT_NINE 0x0039
  1.1028 +
  1.1029 +#define ISDIGIT(s)    (s) == DIGIT_ZERO || \
  1.1030 +            (s) == DIGIT_ONE || \
  1.1031 +            (s) == DIGIT_TWO || \
  1.1032 +            (s) == DIGIT_THREE || \
  1.1033 +            (s) == DIGIT_FOUR || \
  1.1034 +            (s) == DIGIT_FIVE || \
  1.1035 +            (s) == DIGIT_SIX || \
  1.1036 +            (s) == DIGIT_SEVEN || \
  1.1037 +            (s) == DIGIT_EIGHT || \
  1.1038 +            (s) == DIGIT_NINE
  1.1039 +
  1.1040 +/* u_printf modifiers */
  1.1041 +#define MOD_H 0x0068
  1.1042 +#define MOD_LOWERL 0x006C
  1.1043 +#define MOD_L 0x004C
  1.1044 +
  1.1045 +#define ISMOD(s)    (s) == MOD_H || \
  1.1046 +            (s) == MOD_LOWERL || \
  1.1047 +            (s) == MOD_L
  1.1048 +/* Returns an array of the parsed argument type given in the format string. */
  1.1049 +static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
  1.1050 +    ufmt_args *arglist = NULL;
  1.1051 +    ufmt_type_info *typelist = NULL;
  1.1052 +    UBool *islonglong = NULL;
  1.1053 +    int32_t size = 0;
  1.1054 +    int32_t pos = 0;
  1.1055 +    UChar type;
  1.1056 +    uint16_t handlerNum;
  1.1057 +    const UChar *aliasStart = alias;
  1.1058 +
  1.1059 +    /* get maximum number of arguments */
  1.1060 +    for(;;) {
  1.1061 +        /* find % */
  1.1062 +        while(*alias != UP_PERCENT && *alias != 0x0000) {
  1.1063 +            alias++;
  1.1064 +        }
  1.1065 +
  1.1066 +        if(*alias == 0x0000) {
  1.1067 +            break;
  1.1068 +        }
  1.1069 +
  1.1070 +        alias++;
  1.1071 +
  1.1072 +        /* handle the pos number */
  1.1073 +        if(ISDIGIT(*alias)) {
  1.1074 +
  1.1075 +            /* handle positional parameters */
  1.1076 +            if(ISDIGIT(*alias)) {
  1.1077 +                pos = (int) (*alias++ - DIGIT_ZERO);
  1.1078 +
  1.1079 +                while(ISDIGIT(*alias)) {
  1.1080 +                    pos *= 10;
  1.1081 +                    pos += (int) (*alias++ - DIGIT_ZERO);
  1.1082 +                }
  1.1083 +            }
  1.1084 +
  1.1085 +            /* if there is no '$', don't read anything */
  1.1086 +            if(*alias != SPEC_DOLLARSIGN) {
  1.1087 +                return NULL;
  1.1088 +            }
  1.1089 +        } else {
  1.1090 +            return NULL;
  1.1091 +        }
  1.1092 +
  1.1093 +        if (pos > size) {
  1.1094 +            size = pos;
  1.1095 +        }
  1.1096 +    }
  1.1097 +
  1.1098 +    /* create the parsed argument list */
  1.1099 +    typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
  1.1100 +    islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
  1.1101 +    arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
  1.1102 +
  1.1103 +    /* If malloc failed, return NULL */
  1.1104 +    if (!typelist || !islonglong || !arglist) {
  1.1105 +        if (typelist) {
  1.1106 +            uprv_free(typelist);
  1.1107 +        }
  1.1108 +
  1.1109 +        if (islonglong) {
  1.1110 +            uprv_free(islonglong);
  1.1111 +        }
  1.1112 +
  1.1113 +        if (arglist) {
  1.1114 +            uprv_free(arglist);
  1.1115 +        }
  1.1116 +
  1.1117 +        *status = U_MEMORY_ALLOCATION_ERROR;
  1.1118 +        return NULL;
  1.1119 +    }
  1.1120 +
  1.1121 +    /* reset alias back to the beginning */
  1.1122 +    alias = aliasStart;
  1.1123 +
  1.1124 +    for(;;) {
  1.1125 +        /* find % */
  1.1126 +        while(*alias != UP_PERCENT && *alias != 0x0000) {
  1.1127 +            alias++;
  1.1128 +        }
  1.1129 +
  1.1130 +        if(*alias == 0x0000) {
  1.1131 +            break;
  1.1132 +        }
  1.1133 +
  1.1134 +        alias++;
  1.1135 +
  1.1136 +        /* handle positional parameters */
  1.1137 +        if(ISDIGIT(*alias)) {
  1.1138 +            pos = (int) (*alias++ - DIGIT_ZERO);
  1.1139 +
  1.1140 +            while(ISDIGIT(*alias)) {
  1.1141 +                pos *= 10;
  1.1142 +                pos += (int) (*alias++ - DIGIT_ZERO);
  1.1143 +            }
  1.1144 +        }
  1.1145 +        /* offset position by 1 */
  1.1146 +        pos--;
  1.1147 +
  1.1148 +        /* skip over everything except for the type */
  1.1149 +        while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) || 
  1.1150 +            *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
  1.1151 +                islonglong[pos] = FALSE;
  1.1152 +                if (ISMOD(*alias)) {
  1.1153 +                    alias++;
  1.1154 +                    if (*alias == MOD_LOWERL) {
  1.1155 +                        islonglong[pos] = TRUE;
  1.1156 +                    } 
  1.1157 +                } 
  1.1158 +                alias++;
  1.1159 +        }
  1.1160 +        type = *alias;
  1.1161 +
  1.1162 +        /* store the argument type in the correct position of the parsed argument list */
  1.1163 +        handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
  1.1164 +        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
  1.1165 +            typelist[pos] = g_u_printf_infos[ handlerNum ].info;
  1.1166 +        } else {
  1.1167 +            typelist[pos] = ufmt_empty;
  1.1168 +        }
  1.1169 +    }
  1.1170 +
  1.1171 +    /* store argument in arglist */
  1.1172 +    for (pos = 0; pos < size; pos++) {
  1.1173 +        switch (typelist[pos]) {
  1.1174 +        case ufmt_string:
  1.1175 +        case ufmt_ustring:
  1.1176 +        case ufmt_pointer:
  1.1177 +            arglist[pos].ptrValue = va_arg(ap, void*);
  1.1178 +            break;
  1.1179 +        case ufmt_char:
  1.1180 +        case ufmt_uchar:
  1.1181 +        case ufmt_int:
  1.1182 +            if (islonglong[pos]) {
  1.1183 +                arglist[pos].int64Value = va_arg(ap, int64_t);
  1.1184 +            }
  1.1185 +            else {
  1.1186 +                arglist[pos].int64Value = va_arg(ap, int32_t);
  1.1187 +            }
  1.1188 +            break;
  1.1189 +        case ufmt_float:
  1.1190 +            arglist[pos].floatValue = (float) va_arg(ap, double);
  1.1191 +            break;
  1.1192 +        case ufmt_double:
  1.1193 +            arglist[pos].doubleValue = va_arg(ap, double);
  1.1194 +            break;
  1.1195 +        default:
  1.1196 +            /* else args is ignored */
  1.1197 +            arglist[pos].ptrValue = NULL;
  1.1198 +            break;
  1.1199 +        }
  1.1200 +    }
  1.1201 +
  1.1202 +    uprv_free(typelist);
  1.1203 +    uprv_free(islonglong);
  1.1204 +
  1.1205 +    return arglist;
  1.1206 +}
  1.1207 +
  1.1208 +/* We parse the argument list in Unicode */
  1.1209 +U_CFUNC int32_t
  1.1210 +u_printf_parse(const u_printf_stream_handler *streamHandler,
  1.1211 +               const UChar     *fmt,
  1.1212 +               void            *context,
  1.1213 +               u_localized_print_string *locStringContext,
  1.1214 +               ULocaleBundle   *formatBundle,
  1.1215 +               int32_t         *written,
  1.1216 +               va_list         ap)
  1.1217 +{
  1.1218 +    uint16_t         handlerNum;
  1.1219 +    ufmt_args        args;
  1.1220 +    ufmt_type_info   argType;
  1.1221 +    u_printf_handler *handler;
  1.1222 +    u_printf_spec    spec;
  1.1223 +    u_printf_spec_info *info = &(spec.fInfo);
  1.1224 +
  1.1225 +    const UChar *alias = fmt;
  1.1226 +    const UChar *backup;
  1.1227 +    const UChar *lastAlias;
  1.1228 +    const UChar *orgAlias = fmt;
  1.1229 +    /* parsed argument list */
  1.1230 +    ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
  1.1231 +    UErrorCode status = U_ZERO_ERROR;
  1.1232 +    if (!locStringContext || locStringContext->available >= 0) {
  1.1233 +        /* get the parsed list of argument types */
  1.1234 +        arglist = parseArguments(orgAlias, ap, &status);
  1.1235 +
  1.1236 +        /* Return error if parsing failed. */
  1.1237 +        if (U_FAILURE(status)) {
  1.1238 +            return -1;
  1.1239 +        }
  1.1240 +    }
  1.1241 +    
  1.1242 +    /* iterate through the pattern */
  1.1243 +    while(!locStringContext || locStringContext->available >= 0) {
  1.1244 +
  1.1245 +        /* find the next '%' */
  1.1246 +        lastAlias = alias;
  1.1247 +        while(*alias != UP_PERCENT && *alias != 0x0000) {
  1.1248 +            alias++;
  1.1249 +        }
  1.1250 +
  1.1251 +        /* write any characters before the '%' */
  1.1252 +        if(alias > lastAlias) {
  1.1253 +            *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
  1.1254 +        }
  1.1255 +
  1.1256 +        /* break if at end of string */
  1.1257 +        if(*alias == 0x0000) {
  1.1258 +            break;
  1.1259 +        }
  1.1260 +
  1.1261 +        /* initialize spec to default values */
  1.1262 +        spec.fWidthPos     = -1;
  1.1263 +        spec.fPrecisionPos = -1;
  1.1264 +        spec.fArgPos       = -1;
  1.1265 +
  1.1266 +        uprv_memset(info, 0, sizeof(*info));
  1.1267 +        info->fPrecision    = -1;
  1.1268 +        info->fWidth        = -1;
  1.1269 +        info->fPadChar      = 0x0020;
  1.1270 +
  1.1271 +        /* skip over the initial '%' */
  1.1272 +        alias++;
  1.1273 +
  1.1274 +        /* Check for positional argument */
  1.1275 +        if(ISDIGIT(*alias)) {
  1.1276 +
  1.1277 +            /* Save the current position */
  1.1278 +            backup = alias;
  1.1279 +
  1.1280 +            /* handle positional parameters */
  1.1281 +            if(ISDIGIT(*alias)) {
  1.1282 +                spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
  1.1283 +
  1.1284 +                while(ISDIGIT(*alias)) {
  1.1285 +                    spec.fArgPos *= 10;
  1.1286 +                    spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
  1.1287 +                }
  1.1288 +            }
  1.1289 +
  1.1290 +            /* if there is no '$', don't read anything */
  1.1291 +            if(*alias != SPEC_DOLLARSIGN) {
  1.1292 +                spec.fArgPos = -1;
  1.1293 +                alias = backup;
  1.1294 +            }
  1.1295 +            /* munge the '$' */
  1.1296 +            else
  1.1297 +                alias++;
  1.1298 +        }
  1.1299 +
  1.1300 +        /* Get any format flags */
  1.1301 +        while(ISFLAG(*alias)) {
  1.1302 +            switch(*alias++) {
  1.1303 +
  1.1304 +                /* left justify */
  1.1305 +            case FLAG_MINUS:
  1.1306 +                info->fLeft = TRUE;
  1.1307 +                break;
  1.1308 +
  1.1309 +                /* always show sign */
  1.1310 +            case FLAG_PLUS:
  1.1311 +                info->fShowSign = TRUE;
  1.1312 +                break;
  1.1313 +
  1.1314 +                /* use space if no sign present */
  1.1315 +            case FLAG_SPACE:
  1.1316 +                info->fShowSign = TRUE;
  1.1317 +                info->fSpace = TRUE;
  1.1318 +                break;
  1.1319 +
  1.1320 +                /* use alternate form */
  1.1321 +            case FLAG_POUND:
  1.1322 +                info->fAlt = TRUE;
  1.1323 +                break;
  1.1324 +
  1.1325 +                /* pad with leading zeroes */
  1.1326 +            case FLAG_ZERO:
  1.1327 +                info->fZero = TRUE;
  1.1328 +                info->fPadChar = 0x0030;
  1.1329 +                break;
  1.1330 +
  1.1331 +                /* pad character specified */
  1.1332 +            case FLAG_PAREN:
  1.1333 +
  1.1334 +                /* TODO test that all four are numbers */
  1.1335 +                /* first four characters are hex values for pad char */
  1.1336 +                info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
  1.1337 +                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
  1.1338 +                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
  1.1339 +                info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
  1.1340 +
  1.1341 +                /* final character is ignored */
  1.1342 +                alias++;
  1.1343 +
  1.1344 +                break;
  1.1345 +            }
  1.1346 +        }
  1.1347 +
  1.1348 +        /* Get the width */
  1.1349 +
  1.1350 +        /* width is specified out of line */
  1.1351 +        if(*alias == SPEC_ASTERISK) {
  1.1352 +
  1.1353 +            info->fWidth = -2;
  1.1354 +
  1.1355 +            /* Skip the '*' */
  1.1356 +            alias++;
  1.1357 +
  1.1358 +            /* Save the current position */
  1.1359 +            backup = alias;
  1.1360 +
  1.1361 +            /* handle positional parameters */
  1.1362 +            if(ISDIGIT(*alias)) {
  1.1363 +                spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
  1.1364 +
  1.1365 +                while(ISDIGIT(*alias)) {
  1.1366 +                    spec.fWidthPos *= 10;
  1.1367 +                    spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
  1.1368 +                }
  1.1369 +            }
  1.1370 +
  1.1371 +            /* if there is no '$', don't read anything */
  1.1372 +            if(*alias != SPEC_DOLLARSIGN) {
  1.1373 +                spec.fWidthPos = -1;
  1.1374 +                alias = backup;
  1.1375 +            }
  1.1376 +            /* munge the '$' */
  1.1377 +            else
  1.1378 +                alias++;
  1.1379 +        }
  1.1380 +        /* read the width, if present */
  1.1381 +        else if(ISDIGIT(*alias)){
  1.1382 +            info->fWidth = (int) (*alias++ - DIGIT_ZERO);
  1.1383 +
  1.1384 +            while(ISDIGIT(*alias)) {
  1.1385 +                info->fWidth *= 10;
  1.1386 +                info->fWidth += (int) (*alias++ - DIGIT_ZERO);
  1.1387 +            }
  1.1388 +        }
  1.1389 +
  1.1390 +        /* Get the precision */
  1.1391 +
  1.1392 +        if(*alias == SPEC_PERIOD) {
  1.1393 +
  1.1394 +            /* eat up the '.' */
  1.1395 +            alias++;
  1.1396 +
  1.1397 +            /* precision is specified out of line */
  1.1398 +            if(*alias == SPEC_ASTERISK) {
  1.1399 +
  1.1400 +                info->fPrecision = -2;
  1.1401 +
  1.1402 +                /* Skip the '*' */
  1.1403 +                alias++;
  1.1404 +
  1.1405 +                /* save the current position */
  1.1406 +                backup = alias;
  1.1407 +
  1.1408 +                /* handle positional parameters */
  1.1409 +                if(ISDIGIT(*alias)) {
  1.1410 +                    spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
  1.1411 +
  1.1412 +                    while(ISDIGIT(*alias)) {
  1.1413 +                        spec.fPrecisionPos *= 10;
  1.1414 +                        spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
  1.1415 +                    }
  1.1416 +
  1.1417 +                    /* if there is no '$', don't read anything */
  1.1418 +                    if(*alias != SPEC_DOLLARSIGN) {
  1.1419 +                        spec.fPrecisionPos = -1;
  1.1420 +                        alias = backup;
  1.1421 +                    }
  1.1422 +                    else {
  1.1423 +                        /* munge the '$' */
  1.1424 +                        alias++;
  1.1425 +                    }
  1.1426 +                }
  1.1427 +            }
  1.1428 +            /* read the precision */
  1.1429 +            else if(ISDIGIT(*alias)){
  1.1430 +                info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
  1.1431 +
  1.1432 +                while(ISDIGIT(*alias)) {
  1.1433 +                    info->fPrecision *= 10;
  1.1434 +                    info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
  1.1435 +                }
  1.1436 +            }
  1.1437 +        }
  1.1438 +
  1.1439 +        /* Get any modifiers */
  1.1440 +        if(ISMOD(*alias)) {
  1.1441 +            switch(*alias++) {
  1.1442 +
  1.1443 +                /* short */
  1.1444 +            case MOD_H:
  1.1445 +                info->fIsShort = TRUE;
  1.1446 +                break;
  1.1447 +
  1.1448 +                /* long or long long */
  1.1449 +            case MOD_LOWERL:
  1.1450 +                if(*alias == MOD_LOWERL) {
  1.1451 +                    info->fIsLongLong = TRUE;
  1.1452 +                    /* skip over the next 'l' */
  1.1453 +                    alias++;
  1.1454 +                }
  1.1455 +                else
  1.1456 +                    info->fIsLong = TRUE;
  1.1457 +                break;
  1.1458 +
  1.1459 +                /* long double */
  1.1460 +            case MOD_L:
  1.1461 +                info->fIsLongDouble = TRUE;
  1.1462 +                break;
  1.1463 +            }
  1.1464 +        }
  1.1465 +
  1.1466 +        /* finally, get the specifier letter */
  1.1467 +        info->fSpec = *alias++;
  1.1468 +        info->fOrigSpec = info->fSpec;
  1.1469 +
  1.1470 +        /* fill in the precision and width, if specified out of line */
  1.1471 +
  1.1472 +        /* width specified out of line */
  1.1473 +        if(spec.fInfo.fWidth == -2) {
  1.1474 +            if(spec.fWidthPos == -1) {
  1.1475 +                /* read the width from the argument list */
  1.1476 +                info->fWidth = va_arg(ap, int32_t);
  1.1477 +            }
  1.1478 +            /* else handle positional parameter */
  1.1479 +
  1.1480 +            /* if it's negative, take the absolute value and set left alignment */
  1.1481 +            if(info->fWidth < 0) {
  1.1482 +                info->fWidth *= -1; /* Make positive */
  1.1483 +                info->fLeft = TRUE;
  1.1484 +            }
  1.1485 +        }
  1.1486 +
  1.1487 +        /* precision specified out of line */
  1.1488 +        if(info->fPrecision == -2) {
  1.1489 +            if(spec.fPrecisionPos == -1) {
  1.1490 +                /* read the precision from the argument list */
  1.1491 +                info->fPrecision = va_arg(ap, int32_t);
  1.1492 +            }
  1.1493 +            /* else handle positional parameter */
  1.1494 +
  1.1495 +            /* if it's negative, set it to zero */
  1.1496 +            if(info->fPrecision < 0)
  1.1497 +                info->fPrecision = 0;
  1.1498 +        }
  1.1499 +
  1.1500 +        handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
  1.1501 +        if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
  1.1502 +            /* query the info function for argument information */
  1.1503 +            argType = g_u_printf_infos[ handlerNum ].info;
  1.1504 +
  1.1505 +            /* goto the correct argument on arg_list if position is specified */
  1.1506 +            if (spec.fArgPos > 0) {
  1.1507 +                /* offset position by 1 */
  1.1508 +                spec.fArgPos--;
  1.1509 +                switch(argType) {
  1.1510 +                case ufmt_count:
  1.1511 +                    /* set the spec's width to the # of chars written */
  1.1512 +                    info->fWidth = *written;
  1.1513 +                    /* fall through to set the pointer */
  1.1514 +                case ufmt_string:
  1.1515 +                case ufmt_ustring:
  1.1516 +                case ufmt_pointer:
  1.1517 +                    args.ptrValue = arglist[spec.fArgPos].ptrValue;
  1.1518 +                    break;
  1.1519 +                case ufmt_char:
  1.1520 +                case ufmt_uchar:
  1.1521 +                case ufmt_int:
  1.1522 +                    args.int64Value = arglist[spec.fArgPos].int64Value;
  1.1523 +                    break;
  1.1524 +                case ufmt_float:
  1.1525 +                    args.floatValue = arglist[spec.fArgPos].floatValue;
  1.1526 +                    break;
  1.1527 +                case ufmt_double:
  1.1528 +                    args.doubleValue = arglist[spec.fArgPos].doubleValue;
  1.1529 +                    break;
  1.1530 +                default:
  1.1531 +                    /* else args is ignored */
  1.1532 +                    args.ptrValue = NULL;
  1.1533 +                    break;
  1.1534 +                }
  1.1535 +            } else { /* no positional argument specified */
  1.1536 +                switch(argType) {
  1.1537 +                case ufmt_count:
  1.1538 +                    /* set the spec's width to the # of chars written */
  1.1539 +                    info->fWidth = *written;
  1.1540 +                    /* fall through to set the pointer */
  1.1541 +                case ufmt_string:
  1.1542 +                case ufmt_ustring:
  1.1543 +                case ufmt_pointer:
  1.1544 +                    args.ptrValue = va_arg(ap, void*);
  1.1545 +                    break;
  1.1546 +                case ufmt_char:
  1.1547 +                case ufmt_uchar:
  1.1548 +                case ufmt_int:
  1.1549 +                    if (info->fIsLongLong) {
  1.1550 +                        args.int64Value = va_arg(ap, int64_t);
  1.1551 +                    }
  1.1552 +                    else {
  1.1553 +                        args.int64Value = va_arg(ap, int32_t);
  1.1554 +                    }
  1.1555 +                    break;
  1.1556 +                case ufmt_float:
  1.1557 +                    args.floatValue = (float) va_arg(ap, double);
  1.1558 +                    break;
  1.1559 +                case ufmt_double:
  1.1560 +                    args.doubleValue = va_arg(ap, double);
  1.1561 +                    break;
  1.1562 +                default:
  1.1563 +                    /* else args is ignored */
  1.1564 +                    args.ptrValue = NULL;
  1.1565 +                    break;
  1.1566 +                }
  1.1567 +            }
  1.1568 +
  1.1569 +            /* call the handler function */
  1.1570 +            handler = g_u_printf_infos[ handlerNum ].handler;
  1.1571 +            if(handler != 0) {
  1.1572 +                *written += (*handler)(streamHandler, context, formatBundle, info, &args);
  1.1573 +            }
  1.1574 +            else {
  1.1575 +                /* just echo unknown tags */
  1.1576 +                *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
  1.1577 +            }
  1.1578 +        }
  1.1579 +        else {
  1.1580 +            /* just echo unknown tags */
  1.1581 +            *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
  1.1582 +        }
  1.1583 +    }
  1.1584 +    /* delete parsed argument list */
  1.1585 +    if (arglist != NULL) {
  1.1586 +        uprv_free(arglist);
  1.1587 +    }
  1.1588 +    /* return # of characters in this format that have been parsed. */
  1.1589 +    return (int32_t)(alias - fmt);
  1.1590 +}
  1.1591 +
  1.1592 +#endif /* #if !UCONFIG_NO_FORMATTING */

mercurial