Home | History | Annotate | Download | only in io
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1998-2011, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File uprntf_p.c
     10 *
     11 * Modification History:
     12 *
     13 *   Date        Name        Description
     14 *   11/23/98    stephen     Creation.
     15 *   03/12/99    stephen     Modified for new C API.
     16 *   08/07/2003  george      Reunify printf implementations
     17 ******************************************************************************
     18 */
     19 
     20 #include "unicode/utypes.h"
     21 
     22 #if !UCONFIG_NO_FORMATTING
     23 
     24 #include "unicode/ustring.h"
     25 #include "unicode/utf16.h"
     26 #include "uprintf.h"
     27 #include "ufmt_cmn.h"
     28 #include "cmemory.h"
     29 #include "putilimp.h"
     30 
     31 /* ANSI style formatting */
     32 /* Use US-ASCII characters only for formatting */
     33 
     34 /* % */
     35 #define UFMT_SIMPLE_PERCENT {ufmt_simple_percent, u_printf_simple_percent_handler}
     36 /* s */
     37 #define UFMT_STRING         {ufmt_string, u_printf_string_handler}
     38 /* c */
     39 #define UFMT_CHAR           {ufmt_char, u_printf_char_handler}
     40 /* d, i */
     41 #define UFMT_INT            {ufmt_int, u_printf_integer_handler}
     42 /* u */
     43 #define UFMT_UINT           {ufmt_int, u_printf_uinteger_handler}
     44 /* o */
     45 #define UFMT_OCTAL          {ufmt_int, u_printf_octal_handler}
     46 /* x, X */
     47 #define UFMT_HEX            {ufmt_int, u_printf_hex_handler}
     48 /* f */
     49 #define UFMT_DOUBLE         {ufmt_double, u_printf_double_handler}
     50 /* e, E */
     51 #define UFMT_SCIENTIFIC     {ufmt_double, u_printf_scientific_handler}
     52 /* g, G */
     53 #define UFMT_SCIDBL         {ufmt_double, u_printf_scidbl_handler}
     54 /* n */
     55 #define UFMT_COUNT          {ufmt_count, u_printf_count_handler}
     56 
     57 /* non-ANSI extensions */
     58 /* Use US-ASCII characters only for formatting */
     59 
     60 /* p */
     61 #define UFMT_POINTER        {ufmt_pointer, u_printf_pointer_handler}
     62 /* V */
     63 #define UFMT_SPELLOUT       {ufmt_double, u_printf_spellout_handler}
     64 /* P */
     65 #define UFMT_PERCENT        {ufmt_double, u_printf_percent_handler}
     66 /* C  K is old format */
     67 #define UFMT_UCHAR          {ufmt_uchar, u_printf_uchar_handler}
     68 /* S  U is old format */
     69 #define UFMT_USTRING        {ufmt_ustring, u_printf_ustring_handler}
     70 
     71 
     72 #define UFMT_EMPTY {ufmt_empty, NULL}
     73 
     74 /**
     75  * A u_printf handler function.
     76  * A u_printf handler is responsible for handling a single u_printf
     77  * format specification, for example 'd' or 's'.
     78  * @param stream The UFILE to which to write output.
     79  * @param info A pointer to a <TT>u_printf_spec_info</TT> struct containing
     80  * information on the format specification.
     81  * @param args A pointer to the argument data
     82  * @return The number of Unicode characters written to <TT>stream</TT>.
     83  */
     84 typedef int32_t U_EXPORT2
     85 u_printf_handler(const u_printf_stream_handler  *handler,
     86 
     87                  void                           *context,
     88                  ULocaleBundle                  *formatBundle,
     89                  const u_printf_spec_info       *info,
     90                  const ufmt_args                *args);
     91 
     92 typedef struct u_printf_info {
     93     ufmt_type_info info;
     94     u_printf_handler *handler;
     95 } u_printf_info;
     96 
     97 /**
     98  * Struct encapsulating a single uprintf format specification.
     99  */
    100 typedef struct u_printf_spec {
    101   u_printf_spec_info    fInfo;        /* Information on this spec */
    102   int32_t        fWidthPos;     /* Position of width in arg list */
    103   int32_t        fPrecisionPos;    /* Position of precision in arg list */
    104   int32_t        fArgPos;    /* Position of data in arg list */
    105 } u_printf_spec;
    106 
    107 #define UPRINTF_NUM_FMT_HANDLERS 108
    108 
    109 /* We do not use handlers for 0-0x1f */
    110 #define UPRINTF_BASE_FMT_HANDLERS 0x20
    111 
    112 /* buffer size for formatting */
    113 #define UPRINTF_BUFFER_SIZE 1024
    114 #define UPRINTF_SYMBOL_BUFFER_SIZE 8
    115 
    116 static const UChar gNullStr[] = {0x28, 0x6E, 0x75, 0x6C, 0x6C, 0x29, 0}; /* "(null)" */
    117 static const UChar gSpaceStr[] = {0x20, 0}; /* " " */
    118 
    119 /* Sets the sign of a format based on u_printf_spec_info */
    120 /* TODO: Is setting the prefix symbol to a positive sign a good idea in all locales? */
    121 static void
    122 u_printf_set_sign(UNumberFormat        *format,
    123                    const u_printf_spec_info     *info,
    124                    UChar *prefixBuffer,
    125                    int32_t *prefixBufLen,
    126                    UErrorCode *status)
    127 {
    128     if(info->fShowSign) {
    129         *prefixBufLen = unum_getTextAttribute(format,
    130                                               UNUM_POSITIVE_PREFIX,
    131                                               prefixBuffer,
    132                                               *prefixBufLen,
    133                                               status);
    134         if (info->fSpace) {
    135             /* Setting UNUM_PLUS_SIGN_SYMBOL affects the exponent too. */
    136             /* unum_setSymbol(format, UNUM_PLUS_SIGN_SYMBOL, gSpaceStr, 1, &status); */
    137             unum_setTextAttribute(format, UNUM_POSITIVE_PREFIX, gSpaceStr, 1, status);
    138         }
    139         else {
    140             UChar plusSymbol[UPRINTF_SYMBOL_BUFFER_SIZE];
    141             int32_t symbolLen;
    142 
    143             symbolLen = unum_getSymbol(format,
    144                 UNUM_PLUS_SIGN_SYMBOL,
    145                 plusSymbol,
    146                 sizeof(plusSymbol)/sizeof(*plusSymbol),
    147                 status);
    148             unum_setTextAttribute(format,
    149                 UNUM_POSITIVE_PREFIX,
    150                 plusSymbol,
    151                 symbolLen,
    152                 status);
    153         }
    154     }
    155     else {
    156         *prefixBufLen = 0;
    157     }
    158 }
    159 
    160 static void
    161 u_printf_reset_sign(UNumberFormat        *format,
    162                    const u_printf_spec_info     *info,
    163                    UChar *prefixBuffer,
    164                    int32_t *prefixBufLen,
    165                    UErrorCode *status)
    166 {
    167     if(info->fShowSign) {
    168         unum_setTextAttribute(format,
    169                               UNUM_POSITIVE_PREFIX,
    170                               prefixBuffer,
    171                               *prefixBufLen,
    172                               status);
    173     }
    174 }
    175 
    176 
    177 /* handle a '%' */
    178 static int32_t
    179 u_printf_simple_percent_handler(const u_printf_stream_handler  *handler,
    180                                 void                           *context,
    181                                 ULocaleBundle                  *formatBundle,
    182                                 const u_printf_spec_info       *info,
    183                                 const ufmt_args                *args)
    184 {
    185     static const UChar PERCENT[] = { UP_PERCENT };
    186 
    187     /* put a single '%' onto the output */
    188     return handler->write(context, PERCENT, 1);
    189 }
    190 
    191 /* handle 's' */
    192 static int32_t
    193 u_printf_string_handler(const u_printf_stream_handler  *handler,
    194                         void                           *context,
    195                         ULocaleBundle                  *formatBundle,
    196                         const u_printf_spec_info       *info,
    197                         const ufmt_args                *args)
    198 {
    199     UChar *s;
    200     UChar buffer[UFMT_DEFAULT_BUFFER_SIZE];
    201     int32_t len, written;
    202     int32_t argSize;
    203     const char *arg = (const char*)(args[0].ptrValue);
    204 
    205     /* convert from the default codepage to Unicode */
    206     if (arg) {
    207         argSize = (int32_t)strlen(arg) + 1;
    208         if (argSize >= MAX_UCHAR_BUFFER_SIZE(buffer)) {
    209             s = ufmt_defaultCPToUnicode(arg, argSize,
    210                     (UChar *)uprv_malloc(MAX_UCHAR_BUFFER_NEEDED(argSize)),
    211                     MAX_UCHAR_BUFFER_NEEDED(argSize));
    212             if(s == NULL) {
    213                 return 0;
    214             }
    215         }
    216         else {
    217             s = ufmt_defaultCPToUnicode(arg, argSize, buffer,
    218                     sizeof(buffer)/sizeof(UChar));
    219         }
    220     }
    221     else {
    222         s = (UChar *)gNullStr;
    223     }
    224     len = u_strlen(s);
    225 
    226     /* width = minimum # of characters to write */
    227     /* precision = maximum # of characters to write */
    228     if (info->fPrecision != -1 && info->fPrecision < len) {
    229         len = info->fPrecision;
    230     }
    231 
    232     written = handler->pad_and_justify(context, info, s, len);
    233 
    234     /* clean up */
    235     if (gNullStr != s && buffer != s) {
    236         uprv_free(s);
    237     }
    238 
    239     return written;
    240 }
    241 
    242 static int32_t
    243 u_printf_char_handler(const u_printf_stream_handler  *handler,
    244                       void                           *context,
    245                       ULocaleBundle                  *formatBundle,
    246                       const u_printf_spec_info       *info,
    247                       const ufmt_args                *args)
    248 {
    249     UChar s[U16_MAX_LENGTH+1];
    250     int32_t len = 1, written;
    251     unsigned char arg = (unsigned char)(args[0].int64Value);
    252 
    253     /* convert from default codepage to Unicode */
    254     ufmt_defaultCPToUnicode((const char *)&arg, 2, s, sizeof(s)/sizeof(UChar));
    255 
    256     /* Remember that this may be an MBCS character */
    257     if (arg != 0) {
    258         len = u_strlen(s);
    259     }
    260 
    261     /* width = minimum # of characters to write */
    262     /* precision = maximum # of characters to write */
    263     /* precision is ignored when handling a char */
    264 
    265     written = handler->pad_and_justify(context, info, s, len);
    266 
    267     return written;
    268 }
    269 
    270 static int32_t
    271 u_printf_double_handler(const u_printf_stream_handler  *handler,
    272                         void                           *context,
    273                         ULocaleBundle                  *formatBundle,
    274                         const u_printf_spec_info       *info,
    275                         const ufmt_args                *args)
    276 {
    277     double        num         = (double) (args[0].doubleValue);
    278     UNumberFormat  *format;
    279     UChar          result[UPRINTF_BUFFER_SIZE];
    280     UChar          prefixBuffer[UPRINTF_BUFFER_SIZE];
    281     int32_t        prefixBufferLen = sizeof(prefixBuffer);
    282     int32_t        minDecimalDigits;
    283     int32_t        maxDecimalDigits;
    284     int32_t        resultLen;
    285     UErrorCode     status        = U_ZERO_ERROR;
    286 
    287     prefixBuffer[0] = 0;
    288 
    289     /* mask off any necessary bits */
    290     /*  if(! info->fIsLongDouble)
    291     num &= DBL_MAX;*/
    292 
    293     /* get the formatter */
    294     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    295 
    296     /* handle error */
    297     if(format == 0)
    298         return 0;
    299 
    300     /* save the formatter's state */
    301     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    302     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    303 
    304     /* set the appropriate flags and number of decimal digits on the formatter */
    305     if(info->fPrecision != -1) {
    306         /* set the # of decimal digits */
    307         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    308     }
    309     else if(info->fAlt) {
    310         /* '#' means always show decimal point */
    311         /* copy of printf behavior on Solaris - '#' shows 6 digits */
    312         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    313     }
    314     else {
    315         /* # of decimal digits is 6 if precision not specified regardless of locale */
    316         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    317     }
    318 
    319     /* set whether to show the sign */
    320     if (info->fShowSign) {
    321         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    322     }
    323 
    324     /* format the number */
    325     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    326 
    327     if (U_FAILURE(status)) {
    328         resultLen = 0;
    329     }
    330 
    331     /* restore the number format */
    332     /* TODO: Is this needed? */
    333     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    334     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    335 
    336     if (info->fShowSign) {
    337         /* Reset back to original value regardless of what the error was */
    338         UErrorCode localStatus = U_ZERO_ERROR;
    339         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    340     }
    341 
    342     return handler->pad_and_justify(context, info, result, resultLen);
    343 }
    344 
    345 /* HSYS */
    346 static int32_t
    347 u_printf_integer_handler(const u_printf_stream_handler  *handler,
    348                          void                           *context,
    349                          ULocaleBundle                  *formatBundle,
    350                          const u_printf_spec_info       *info,
    351                          const ufmt_args                *args)
    352 {
    353     int64_t         num        = args[0].int64Value;
    354     UNumberFormat   *format;
    355     UChar           result[UPRINTF_BUFFER_SIZE];
    356     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
    357     int32_t         prefixBufferLen = sizeof(prefixBuffer);
    358     int32_t         minDigits     = -1;
    359     int32_t         resultLen;
    360     UErrorCode      status        = U_ZERO_ERROR;
    361 
    362     prefixBuffer[0] = 0;
    363 
    364     /* mask off any necessary bits */
    365     if (info->fIsShort)
    366         num = (int16_t)num;
    367     else if (!info->fIsLongLong)
    368         num = (int32_t)num;
    369 
    370     /* get the formatter */
    371     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    372 
    373     /* handle error */
    374     if(format == 0)
    375         return 0;
    376 
    377     /* set the appropriate flags on the formatter */
    378 
    379     /* set the minimum integer digits */
    380     if(info->fPrecision != -1) {
    381         /* set the minimum # of digits */
    382         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
    383         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    384     }
    385 
    386     /* set whether to show the sign */
    387     if(info->fShowSign) {
    388         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    389     }
    390 
    391     /* format the number */
    392     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    393 
    394     if (U_FAILURE(status)) {
    395         resultLen = 0;
    396     }
    397 
    398     /* restore the number format */
    399     if (minDigits != -1) {
    400         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    401     }
    402 
    403     if (info->fShowSign) {
    404         /* Reset back to original value regardless of what the error was */
    405         UErrorCode localStatus = U_ZERO_ERROR;
    406         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    407     }
    408 
    409     return handler->pad_and_justify(context, info, result, resultLen);
    410 }
    411 
    412 static int32_t
    413 u_printf_hex_handler(const u_printf_stream_handler  *handler,
    414                      void                           *context,
    415                      ULocaleBundle                  *formatBundle,
    416                      const u_printf_spec_info       *info,
    417                      const ufmt_args                *args)
    418 {
    419     int64_t         num        = args[0].int64Value;
    420     UChar           result[UPRINTF_BUFFER_SIZE];
    421     int32_t         len        = UPRINTF_BUFFER_SIZE;
    422 
    423 
    424     /* mask off any necessary bits */
    425     if (info->fIsShort)
    426         num &= UINT16_MAX;
    427     else if (!info->fIsLongLong)
    428         num &= UINT32_MAX;
    429 
    430     /* format the number, preserving the minimum # of digits */
    431     ufmt_64tou(result, &len, num, 16,
    432         (UBool)(info->fSpec == 0x0078),
    433         (info->fPrecision == -1 && info->fZero) ? info->fWidth : info->fPrecision);
    434 
    435     /* convert to alt form, if desired */
    436     if(num != 0 && info->fAlt && len < UPRINTF_BUFFER_SIZE - 2) {
    437         /* shift the formatted string right by 2 chars */
    438         memmove(result + 2, result, len * sizeof(UChar));
    439         result[0] = 0x0030;
    440         result[1] = info->fSpec;
    441         len += 2;
    442     }
    443 
    444     return handler->pad_and_justify(context, info, result, len);
    445 }
    446 
    447 static int32_t
    448 u_printf_octal_handler(const u_printf_stream_handler  *handler,
    449                        void                           *context,
    450                        ULocaleBundle                  *formatBundle,
    451                        const u_printf_spec_info       *info,
    452                        const ufmt_args                *args)
    453 {
    454     int64_t         num        = args[0].int64Value;
    455     UChar           result[UPRINTF_BUFFER_SIZE];
    456     int32_t         len        = UPRINTF_BUFFER_SIZE;
    457 
    458 
    459     /* mask off any necessary bits */
    460     if (info->fIsShort)
    461         num &= UINT16_MAX;
    462     else if (!info->fIsLongLong)
    463         num &= UINT32_MAX;
    464 
    465     /* format the number, preserving the minimum # of digits */
    466     ufmt_64tou(result, &len, num, 8,
    467         FALSE, /* doesn't matter for octal */
    468         info->fPrecision == -1 && info->fZero ? info->fWidth : info->fPrecision);
    469 
    470     /* convert to alt form, if desired */
    471     if(info->fAlt && result[0] != 0x0030 && len < UPRINTF_BUFFER_SIZE - 1) {
    472         /* shift the formatted string right by 1 char */
    473         memmove(result + 1, result, len * sizeof(UChar));
    474         result[0] = 0x0030;
    475         len += 1;
    476     }
    477 
    478     return handler->pad_and_justify(context, info, result, len);
    479 }
    480 
    481 static int32_t
    482 u_printf_uinteger_handler(const u_printf_stream_handler *handler,
    483                           void                          *context,
    484                           ULocaleBundle                 *formatBundle,
    485                           const u_printf_spec_info      *info,
    486                           const ufmt_args               *args)
    487 {
    488     int64_t         num        = args[0].int64Value;
    489     UNumberFormat   *format;
    490     UChar           result[UPRINTF_BUFFER_SIZE];
    491     int32_t         minDigits     = -1;
    492     int32_t         resultLen;
    493     UErrorCode      status        = U_ZERO_ERROR;
    494 
    495     /* TODO: Fix this once uint64_t can be formatted. */
    496     if (info->fIsShort)
    497         num &= UINT16_MAX;
    498     else if (!info->fIsLongLong)
    499         num &= UINT32_MAX;
    500 
    501     /* get the formatter */
    502     format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    503 
    504     /* handle error */
    505     if(format == 0)
    506         return 0;
    507 
    508     /* set the appropriate flags on the formatter */
    509 
    510     /* set the minimum integer digits */
    511     if(info->fPrecision != -1) {
    512         /* set the minimum # of digits */
    513         minDigits = unum_getAttribute(format, UNUM_MIN_INTEGER_DIGITS);
    514         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, info->fPrecision);
    515     }
    516 
    517     /* To mirror other stdio implementations, we ignore the sign argument */
    518 
    519     /* format the number */
    520     resultLen = unum_formatInt64(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    521 
    522     if (U_FAILURE(status)) {
    523         resultLen = 0;
    524     }
    525 
    526     /* restore the number format */
    527     if (minDigits != -1) {
    528         unum_setAttribute(format, UNUM_MIN_INTEGER_DIGITS, minDigits);
    529     }
    530 
    531     return handler->pad_and_justify(context, info, result, resultLen);
    532 }
    533 
    534 static int32_t
    535 u_printf_pointer_handler(const u_printf_stream_handler  *handler,
    536                          void                           *context,
    537                          ULocaleBundle                  *formatBundle,
    538                          const u_printf_spec_info       *info,
    539                          const ufmt_args                *args)
    540 {
    541     UChar           result[UPRINTF_BUFFER_SIZE];
    542     int32_t         len  = UPRINTF_BUFFER_SIZE;
    543 
    544     /* format the pointer in hex */
    545     ufmt_ptou(result, &len, args[0].ptrValue, TRUE/*, info->fPrecision*/);
    546 
    547     return handler->pad_and_justify(context, info, result, len);
    548 }
    549 
    550 static int32_t
    551 u_printf_scientific_handler(const u_printf_stream_handler  *handler,
    552                             void                           *context,
    553                             ULocaleBundle                  *formatBundle,
    554                             const u_printf_spec_info       *info,
    555                             const ufmt_args                *args)
    556 {
    557     double          num         = (double) (args[0].doubleValue);
    558     UNumberFormat   *format;
    559     UChar           result[UPRINTF_BUFFER_SIZE];
    560     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
    561     int32_t         prefixBufferLen = sizeof(prefixBuffer);
    562     int32_t         minDecimalDigits;
    563     int32_t         maxDecimalDigits;
    564     UErrorCode      status        = U_ZERO_ERROR;
    565     UChar srcExpBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
    566     int32_t srcLen, expLen;
    567     int32_t resultLen;
    568     UChar expBuf[UPRINTF_SYMBOL_BUFFER_SIZE];
    569 
    570     prefixBuffer[0] = 0;
    571 
    572     /* mask off any necessary bits */
    573     /*  if(! info->fIsLongDouble)
    574     num &= DBL_MAX;*/
    575 
    576     /* get the formatter */
    577     format = u_locbund_getNumberFormat(formatBundle, UNUM_SCIENTIFIC);
    578 
    579     /* handle error */
    580     if(format == 0)
    581         return 0;
    582 
    583     /* set the appropriate flags on the formatter */
    584 
    585     srcLen = unum_getSymbol(format,
    586         UNUM_EXPONENTIAL_SYMBOL,
    587         srcExpBuf,
    588         sizeof(srcExpBuf),
    589         &status);
    590 
    591     /* Upper/lower case the e */
    592     if (info->fSpec == (UChar)0x65 /* e */) {
    593         expLen = u_strToLower(expBuf, (int32_t)sizeof(expBuf),
    594             srcExpBuf, srcLen,
    595             formatBundle->fLocale,
    596             &status);
    597     }
    598     else {
    599         expLen = u_strToUpper(expBuf, (int32_t)sizeof(expBuf),
    600             srcExpBuf, srcLen,
    601             formatBundle->fLocale,
    602             &status);
    603     }
    604 
    605     unum_setSymbol(format,
    606         UNUM_EXPONENTIAL_SYMBOL,
    607         expBuf,
    608         expLen,
    609         &status);
    610 
    611     /* save the formatter's state */
    612     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    613     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    614 
    615     /* set the appropriate flags and number of decimal digits on the formatter */
    616     if(info->fPrecision != -1) {
    617         /* set the # of decimal digits */
    618         if (info->fOrigSpec == (UChar)0x65 /* e */ || info->fOrigSpec == (UChar)0x45 /* E */) {
    619             unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    620         }
    621         else {
    622             unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, 1);
    623             unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, info->fPrecision);
    624         }
    625     }
    626     else if(info->fAlt) {
    627         /* '#' means always show decimal point */
    628         /* copy of printf behavior on Solaris - '#' shows 6 digits */
    629         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    630     }
    631     else {
    632         /* # of decimal digits is 6 if precision not specified */
    633         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    634     }
    635 
    636     /* set whether to show the sign */
    637     if (info->fShowSign) {
    638         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    639     }
    640 
    641     /* format the number */
    642     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    643 
    644     if (U_FAILURE(status)) {
    645         resultLen = 0;
    646     }
    647 
    648     /* restore the number format */
    649     /* TODO: Is this needed? */
    650     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    651     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    652 
    653     /* Since we're the only one using the scientific
    654        format, we don't need to save the old exponent value. */
    655     /*unum_setSymbol(format,
    656         UNUM_EXPONENTIAL_SYMBOL,
    657         srcExpBuf,
    658         srcLen,
    659         &status);*/
    660 
    661     if (info->fShowSign) {
    662         /* Reset back to original value regardless of what the error was */
    663         UErrorCode localStatus = U_ZERO_ERROR;
    664         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    665     }
    666 
    667     return handler->pad_and_justify(context, info, result, resultLen);
    668 }
    669 
    670 static int32_t
    671 u_printf_percent_handler(const u_printf_stream_handler  *handler,
    672                          void                           *context,
    673                          ULocaleBundle                  *formatBundle,
    674                          const u_printf_spec_info       *info,
    675                          const ufmt_args                *args)
    676 {
    677     double          num         = (double) (args[0].doubleValue);
    678     UNumberFormat   *format;
    679     UChar           result[UPRINTF_BUFFER_SIZE];
    680     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
    681     int32_t         prefixBufferLen = sizeof(prefixBuffer);
    682     int32_t         minDecimalDigits;
    683     int32_t         maxDecimalDigits;
    684     int32_t         resultLen;
    685     UErrorCode      status        = U_ZERO_ERROR;
    686 
    687     prefixBuffer[0] = 0;
    688 
    689     /* mask off any necessary bits */
    690     /*  if(! info->fIsLongDouble)
    691     num &= DBL_MAX;*/
    692 
    693     /* get the formatter */
    694     format = u_locbund_getNumberFormat(formatBundle, UNUM_PERCENT);
    695 
    696     /* handle error */
    697     if(format == 0)
    698         return 0;
    699 
    700     /* save the formatter's state */
    701     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    702     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    703 
    704     /* set the appropriate flags and number of decimal digits on the formatter */
    705     if(info->fPrecision != -1) {
    706         /* set the # of decimal digits */
    707         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    708     }
    709     else if(info->fAlt) {
    710         /* '#' means always show decimal point */
    711         /* copy of printf behavior on Solaris - '#' shows 6 digits */
    712         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    713     }
    714     else {
    715         /* # of decimal digits is 6 if precision not specified */
    716         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    717     }
    718 
    719     /* set whether to show the sign */
    720     if (info->fShowSign) {
    721         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    722     }
    723 
    724     /* format the number */
    725     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    726 
    727     if (U_FAILURE(status)) {
    728         resultLen = 0;
    729     }
    730 
    731     /* restore the number format */
    732     /* TODO: Is this needed? */
    733     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    734     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    735 
    736     if (info->fShowSign) {
    737         /* Reset back to original value regardless of what the error was */
    738         UErrorCode localStatus = U_ZERO_ERROR;
    739         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    740     }
    741 
    742     return handler->pad_and_justify(context, info, result, resultLen);
    743 }
    744 
    745 static int32_t
    746 u_printf_ustring_handler(const u_printf_stream_handler  *handler,
    747                          void                           *context,
    748                          ULocaleBundle                  *formatBundle,
    749                          const u_printf_spec_info       *info,
    750                          const ufmt_args                *args)
    751 {
    752     int32_t len, written;
    753     const UChar *arg = (const UChar*)(args[0].ptrValue);
    754 
    755     /* allocate enough space for the buffer */
    756     if (arg == NULL) {
    757         arg = gNullStr;
    758     }
    759     len = u_strlen(arg);
    760 
    761     /* width = minimum # of characters to write */
    762     /* precision = maximum # of characters to write */
    763     if (info->fPrecision != -1 && info->fPrecision < len) {
    764         len = info->fPrecision;
    765     }
    766 
    767     /* determine if the string should be padded */
    768     written = handler->pad_and_justify(context, info, arg, len);
    769 
    770     return written;
    771 }
    772 
    773 static int32_t
    774 u_printf_uchar_handler(const u_printf_stream_handler  *handler,
    775                        void                           *context,
    776                        ULocaleBundle                  *formatBundle,
    777                        const u_printf_spec_info       *info,
    778                        const ufmt_args                *args)
    779 {
    780     int32_t written = 0;
    781     UChar arg = (UChar)(args[0].int64Value);
    782 
    783     /* width = minimum # of characters to write */
    784     /* precision = maximum # of characters to write */
    785     /* precision is ignored when handling a uchar */
    786 
    787     /* determine if the string should be padded */
    788     written = handler->pad_and_justify(context, info, &arg, 1);
    789 
    790     return written;
    791 }
    792 
    793 static int32_t
    794 u_printf_scidbl_handler(const u_printf_stream_handler  *handler,
    795                         void                           *context,
    796                         ULocaleBundle                  *formatBundle,
    797                         const u_printf_spec_info       *info,
    798                         const ufmt_args                *args)
    799 {
    800     u_printf_spec_info scidbl_info;
    801     double      num = args[0].doubleValue;
    802     int32_t     retVal;
    803     UNumberFormat *format;
    804     int32_t maxSigDecimalDigits, significantDigits;
    805 
    806     memcpy(&scidbl_info, info, sizeof(u_printf_spec_info));
    807 
    808     /* determine whether to use 'd', 'e' or 'f' notation */
    809     if (scidbl_info.fPrecision == -1 && num == uprv_trunc(num))
    810     {
    811         /* use 'f' notation */
    812         scidbl_info.fSpec = 0x0066;
    813         scidbl_info.fPrecision = 0;
    814         /* call the double handler */
    815         retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
    816     }
    817     else if(num < 0.0001 || (scidbl_info.fPrecision < 1 && 1000000.0 <= num)
    818         || (scidbl_info.fPrecision != -1 && num > uprv_pow10(scidbl_info.fPrecision)))
    819     {
    820         /* use 'e' or 'E' notation */
    821         scidbl_info.fSpec = scidbl_info.fSpec - 2;
    822         if (scidbl_info.fPrecision == -1) {
    823             scidbl_info.fPrecision = 5;
    824         }
    825         /* call the scientific handler */
    826         retVal = u_printf_scientific_handler(handler, context, formatBundle, &scidbl_info, args);
    827     }
    828     else {
    829         format = u_locbund_getNumberFormat(formatBundle, UNUM_DECIMAL);
    830         /* Check for null pointer */
    831         if (format == NULL) {
    832             return 0;
    833         }
    834         maxSigDecimalDigits = unum_getAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS);
    835         significantDigits = scidbl_info.fPrecision;
    836 
    837         /* use 'f' notation */
    838         scidbl_info.fSpec = 0x0066;
    839         if (significantDigits == -1) {
    840             significantDigits = 6;
    841         }
    842         unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, TRUE);
    843         unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, significantDigits);
    844         /* call the double handler */
    845         retVal = u_printf_double_handler(handler, context, formatBundle, &scidbl_info, args);
    846         unum_setAttribute(format, UNUM_MAX_SIGNIFICANT_DIGITS, maxSigDecimalDigits);
    847         unum_setAttribute(format, UNUM_SIGNIFICANT_DIGITS_USED, FALSE);
    848     }
    849     return retVal;
    850 }
    851 
    852 static int32_t
    853 u_printf_count_handler(const u_printf_stream_handler  *handler,
    854                        void                           *context,
    855                        ULocaleBundle                  *formatBundle,
    856                        const u_printf_spec_info       *info,
    857                        const ufmt_args                *args)
    858 {
    859     int32_t *count = (int32_t*)(args[0].ptrValue);
    860 
    861     /* in the special case of count, the u_printf_spec_info's width */
    862     /* will contain the # of chars written thus far */
    863     *count = info->fWidth;
    864 
    865     return 0;
    866 }
    867 
    868 static int32_t
    869 u_printf_spellout_handler(const u_printf_stream_handler *handler,
    870                           void                          *context,
    871                           ULocaleBundle                 *formatBundle,
    872                           const u_printf_spec_info      *info,
    873                           const ufmt_args               *args)
    874 {
    875     double          num         = (double) (args[0].doubleValue);
    876     UNumberFormat   *format;
    877     UChar           result[UPRINTF_BUFFER_SIZE];
    878     UChar           prefixBuffer[UPRINTF_BUFFER_SIZE];
    879     int32_t         prefixBufferLen = sizeof(prefixBuffer);
    880     int32_t         minDecimalDigits;
    881     int32_t         maxDecimalDigits;
    882     int32_t         resultLen;
    883     UErrorCode      status        = U_ZERO_ERROR;
    884 
    885     prefixBuffer[0] = 0;
    886 
    887     /* mask off any necessary bits */
    888     /*  if(! info->fIsLongDouble)
    889     num &= DBL_MAX;*/
    890 
    891     /* get the formatter */
    892     format = u_locbund_getNumberFormat(formatBundle, UNUM_SPELLOUT);
    893 
    894     /* handle error */
    895     if(format == 0)
    896         return 0;
    897 
    898     /* save the formatter's state */
    899     minDecimalDigits = unum_getAttribute(format, UNUM_MIN_FRACTION_DIGITS);
    900     maxDecimalDigits = unum_getAttribute(format, UNUM_MAX_FRACTION_DIGITS);
    901 
    902     /* set the appropriate flags and number of decimal digits on the formatter */
    903     if(info->fPrecision != -1) {
    904         /* set the # of decimal digits */
    905         unum_setAttribute(format, UNUM_FRACTION_DIGITS, info->fPrecision);
    906     }
    907     else if(info->fAlt) {
    908         /* '#' means always show decimal point */
    909         /* copy of printf behavior on Solaris - '#' shows 6 digits */
    910         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    911     }
    912     else {
    913         /* # of decimal digits is 6 if precision not specified */
    914         unum_setAttribute(format, UNUM_FRACTION_DIGITS, 6);
    915     }
    916 
    917     /* set whether to show the sign */
    918     if (info->fShowSign) {
    919         u_printf_set_sign(format, info, prefixBuffer, &prefixBufferLen, &status);
    920     }
    921 
    922     /* format the number */
    923     resultLen = unum_formatDouble(format, num, result, UPRINTF_BUFFER_SIZE, 0, &status);
    924 
    925     if (U_FAILURE(status)) {
    926         resultLen = 0;
    927     }
    928 
    929     /* restore the number format */
    930     /* TODO: Is this needed? */
    931     unum_setAttribute(format, UNUM_MIN_FRACTION_DIGITS, minDecimalDigits);
    932     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, maxDecimalDigits);
    933 
    934     if (info->fShowSign) {
    935         /* Reset back to original value regardless of what the error was */
    936         UErrorCode localStatus = U_ZERO_ERROR;
    937         u_printf_reset_sign(format, info, prefixBuffer, &prefixBufferLen, &localStatus);
    938     }
    939 
    940     return handler->pad_and_justify(context, info, result, resultLen);
    941 }
    942 
    943 /* Use US-ASCII characters only for formatting. Most codepages have
    944  characters 20-7F from Unicode. Using any other codepage specific
    945  characters will make it very difficult to format the string on
    946  non-Unicode machines */
    947 static const u_printf_info g_u_printf_infos[UPRINTF_NUM_FMT_HANDLERS] = {
    948 /* 0x20 */
    949     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    950     UFMT_EMPTY,         UFMT_SIMPLE_PERCENT,UFMT_EMPTY,         UFMT_EMPTY,
    951     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    952     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    953 
    954 /* 0x30 */
    955     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    956     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    957     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    958     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    959 
    960 /* 0x40 */
    961     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR,
    962     UFMT_EMPTY,         UFMT_SCIENTIFIC,    UFMT_EMPTY,         UFMT_SCIDBL,
    963 #ifdef U_USE_OBSOLETE_IO_FORMATTING
    964     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_UCHAR/*deprecated*/,
    965 #else
    966     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    967 #endif
    968     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    969 
    970 /* 0x50 */
    971     UFMT_PERCENT,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_USTRING,
    972 #ifdef U_USE_OBSOLETE_IO_FORMATTING
    973     UFMT_EMPTY,         UFMT_USTRING/*deprecated*/,UFMT_SPELLOUT,      UFMT_EMPTY,
    974 #else
    975     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_SPELLOUT,      UFMT_EMPTY,
    976 #endif
    977     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    978     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    979 
    980 /* 0x60 */
    981     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_CHAR,
    982     UFMT_INT,           UFMT_SCIENTIFIC,    UFMT_DOUBLE,        UFMT_SCIDBL,
    983     UFMT_EMPTY,         UFMT_INT,           UFMT_EMPTY,         UFMT_EMPTY,
    984     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_COUNT,         UFMT_OCTAL,
    985 
    986 /* 0x70 */
    987     UFMT_POINTER,       UFMT_EMPTY,         UFMT_EMPTY,         UFMT_STRING,
    988     UFMT_EMPTY,         UFMT_UINT,          UFMT_EMPTY,         UFMT_EMPTY,
    989     UFMT_HEX,           UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    990     UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,         UFMT_EMPTY,
    991 };
    992 
    993 /* flag characters for uprintf */
    994 #define FLAG_MINUS 0x002D
    995 #define FLAG_PLUS 0x002B
    996 #define FLAG_SPACE 0x0020
    997 #define FLAG_POUND 0x0023
    998 #define FLAG_ZERO  0x0030
    999 #define FLAG_PAREN 0x0028
   1000 
   1001 #define ISFLAG(s)    (s) == FLAG_MINUS || \
   1002             (s) == FLAG_PLUS || \
   1003             (s) == FLAG_SPACE || \
   1004             (s) == FLAG_POUND || \
   1005             (s) == FLAG_ZERO || \
   1006             (s) == FLAG_PAREN
   1007 
   1008 /* special characters for uprintf */
   1009 #define SPEC_ASTERISK 0x002A
   1010 #define SPEC_DOLLARSIGN 0x0024
   1011 #define SPEC_PERIOD 0x002E
   1012 #define SPEC_PERCENT 0x0025
   1013 
   1014 /* unicode digits */
   1015 #define DIGIT_ZERO 0x0030
   1016 #define DIGIT_ONE 0x0031
   1017 #define DIGIT_TWO 0x0032
   1018 #define DIGIT_THREE 0x0033
   1019 #define DIGIT_FOUR 0x0034
   1020 #define DIGIT_FIVE 0x0035
   1021 #define DIGIT_SIX 0x0036
   1022 #define DIGIT_SEVEN 0x0037
   1023 #define DIGIT_EIGHT 0x0038
   1024 #define DIGIT_NINE 0x0039
   1025 
   1026 #define ISDIGIT(s)    (s) == DIGIT_ZERO || \
   1027             (s) == DIGIT_ONE || \
   1028             (s) == DIGIT_TWO || \
   1029             (s) == DIGIT_THREE || \
   1030             (s) == DIGIT_FOUR || \
   1031             (s) == DIGIT_FIVE || \
   1032             (s) == DIGIT_SIX || \
   1033             (s) == DIGIT_SEVEN || \
   1034             (s) == DIGIT_EIGHT || \
   1035             (s) == DIGIT_NINE
   1036 
   1037 /* u_printf modifiers */
   1038 #define MOD_H 0x0068
   1039 #define MOD_LOWERL 0x006C
   1040 #define MOD_L 0x004C
   1041 
   1042 #define ISMOD(s)    (s) == MOD_H || \
   1043             (s) == MOD_LOWERL || \
   1044             (s) == MOD_L
   1045 /* Returns an array of the parsed argument type given in the format string. */
   1046 static ufmt_args* parseArguments(const UChar *alias, va_list ap, UErrorCode *status) {
   1047     ufmt_args *arglist = NULL;
   1048     ufmt_type_info *typelist = NULL;
   1049     UBool *islonglong = NULL;
   1050     int32_t size = 0;
   1051     int32_t pos = 0;
   1052     UChar type;
   1053     uint16_t handlerNum;
   1054     const UChar *aliasStart = alias;
   1055 
   1056     /* get maximum number of arguments */
   1057     for(;;) {
   1058         /* find % */
   1059         while(*alias != UP_PERCENT && *alias != 0x0000) {
   1060             alias++;
   1061         }
   1062 
   1063         if(*alias == 0x0000) {
   1064             break;
   1065         }
   1066 
   1067         alias++;
   1068 
   1069         /* handle the pos number */
   1070         if(ISDIGIT(*alias)) {
   1071 
   1072             /* handle positional parameters */
   1073             if(ISDIGIT(*alias)) {
   1074                 pos = (int) (*alias++ - DIGIT_ZERO);
   1075 
   1076                 while(ISDIGIT(*alias)) {
   1077                     pos *= 10;
   1078                     pos += (int) (*alias++ - DIGIT_ZERO);
   1079                 }
   1080             }
   1081 
   1082             /* if there is no '$', don't read anything */
   1083             if(*alias != SPEC_DOLLARSIGN) {
   1084                 return NULL;
   1085             }
   1086         } else {
   1087             return NULL;
   1088         }
   1089 
   1090         if (pos > size) {
   1091             size = pos;
   1092         }
   1093     }
   1094 
   1095     /* create the parsed argument list */
   1096     typelist = (ufmt_type_info*)uprv_malloc(sizeof(ufmt_type_info) * size);
   1097     islonglong = (UBool*)uprv_malloc(sizeof(UBool) * size);
   1098     arglist = (ufmt_args*)uprv_malloc(sizeof(ufmt_args) * size);
   1099 
   1100     /* If malloc failed, return NULL */
   1101     if (!typelist || !islonglong || !arglist) {
   1102         if (typelist) {
   1103             uprv_free(typelist);
   1104         }
   1105 
   1106         if (islonglong) {
   1107             uprv_free(islonglong);
   1108         }
   1109 
   1110         if (arglist) {
   1111             uprv_free(arglist);
   1112         }
   1113 
   1114         *status = U_MEMORY_ALLOCATION_ERROR;
   1115         return NULL;
   1116     }
   1117 
   1118     /* reset alias back to the beginning */
   1119     alias = aliasStart;
   1120 
   1121     for(;;) {
   1122         /* find % */
   1123         while(*alias != UP_PERCENT && *alias != 0x0000) {
   1124             alias++;
   1125         }
   1126 
   1127         if(*alias == 0x0000) {
   1128             break;
   1129         }
   1130 
   1131         alias++;
   1132 
   1133         /* handle positional parameters */
   1134         if(ISDIGIT(*alias)) {
   1135             pos = (int) (*alias++ - DIGIT_ZERO);
   1136 
   1137             while(ISDIGIT(*alias)) {
   1138                 pos *= 10;
   1139                 pos += (int) (*alias++ - DIGIT_ZERO);
   1140             }
   1141         }
   1142         /* offset position by 1 */
   1143         pos--;
   1144 
   1145         /* skip over everything except for the type */
   1146         while (ISMOD(*alias) || ISFLAG(*alias) || ISDIGIT(*alias) ||
   1147             *alias == SPEC_ASTERISK || *alias == SPEC_PERIOD || *alias == SPEC_DOLLARSIGN) {
   1148                 islonglong[pos] = FALSE;
   1149                 if (ISMOD(*alias)) {
   1150                     alias++;
   1151                     if (*alias == MOD_LOWERL) {
   1152                         islonglong[pos] = TRUE;
   1153                     }
   1154                 }
   1155                 alias++;
   1156         }
   1157         type = *alias;
   1158 
   1159         /* store the argument type in the correct position of the parsed argument list */
   1160         handlerNum = (uint16_t)(type - UPRINTF_BASE_FMT_HANDLERS);
   1161         if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
   1162             typelist[pos] = g_u_printf_infos[ handlerNum ].info;
   1163         } else {
   1164             typelist[pos] = ufmt_empty;
   1165         }
   1166     }
   1167 
   1168     /* store argument in arglist */
   1169     for (pos = 0; pos < size; pos++) {
   1170         switch (typelist[pos]) {
   1171         case ufmt_string:
   1172         case ufmt_ustring:
   1173         case ufmt_pointer:
   1174             arglist[pos].ptrValue = va_arg(ap, void*);
   1175             break;
   1176         case ufmt_char:
   1177         case ufmt_uchar:
   1178         case ufmt_int:
   1179             if (islonglong[pos]) {
   1180                 arglist[pos].int64Value = va_arg(ap, int64_t);
   1181             }
   1182             else {
   1183                 arglist[pos].int64Value = va_arg(ap, int32_t);
   1184             }
   1185             break;
   1186         case ufmt_float:
   1187             arglist[pos].floatValue = (float) va_arg(ap, double);
   1188             break;
   1189         case ufmt_double:
   1190             arglist[pos].doubleValue = va_arg(ap, double);
   1191             break;
   1192         default:
   1193             /* else args is ignored */
   1194             arglist[pos].ptrValue = NULL;
   1195             break;
   1196         }
   1197     }
   1198 
   1199     uprv_free(typelist);
   1200     uprv_free(islonglong);
   1201 
   1202     return arglist;
   1203 }
   1204 
   1205 /* We parse the argument list in Unicode */
   1206 U_CFUNC int32_t
   1207 u_printf_parse(const u_printf_stream_handler *streamHandler,
   1208                const UChar     *fmt,
   1209                void            *context,
   1210                u_localized_print_string *locStringContext,
   1211                ULocaleBundle   *formatBundle,
   1212                int32_t         *written,
   1213                va_list         ap)
   1214 {
   1215     uint16_t         handlerNum;
   1216     ufmt_args        args;
   1217     ufmt_type_info   argType;
   1218     u_printf_handler *handler;
   1219     u_printf_spec    spec;
   1220     u_printf_spec_info *info = &(spec.fInfo);
   1221 
   1222     const UChar *alias = fmt;
   1223     const UChar *backup;
   1224     const UChar *lastAlias;
   1225     const UChar *orgAlias = fmt;
   1226     /* parsed argument list */
   1227     ufmt_args *arglist = NULL; /* initialized it to avoid compiler warnings */
   1228     UErrorCode status = U_ZERO_ERROR;
   1229     if (!locStringContext || locStringContext->available >= 0) {
   1230         /* get the parsed list of argument types */
   1231         arglist = parseArguments(orgAlias, ap, &status);
   1232 
   1233         /* Return error if parsing failed. */
   1234         if (U_FAILURE(status)) {
   1235             return -1;
   1236         }
   1237     }
   1238 
   1239     /* iterate through the pattern */
   1240     while(!locStringContext || locStringContext->available >= 0) {
   1241 
   1242         /* find the next '%' */
   1243         lastAlias = alias;
   1244         while(*alias != UP_PERCENT && *alias != 0x0000) {
   1245             alias++;
   1246         }
   1247 
   1248         /* write any characters before the '%' */
   1249         if(alias > lastAlias) {
   1250             *written += (streamHandler->write)(context, lastAlias, (int32_t)(alias - lastAlias));
   1251         }
   1252 
   1253         /* break if at end of string */
   1254         if(*alias == 0x0000) {
   1255             break;
   1256         }
   1257 
   1258         /* initialize spec to default values */
   1259         spec.fWidthPos     = -1;
   1260         spec.fPrecisionPos = -1;
   1261         spec.fArgPos       = -1;
   1262 
   1263         uprv_memset(info, 0, sizeof(*info));
   1264         info->fPrecision    = -1;
   1265         info->fWidth        = -1;
   1266         info->fPadChar      = 0x0020;
   1267 
   1268         /* skip over the initial '%' */
   1269         alias++;
   1270 
   1271         /* Check for positional argument */
   1272         if(ISDIGIT(*alias)) {
   1273 
   1274             /* Save the current position */
   1275             backup = alias;
   1276 
   1277             /* handle positional parameters */
   1278             if(ISDIGIT(*alias)) {
   1279                 spec.fArgPos = (int) (*alias++ - DIGIT_ZERO);
   1280 
   1281                 while(ISDIGIT(*alias)) {
   1282                     spec.fArgPos *= 10;
   1283                     spec.fArgPos += (int) (*alias++ - DIGIT_ZERO);
   1284                 }
   1285             }
   1286 
   1287             /* if there is no '$', don't read anything */
   1288             if(*alias != SPEC_DOLLARSIGN) {
   1289                 spec.fArgPos = -1;
   1290                 alias = backup;
   1291             }
   1292             /* munge the '$' */
   1293             else
   1294                 alias++;
   1295         }
   1296 
   1297         /* Get any format flags */
   1298         while(ISFLAG(*alias)) {
   1299             switch(*alias++) {
   1300 
   1301                 /* left justify */
   1302             case FLAG_MINUS:
   1303                 info->fLeft = TRUE;
   1304                 break;
   1305 
   1306                 /* always show sign */
   1307             case FLAG_PLUS:
   1308                 info->fShowSign = TRUE;
   1309                 break;
   1310 
   1311                 /* use space if no sign present */
   1312             case FLAG_SPACE:
   1313                 info->fShowSign = TRUE;
   1314                 info->fSpace = TRUE;
   1315                 break;
   1316 
   1317                 /* use alternate form */
   1318             case FLAG_POUND:
   1319                 info->fAlt = TRUE;
   1320                 break;
   1321 
   1322                 /* pad with leading zeroes */
   1323             case FLAG_ZERO:
   1324                 info->fZero = TRUE;
   1325                 info->fPadChar = 0x0030;
   1326                 break;
   1327 
   1328                 /* pad character specified */
   1329             case FLAG_PAREN:
   1330 
   1331                 /* TODO test that all four are numbers */
   1332                 /* first four characters are hex values for pad char */
   1333                 info->fPadChar = (UChar)ufmt_digitvalue(*alias++);
   1334                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1335                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1336                 info->fPadChar = (UChar)((info->fPadChar * 16) + ufmt_digitvalue(*alias++));
   1337 
   1338                 /* final character is ignored */
   1339                 alias++;
   1340 
   1341                 break;
   1342             }
   1343         }
   1344 
   1345         /* Get the width */
   1346 
   1347         /* width is specified out of line */
   1348         if(*alias == SPEC_ASTERISK) {
   1349 
   1350             info->fWidth = -2;
   1351 
   1352             /* Skip the '*' */
   1353             alias++;
   1354 
   1355             /* Save the current position */
   1356             backup = alias;
   1357 
   1358             /* handle positional parameters */
   1359             if(ISDIGIT(*alias)) {
   1360                 spec.fWidthPos = (int) (*alias++ - DIGIT_ZERO);
   1361 
   1362                 while(ISDIGIT(*alias)) {
   1363                     spec.fWidthPos *= 10;
   1364                     spec.fWidthPos += (int) (*alias++ - DIGIT_ZERO);
   1365                 }
   1366             }
   1367 
   1368             /* if there is no '$', don't read anything */
   1369             if(*alias != SPEC_DOLLARSIGN) {
   1370                 spec.fWidthPos = -1;
   1371                 alias = backup;
   1372             }
   1373             /* munge the '$' */
   1374             else
   1375                 alias++;
   1376         }
   1377         /* read the width, if present */
   1378         else if(ISDIGIT(*alias)){
   1379             info->fWidth = (int) (*alias++ - DIGIT_ZERO);
   1380 
   1381             while(ISDIGIT(*alias)) {
   1382                 info->fWidth *= 10;
   1383                 info->fWidth += (int) (*alias++ - DIGIT_ZERO);
   1384             }
   1385         }
   1386 
   1387         /* Get the precision */
   1388 
   1389         if(*alias == SPEC_PERIOD) {
   1390 
   1391             /* eat up the '.' */
   1392             alias++;
   1393 
   1394             /* precision is specified out of line */
   1395             if(*alias == SPEC_ASTERISK) {
   1396 
   1397                 info->fPrecision = -2;
   1398 
   1399                 /* Skip the '*' */
   1400                 alias++;
   1401 
   1402                 /* save the current position */
   1403                 backup = alias;
   1404 
   1405                 /* handle positional parameters */
   1406                 if(ISDIGIT(*alias)) {
   1407                     spec.fPrecisionPos = (int) (*alias++ - DIGIT_ZERO);
   1408 
   1409                     while(ISDIGIT(*alias)) {
   1410                         spec.fPrecisionPos *= 10;
   1411                         spec.fPrecisionPos += (int) (*alias++ - DIGIT_ZERO);
   1412                     }
   1413 
   1414                     /* if there is no '$', don't read anything */
   1415                     if(*alias != SPEC_DOLLARSIGN) {
   1416                         spec.fPrecisionPos = -1;
   1417                         alias = backup;
   1418                     }
   1419                     else {
   1420                         /* munge the '$' */
   1421                         alias++;
   1422                     }
   1423                 }
   1424             }
   1425             /* read the precision */
   1426             else if(ISDIGIT(*alias)){
   1427                 info->fPrecision = (int) (*alias++ - DIGIT_ZERO);
   1428 
   1429                 while(ISDIGIT(*alias)) {
   1430                     info->fPrecision *= 10;
   1431                     info->fPrecision += (int) (*alias++ - DIGIT_ZERO);
   1432                 }
   1433             }
   1434         }
   1435 
   1436         /* Get any modifiers */
   1437         if(ISMOD(*alias)) {
   1438             switch(*alias++) {
   1439 
   1440                 /* short */
   1441             case MOD_H:
   1442                 info->fIsShort = TRUE;
   1443                 break;
   1444 
   1445                 /* long or long long */
   1446             case MOD_LOWERL:
   1447                 if(*alias == MOD_LOWERL) {
   1448                     info->fIsLongLong = TRUE;
   1449                     /* skip over the next 'l' */
   1450                     alias++;
   1451                 }
   1452                 else
   1453                     info->fIsLong = TRUE;
   1454                 break;
   1455 
   1456                 /* long double */
   1457             case MOD_L:
   1458                 info->fIsLongDouble = TRUE;
   1459                 break;
   1460             }
   1461         }
   1462 
   1463         /* finally, get the specifier letter */
   1464         info->fSpec = *alias++;
   1465         info->fOrigSpec = info->fSpec;
   1466 
   1467         /* fill in the precision and width, if specified out of line */
   1468 
   1469         /* width specified out of line */
   1470         if(spec.fInfo.fWidth == -2) {
   1471             if(spec.fWidthPos == -1) {
   1472                 /* read the width from the argument list */
   1473                 info->fWidth = va_arg(ap, int32_t);
   1474             }
   1475             /* else handle positional parameter */
   1476 
   1477             /* if it's negative, take the absolute value and set left alignment */
   1478             if(info->fWidth < 0) {
   1479                 info->fWidth *= -1; /* Make positive */
   1480                 info->fLeft = TRUE;
   1481             }
   1482         }
   1483 
   1484         /* precision specified out of line */
   1485         if(info->fPrecision == -2) {
   1486             if(spec.fPrecisionPos == -1) {
   1487                 /* read the precision from the argument list */
   1488                 info->fPrecision = va_arg(ap, int32_t);
   1489             }
   1490             /* else handle positional parameter */
   1491 
   1492             /* if it's negative, set it to zero */
   1493             if(info->fPrecision < 0)
   1494                 info->fPrecision = 0;
   1495         }
   1496 
   1497         handlerNum = (uint16_t)(info->fSpec - UPRINTF_BASE_FMT_HANDLERS);
   1498         if (handlerNum < UPRINTF_NUM_FMT_HANDLERS) {
   1499             /* query the info function for argument information */
   1500             argType = g_u_printf_infos[ handlerNum ].info;
   1501 
   1502             /* goto the correct argument on arg_list if position is specified */
   1503             if (spec.fArgPos > 0) {
   1504                 /* offset position by 1 */
   1505                 spec.fArgPos--;
   1506                 switch(argType) {
   1507                 case ufmt_count:
   1508                     /* set the spec's width to the # of chars written */
   1509                     info->fWidth = *written;
   1510                     /* fall through to set the pointer */
   1511                 case ufmt_string:
   1512                 case ufmt_ustring:
   1513                 case ufmt_pointer:
   1514                     args.ptrValue = arglist[spec.fArgPos].ptrValue;
   1515                     break;
   1516                 case ufmt_char:
   1517                 case ufmt_uchar:
   1518                 case ufmt_int:
   1519                     args.int64Value = arglist[spec.fArgPos].int64Value;
   1520                     break;
   1521                 case ufmt_float:
   1522                     args.floatValue = arglist[spec.fArgPos].floatValue;
   1523                     break;
   1524                 case ufmt_double:
   1525                     args.doubleValue = arglist[spec.fArgPos].doubleValue;
   1526                     break;
   1527                 default:
   1528                     /* else args is ignored */
   1529                     args.ptrValue = NULL;
   1530                     break;
   1531                 }
   1532             } else { /* no positional argument specified */
   1533                 switch(argType) {
   1534                 case ufmt_count:
   1535                     /* set the spec's width to the # of chars written */
   1536                     info->fWidth = *written;
   1537                     /* fall through to set the pointer */
   1538                 case ufmt_string:
   1539                 case ufmt_ustring:
   1540                 case ufmt_pointer:
   1541                     args.ptrValue = va_arg(ap, void*);
   1542                     break;
   1543                 case ufmt_char:
   1544                 case ufmt_uchar:
   1545                 case ufmt_int:
   1546                     if (info->fIsLongLong) {
   1547                         args.int64Value = va_arg(ap, int64_t);
   1548                     }
   1549                     else {
   1550                         args.int64Value = va_arg(ap, int32_t);
   1551                     }
   1552                     break;
   1553                 case ufmt_float:
   1554                     args.floatValue = (float) va_arg(ap, double);
   1555                     break;
   1556                 case ufmt_double:
   1557                     args.doubleValue = va_arg(ap, double);
   1558                     break;
   1559                 default:
   1560                     /* else args is ignored */
   1561                     args.ptrValue = NULL;
   1562                     break;
   1563                 }
   1564             }
   1565 
   1566             /* call the handler function */
   1567             handler = g_u_printf_infos[ handlerNum ].handler;
   1568             if(handler != 0) {
   1569                 *written += (*handler)(streamHandler, context, formatBundle, info, &args);
   1570             }
   1571             else {
   1572                 /* just echo unknown tags */
   1573                 *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
   1574             }
   1575         }
   1576         else {
   1577             /* just echo unknown tags */
   1578             *written += (streamHandler->write)(context, fmt, (int32_t)(alias - lastAlias));
   1579         }
   1580     }
   1581     /* delete parsed argument list */
   1582     if (arglist != NULL) {
   1583         uprv_free(arglist);
   1584     }
   1585     /* return # of characters in this format that have been parsed. */
   1586     return (int32_t)(alias - fmt);
   1587 }
   1588 
   1589 #endif /* #if !UCONFIG_NO_FORMATTING */
   1590