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